superTrendMT5/superTrendMT5.mq5

1134 lines
42 KiB
MQL5

2026-09-18 17:23:49 +03:00
//+------------------------------------------------------------------+
2026-09-18 17:37:34 +03:00
//| supertrendPro.mq5 |
//| Copyright 2026, MetaQuotes Ltd. Developer: Gloria Diana |
//| https://www.mql5.com/en/users/gloriadiana |
2026-09-18 17:23:49 +03:00
//+------------------------------------------------------------------+
2026-09-18 17:37:34 +03:00
#property copyright "Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian"
#property link "https://www.mql5.com/en/users/chachaian"
#property version "1.00"
#property indicator_chart_window
#property indicator_buffers 8
#property indicator_plots 3
#property indicator_type1 DRAW_COLOR_CANDLES
#property indicator_type2 DRAW_LINE
#property indicator_type3 DRAW_LINE
2026-09-18 17:23:49 +03:00
//+------------------------------------------------------------------+
2026-09-18 17:37:34 +03:00
//| Input parameters |
//+------------------------------------------------------------------+
input group "Supertrend Settings"
input int InpATRPeriod = 10; // ATR calculation period
input double InpATRMultiplier = 1.5; // ATR multiplier used to position the Supertrend bands
input group "Notifications"
input bool InpEnablePushNotifications = true; // Send mobile push notifications on confirmed trend changes
//+------------------------------------------------------------------+
//| Trend states exposed through Buffer 7 |
//+------------------------------------------------------------------+
const double TREND_BULLISH = 1.0; // Confirmed bullish trend
const double TREND_BEARISH = 0.0; // Confirmed bearish trend
const double TREND_NEUTRAL = -1.0; // Initial unresolved trend state
//+------------------------------------------------------------------+
//| Indicator theme colors |
//+------------------------------------------------------------------+
const color COLOR_BACKGROUND = clrWhiteSmoke; // Main chart background
const color COLOR_FOREGROUND = clrBlack; // Chart text and scale labels
const color COLOR_BULLISH = clrSeaGreen; // Bullish candles, bands, and Bid line
const color COLOR_BEARISH = clrCrimson; // Bearish candles, bands, and Ask line
//+------------------------------------------------------------------+
//| Stores the chart appearance before Supertrend Pro changes it |
//+------------------------------------------------------------------+
struct SChartAppearance
{
long backgroundColor; // Original chart background color
long foregroundColor; // Original chart text and scale color
long showGrid; // Original grid visibility
long chartMode; // Original chart drawing mode
long chartUpColor; // Original bullish chart color
long chartDownColor; // Original bearish chart color
long candleBullColor; // Original bullish candle color
long candleBearColor; // Original bearish candle color
long bidColor; // Original Bid line color
long askColor; // Original Ask line color
};
//+------------------------------------------------------------------+
//| Global variables |
//+------------------------------------------------------------------+
int g_atrHandle = INVALID_HANDLE; // Handle of the ATR indicator
double g_atrValues[]; // Working array for copied ATR values
SChartAppearance g_chartAppearance; // Chart appearance saved before applying the theme
bool g_chartAppearanceSaved = false; // Confirms that restoration data is available
datetime g_lastNotifiedBarTime = 0; // Open time of the last bar that generated a push notification
datetime g_lastObservedLiveBarTime = 0; // Live bar tracked during the previous successful calculation
//+------------------------------------------------------------------+
//| Public indicator buffers |
//+------------------------------------------------------------------+
double g_candleOpen[]; // Buffer 0: trend-colored candle Open
double g_candleHigh[]; // Buffer 1: trend-colored candle High
double g_candleLow[]; // Buffer 2: trend-colored candle Low
double g_candleClose[]; // Buffer 3: trend-colored candle Close
double g_candleColor[]; // Buffer 4: candle trend color index
double g_upperBand[]; // Buffer 5: upper/bearish Supertrend band
double g_lowerBand[]; // Buffer 6: lower/bullish Supertrend band
double g_trendState[]; // Buffer 7: 1.0 bullish, 0.0 bearish, -1.0 neutral
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
2026-09-18 17:23:49 +03:00
//+------------------------------------------------------------------+
int OnInit()
{
2026-09-18 17:37:34 +03:00
//--- Validate all user-configurable Supertrend parameters before
//--- allocating or configuring indicator resources.
if(!ValidateInputs())
return(INIT_PARAMETERS_INCORRECT);
//--- Reset notification tracking so every initialization establishes
//--- a fresh live-bar baseline before any push alert can be generated.
g_lastNotifiedBarTime=0;
g_lastObservedLiveBarTime=0;
//--- Bind the declared arrays to their permanent indicator buffer
//--- indexes before configuring their visual plots.
if(!ConfigureIndicatorBuffers())
{
Print("Failed to configure Supertrend Pro indicator buffers.");
return(INIT_FAILED);
}
//--- Configure the candle and Supertrend plots that present the
//--- calculated trend state on the chart.
if(!ConfigureIndicatorPlots())
{
Print("Failed to configure Supertrend Pro indicator plots.");
return(INIT_FAILED);
}
//--- Create the ATR handle used by the Supertrend calculation.
g_atrHandle=iATR(_Symbol,PERIOD_CURRENT,InpATRPeriod);
if(g_atrHandle==INVALID_HANDLE)
{
PrintFormat("Failed to create ATR handle. Error=%d",GetLastError());
return(INIT_FAILED);
}
//--- Preserve the user's current chart appearance before applying
//--- the mandatory Supertrend Pro visual theme.
if(!SaveChartAppearance())
{
Print("Failed to save the current chart appearance.");
return(INIT_FAILED);
}
//--- Apply the Supertrend Pro theme after the original appearance
//--- has been stored successfully.
if(!ApplyIndicatorTheme())
{
Print("Failed to apply the Supertrend Pro chart theme.");
//--- Restore any chart properties changed before theme setup failed.
RestoreChartAppearance();
return(INIT_FAILED);
}
2026-09-18 17:23:49 +03:00
return(INIT_SUCCEEDED);
}
2026-09-18 17:37:34 +03:00
//+------------------------------------------------------------------+
//| 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[])
{
//--- Explicitly use chronological indexing throughout the indicator.
ArraySetAsSeries(time,false);
ArraySetAsSeries(open,false);
ArraySetAsSeries(high,false);
ArraySetAsSeries(low,false);
ArraySetAsSeries(close,false);
ArraySetAsSeries(tick_volume,false);
ArraySetAsSeries(volume,false);
ArraySetAsSeries(spread,false);
//--- Wait until enough price history exists to calculate the ATR.
if(rates_total<InpATRPeriod)
return(prev_calculated);
//--- Separate the forming bar from the latest confirmed bar.
int liveIndex=rates_total-1;
int lastClosedIndex=rates_total-2;
int firstValidIndex=InpATRPeriod-1;
int start=0;
if(lastClosedIndex<firstValidIndex)
return(prev_calculated);
//--- A notification is eligible only when exactly one new bar has
//--- opened since the previous successful calculation and the bar that
//--- has just closed was previously tracked as the live bar.
bool liveTrendChange=false;
if(prev_calculated>0 &&
rates_total==prev_calculated+1 &&
g_lastObservedLiveBarTime!=0 &&
time[lastClosedIndex]==g_lastObservedLiveBarTime)
liveTrendChange=true;
//--- Rebuild the complete Supertrend state when previous calculations
//--- cannot be reused. Historical reconstruction never generates alerts.
if(prev_calculated==0)
{
//--- Clear all public buffers before reconstructing history.
ArrayInitialize(g_candleOpen,EMPTY_VALUE);
ArrayInitialize(g_candleHigh,EMPTY_VALUE);
ArrayInitialize(g_candleLow,EMPTY_VALUE);
ArrayInitialize(g_candleClose,EMPTY_VALUE);
ArrayInitialize(g_candleColor,0.0);
ArrayInitialize(g_upperBand,EMPTY_VALUE);
ArrayInitialize(g_lowerBand,EMPTY_VALUE);
ArrayInitialize(g_trendState,EMPTY_VALUE);
//--- ATR data is required from the first valid seed bar onward.
start=firstValidIndex;
}
else
{
//--- Resume from the bar that was live during the previous
//--- calculation and may now have become confirmed.
start=prev_calculated-1;
if(start<firstValidIndex+1)
start=firstValidIndex+1;
}
//--- Copy ATR values only for confirmed bars that require calculation.
if(start<=lastClosedIndex)
{
if(!GetATRValues(start,lastClosedIndex,rates_total))
return(prev_calculated);
}
//--- Seed the neutral state only during a complete historical rebuild.
if(prev_calculated==0)
{
double barMidpoint=(high[firstValidIndex]+low[firstValidIndex])/2.0;
g_upperBand[firstValidIndex]=barMidpoint+
g_atrValues[firstValidIndex]*InpATRMultiplier;
g_lowerBand[firstValidIndex]=barMidpoint-
g_atrValues[firstValidIndex]*InpATRMultiplier;
g_trendState[firstValidIndex]=TREND_NEUTRAL;
//--- The seed bar is complete, so subsequent bars can enter
//--- the unified Supertrend state machine.
start=firstValidIndex+1;
}
//--- Process every newly confirmed bar through the common Supertrend
//--- state machine, including any bars recovered after inactivity.
for(int i=start;i<=lastClosedIndex;i++)
CalculateBar(i,open,high,low,close);
//--- Notify only when the newest confirmed bar was genuinely observed
//--- forming during the preceding successful indicator calculation.
if(liveTrendChange)
NotifyConfirmedTrendChange(lastClosedIndex,time);
//--- Keep the forming bar outside the confirmed indicator state.
g_candleOpen[liveIndex]=EMPTY_VALUE;
g_candleHigh[liveIndex]=EMPTY_VALUE;
g_candleLow[liveIndex]=EMPTY_VALUE;
g_candleClose[liveIndex]=EMPTY_VALUE;
g_candleColor[liveIndex]=0.0;
g_upperBand[liveIndex]=EMPTY_VALUE;
g_lowerBand[liveIndex]=EMPTY_VALUE;
g_trendState[liveIndex]=EMPTY_VALUE;
//--- Record the current live bar only after this calculation completes
//--- successfully. It becomes eligible for notification after it closes.
g_lastObservedLiveBarTime=time[liveIndex];
return(rates_total);
}
2026-09-18 17:23:49 +03:00
//+------------------------------------------------------------------+
2026-09-18 17:37:34 +03:00
//| Custom indicator deinitialization function |
2026-09-18 17:23:49 +03:00
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
2026-09-18 17:37:34 +03:00
//--- Restore the user's previous chart appearance before the
//--- Supertrend Pro instance leaves the chart.
if(g_chartAppearanceSaved)
RestoreChartAppearance();
//--- Release the ATR resource only when a valid handle was created.
if(g_atrHandle!=INVALID_HANDLE)
{
IndicatorRelease(g_atrHandle);
g_atrHandle=INVALID_HANDLE;
}
}
//+------------------------------------------------------------------+
//| Validates the Supertrend input parameters |
//+------------------------------------------------------------------+
bool ValidateInputs()
{
//--- The ATR period must contain at least one bar.
if(InpATRPeriod < 1)
{
Print("Invalid ATR period. InpATRPeriod must be greater than or equal to 1.");
return(false);
}
//--- The ATR multiplier must be positive because zero or negative
//--- values cannot produce valid Supertrend band distances.
if(InpATRMultiplier <= 0.0)
{
Print("Invalid ATR multiplier. InpATRMultiplier must be greater than 0.");
return(false);
}
return(true);
}
//+------------------------------------------------------------------+
//| Binds all arrays to their permanent indicator buffer indexes |
//+------------------------------------------------------------------+
bool ConfigureIndicatorBuffers()
{
//--- Buffers 0-3 provide the OHLC values required by the
//--- DRAW_COLOR_CANDLES plot used for trend-colored candles.
if(!SetIndexBuffer(0,g_candleOpen,INDICATOR_DATA))
{
Print("Failed to bind candle Open buffer. Error: ",GetLastError());
return(false);
}
if(!SetIndexBuffer(1,g_candleHigh,INDICATOR_DATA))
{
Print("Failed to bind candle High buffer. Error: ",GetLastError());
return(false);
}
if(!SetIndexBuffer(2,g_candleLow,INDICATOR_DATA))
{
Print("Failed to bind candle Low buffer. Error: ",GetLastError());
return(false);
}
if(!SetIndexBuffer(3,g_candleClose,INDICATOR_DATA))
{
Print("Failed to bind candle Close buffer. Error: ",GetLastError());
return(false);
}
//--- Buffer 4 stores the color index used to select the bullish
//--- or bearish candle color for each calculated bar.
if(!SetIndexBuffer(4,g_candleColor,INDICATOR_COLOR_INDEX))
{
Print("Failed to bind candle color buffer. Error: ",GetLastError());
return(false);
}
//--- Buffers 5 and 6 remain separate so bearish and bullish
//--- Supertrend segments are never visually joined at reversals.
if(!SetIndexBuffer(5,g_upperBand,INDICATOR_DATA))
{
Print("Failed to bind upper Supertrend band buffer. Error: ",GetLastError());
return(false);
}
if(!SetIndexBuffer(6,g_lowerBand,INDICATOR_DATA))
{
Print("Failed to bind lower Supertrend band buffer. Error: ",GetLastError());
return(false);
}
//--- Buffer 7 exposes the numerical trend state for programmatic
//--- access by Expert Advisors and other MQL5 applications.
if(!SetIndexBuffer(7,g_trendState,INDICATOR_DATA))
{
Print("Failed to bind trend-state buffer. Error: ",GetLastError());
return(false);
}
//--- Explicitly keep every indicator buffer in chronological order.
//--- Index 0 represents the oldest available bar and higher indexes
//--- progress toward the current bar.
if(!ArraySetAsSeries(g_candleOpen,false) ||
!ArraySetAsSeries(g_candleHigh,false) ||
!ArraySetAsSeries(g_candleLow,false) ||
!ArraySetAsSeries(g_candleClose,false) ||
!ArraySetAsSeries(g_candleColor,false) ||
!ArraySetAsSeries(g_upperBand,false) ||
!ArraySetAsSeries(g_lowerBand,false) ||
!ArraySetAsSeries(g_trendState,false))
{
Print("Failed to configure chronological indexing for indicator buffers.");
return(false);
}
return(true);
}
//+------------------------------------------------------------------+
//| Applies the Supertrend Pro visual theme to the chart |
//+------------------------------------------------------------------+
bool ApplyIndicatorTheme()
{
//--- Apply the neutral chart background and foreground colors.
if(!ChartSetInteger(0,CHART_COLOR_BACKGROUND,COLOR_BACKGROUND))
{
PrintFormat("Failed to set chart background color. Error=%d",GetLastError());
return(false);
}
if(!ChartSetInteger(0,CHART_COLOR_FOREGROUND,COLOR_FOREGROUND))
{
PrintFormat("Failed to set chart foreground color. Error=%d",GetLastError());
return(false);
}
//--- Remove the chart grid to keep the trend candles and Supertrend
//--- bands visually dominant against the WhiteSmoke background.
if(!ChartSetInteger(0,CHART_SHOW_GRID,false))
{
PrintFormat("Failed to configure chart grid visibility. Error=%d",GetLastError());
return(false);
}
//--- Use candle-chart mode throughout the Supertrend Pro presentation.
if(!ChartSetInteger(0,CHART_MODE,CHART_CANDLES))
{
PrintFormat("Failed to set candle chart mode. Error=%d",GetLastError());
return(false);
}
//--- Apply the bullish theme to native bullish chart elements.
if(!ChartSetInteger(0,CHART_COLOR_CHART_UP,COLOR_BULLISH))
{
PrintFormat("Failed to set bullish chart color. Error=%d",GetLastError());
return(false);
}
if(!ChartSetInteger(0,CHART_COLOR_CANDLE_BULL,COLOR_BULLISH))
{
PrintFormat("Failed to set bullish candle color. Error=%d",GetLastError());
return(false);
}
//--- Apply the bearish theme to native bearish chart elements.
if(!ChartSetInteger(0,CHART_COLOR_CHART_DOWN,COLOR_BEARISH))
{
PrintFormat("Failed to set bearish chart color. Error=%d",GetLastError());
return(false);
}
if(!ChartSetInteger(0,CHART_COLOR_CANDLE_BEAR,COLOR_BEARISH))
{
PrintFormat("Failed to set bearish candle color. Error=%d",GetLastError());
return(false);
}
//--- Match Bid and Ask line colors to the directional theme.
if(!ChartSetInteger(0,CHART_COLOR_BID,COLOR_BULLISH))
{
PrintFormat("Failed to set Bid line color. Error=%d",GetLastError());
return(false);
}
if(!ChartSetInteger(0,CHART_COLOR_ASK,COLOR_BEARISH))
{
PrintFormat("Failed to set Ask line color. Error=%d",GetLastError());
return(false);
}
//--- Refresh the chart after applying the complete visual theme.
ChartRedraw(0);
return(true);
}
//+------------------------------------------------------------------+
//| Saves the chart appearance before applying the indicator theme |
//+------------------------------------------------------------------+
bool SaveChartAppearance()
{
//--- Read the chart colors that Supertrend Pro will temporarily replace.
if(!ChartGetInteger(0,CHART_COLOR_BACKGROUND,0,g_chartAppearance.backgroundColor))
{
PrintFormat("Failed to read chart background color. Error=%d",GetLastError());
return(false);
}
if(!ChartGetInteger(0,CHART_COLOR_FOREGROUND,0,g_chartAppearance.foregroundColor))
{
PrintFormat("Failed to read chart foreground color. Error=%d",GetLastError());
return(false);
}
if(!ChartGetInteger(0,CHART_COLOR_CHART_UP,0,g_chartAppearance.chartUpColor))
{
PrintFormat("Failed to read bullish chart color. Error=%d",GetLastError());
return(false);
}
if(!ChartGetInteger(0,CHART_COLOR_CHART_DOWN,0,g_chartAppearance.chartDownColor))
{
PrintFormat("Failed to read bearish chart color. Error=%d",GetLastError());
return(false);
}
if(!ChartGetInteger(0,CHART_COLOR_CANDLE_BULL,0,g_chartAppearance.candleBullColor))
{
PrintFormat("Failed to read bullish candle color. Error=%d",GetLastError());
return(false);
}
if(!ChartGetInteger(0,CHART_COLOR_CANDLE_BEAR,0,g_chartAppearance.candleBearColor))
{
PrintFormat("Failed to read bearish candle color. Error=%d",GetLastError());
return(false);
}
if(!ChartGetInteger(0,CHART_COLOR_BID,0,g_chartAppearance.bidColor))
{
PrintFormat("Failed to read Bid line color. Error=%d",GetLastError());
return(false);
}
if(!ChartGetInteger(0,CHART_COLOR_ASK,0,g_chartAppearance.askColor))
{
PrintFormat("Failed to read Ask line color. Error=%d",GetLastError());
return(false);
}
//--- Preserve the non-color chart properties changed by the theme.
if(!ChartGetInteger(0,CHART_SHOW_GRID,0,g_chartAppearance.showGrid))
{
PrintFormat("Failed to read chart grid visibility. Error=%d",GetLastError());
return(false);
}
if(!ChartGetInteger(0,CHART_MODE,0,g_chartAppearance.chartMode))
{
PrintFormat("Failed to read chart mode. Error=%d",GetLastError());
return(false);
}
//--- The complete appearance snapshot is now safe to restore later.
g_chartAppearanceSaved=true;
return(true);
}
//+------------------------------------------------------------------+
//| Restores the chart appearance saved before theme application |
//+------------------------------------------------------------------+
bool RestoreChartAppearance()
{
bool restored=true;
//--- Restore the original background and foreground colors.
if(!ChartSetInteger(0,CHART_COLOR_BACKGROUND,g_chartAppearance.backgroundColor))
{
PrintFormat("Failed to restore chart background color. Error=%d",GetLastError());
restored=false;
}
if(!ChartSetInteger(0,CHART_COLOR_FOREGROUND,g_chartAppearance.foregroundColor))
{
PrintFormat("Failed to restore chart foreground color. Error=%d",GetLastError());
restored=false;
}
//--- Restore the original grid visibility and chart drawing mode.
if(!ChartSetInteger(0,CHART_SHOW_GRID,g_chartAppearance.showGrid))
{
PrintFormat("Failed to restore chart grid visibility. Error=%d",GetLastError());
restored=false;
}
if(!ChartSetInteger(0,CHART_MODE,g_chartAppearance.chartMode))
{
PrintFormat("Failed to restore chart mode. Error=%d",GetLastError());
restored=false;
}
//--- Restore the original bullish chart and candle colors.
if(!ChartSetInteger(0,CHART_COLOR_CHART_UP,g_chartAppearance.chartUpColor))
{
PrintFormat("Failed to restore bullish chart color. Error=%d",GetLastError());
restored=false;
}
if(!ChartSetInteger(0,CHART_COLOR_CANDLE_BULL,g_chartAppearance.candleBullColor))
{
PrintFormat("Failed to restore bullish candle color. Error=%d",GetLastError());
restored=false;
}
//--- Restore the original bearish chart and candle colors.
if(!ChartSetInteger(0,CHART_COLOR_CHART_DOWN,g_chartAppearance.chartDownColor))
{
PrintFormat("Failed to restore bearish chart color. Error=%d",GetLastError());
restored=false;
}
if(!ChartSetInteger(0,CHART_COLOR_CANDLE_BEAR,g_chartAppearance.candleBearColor))
{
PrintFormat("Failed to restore bearish candle color. Error=%d",GetLastError());
restored=false;
}
//--- Restore the original Bid and Ask line colors.
if(!ChartSetInteger(0,CHART_COLOR_BID,g_chartAppearance.bidColor))
{
PrintFormat("Failed to restore Bid line color. Error=%d",GetLastError());
restored=false;
}
if(!ChartSetInteger(0,CHART_COLOR_ASK,g_chartAppearance.askColor))
{
PrintFormat("Failed to restore Ask line color. Error=%d",GetLastError());
restored=false;
}
//--- Refresh the chart after restoring all saved appearance properties.
ChartRedraw(0);
//--- Clear the saved-state flag only after a successful restoration.
if(restored)
g_chartAppearanceSaved=false;
return(restored);
}
//+------------------------------------------------------------------+
//| Configures the visual plots used by Supertrend Pro |
//+------------------------------------------------------------------+
bool ConfigureIndicatorPlots()
{
//--- Configure Plot 0 as two-color candles. Color index 0 represents
//--- bearish candles and color index 1 represents bullish candles.
if(!PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_COLOR_CANDLES))
{
PrintFormat("Failed to set the candle plot type. Error=%d",GetLastError());
return(false);
}
if(!PlotIndexSetInteger(0,PLOT_COLOR_INDEXES,2))
{
PrintFormat("Failed to configure candle color indexes. Error=%d",GetLastError());
return(false);
}
if(!PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,COLOR_BEARISH))
{
PrintFormat("Failed to set bearish candle color. Error=%d",GetLastError());
return(false);
}
if(!PlotIndexSetInteger(0,PLOT_LINE_COLOR,1,COLOR_BULLISH))
{
PrintFormat("Failed to set bullish candle color. Error=%d",GetLastError());
return(false);
}
if(!PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE))
{
PrintFormat("Failed to set the candle plot empty value. Error=%d",GetLastError());
return(false);
}
if(!PlotIndexSetString(0,PLOT_LABEL,
"Supertrend Open;Supertrend High;Supertrend Low;Supertrend Close"))
{
PrintFormat("Failed to set the candle plot label. Error=%d",GetLastError());
return(false);
}
//--- Configure Plot 1 as the bearish upper Supertrend band.
if(!PlotIndexSetInteger(1,PLOT_DRAW_TYPE,DRAW_LINE))
{
PrintFormat("Failed to set upper Supertrend plot type. Error=%d",GetLastError());
return(false);
}
if(!PlotIndexSetInteger(1,PLOT_LINE_STYLE,STYLE_SOLID))
{
PrintFormat("Failed to set upper Supertrend line style. Error=%d",GetLastError());
return(false);
}
if(!PlotIndexSetInteger(1,PLOT_LINE_WIDTH,2))
{
PrintFormat("Failed to set upper Supertrend line width. Error=%d",GetLastError());
return(false);
}
if(!PlotIndexSetInteger(1,PLOT_LINE_COLOR,COLOR_BEARISH))
{
PrintFormat("Failed to set upper Supertrend line color. Error=%d",GetLastError());
return(false);
}
if(!PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,EMPTY_VALUE))
{
PrintFormat("Failed to set upper Supertrend empty value. Error=%d",GetLastError());
return(false);
}
if(!PlotIndexSetString(1,PLOT_LABEL,"Bearish Supertrend"))
{
PrintFormat("Failed to set upper Supertrend plot label. Error=%d",GetLastError());
return(false);
}
//--- Configure Plot 2 as the bullish lower Supertrend band.
if(!PlotIndexSetInteger(2,PLOT_DRAW_TYPE,DRAW_LINE))
{
PrintFormat("Failed to set lower Supertrend plot type. Error=%d",GetLastError());
return(false);
}
if(!PlotIndexSetInteger(2,PLOT_LINE_STYLE,STYLE_SOLID))
{
PrintFormat("Failed to set lower Supertrend line style. Error=%d",GetLastError());
return(false);
}
if(!PlotIndexSetInteger(2,PLOT_LINE_WIDTH,2))
{
PrintFormat("Failed to set lower Supertrend line width. Error=%d",GetLastError());
return(false);
}
if(!PlotIndexSetInteger(2,PLOT_LINE_COLOR,COLOR_BULLISH))
{
PrintFormat("Failed to set lower Supertrend line color. Error=%d",GetLastError());
return(false);
}
if(!PlotIndexSetDouble(2,PLOT_EMPTY_VALUE,EMPTY_VALUE))
{
PrintFormat("Failed to set lower Supertrend empty value. Error=%d",GetLastError());
return(false);
}
if(!PlotIndexSetString(2,PLOT_LABEL,"Bullish Supertrend"))
{
PrintFormat("Failed to set lower Supertrend plot label. Error=%d",GetLastError());
return(false);
}
//--- Prevent plotting before enough bars exist to produce the first
//--- ATR value required by the Supertrend calculation.
int drawBegin=InpATRPeriod-1;
if(!PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,drawBegin) ||
!PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,drawBegin) ||
!PlotIndexSetInteger(2,PLOT_DRAW_BEGIN,drawBegin))
{
PrintFormat("Failed to configure the plot starting position. Error=%d",GetLastError());
return(false);
}
//--- Configure the indicator identity and displayed price precision.
if(!IndicatorSetString(INDICATOR_SHORTNAME,"Supertrend Pro"))
{
PrintFormat("Failed to set indicator short name. Error=%d",GetLastError());
return(false);
}
if(!IndicatorSetInteger(INDICATOR_DIGITS,_Digits))
{
PrintFormat("Failed to set indicator precision. Error=%d",GetLastError());
return(false);
}
return(true);
}
//+------------------------------------------------------------------+
//| Copies ATR values required for the current calculation range |
//+------------------------------------------------------------------+
bool GetATRValues(const int startIndex,
const int lastClosedIndex,
const int ratesTotal)
{
//--- Determine how many confirmed ATR values are required.
int valuesRequired=lastClosedIndex-startIndex+1;
if(valuesRequired<=0)
return(true);
//--- Confirm that the ATR handle has calculated enough recent values
//--- to cover the requested closed-bar range.
int calculatedBars=BarsCalculated(g_atrHandle);
if(calculatedBars<valuesRequired+1)
return(false);
//--- Keep the persistent ATR array aligned with the complete price
//--- history so each ATR value uses the same chronological bar index.
if(ArraySize(g_atrValues)!=ratesTotal)
{
if(ArrayResize(g_atrValues,ratesTotal)!=ratesTotal)
{
PrintFormat("Failed to resize the ATR working array to %d elements.",
ratesTotal);
return(false);
}
if(!ArraySetAsSeries(g_atrValues,false))
{
Print("Failed to configure chronological indexing for ATR values.");
return(false);
}
}
//--- Create a temporary array for only the recent ATR values required
//--- by this calculation pass.
double atrValues[];
if(ArrayResize(atrValues,valuesRequired)!=valuesRequired)
{
PrintFormat("Failed to resize the temporary ATR array to %d elements.",
valuesRequired);
return(false);
}
ArraySetAsSeries(atrValues,false);
//--- Start from shift 1 because the current live bar is intentionally
//--- excluded from confirmed Supertrend calculations.
ResetLastError();
int copiedValues=CopyBuffer(g_atrHandle,0,1,valuesRequired,atrValues);
if(copiedValues<0)
{
PrintFormat("Failed to copy ATR values. Error=%d",GetLastError());
return(false);
}
//--- A partial copy means the requested ATR range is not fully ready.
if(copiedValues!=valuesRequired)
return(false);
//--- Transfer the copied ATR segment into its matching chronological
//--- positions in the persistent ATR working array.
for(int i=0;i<valuesRequired;i++)
g_atrValues[startIndex+i]=atrValues[i];
return(true);
}
//+------------------------------------------------------------------+
//| Calculates one bar according to the previous Supertrend state |
//+------------------------------------------------------------------+
void CalculateBar(const int index,
const double &open[],
const double &high[],
const double &low[],
const double &close[])
{
int previousIndex=index-1;
//--- Continue resolving the initial neutral state until price
//--- establishes the first confirmed directional trend.
if(g_trendState[previousIndex]==TREND_NEUTRAL)
{
CalculateNeutralState(index,high,low,close);
//--- Color the bar only after the neutral state resolves into
//--- a confirmed bullish or bearish trend.
if(g_trendState[index]==TREND_BULLISH)
SetBullishCandle(index,open,high,low,close);
else
if(g_trendState[index]==TREND_BEARISH)
SetBearishCandle(index,open,high,low,close);
return;
}
//--- Apply bullish continuation or bearish reversal logic when the
//--- preceding confirmed bar belongs to an established bullish trend.
if(g_trendState[previousIndex]==TREND_BULLISH)
{
CalculateBullishState(index,open,high,low,close);
return;
}
//--- Apply bearish continuation or bullish reversal logic when the
//--- preceding confirmed bar belongs to an established bearish trend.
if(g_trendState[previousIndex]==TREND_BEARISH)
CalculateBearishState(index,open,high,low,close);
2026-09-18 17:23:49 +03:00
}
2026-09-18 17:37:34 +03:00
2026-09-18 17:23:49 +03:00
//+------------------------------------------------------------------+
2026-09-18 17:37:34 +03:00
//| Processes one bar while the Supertrend state remains neutral |
2026-09-18 17:23:49 +03:00
//+------------------------------------------------------------------+
2026-09-18 17:37:34 +03:00
bool CalculateNeutralState(const int index,
const double &high[],
const double &low[],
const double &close[])
2026-09-18 17:23:49 +03:00
{
2026-09-18 17:37:34 +03:00
//--- Calculate the raw ATR-based bands for the current closed bar.
double barMidpoint=(high[index]+low[index])/2.0;
double upperBandValue=barMidpoint+
g_atrValues[index]*InpATRMultiplier;
double lowerBandValue=barMidpoint-
g_atrValues[index]*InpATRMultiplier;
int previousIndex=index-1;
//--- Establish the first bullish trend when price closes above the
//--- previous neutral upper band.
if(close[index]>g_upperBand[previousIndex])
{
g_trendState[index]=TREND_BULLISH;
g_upperBand[index]=EMPTY_VALUE;
g_lowerBand[index]=lowerBandValue;
return(true);
}
//--- Establish the first bearish trend when price closes below the
//--- previous neutral lower band.
if(close[index]<g_lowerBand[previousIndex])
{
g_trendState[index]=TREND_BEARISH;
g_lowerBand[index]=EMPTY_VALUE;
g_upperBand[index]=upperBandValue;
return(true);
}
//--- Keep the state neutral while price remains between both bands.
//--- The upper band may only move downward during this stage.
if(upperBandValue<g_upperBand[previousIndex])
g_upperBand[index]=upperBandValue;
else
g_upperBand[index]=g_upperBand[previousIndex];
//--- The lower band may only move upward while the initial trend
//--- remains unresolved.
if(lowerBandValue>g_lowerBand[previousIndex])
g_lowerBand[index]=lowerBandValue;
else
g_lowerBand[index]=g_lowerBand[previousIndex];
//--- Preserve the neutral state until either boundary is breached.
g_trendState[index]=TREND_NEUTRAL;
return(false);
2026-09-18 17:23:49 +03:00
}
2026-09-18 17:37:34 +03:00
2026-09-18 17:23:49 +03:00
//+------------------------------------------------------------------+
2026-09-18 17:37:34 +03:00
//| Processes one bar when the previous trend state is bullish |
2026-09-18 17:23:49 +03:00
//+------------------------------------------------------------------+
2026-09-18 17:37:34 +03:00
void CalculateBullishState(const int index,
const double &open[],
const double &high[],
const double &low[],
const double &close[])
2026-09-18 17:23:49 +03:00
{
2026-09-18 17:37:34 +03:00
//--- Calculate the raw ATR-based bands for the current confirmed bar.
double barMidpoint=(high[index]+low[index])/2.0;
double upperBandValue=barMidpoint+
g_atrValues[index]*InpATRMultiplier;
double lowerBandValue=barMidpoint-
g_atrValues[index]*InpATRMultiplier;
int previousIndex=index-1;
//--- Reverse to bearish when price closes below the previous active
//--- lower band. The upper band becomes active from this bar onward.
if(close[index]<g_lowerBand[previousIndex])
{
g_trendState[index]=TREND_BEARISH;
g_lowerBand[index]=EMPTY_VALUE;
g_upperBand[index]=upperBandValue;
//--- Recolor the reversal bar immediately as part of the new
//--- confirmed bearish trend.
SetBearishCandle(index,open,high,low,close);
return;
}
//--- Preserve the bullish trend while allowing the lower band to
//--- tighten upward without moving back down.
if(lowerBandValue>g_lowerBand[previousIndex])
g_lowerBand[index]=lowerBandValue;
else
g_lowerBand[index]=g_lowerBand[previousIndex];
//--- Keep the bearish upper band inactive while bullish control remains.
g_upperBand[index]=EMPTY_VALUE;
g_trendState[index]=TREND_BULLISH;
//--- Draw the confirmed bar using the bullish candle color.
SetBullishCandle(index,open,high,low,close);
2026-09-18 17:23:49 +03:00
}
2026-09-18 17:37:34 +03:00
2026-09-18 17:23:49 +03:00
//+------------------------------------------------------------------+
2026-09-18 17:37:34 +03:00
//| Processes one bar when the previous trend state is bearish |
2026-09-18 17:23:49 +03:00
//+------------------------------------------------------------------+
2026-09-18 17:37:34 +03:00
void CalculateBearishState(const int index,
const double &open[],
const double &high[],
const double &low[],
const double &close[])
2026-09-18 17:23:49 +03:00
{
2026-09-18 17:37:34 +03:00
//--- Calculate the raw ATR-based bands for the current confirmed bar.
double barMidpoint=(high[index]+low[index])/2.0;
double upperBandValue=barMidpoint+
g_atrValues[index]*InpATRMultiplier;
double lowerBandValue=barMidpoint-
g_atrValues[index]*InpATRMultiplier;
int previousIndex=index-1;
//--- Reverse to bullish when price closes above the previous active
//--- upper band. The lower band becomes active from this bar onward.
if(close[index]>g_upperBand[previousIndex])
{
g_trendState[index]=TREND_BULLISH;
g_upperBand[index]=EMPTY_VALUE;
g_lowerBand[index]=lowerBandValue;
//--- Recolor the reversal bar immediately as part of the new
//--- confirmed bullish trend.
SetBullishCandle(index,open,high,low,close);
return;
}
//--- Preserve the bearish trend while allowing the upper band to
//--- tighten downward without moving back upward.
if(upperBandValue<g_upperBand[previousIndex])
g_upperBand[index]=upperBandValue;
else
g_upperBand[index]=g_upperBand[previousIndex];
//--- Keep the bullish lower band inactive while bearish control remains.
g_lowerBand[index]=EMPTY_VALUE;
g_trendState[index]=TREND_BEARISH;
//--- Draw the confirmed bar using the bearish candle color.
SetBearishCandle(index,open,high,low,close);
2026-09-18 17:23:49 +03:00
}
2026-09-18 17:37:34 +03:00
2026-09-18 17:23:49 +03:00
//+------------------------------------------------------------------+
2026-09-18 17:37:34 +03:00
//| Populates the candle buffers for a confirmed bullish bar |
2026-09-18 17:23:49 +03:00
//+------------------------------------------------------------------+
2026-09-18 17:37:34 +03:00
void SetBullishCandle(const int index,
const double &open[],
const double &high[],
const double &low[],
const double &close[])
2026-09-18 17:23:49 +03:00
{
2026-09-18 17:37:34 +03:00
//--- Copy the original OHLC values so the indicator can redraw the
//--- completed candle using the bullish color index.
g_candleOpen[index]=open[index];
g_candleHigh[index]=high[index];
g_candleLow[index]=low[index];
g_candleClose[index]=close[index];
g_candleColor[index]=1.0;
2026-09-18 17:23:49 +03:00
}
2026-09-18 17:37:34 +03:00
2026-09-18 17:23:49 +03:00
//+------------------------------------------------------------------+
2026-09-18 17:37:34 +03:00
//| Populates the candle buffers for a confirmed bearish bar |
//+------------------------------------------------------------------+
void SetBearishCandle(const int index,
const double &open[],
const double &high[],
const double &low[],
const double &close[])
{
//--- Copy the original OHLC values so the indicator can redraw the
//--- completed candle using the bearish color index.
g_candleOpen[index]=open[index];
g_candleHigh[index]=high[index];
g_candleLow[index]=low[index];
g_candleClose[index]=close[index];
g_candleColor[index]=0.0;
}
//+------------------------------------------------------------------+
//| Sends a push notification for a confirmed directional reversal |
//+------------------------------------------------------------------+
void NotifyConfirmedTrendChange(const int index,
const datetime &time[])
{
if(!InpEnablePushNotifications)
return;
//--- A previous confirmed bar is required to determine whether the
//--- current state represents an actual trend change.
if(index<1)
return;
int previousIndex=index-1;
//--- Ignore the first directional trend established from the neutral
//--- startup state because it is not a bullish-to-bearish reversal.
if(g_trendState[previousIndex]==TREND_NEUTRAL)
return;
//--- Ignore bars whose directional state did not change.
if(g_trendState[index]==g_trendState[previousIndex])
return;
//--- Only confirmed bullish and bearish states are valid notification
//--- targets.
if(g_trendState[index]!=TREND_BULLISH &&
g_trendState[index]!=TREND_BEARISH)
return;
//--- Prevent recalculation of the same confirmed bar from generating
//--- another push notification.
if(time[index]==g_lastNotifiedBarTime)
return;
//--- Build a concise message containing the symbol, timeframe, and
//--- newly confirmed Supertrend direction.
string trendText=(g_trendState[index]==TREND_BULLISH) ?
"BULLISH" :
"BEARISH";
string message=StringFormat("Supertrend | %s %s | Trend changed to %s",
_Symbol,
EnumToString((ENUM_TIMEFRAMES)_Period),
trendText);
//--- Send the notification and record the bar only after MetaTrader
//--- confirms that the message was accepted for delivery.
ResetLastError();
if(!SendNotification(message))
{
PrintFormat("Failed to send Supertrend push notification. Error=%d",
GetLastError());
return;
}
g_lastNotifiedBarTime=time[index];
}
//+------------------------------------------------------------------+