แจกฟรี 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_level1 0.0
//---- ไม่ใช้ #property indicator_label/type/color ที่นี่
//---- เพราะ MQL5 จะ warning "property already exists" เมื่อ type หรือ color ซ้ำกัน
//---- ตั้งค่าทั้งหมดใน OnInit() ด้วย PlotIndexSet แทน
#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);
//---- Bind 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);
//---- Plot 0: MACD Line (DodgerBlue)
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_LINE);
PlotIndexSetInteger(0, PLOT_LINE_COLOR, clrDodgerBlue);
PlotIndexSetInteger(0, PLOT_LINE_WIDTH, 1);
PlotIndexSetString (0, PLOT_LABEL, "MACD Line");
PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, SlowMAPeriod);
//---- Plot 1: Signal Line (Red)
PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_LINE);
PlotIndexSetInteger(1, PLOT_LINE_COLOR, clrRed);
PlotIndexSetInteger(1, PLOT_LINE_WIDTH, 1);
PlotIndexSetString (1, PLOT_LABEL, "Signal Line");
PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, SlowMAPeriod + SignalMAPeriod);
//---- Plot 2: Histogram (Silver)
PlotIndexSetInteger(2, PLOT_DRAW_TYPE, DRAW_HISTOGRAM);
PlotIndexSetInteger(2, PLOT_LINE_COLOR, clrSilver);
PlotIndexSetInteger(2, PLOT_LINE_WIDTH, 2);
PlotIndexSetString (2, PLOT_LABEL, "Histogram");
PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, SlowMAPeriod + SignalMAPeriod);
//---- Plot 3: Bullish Divergence arrow (Lime, arrow 233 = up)
PlotIndexSetInteger(3, PLOT_DRAW_TYPE, DRAW_ARROW);
PlotIndexSetInteger(3, PLOT_ARROW, 233);
PlotIndexSetInteger(3, PLOT_LINE_COLOR, clrLime);
PlotIndexSetString (3, PLOT_LABEL, "Bullish Divergence");
PlotIndexSetDouble (3, PLOT_EMPTY_VALUE, EMPTY_VALUE);
//---- Plot 4: Bearish Divergence arrow (Red, arrow 234 = down)
PlotIndexSetInteger(4, PLOT_DRAW_TYPE, DRAW_ARROW);
PlotIndexSetInteger(4, PLOT_ARROW, 234);
PlotIndexSetInteger(4, PLOT_LINE_COLOR, clrRed);
PlotIndexSetString (4, PLOT_LABEL, "Bearish Divergence");
PlotIndexSetDouble (4, PLOT_EMPTY_VALUE, EMPTY_VALUE);
//---- Indicator short name
indicatorName = "MACD(" + IntegerToString(FastMAPeriod) + "," +
IntegerToString(SlowMAPeriod) + "," +
IntegerToString(SignalMAPeriod) + ")";
IndicatorSetString(INDICATOR_SHORTNAME, indicatorName);
//---- EMA smoothing factor
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)
{
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);
}
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 buffers
double fastMA[], slowMA[];
if(CopyBuffer(hFastMA, 0, 0, rates_total, fastMA) <= 0) return(prev_calculated);
if(CopyBuffer(hSlowMA, 0, 0, rates_total, slowMA) <= 0) return(prev_calculated);
//---- Use chronological order: index 0 = oldest bar
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, Signal, Histogram
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 (skip last 2 unconfirmed bars)
for(int i = limit; i < rates_total - 2; i++)
{
CatchBullishDivergence(i, time, low, rates_total);
CatchBearishDivergence(i, time, high, rates_total);
}
return(rates_total);
}
//+------------------------------------------------------------------+
//| Returns true if bar[shift] is a MACD 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]);
}
//+------------------------------------------------------------------+
//| Returns true if bar[shift] is a MACD 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 the previous MACD trough before 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 the previous MACD peak before 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);
}
//+------------------------------------------------------------------+
//| Detect and mark bullish divergence at bar[shift] |
//+------------------------------------------------------------------+
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: 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: 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);
}
}
//+------------------------------------------------------------------+
//| Detect and mark bearish divergence at bar[shift] |
//+------------------------------------------------------------------+
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: 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: 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);
}
}
//+------------------------------------------------------------------+
//| Alert only on the 2 most recent bars |
//+------------------------------------------------------------------+
void DisplayAlert(string message, int shift, const datetime &time[])
{
int fromEnd = ArraySize(time) - 1 - shift;
if(fromEnd <= 2 && time[shift] != lastAlertTime)
{
lastAlertTime = time[shift];
Alert(message, _Symbol, " , ", _Period, " minutes chart");
}
}
//+------------------------------------------------------------------+
//| Draw trend line on price chart (main window) |
//+------------------------------------------------------------------+
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);
}
//+------------------------------------------------------------------+