This script is a specialized technical analysis tool designed to help traders identify specific price patterns known as "divergences" using the MACD (Moving Average Convergence Divergence) indicator. It goes beyond simply plotting lines; it actively monitors the relationship between price movements and momentum shifts to signal potential trend reversals.
Core Functionality
The script operates by performing three primary tasks simultaneously:
1. Standard MACD Calculation It calculates the standard MACD components used by most traders:
- MACD Line: The difference between two moving averages (fast and slow).
- Signal Line: A smoothed version of the MACD line.
- Histogram: The visual difference between the MACD line and the Signal line.
2. Divergence Detection The most advanced feature of this script is its ability to "catch" divergences. It constantly compares the peaks and troughs (highs and lows) of the actual price against the peaks and troughs of the MACD indicator. It looks for two specific scenarios:
- Bullish Divergence: This occurs when the market price is making lower lows, but the MACD indicator is making higher lows. This often suggests that downward momentum is weakening and a price increase may be coming.
- Bearish Divergence: This occurs when the market price is making higher highs, but the MACD indicator is making lower highs. This suggests that upward momentum is fading and a price drop might be imminent.
The script distinguishes between "Classical" divergences (where the trend is weakening) and "Reverse" divergences (which indicate different nuances in momentum shifts).
3. Visual Mapping and Alerts When the logic identifies one of these divergences, the script provides immediate visual and auditory feedback:
- Trend Lines: It automatically draws connecting lines on your chart. These lines link the price points and the corresponding indicator points, making it easy to see exactly where the divergence started and ended.
- Visual Markers: It places specific arrows (Bullish/Bearish) at the exact moment a divergence is confirmed.
- Real-Time Alerts: The script can trigger a pop-up notification on your trading platform to alert you immediately when a new divergence appears, ensuring you don't miss a potential entry or exit point.
User Customization
The logic includes several settings that allow users to tailor the experience:
- Technical Parameters: You can adjust the periods for the Fast, Slow, and Signal lines to suit different trading styles (e.g., scalping vs. long-termswing trading).
- Visual Toggles: Users can choose whether to see the trend lines on the price chart, the indicator window, or both.
- Alert Management: You can enable or disable the automated notifications based on your preferred workflow.
//+------------------------------------------------------------------+
//| MACD_Histogram.mq4 |
//| Copyright © 2008, MetaQuotes Software Corp. |
//| http://www.frankie-prasetio.blogspot.com |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2008, MetaQuotes Software Corp."
#property link "http://www.frankie-prasetio.blogspot.com"
#property indicator_separate_window
#property indicator_buffers 5
#property indicator_color1 DodgerBlue
#property indicator_color2 Red
#property indicator_color3 Silver
#property indicator_color4 Lime
#property indicator_color5 Red
#property indicator_level1 0
//----
#define arrowsDisplacement 0.0001
//---- input parameters
extern string separator1 = "*** MACD Settings ***";
extern int FastMAPeriod = 12;
extern int SlowMAPeriod = 26;
extern int SignalMAPeriod = 9;
extern string separator2 = "*** Indicator Settings ***";
extern bool drawIndicatorTrendLines = true;
extern bool drawPriceTrendLines = true;
extern bool displayAlert = true;
//---- buffers
double MACDLineBuffer[];
double SignalLineBuffer[];
double HistogramBuffer[];
double bullishDivergence[];
double bearishDivergence[];
//---- variables
double alpha = 0;
double alpha_1 = 0;
//----
static datetime lastAlertTime;
static string indicatorName;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
IndicatorDigits(Digits + 1);
//---- indicators
SetIndexStyle(0, DRAW_LINE);
SetIndexBuffer(0, MACDLineBuffer);
SetIndexDrawBegin(0, SlowMAPeriod);
SetIndexStyle(1, DRAW_LINE);
SetIndexBuffer(1, SignalLineBuffer);
SetIndexDrawBegin(1, SlowMAPeriod + SignalMAPeriod);
SetIndexStyle(2, DRAW_HISTOGRAM, STYLE_SOLID,2);
SetIndexBuffer(2, HistogramBuffer);
SetIndexDrawBegin(2, SlowMAPeriod + SignalMAPeriod);
SetIndexStyle(3, DRAW_ARROW);
SetIndexArrow(3, 233);
SetIndexBuffer(3, bullishDivergence);
SetIndexStyle(4, DRAW_ARROW);
SetIndexArrow(4, 234);
SetIndexBuffer(4, bearishDivergence);
//---- name for DataWindow and indicator subwindow label
indicatorName =("MACD(" + FastMAPeriod+"," + SlowMAPeriod + "," + SignalMAPeriod + ")");
SetIndexLabel(2, "MACD");
SetIndexLabel(3, "Signal");
SetIndexLabel(4, "Histogr");
IndicatorShortName(indicatorName);
//----
alpha = 2.0 / (SignalMAPeriod + 1.0);
alpha_1 = 1.0 - alpha;
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custor indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
for(int i = ObjectsTotal() - 1; i >= 0; i--)
{
string label = ObjectName(i);
if(StringSubstr(label, 0, 19) != "MACD_DivergenceLine")
continue;
ObjectDelete(label);
}
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
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);
//----
for(int i = limit; i >= 0; i--)
{
MACDLineBuffer[i] = iMA(NULL, 0, FastMAPeriod, 0, MODE_EMA, PRICE_CLOSE, i) -
iMA(NULL, 0, SlowMAPeriod, 0, MODE_EMA, PRICE_CLOSE, i);
SignalLineBuffer[i] = alpha*MACDLineBuffer[i] + alpha_1*SignalLineBuffer[i+1];
HistogramBuffer[i] = MACDLineBuffer[i] - SignalLineBuffer[i];
}
//----
return(0);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CalculateIndicator(int countedBars)
{
for(int i = Bars - countedBars; i >= 0; i--)
{
CalculateMACD(i);
CatchBullishDivergence(i + 2);
CatchBearishDivergence(i + 2);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CalculateMACD(int i)
{
MACDLineBuffer[i] = iMA(NULL, 0, FastMAPeriod, 0, MODE_EMA, PRICE_CLOSE, i) -
iMA(NULL, 0, SlowMAPeriod, 0, MODE_EMA, PRICE_CLOSE, i);
SignalLineBuffer[i] = alpha*MACDLineBuffer[i] + alpha_1*SignalLineBuffer[i+1];
HistogramBuffer[i] = MACDLineBuffer[i] - SignalLineBuffer[i];
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CatchBullishDivergence(int shift)
{
if(IsIndicatorTrough(shift) == false)
return;
int currentTrough = shift;
int lastTrough = GetIndicatorLastTrough(shift);
//----
if(MACDLineBuffer[currentTrough] > MACDLineBuffer[lastTrough] &&
Low[currentTrough] < Low[lastTrough])
{
bullishDivergence[currentTrough] = MACDLineBuffer[currentTrough] -
arrowsDisplacement;
//----
if(drawPriceTrendLines == true)
DrawPriceTrendLine(Time[currentTrough], Time[lastTrough],
Low[currentTrough],
Low[lastTrough], Lime, STYLE_SOLID);
//----
if(drawIndicatorTrendLines == true)
DrawIndicatorTrendLine(Time[currentTrough],
Time[lastTrough],
MACDLineBuffer[currentTrough],
MACDLineBuffer[lastTrough],
Lime, STYLE_SOLID);
//----
if(displayAlert == true)
DisplayAlert("Classical bullish divergence on: ",
currentTrough);
}
//----
if(MACDLineBuffer[currentTrough] < MACDLineBuffer[lastTrough] &&
Low[currentTrough] > Low[lastTrough])
{
bullishDivergence[currentTrough] = MACDLineBuffer[currentTrough] -
arrowsDisplacement;
//----
if(drawPriceTrendLines == true)
DrawPriceTrendLine(Time[currentTrough], Time[lastTrough],
Low[currentTrough],
Low[lastTrough], Lime, STYLE_DOT);
//----
if(drawIndicatorTrendLines == true)
DrawIndicatorTrendLine(Time[currentTrough],
Time[lastTrough],
MACDLineBuffer[currentTrough],
MACDLineBuffer[lastTrough],
Lime, STYLE_DOT);
//----
if(displayAlert == true)
DisplayAlert("Reverse bullish divergence on: ",
currentTrough);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CatchBearishDivergence(int shift)
{
if(IsIndicatorPeak(shift) == false)
return;
int currentPeak = shift;
int lastPeak = GetIndicatorLastPeak(shift);
//----
if(MACDLineBuffer[currentPeak] < MACDLineBuffer[lastPeak] &&
High[currentPeak] > High[lastPeak])
{
bearishDivergence[currentPeak] = MACDLineBuffer[currentPeak] +
arrowsDisplacement;
if(drawPriceTrendLines == true)
DrawPriceTrendLine(Time[currentPeak], Time[lastPeak],
High[currentPeak],
High[lastPeak], Red, STYLE_SOLID);
if(drawIndicatorTrendLines == true)
DrawIndicatorTrendLine(Time[currentPeak], Time[lastPeak],
MACDLineBuffer[currentPeak],
MACDLineBuffer[lastPeak], Red, STYLE_SOLID);
if(displayAlert == true)
DisplayAlert("Classical bearish divergence on: ",
currentPeak);
}
if(MACDLineBuffer[currentPeak] > MACDLineBuffer[lastPeak] &&
High[currentPeak] < High[lastPeak])
{
bearishDivergence[currentPeak] = MACDLineBuffer[currentPeak] +
arrowsDisplacement;
//----
if(drawPriceTrendLines == true)
DrawPriceTrendLine(Time[currentPeak], Time[lastPeak],
High[currentPeak],
High[lastPeak], Red, STYLE_DOT);
//----
if(drawIndicatorTrendLines == true)
DrawIndicatorTrendLine(Time[currentPeak], Time[lastPeak],
MACDLineBuffer[currentPeak],
MACDLineBuffer[lastPeak], Red, STYLE_DOT);
//----
if(displayAlert == true)
DisplayAlert("Reverse bearish divergence on: ",
currentPeak);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool IsIndicatorPeak(int shift)
{
if(MACDLineBuffer[shift] >= MACDLineBuffer[shift+1] && MACDLineBuffer[shift] > MACDLineBuffer[shift+2] &&
MACDLineBuffer[shift] > MACDLineBuffer[shift-1])
return(true);
else
return(false);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool IsIndicatorTrough(int shift)
{
if(MACDLineBuffer[shift] <= MACDLineBuffer[shift+1] && MACDLineBuffer[shift] < MACDLineBuffer[shift+2] &&
MACDLineBuffer[shift] < MACDLineBuffer[shift-1])
return(true);
else
return(false);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int GetIndicatorLastPeak(int shift)
{
for(int i = shift + 5; i < Bars; i++)
{
if(SignalLineBuffer[i] >= SignalLineBuffer[i+1] && SignalLineBuffer[i] >= SignalLineBuffer[i+2] &&
SignalLineBuffer[i] >= SignalLineBuffer[i-1] && SignalLineBuffer[i] >= SignalLineBuffer[i-2])
{
for(int j = i; j < Bars; j++)
{
if(MACDLineBuffer[j] >= MACDLineBuffer[j+1] && MACDLineBuffer[j] > MACDLineBuffer[j+2] &&
MACDLineBuffer[j] >= MACDLineBuffer[j-1] && MACDLineBuffer[j] > MACDLineBuffer[j-2])
return(j);
}
}
}
return(-1);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int GetIndicatorLastTrough(int shift)
{
for(int i = shift + 5; i < Bars; i++)
{
if(SignalLineBuffer[i] <= SignalLineBuffer[i+1] && SignalLineBuffer[i] <= SignalLineBuffer[i+2] &&
SignalLineBuffer[i] <= SignalLineBuffer[i-1] && SignalLineBuffer[i] <= SignalLineBuffer[i-2])
{
for (int j = i; j < Bars; j++)
{
if(MACDLineBuffer[j] <= MACDLineBuffer[j+1] && MACDLineBuffer[j] < MACDLineBuffer[j+2] &&
MACDLineBuffer[j] <= MACDLineBuffer[j-1] && MACDLineBuffer[j] < MACDLineBuffer[j-2])
return(j);
}
}
}
return(-1);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void DisplayAlert(string message, int shift)
{
if(shift <= 2 && Time[shift] != lastAlertTime)
{
lastAlertTime = Time[shift];
Alert(message, Symbol(), " , ", Period(), " minutes chart");
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void DrawPriceTrendLine(datetime x1, datetime x2, double y1,
double y2, color lineColor, double style)
{
string label = "MACD_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 = "MACD_DivergenceLine.0$# " + 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);
}
//+------------------------------------------------------------------+
Comments