Author: ViDan
DiverStoch

This tool is designed to identify specific price movements known as "divergences." In trading, a divergence occurs when the price of an asset moves in one direction, but a secondary technical indicator—in this case, the Stochastic Oscillator—moves in the opposite direction. This mismatch often suggests that the current trend is losing momentum and a reversal might be approaching.

Core Functionality

The script automatically scans your trading chart to perform the following actions:

1. Automatic Indicator Detection Instead of requiring you to manually enter complex settings, the script actively looks for an existing Stochastic Oscillator on your chart. Once it finds one, it automatically syncs its own calculations with that indicator’s specific periods and settings (K-period, D-period, and Slowing).

2. Divergence Identification The logic focuses on two primary types of signals:

  • Bullish Divergence: The script looks for moments where the price reaches a "lower low" (the price is dropping), but the Stochastic indicator forms a "higher low." This can signal that selling pressure is weakening and an upward move may be coming.
  • Bearish Divergence: The script identifies points where the price hits a "higher high," but the Stochastic indicator shows a "lower high." This suggests that buying momentum is fading and a downward move might follow.

3. Visual Mapping When the script detects these patterns, it draws clear visual aids directly on your chart:

  • Price Trend Lines: It draws lines connecting the highs or lows of the actual price candles to show you exactly where the divergence began.
  • Indicator Trend Lines: Simultaneously, it draws corresponding lines on the Stochastic Oscillator window to highlight the opposing movement.
  • Visual Distinction: The script uses different line styles (solid vs. dotted) to differentiate between "Classical" divergences and "Reverse" divergences, providing a clearer picture of the market's character.

4. Notifications For traders who need immediate attention, the script includes an optional alert system. If enabled, it will generate a pop-up notification on your screen whenever a new divergence is detected, specifying whether it is bullish or bearish and which specific timeframe/indicator it occurred on.

Summary of Logic Flow

  1. Scan: The tool identifies the Stochastic settings from your current chart.
  2. Monitor: It continuously watches for "peaks" (high points) and "troughs" (low points) in both the price and the indicator.
  3. Compare: It compares the most recent peak/trough to the previous one.
  4. Signal: If the price and the indicator disagree on the direction of the move, it draws lines on both the price chart and the indicator window to alert you to the potential reversal.
Indicators Used
Stochastic oscillator
Miscellaneous
Implements a curve of type %1It issuies visual alerts to the screen
18 Views
0 Downloads
0 Favorites
DiverStoch
//+------------------------------------------------------------------+
//|                                                   DiverStoch.mq4 |
//|                                                            ViDan |
//|                                                vi_dancom@mail.ru |
//+------------------------------------------------------------------+
#property copyright "ViDan"
#property link      "vi_dancom@mail.ru"

#property indicator_chart_window
#property indicator_buffers 3

#define arrowsDisplacement 0.0001
extern color  ColorBull = Blue;
extern color  ColorBear = Red;
extern bool   displayAlert = false;//true;
extern bool   English = false;
//---- buffers
//Äëÿ ñòîõàñòèêà
extern int KPeriod = 5;
extern int DPeriod = 3;
extern int Slowing = 3;
double StochLineBuffer[];
double bullishDivergence[];
double bearishDivergence[];
//---- variables
//////
//----
static datetime lastAlertTime;
static string   indicatorName;
static bool b_first = true;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
{
   //---- indicators
   SetIndexStyle(0, DRAW_NONE);
   SetIndexBuffer(0, StochLineBuffer);
   SetIndexStyle(1, DRAW_NONE);
   SetIndexBuffer(1, bullishDivergence);
   SetIndexStyle(2, DRAW_NONE);
   SetIndexBuffer(2, bearishDivergence);
   return(0);
}
//+------------------------------------------------------------------+
//| Custor indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
   for(int i = ObjectsTotal() - 1; i >= 0; i--)
     {
       string label = ObjectName(i);
       if(StringSubstr(label, 0, 20) != "Stoch_DivergenceLine")
           continue;
       ObjectDelete(label);   
     }
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   if (b_first)
//Åñëè ïåðâûé çàïóñê - íàéäåì ñòîõàñòèê è îïðåäåëèì åãî ïàðàìåòðû
   {
   string s_parStoch = s_isStoch();
if (s_parStoch !="")
{ 
//   if (s_parStoch =="") 
//   {
//   if (English) Alert ("No Stochastic!   ", Symbol(), " , ", s_GetPeriod (Period()));
//   else Alert ("Íà ãðàôèêå íåò ñòîõàñòèêà!   ", Symbol(), " , ", s_GetPeriod (Period()));
      //return(0);
//   }
 KPeriod = StrToDouble(s_GetPer(s_parStoch, ",",1));
 DPeriod = StrToDouble(s_GetPer(s_parStoch, ",",2));
 Slowing = StrToDouble(s_GetPer(s_parStoch, ",",3));
indicatorName =("Stoch(" + KPeriod+"," + DPeriod + "," + Slowing + ")");
}
b_first = false;
   }
      
   int limit;
   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--;
   limit = Bars - counted_bars;
   CalculateIndicator(counted_bars);
