Complete .mq5 source code

MT5 Supertrend Indicator: MQL5 Code and Alerts

A Supertrend indicator for MT5 is a custom MQL5 chart overlay that uses Average True Range to place a trailing band above or below price. This implementation includes complete source code, configurable ATR settings, separate bullish and bearish buffers, and alerts that trigger only after a candle closes.

What this MT5 indicator includes

The standard starting point is ATR period 10 with a multiplier of 3.0.

The code calculates signals in OnCalculate() and keeps indicator logic separate from order execution.

Closed-bar alerts use the last completed candle, so a forming candle cannot trigger a final signal.

Supertrend follows trends well but can flip repeatedly when price moves sideways.

How the Supertrend signal works

Bullish flip

A bullish flip occurs when the current close moves above the final upper band after the previous state was bearish. The indicator then plots the final lower band beneath price. The code calculates the active candle for visual feedback, but alerts inspect the last completed candle and compare it with the candle before it. When I review a Supertrend port, this is the first indexing check I make because reading the forming candle as a confirmed signal is a common source of unstable alerts.

Bearish flip

A bearish flip occurs when the current close falls below the final lower band after the previous state was bullish. The plotted line moves above price and switches to the bearish buffer. Supertrend can be used as a direction filter or a trailing reference, but it is not an order system by itself. If an Expert Advisor uses these buffers, its own position sizing, spread checks, stop placement, and execution rules still need to be defined and tested.

MQL5 Custom Indicator Code

//+------------------------------------------------------------------+
//| SuperTrend_Custom.mq5                                            |
//| MT5 custom indicator with ATR bands and closed-bar alerts        |
//| Educational example. This is not financial advice.              |
//+------------------------------------------------------------------+
#property copyright "Pineify"
#property link      "https://pineify.app"
#property version   "1.10"
#property strict

#property indicator_chart_window
#property indicator_buffers 6
#property indicator_plots   2

#property indicator_label1  "Supertrend Up"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrLimeGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2

#property indicator_label2  "Supertrend Down"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrTomato
#property indicator_style2  STYLE_SOLID
#property indicator_width2  2

input int    InpAtrPeriod    = 10;
input double InpMultiplier   = 3.0;
input bool   InpDesktopAlert = true;
input bool   InpPushAlert    = false;

double UpBuffer[];
double DownBuffer[];
double TrendBuffer[];
double FinalUpperBuffer[];
double FinalLowerBuffer[];
double AtrBuffer[];

int      atrHandle = INVALID_HANDLE;
datetime lastAlertBar = 0;

