Complete .mq5 source code

Supertrend H1 MQL5 Indicator: Hourly Trend Direction & Entry Signals

An H1-only Supertrend overlay with explicit carried-band recurrence, two plotted buffers and completed-hour flip alerts. ATR 10 and multiplier 3.0 are editable examples, not an optimized configuration. The implementation uses MetaTrader iATR and starts with a bearish seed; its output needs data-level comparison before claiming parity with another platform.

How the indicator signal works

Calculation and signal conditions

Basic bands are the hourly high-low midpoint plus or minus multiplier times ATR. The upper band carries forward unless the new basic upper is lower or the preceding close exceeded the preceding upper; the lower band uses the symmetric rule. Direction flips when the close crosses the relevant carried band. The line includes the forming bar, while alerts compare the two most recent completed bars.

Interpretation and limitations

The overlay does not open or close trades. A plotted line may be used as a reference in a separately tested EA, but it does not place broker stops, guarantee locked profit or implement H4 EMA confirmation, 1.5 ATR initial risk or 3 ATR take profit. History correction, extension, changed inputs and recursive seed can change past output.

MQL5 Custom Indicator Code

//+------------------------------------------------------------------+
//| SuperTrend_H1.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(_Period!=PERIOD_H1 || 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_H1, InpAtrPeriod);
   if(atrHandle == INVALID_HANDLE)
     {
      Print("Could not create iATR handle. Error: ", GetLastError());
      return INIT_FAILED;
     }

   IndicatorSetString(
      INDICATOR_SHORTNAME,
      StringFormat("Supertrend H1(%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;

   bool reset=prev_calculated==0 || prev_calculated>rates_total;
   int start = reset ? InpAtrPeriod : (int)MathMax(InpAtrPeriod,prev_calculated-1);

   if(reset)
     {
      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];
        }
     }

   int closedBar=rates_total-2,priorBar=rates_total-3;
   if(reset || lastAlertBar==0) lastAlertBar=time[closedBar];
   else if(time[closedBar]!=lastAlertBar)
   {
      lastAlertBar=time[closedBar];
      if(TrendBuffer[closedBar]!=TrendBuffer[priorBar])
      {
         string message=StringFormat("%s %s Supertrend completed %s at %.*f",_Symbol,
            EnumToString(_Period),TrendBuffer[closedBar]>0?"up":"down",_Digits,close[closedBar]);
         if(InpDesktopAlert) Alert(message);
         if(InpPushAlert && !SendNotification(message)) Print("Push failed: ",GetLastError());
      }
   }

   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 inputs, buffers, alerts, visual style, or confirmation filter you want. Pineify generates editable MQL5 source code that you can inspect and compile in MetaEditor.

Frequently Asked Questions

Related MQL5 pages

Risk and testing note

These educational examples require independent compilation and testing. A compile pass or an illustrative setting does not establish execution correctness or profitability. Any reported performance must be supported by reproducible data and test settings; past results do not predict future returns. Trading involves significant risk of loss. This content is not financial advice.