//----
   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CalculateIndicator(int countedBars)
  {
   for(int i = Bars - countedBars; i >= 0; i--)
     {
       CalculateStoch(i);
       CatchBullishDivergence(i + 2);
       CatchBearishDivergence(i + 2);
     }              
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CalculateStoch(int i)
  {
   StochLineBuffer[i] = iStochastic(NULL, 0,KPeriod,DPeriod,Slowing,MODE_SMA,0,MODE_MAIN,i);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CatchBullishDivergence(int shift)
  {
   if(IsIndicatorTrough(shift) == false)
       return;  
   int currentTrough = shift;
   int lastTrough = GetIndicatorLastTrough(shift);
//----   
   if(StochLineBuffer[currentTrough] > StochLineBuffer[lastTrough] && 
      Low[currentTrough] < Low[lastTrough])
     {
       bullishDivergence[currentTrough] = StochLineBuffer[currentTrough] - 
                                          arrowsDisplacement;
       //----
           DrawPriceTrendLine(Time[currentTrough], Time[lastTrough], 
                              Low[currentTrough], 
                             Low[lastTrough], ColorBull, STYLE_SOLID);
       //----
          DrawIndicatorTrendLine(Time[currentTrough], 
                                 Time[lastTrough], 
                                 StochLineBuffer[currentTrough],
                                 StochLineBuffer[lastTrough], 
                                 ColorBull, STYLE_SOLID);
       //----
       if(displayAlert == true)
          if (English) DisplayAlert("Classical bullish divergence on: "+indicatorName+", ", currentTrough);  
          else  DisplayAlert("Êëàññè÷åñêàÿ áû÷üÿ äèâåðãåíöèÿ íà: "+indicatorName+", ", currentTrough);  
     }
//----   
   if(StochLineBuffer[currentTrough] < StochLineBuffer[lastTrough] && 
      Low[currentTrough] > Low[lastTrough])
     {
       bullishDivergence[currentTrough] = StochLineBuffer[currentTrough] - 
                                          arrowsDisplacement;
       //----
           DrawPriceTrendLine(Time[currentTrough], Time[lastTrough], 
                              Low[currentTrough], 
                              Low[lastTrough], ColorBull, STYLE_DOT);
       //----
           DrawIndicatorTrendLine(Time[currentTrough], 
                                  Time[lastTrough], 
                                  StochLineBuffer[currentTrough],
                                  StochLineBuffer[lastTrough], 
                                  ColorBull, STYLE_DOT);
       //----
       if(displayAlert == true)
           if (English)DisplayAlert("Reverse bullish divergence on: "+indicatorName+", ", currentTrough);   
           else DisplayAlert("Îáðàòíàÿ áû÷üÿ äèâåðãåíöèÿ íà: "+indicatorName+", ", currentTrough);   
     }      
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CatchBearishDivergence(int shift)
  {
   if(IsIndicatorPeak(shift) == false)
       return;
   int currentPeak = shift;
   int lastPeak = GetIndicatorLastPeak(shift);
//----   
   if(StochLineBuffer[currentPeak] < StochLineBuffer[lastPeak] && 
      High[currentPeak] > High[lastPeak])
     {
       bearishDivergence[currentPeak] = StochLineBuffer[currentPeak] + 
                                        arrowsDisplacement;
      
           DrawPriceTrendLine(Time[currentPeak], Time[lastPeak], 
                              High[currentPeak], 
                              High[lastPeak], ColorBear, STYLE_SOLID);
                            
           DrawIndicatorTrendLine(Time[currentPeak], Time[lastPeak], 
                                  StochLineBuffer[currentPeak],
                                  StochLineBuffer[lastPeak], ColorBear, STYLE_SOLID);

       if(displayAlert == true)
           if (English) DisplayAlert("Classical bearish divergence on: "+indicatorName+", ", currentPeak);  
           else DisplayAlert("Êëàññè÷åñêàÿ ìåäâåæüÿ äèâåðãåíöèÿ íà: "+indicatorName+", ", currentPeak);  
     }
   if(StochLineBuffer[currentPeak] > StochLineBuffer[lastPeak] && 
      High[currentPeak] < High[lastPeak])
     {
       bearishDivergence[currentPeak] = StochLineBuffer[currentPeak] + 
                                        arrowsDisplacement;
       //----
           DrawPriceTrendLine(Time[currentPeak], Time[lastPeak], 
                              High[currentPeak], 
                              High[lastPeak], ColorBear, STYLE_DOT);
       //----
           DrawIndicatorTrendLine(Time[currentPeak], Time[lastPeak], 
                                  StochLineBuffer[currentPeak],
                                  StochLineBuffer[lastPeak], ColorBear, STYLE_DOT);
       //----
       if(displayAlert == true)
           if (English) DisplayAlert("Reverse bearish divergence on: "+indicatorName+", ", currentPeak);   
           else DisplayAlert("Îáðàòíàÿ ìåäâåæüÿ äèâåðãåíöèÿ íà: "+indicatorName+", ", currentPeak);   
        }   
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsIndicatorPeak(int shift)
  {
   if(StochLineBuffer[shift] >= StochLineBuffer[shift+1] && StochLineBuffer[shift] > StochLineBuffer[shift+2] && 
      StochLineBuffer[shift] > StochLineBuffer[shift-1])
       return(true);
   else 
       return(false);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsIndicatorTrough(int shift)
  {
   if(StochLineBuffer[shift] <= StochLineBuffer[shift+1] && StochLineBuffer[shift] < StochLineBuffer[shift+2] && 
      StochLineBuffer[shift] < StochLineBuffer[shift-1])
       return(true);
   else 
       return(false);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int GetIndicatorLastPeak(int shift)
  {
   for(int i = shift + 5; i < Bars; i++)
     {
         {
           for(int j = i; j < Bars; j++)
             {
               if(StochLineBuffer[j] >= StochLineBuffer[j+1] && StochLineBuffer[j] > StochLineBuffer[j+2] &&
                  StochLineBuffer[j] >= StochLineBuffer[j-1] && StochLineBuffer[j] > StochLineBuffer[j-2])
                   return(j);
             }
         }
     }
   return(-1);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int GetIndicatorLastTrough(int shift)
  {
    for(int i = shift + 5; i < Bars; i++)
      {
          {
            for (int j = i; j < Bars; j++)
              {
                if(StochLineBuffer[j] <= StochLineBuffer[j+1] && StochLineBuffer[j] < StochLineBuffer[j+2] &&
                   StochLineBuffer[j] <= StochLineBuffer[j-1] && StochLineBuffer[j] < StochLineBuffer[j-2])
                    return(j);
              }
          }
      }
    return(-1);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DisplayAlert(string message, int shift)
  {
   if(shift <= 2 && Time[shift] != lastAlertTime)
     {
       lastAlertTime = Time[shift];
       Alert(message, Symbol(), " , ", s_GetPeriod (Period()));
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DrawPriceTrendLine(datetime x1, datetime x2, double y1, 
                        double y2, color lineColor, double style)
  {
   string label = "Stoch_DivergenceLine.0# " + 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(indicatorName);
   if(indicatorWindow < 0)
       return;
   string label = "Stoch_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);
  }
//+------------------------------------------------------------------+
////Ôóíêöèÿ âîçâðàùàåò ïàðàìåòðû ñòàíäàðòíîãî ñòîõàñòèêà, åñëè îí ïðèñóòñòâóåò íà ãðàôèêå
  string s_isStoch()
 {
    for (int j = 1; j <=34; j++)
    {
      for (int i = 1; i <=13; i++)
      {
         for (int k = 1; k <=13; k++)
         {
          if (WindowFind("Stoch(" + DoubleToStr(j,0)+"," + DoubleToStr(i,0) + "," 
          + DoubleToStr(k,0) + ")") != -1) return(DoubleToStr(j,0)+"," + DoubleToStr(i,0) 
          + "," + DoubleToStr(k,0));
         }
      }
    }
 }
//+------------------------------------------------------------------+
////Âûäåëÿåò ïåðåìåííóþ èç ïåðå÷èñëåíèÿ ñ ðàçäåëèòåëåì razD
string s_GetPer(string s_stRoka, string s_razD,int i_pozPer)
{
string s_vrPer = s_stRoka + s_razD;
string s_mnk1S = "", s_mnk1;
int i_mnk = 0;
for (int j = 0; j <= StringLen(s_vrPer)-1;j++)
  {
s_mnk1 = StringSubstr(s_vrPer, j, 1);
    if (s_mnk1 == s_razD) 
    {
     i_mnk++;
     if (i_mnk < i_pozPer) s_mnk1S = "";
    }
    else
    {
     s_mnk1S = s_mnk1S + s_mnk1;
    }
     if (i_mnk == i_pozPer) return (s_mnk1S);
  }
}

///Âîçâðàùàåò ïåðèîä ãðàôèêà â âèäå ñòðîêè
string s_GetPeriod (int i_per)
{
switch ( i_per )
    {
        case 1:            return("M1 ");
        case 5:            return("M5 ");
        case 15:           return("M15");
        case 30:           return("M30");
        case 60:           return("H1 ");
        case 240:          return("H4 ");
        case 1440:         return("D1 ");
        case 10080:        return("W1 ");
        case 43200:        return("MN1");
    }
}

Comments