int OnInit()
  {
   if(InpAtrPeriod < 1 || InpMultiplier <= 0.0)
      return INIT_PARAMETERS_INCORRECT;

   SetIndexBuffer(0, UpBuffer, INDICATOR_DATA);
   SetIndexBuffer(1, DownBuffer, INDICATOR_DATA);
   SetIndexBuffer(2, TrendBuffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(3, FinalUpperBuffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(4, FinalLowerBuffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(5, AtrBuffer, INDICATOR_CALCULATIONS);

   ArraySetAsSeries(UpBuffer, false);
   ArraySetAsSeries(DownBuffer, false);
   ArraySetAsSeries(TrendBuffer, false);
   ArraySetAsSeries(FinalUpperBuffer, false);
   ArraySetAsSeries(FinalLowerBuffer, false);
   ArraySetAsSeries(AtrBuffer, false);

   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, InpAtrPeriod);
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, InpAtrPeriod);

   atrHandle = iATR(_Symbol, _Period, InpAtrPeriod);
   if(atrHandle == INVALID_HANDLE)
     {
      Print("Could not create iATR handle. Error: ", GetLastError());
      return INIT_FAILED;
     }

   IndicatorSetString(
      INDICATOR_SHORTNAME,
      StringFormat("Supertrend(%d, %.2f)", InpAtrPeriod, InpMultiplier)
   );
   IndicatorSetInteger(INDICATOR_DIGITS, _Digits);

   return INIT_SUCCEEDED;
  }

void OnDeinit(const int reason)
  {
   if(atrHandle != INVALID_HANDLE)
      IndicatorRelease(atrHandle);
  }

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 <= InpAtrPeriod + 2)
      return 0;

   ArraySetAsSeries(time, false);
   ArraySetAsSeries(high, false);
   ArraySetAsSeries(low, false);
   ArraySetAsSeries(close, false);

   int copied = CopyBuffer(atrHandle, 0, 0, rates_total, AtrBuffer);
   if(copied < rates_total)
      return prev_calculated;

   int start = prev_calculated > 0 ? prev_calculated - 1 : InpAtrPeriod;

   if(prev_calculated == 0)
     {
      for(int i = 0; i < InpAtrPeriod; i++)
        {
         UpBuffer[i] = EMPTY_VALUE;
         DownBuffer[i] = EMPTY_VALUE;
         TrendBuffer[i] = 0.0;
         FinalUpperBuffer[i] = 0.0;
         FinalLowerBuffer[i] = 0.0;
        }
     }

   for(int i = start; i < rates_total && !IsStopped(); i++)
     {
      double midpoint = (high[i] + low[i]) * 0.5;
      double basicUpper = midpoint + InpMultiplier * AtrBuffer[i];
      double basicLower = midpoint - InpMultiplier * AtrBuffer[i];

      if(i == InpAtrPeriod)
        {
         FinalUpperBuffer[i] = basicUpper;
         FinalLowerBuffer[i] = basicLower;
         TrendBuffer[i] = 1.0;
        }
      else
        {
         int previous = i - 1;

         FinalUpperBuffer[i] =
            (basicUpper < FinalUpperBuffer[previous] ||
             close[previous] > FinalUpperBuffer[previous])
            ? basicUpper
            : FinalUpperBuffer[previous];

         FinalLowerBuffer[i] =
            (basicLower > FinalLowerBuffer[previous] ||
             close[previous] < FinalLowerBuffer[previous])
            ? basicLower
            : FinalLowerBuffer[previous];

         if(TrendBuffer[previous] < 0.0)
            TrendBuffer[i] =
               close[i] > FinalUpperBuffer[i] ? 1.0 : -1.0;
         else
            TrendBuffer[i] =
               close[i] < FinalLowerBuffer[i] ? -1.0 : 1.0;
        }

      if(TrendBuffer[i] > 0.0)
        {
         UpBuffer[i] = FinalLowerBuffer[i];
         DownBuffer[i] = EMPTY_VALUE;
        }
      else
        {
         UpBuffer[i] = EMPTY_VALUE;
         DownBuffer[i] = FinalUpperBuffer[i];
        }
     }

   if(prev_calculated > 0 &&
      (InpDesktopAlert || InpPushAlert) &&
      rates_total > InpAtrPeriod + 3)
     {
      int closedBar = rates_total - 2;
      int priorBar = rates_total - 3;

      if(TrendBuffer[closedBar] != TrendBuffer[priorBar] &&
         time[closedBar] != lastAlertBar)
        {
         string direction =
            TrendBuffer[closedBar] > 0.0 ? "bullish" : "bearish";
         string message = StringFormat(
            "%s %s Supertrend closed %s at %.*f",
            _Symbol,
            EnumToString(_Period),
            direction,
            _Digits,
            close[closedBar]
         );

         if(InpDesktopAlert)
            Alert(message);
         if(InpPushAlert)
            SendNotification(message);

         lastAlertBar = time[closedBar];
        }
     }

   return rates_total;
  }

Copy this code into MetaEditor, save it in the MQL5/Indicators folder, and compile with F7.

Change the settings or add your own signal filter

Describe the ATR inputs, alert rules, visual style, or confirmation filter you want. Pineify generates editable MQL5 source code that you can inspect and compile in MetaEditor.

Pine Script vs MQL5: Same Strategy, Different Platforms

AspectPine Script (TradingView)MQL5 (MetaTrader 5)
ExecutionSeries evaluated on chart updatesEvent handlers with explicit buffers
DeploymentRuns in TradingView with alertsRuns in the MT5 terminal or on a VPS
Broker accessVia TradingView broker integrationDirect broker connectivity
BacktestingStrategy Tester for strategy scriptsStrategy Tester for Expert Advisors
Code complexitySimpler, functional syntaxC++-like, more powerful

The calculation can be implemented on either platform, but the runtime model and buffer APIs differ. Read the Pine Script Supertrend reference before porting logic between them.

Frequently Asked Questions

Related MQL5 pages

Technical references

Risk and testing note

Past performance is not indicative of future results. Backtest statistics are based on historical data and do not guarantee future profits. Trading involves significant risk of loss. This content is for educational purposes only and does not constitute financial advice.