แจกฟรี MACD Divergence Indicator (MQL5)
เปิดบัญชีมืออาชีพได้ที่ https://www.exness.com/a/73208
ไว้ดูกราฟ MT5 หาประกอบกับ EA ที่ได้เขียนมาใช้งานเทรด
//+------------------------------------------------------------------+
//| MACD Divergence Indicator (MQL5) |
//| Converted from MQL4 original |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2026, junjao.com."
#property link "http://www.exness.com/a/73208"
#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots 5
#property indicator_label1 "MACD Line"
#property indicator_type1 DRAW_LINE
#property indicator_color1 DodgerBlue
#property indicator_width1 1
#property indicator_label2 "Signal Line"
#property indicator_type2 DRAW_LINE
#property indicator_color2 Red
#property indicator_width2 1
#property indicator_label3 "Histogram"
#property indicator_type3 DRAW_HISTOGRAM
#property indicator_color3 Silver
#property indicator_width3 2
#property indicator_label4 "Bullish Divergence"
#property indicator_type4 DRAW_ARROW
#property indicator_color4 Lime
#property indicator_label5 "Bearish Divergence"
#property indicator_type5 DRAW_ARROW
#property indicator_color5 Red
#property indicator_level1 0.0
//----
#define arrowsDisplacement 0.0001
//---- Input parameters
input string separator1 = "*** MACD Settings ***";
input int FastMAPeriod = 12;
input int SlowMAPeriod = 26;
input int SignalMAPeriod = 9;
input string separator2 = "*** Indicator Settings ***";
input bool drawIndicatorTrendLines = true;
input bool drawPriceTrendLines = true;
input 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;
//---- Handles for iMA
int hFastMA;
int hSlowMA;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
IndicatorSetInteger(INDICATOR_DIGITS, _Digits + 1);
//---- Set index buffers
SetIndexBuffer(0, MACDLineBuffer, INDICATOR_DATA);
SetIndexBuffer(1, SignalLineBuffer, INDICATOR_DATA);
SetIndexBuffer(2, HistogramBuffer, INDICATOR_DATA);
SetIndexBuffer(3, bullishDivergence, INDICATOR_DATA);
SetIndexBuffer(4, bearishDivergence, INDICATOR_DATA);
//---- Arrow codes
PlotIndexSetInteger(3, PLOT_ARROW, 233);
PlotIndexSetInteger(4, PLOT_ARROW, 234);
//---- Draw begin
PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, SlowMAPeriod);
PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, SlowMAPeriod + SignalMAPeriod);
PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, SlowMAPeriod + SignalMAPeriod);
//---- Empty value
PlotIndexSetDouble(3, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetDouble(4, PLOT_EMPTY_VALUE, EMPTY_VALUE);
//---- Indicator name
indicatorName = "MACD(" + IntegerToString(FastMAPeriod) + "," +
IntegerToString(SlowMAPeriod) + "," +
IntegerToString(SignalMAPeriod) + ")";
IndicatorSetString(INDICATOR_SHORTNAME, indicatorName);
//---- EMA alpha
alpha = 2.0 / (SignalMAPeriod + 1.0);
alpha_1 = 1.0 - alpha;
//---- Create MA handles
hFastMA = iMA(NULL, 0, FastMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
hSlowMA = iMA(NULL, 0, SlowMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
if(hFastMA == INVALID_HANDLE || hSlowMA == INVALID_HANDLE)
{
Print("Failed to create MA handles");
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---- Remove divergence lines drawn by this indicator
for(int i = ObjectsTotal(0, 0, -1) - 1; i >= 0; i--)
{
string label = ObjectName(0, i, 0, -1);
if(StringSubstr(label, 0, 19) != "MACD_DivergenceLine")
continue;
ObjectDelete(0, label);
}
//---- Release MA handles
IndicatorRelease(hFastMA);
IndicatorRelease(hSlowMA);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
if(rates_total < SlowMAPeriod + SignalMAPeriod + 5)
return(0);
//---- Copy MA data
double fastMA[], slowMA[];
if(CopyBuffer(hFastMA, 0, 0, rates_total, fastMA) <= 0) return(0);
if(CopyBuffer(hSlowMA, 0, 0, rates_total, slowMA) <= 0) return(0);
//---- Reverse arrays to match bar indexing (0 = oldest, rates_total-1 = newest)
ArraySetAsSeries(fastMA, false);
ArraySetAsSeries(slowMA, false);
ArraySetAsSeries(time, false);
ArraySetAsSeries(high, false);
ArraySetAsSeries(low, false);
int limit = (prev_calculated == 0) ? SlowMAPeriod : prev_calculated - 1;
//---- Calculate MACD and Signal lines
for(int i = limit; i < rates_total; i++)
{
MACDLineBuffer = fastMA - slowMA;
if(i == 0)
SignalLineBuffer = MACDLineBuffer;
else
SignalLineBuffer = alpha * MACDLineBuffer + alpha_1 * SignalLineBuffer[i - 1];
HistogramBuffer = MACDLineBuffer - SignalLineBuffer;
bullishDivergence = EMPTY_VALUE;
bearishDivergence = EMPTY_VALUE;
}
//---- Detect divergences (leave last 2 bars unconfirmed)
for(int i = limit; i < rates_total - 2; i++)
{
CatchBullishDivergence(i, time, low, rates_total);
CatchBearishDivergence(i, time, high, rates_total);
}
return(rates_total);
}
//+------------------------------------------------------------------+
//| Check if index is an indicator trough |
//+------------------------------------------------------------------+
bool IsIndicatorTrough(int shift, int total)
{
if(shift < 2 || shift >= total - 1) return(false);
return(MACDLineBuffer[shift] <= MACDLineBuffer[shift - 1] &&
MACDLineBuffer[shift] < MACDLineBuffer[shift - 2] &&
MACDLineBuffer[shift] < MACDLineBuffer[shift + 1]);
}
//+------------------------------------------------------------------+
//| Check if index is an indicator peak |
//+------------------------------------------------------------------+
bool IsIndicatorPeak(int shift, int total)
{
if(shift < 2 || shift >= total - 1) return(false);
return(MACDLineBuffer[shift] >= MACDLineBuffer[shift - 1] &&
MACDLineBuffer[shift] > MACDLineBuffer[shift - 2] &&
MACDLineBuffer[shift] > MACDLineBuffer[shift + 1]);
}
//+------------------------------------------------------------------+
//| Find last indicator trough before given shift |
//+------------------------------------------------------------------+
int GetIndicatorLastTrough(int shift, int total)
{
for(int i = shift - 5; i >= 2; i--)
{
if(SignalLineBuffer <= SignalLineBuffer[i - 1] &&
SignalLineBuffer <= SignalLineBuffer[i - 2] &&
SignalLineBuffer <= SignalLineBuffer[i + 1] &&
SignalLineBuffer <= SignalLineBuffer[i + 2])
{
for(int j = i; j >= 2; 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);
}
//+------------------------------------------------------------------+
//| Find last indicator peak before given shift |
//+------------------------------------------------------------------+
int GetIndicatorLastPeak(int shift, int total)
{
for(int i = shift - 5; i >= 2; i--)
{
if(SignalLineBuffer >= SignalLineBuffer[i - 1] &&
SignalLineBuffer >= SignalLineBuffer[i - 2] &&
SignalLineBuffer >= SignalLineBuffer[i + 1] &&
SignalLineBuffer >= SignalLineBuffer[i + 2])
{
for(int j = i; j >= 2; 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);
}
//+------------------------------------------------------------------+
//| Catch bullish divergence at given bar index |
//+------------------------------------------------------------------+
void CatchBullishDivergence(int shift,
const datetime &time[],
const double &low[],
int total)
{
if(!IsIndicatorTrough(shift, total)) return;
int currentTrough = shift;
int lastTrough = GetIndicatorLastTrough(shift, total);
if(lastTrough == -1) return;
//---- Classical bullish divergence: MACD higher low, price lower low
if(MACDLineBuffer[currentTrough] > MACDLineBuffer[lastTrough] &&
low[currentTrough] < low[lastTrough])
{
bullishDivergence[currentTrough] = MACDLineBuffer[currentTrough] - arrowsDisplacement;
if(drawPriceTrendLines)
DrawPriceTrendLine(time[currentTrough], time[lastTrough],
low[currentTrough], low[lastTrough],
clrLime, STYLE_SOLID);
if(drawIndicatorTrendLines)
DrawIndicatorTrendLine(time[currentTrough], time[lastTrough],
MACDLineBuffer[currentTrough], MACDLineBuffer[lastTrough],
clrLime, STYLE_SOLID);
if(displayAlert)
DisplayAlert("Classical bullish divergence on: ", shift, time);
}
//---- Reverse bullish divergence: MACD lower low, price higher low
if(MACDLineBuffer[currentTrough] < MACDLineBuffer[lastTrough] &&
low[currentTrough] > low[lastTrough])
{
bullishDivergence[currentTrough] = MACDLineBuffer[currentTrough] - arrowsDisplacement;
if(drawPriceTrendLines)
DrawPriceTrendLine(time[currentTrough], time[lastTrough],
low[currentTrough], low[lastTrough],
clrLime, STYLE_DOT);
if(drawIndicatorTrendLines)
DrawIndicatorTrendLine(time[currentTrough], time[lastTrough],
MACDLineBuffer[currentTrough], MACDLineBuffer[lastTrough],
clrLime, STYLE_DOT);
if(displayAlert)
DisplayAlert("Reverse bullish divergence on: ", shift, time);
}
}
//+------------------------------------------------------------------+
//| Catch bearish divergence at given bar index |
//+------------------------------------------------------------------+
void CatchBearishDivergence(int shift,
const datetime &time[],
const double &high[],
int total)
{
if(!IsIndicatorPeak(shift, total)) return;
int currentPeak = shift;
int lastPeak = GetIndicatorLastPeak(shift, total);
if(lastPeak == -1) return;
//---- Classical bearish divergence: MACD lower high, price higher high
if(MACDLineBuffer[currentPeak] < MACDLineBuffer[lastPeak] &&
high[currentPeak] > high[lastPeak])
{
bearishDivergence[currentPeak] = MACDLineBuffer[currentPeak] + arrowsDisplacement;
if(drawPriceTrendLines)
DrawPriceTrendLine(time[currentPeak], time[lastPeak],
high[currentPeak], high[lastPeak],
clrRed, STYLE_SOLID);
if(drawIndicatorTrendLines)
DrawIndicatorTrendLine(time[currentPeak], time[lastPeak],
MACDLineBuffer[currentPeak], MACDLineBuffer[lastPeak],
clrRed, STYLE_SOLID);
if(displayAlert)
DisplayAlert("Classical bearish divergence on: ", shift, time);
}
//---- Reverse bearish divergence: MACD higher high, price lower high
if(MACDLineBuffer[currentPeak] > MACDLineBuffer[lastPeak] &&
high[currentPeak] < high[lastPeak])
{
bearishDivergence[currentPeak] = MACDLineBuffer[currentPeak] + arrowsDisplacement;
if(drawPriceTrendLines)
DrawPriceTrendLine(time[currentPeak], time[lastPeak],
high[currentPeak], high[lastPeak],
clrRed, STYLE_DOT);
if(drawIndicatorTrendLines)
DrawIndicatorTrendLine(time[currentPeak], time[lastPeak],
MACDLineBuffer[currentPeak], MACDLineBuffer[lastPeak],
clrRed, STYLE_DOT);
if(displayAlert)
DisplayAlert("Reverse bearish divergence on: ", shift, time);
}
}
//+------------------------------------------------------------------+
//| Display alert (only on recent bars) |
//+------------------------------------------------------------------+
void DisplayAlert(string message, int shift, const datetime &time[])
{
int totalBars = ArraySize(time);
int fromEnd = totalBars - 1 - shift;
if(fromEnd <= 2 && time[shift] != lastAlertTime)
{
lastAlertTime = time[shift];
Alert(message, _Symbol, " , ", _Period, " minutes chart");
}
}
//+------------------------------------------------------------------+
//| Draw trend line on price chart |
//+------------------------------------------------------------------+
void DrawPriceTrendLine(datetime x1, datetime x2,
double y1, double y2,
color lineColor, ENUM_LINE_STYLE style)
{
string label = "MACD_DivergenceLine.0# " + IntegerToString((long)x1);
ObjectDelete(0, label);
ObjectCreate(0, label, OBJ_TREND, 0, x1, y1, x2, y2);
ObjectSetInteger(0, label, OBJPROP_RAY_RIGHT, false);
ObjectSetInteger(0, label, OBJPROP_COLOR, lineColor);
ObjectSetInteger(0, label, OBJPROP_STYLE, style);
}
//+------------------------------------------------------------------+
//| Draw trend line on indicator sub-window |
//+------------------------------------------------------------------+
void DrawIndicatorTrendLine(datetime x1, datetime x2,
double y1, double y2,
color lineColor, ENUM_LINE_STYLE style)
{
int indicatorWindow = ChartWindowFind(0, indicatorName);
if(indicatorWindow < 0) return;
string label = "MACD_DivergenceLine.0$# " + IntegerToString((long)x1);
ObjectDelete(0, label);
ObjectCreate(0, label, OBJ_TREND, indicatorWindow, x1, y1, x2, y2);
ObjectSetInteger(0, label, OBJPROP_RAY_RIGHT, false);
ObjectSetInteger(0, label, OBJPROP_COLOR, lineColor);
ObjectSetInteger(0, label, OBJPROP_STYLE, style);
}
//+------------------------------------------------------------------+