FX5_Divergence_v1.1_v1
Download scriptThis script is a specialized technical analysis tool designed for the MetaTrader 4 platform to identify "divergences"—a significant market phenomenon where the price movement of an asset contradicts the momentum shown by a technical indicator. By highlighting these discrepancies, the tool aims to help traders spot potential trend reversals before they happen.
Core Mathematical Foundation
The logic begins by calculating two primary components:
- MACD (Moving Average Convergence Divergence): The script first measures the distance between two different types of moving averages (Fast and Slow).
- OSMA (Oscillating Stochastic Momentum Accelerator): It then takes that MACD value and subtracts a "Signal" line from it. This produces the OSMA, which oscillates above and below a zero line, representing the underlying momentum of the market.
The Detection Logic
The primary purpose of this script is to look for specific patterns between the actual price of the asset and the values on the OSMA indicator. It scans the historical data to find "peaks" (high points) and "troughs" (low points) in both the price and the indicator.
Bearish Divergence (Potential Sell Signal): The script looks for a situation where:
- The Price makes a new higher high (the current peak is higher than the previous peak).
- However, the OSMA Indicator fails to reach that same height (the current indicator peak is lower than the previous one).
- Meaning: The price is pushing up, but the momentum behind it is weakening.
Bullish Divergence (Potential Buy Signal): The script looks for a situation where:
- The Price makes a new lower low (the current trough is lower than the previous one).
- However, the OSMA Indicator fails to drop that low (the current indicator trough is higher than the previous one).
- Meaning: The price is dropping, but the selling pressure is losing strength.
Visual Presentation
To make these findings easy for a trader to see at a glance, the script provides several visual aids:
- Arrows: It places specific colored arrows (Red for Bearish, Green for Bullish) on the chart at the exact moment it detects a divergence.
- Trend Lines: If enabled in the settings, the script automatically draws connecting lines. It links the two price peaks/troughs together and simultaneously draws a corresponding line on the indicator window. This allows the user to visually "see" the gap between the price action and the momentum.
- Histogram: It maintains a visual representation of the OSMA values in a separate window, providing a steady stream of data for the user to monitor.
Summary for the User
In simple terms, this tool acts as a "contradiction detector." It watches the market to see if the price is lying about its strength. When the price tries to move in one direction but the internal momentum (OSMA) shows it is getting tired, the script flags this with colors and lines to alert you of a potential change in trend.
//+------------------------------------------------------------------+
//| 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 Gold
#property indicator_color2 FireBrick
#property indicator_color3 Green
#property indicator_color4 Red
//---- input parameters
extern string separator1="*** OSMA Settings ***";
extern int fastEMA=12;
extern int slowEMA=26;
extern int signal=9;
extern string separator2="*** Indicator Settings";
extern double positiveSensitivity=0.0001;
extern double negativeSensitivity=-0.0001;
extern double historyBarsCount=0;
extern bool drawDivergenceLines=true;
//---- 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("FX5_Divergence(" + fastEMA + "," + slowEMA +
"," + signal + ")");
//----
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]=MACD[i] - Signal[i];
//----
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