FX5_Divergence_v1-1_realtime[1]
Download scriptThis tool is designed to identify "divergences" in the financial markets—a specific scenario where the price action of an asset moves in one direction while its underlying momentum (measured by a technical indicator) moves in the opposite direction. By spotting these discrepancies, traders can often identify potential trend reversals before they happen.
Core Mechanism
The script operates using a variation of the Oscillator Moving Average (OsMA). It calculates this based on standard components:
- MACD Logic: It compares a "fast" moving average against a "slow" moving average to determine momentum.
- Signal Smoothing: It then applies a signal line to that MACD value.
- The Oscillator: The final result is a custom oscillator (OsMA) that fluctuates above and below a zero line.
How the Logic Works
The script automatically scans the price history and the oscillator's performance to find two specific types of signals:
1. Bearish Divergence (Potential Sell Signal)
The script looks for instances where:
- Price Action: The market reaches a new high (or higher than the previous peak).
- Oscillator Momentum: The indicator, however, fails to reach a new high and instead shows a lower peak than before.
- Visual Feedback: When this happens, the script places a Red arrow and draws connecting lines to highlight the mismatch between the rising price and the weakening momentum.
2. Bullish Divergence (Potential Buy Signal)
The script looks for instances where:
- Price Action: The market drops to a new low (or lower than the previous trough).
- Oscillator Momentum: The indicator fails to reach a new low and shows a higher trough than before, suggesting that the selling pressure is exhausting.
- Visual Feedback: When this occurs, the script places a Green arrow and draws connecting lines to highlight the mismatch between the falling price and the strengthening momentum.
Key Features for the User
- Automated Peak/Trough Detection: You do not need to manually identify where highs and lows occur; the logic automatically searches backward through the chart to find significant turning points in both price and the oscillator.
- Visual Drawing: If enabled, the tool automatically draws trend lines on both the main price chart and the indicator window. This allows you to see exactly how "out of sync" the price is compared to the momentum.
- Customizable Sensitivity: The logic includes settings that allow you to adjust how sensitive the indicator is to these changes, helping to filter out "noise" in volatile markets.
Summary for the Trader
In plain terms, this script acts as a "momentum detective." It watches for moments where the price is trying to move in one direction, but the internal engine of the market (the oscillator) is showing signs of fatigue or weakness. It flags these moments with arrows and lines to help you spot high-probability reversal zones.
//+------------------------------------------------------------------+
//| FX5_Divergence_v1-1_realtime.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 = "*** 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;
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()
{
if(historyBarsCount <= 0 || historyBarsCount > Bars)
chartBarsCount = Bars;
else
chartBarsCount = historyBarsCount;
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