//+------------------------------------------------------------------+ //| SuperTrendSignalAlerts.mq5 | //| Copyright 2026, Allan Niñal | //| https://www.allanninal.dev/mql5 | //+------------------------------------------------------------------+ //| SuperTrend: bands at hl2 -/+ multiplier x ATR that only ratchet | //| in the direction of the trend. The trend flips when the close | //| breaks the opposite band. ATR is Wilder's (RMA, as ta.atr) or an | //| SMA of the true range. Optional filters on the arrows and alerts:| //| EMA trend and RSI side. | //| Arrows and alerts come from closed bars only, so a signal never | //| appears and then disappears. The line moves on the live bar. | //+------------------------------------------------------------------+ // Licence: Mozilla Public License 2.0. This Source Code Form is subject // to the terms of the MPL, v. 2.0. If a copy of the MPL was not // distributed with this file, You can obtain one at // https://mozilla.org/MPL/2.0/ // Origin: the SuperTrend method (ATR bands that only ratchet with the trend) is by // Olivier Seban; the TradingView "SuperTrend" script is by KivancOzbilgic. This file is // an independent MQL implementation of that published method. // SPDX-License-Identifier: MPL-2.0 #property copyright "Copyright 2026, Allan Niñal " #property link "https://www.allanninal.dev/mql5" #property version "1.1" #property description "SuperTrend line with buy/sell arrows on closed bars, optional EMA and RSI filters." #property description "Alerts: pop-up, sound, push, e-mail. Non-repainting: signals only on closed bars." #property indicator_chart_window #property indicator_buffers 13 #property indicator_plots 4 #property indicator_label1 "SuperTrend" #property indicator_type1 DRAW_COLOR_LINE #property indicator_color1 clrDodgerBlue,clrTomato #property indicator_width1 2 #property indicator_label2 "Buy" #property indicator_type2 DRAW_ARROW #property indicator_color2 clrDodgerBlue #property indicator_width2 2 #property indicator_label3 "Sell" #property indicator_type3 DRAW_ARROW #property indicator_color3 clrTomato #property indicator_width3 2 #property indicator_label4 "Trend EMA" #property indicator_type4 DRAW_LINE #property indicator_color4 clrGoldenrod #property indicator_style4 STYLE_DOT enum ENUM_ST_ATR { ST_ATR_RMA=0, // RMA / Wilder (same as ta.atr) ST_ATR_SMA=1 // SMA of the true range }; input group "SuperTrend" input int InpATR = 10; // ATR period input double InpMult = 3.0; // ATR multiplier input ENUM_ST_ATR InpMethod = ST_ATR_RMA; // ATR method input group "Trend filter" input bool InpUseEMA = false; // Only signals with the EMA trend input int InpEMA = 200; // EMA period input bool InpShowEMA = true; // Draw the EMA (when the filter is on) input group "RSI filter" input bool InpUseRSI = false; // Buy only RSI above 50, sell only below input int InpRSI = 14; // RSI period input group "Display" input bool InpShowLine = true; // Draw the SuperTrend line input int InpArrowGap = 12; // Arrow distance from the candle, pixels #include "SignalAlerts.mqh" double g_line[],g_clr[],g_buy[],g_sell[],g_ema_draw[]; double g_up[],g_dn[],g_trend[],g_atr[],g_ema[],g_rsi[],g_gain[],g_loss[]; const string PRODUCT="SuperTrend"; int OnInit() { CkDebugStart(PRODUCT,"1.1",InpDebug,StringFormat("ATR %d, multiplier %.2f, method %d, EMA filter %d (%d), RSI filter %d (%d), arrow gap %s, line %d, alerts popup %d sound %d push %d e-mail %d", InpATR,InpMult,(int)InpMethod,(int)InpUseEMA,InpEMA,(int)InpUseRSI,InpRSI,IntegerToString(InpArrowGap),(int)InpShowLine,(int)InpAlertPopup,(int)InpAlertSound,(int)InpAlertPush,(int)InpAlertEmail)); if(InpATR<1 || InpATR>1000 || InpMult<=0 || InpMult>100 || InpEMA<1 || InpEMA>5000 || InpRSI<1 || InpRSI>1000 || InpArrowGap<0) { Print("SuperTrend: ATR period 1-1000, multiplier above 0 up to 100, EMA period 1-5000, RSI period 1-1000, arrow distance 0 or more"); CkDbg("init refused: parameters out of range"); return(INIT_PARAMETERS_INCORRECT); } SetIndexBuffer(0,g_line,INDICATOR_DATA); SetIndexBuffer(1,g_clr,INDICATOR_COLOR_INDEX); SetIndexBuffer(2,g_buy,INDICATOR_DATA); SetIndexBuffer(3,g_sell,INDICATOR_DATA); SetIndexBuffer(4,g_ema_draw,INDICATOR_DATA); SetIndexBuffer(5,g_up,INDICATOR_CALCULATIONS); SetIndexBuffer(6,g_dn,INDICATOR_CALCULATIONS); SetIndexBuffer(7,g_trend,INDICATOR_CALCULATIONS); SetIndexBuffer(8,g_atr,INDICATOR_CALCULATIONS); SetIndexBuffer(9,g_ema,INDICATOR_CALCULATIONS); SetIndexBuffer(10,g_rsi,INDICATOR_CALCULATIONS); SetIndexBuffer(11,g_gain,INDICATOR_CALCULATIONS); SetIndexBuffer(12,g_loss,INDICATOR_CALCULATIONS); PlotIndexSetInteger(1,PLOT_ARROW,233); PlotIndexSetInteger(2,PLOT_ARROW,234); PlotIndexSetInteger(1,PLOT_ARROW_SHIFT,InpArrowGap); PlotIndexSetInteger(2,PLOT_ARROW_SHIFT,-InpArrowGap); for(int p=0; p<4; p++) PlotIndexSetDouble(p,PLOT_EMPTY_VALUE,EMPTY_VALUE); PlotIndexSetInteger(0,PLOT_DRAW_TYPE,InpShowLine ? DRAW_COLOR_LINE : DRAW_NONE); PlotIndexSetInteger(3,PLOT_DRAW_TYPE,(InpUseEMA && InpShowEMA) ? DRAW_LINE : DRAW_NONE); IndicatorSetString(INDICATOR_SHORTNAME,StringFormat("SuperTrend (%d, %.1f)",InpATR,InpMult)); IndicatorSetInteger(INDICATOR_DIGITS,_Digits); return(INIT_SUCCEEDED); } //--- true range of bar k //--- strict a>b / a1e-10*MathAbs(b)); } bool Below(const double a,const double b) { return(b-a>1e-10*MathAbs(b)); } double TrueRange(const int k,const double &high[],const double &low[],const double &close[]) { if(k==0) return(high[k]-low[k]); return(MathMax(high[k]-low[k],MathMax(MathAbs(high[k]-close[k-1]),MathAbs(low[k]-close[k-1])))); } 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<2) return(0); if(prev_calculated==0) CkDbg(StringFormat("full calculation, %d bars",rates_total)); int start=(prev_calculated>0 ? prev_calculated-1 : 0); for(int i=start; i=InpATR-1) { if(InpMethod==ST_ATR_SMA || i==InpATR-1) { double s=0; for(int k=i-InpATR+1; k<=i; k++) s+=TrueRange(k,high,low,close); g_atr[i]=s/InpATR; } else g_atr[i]=(g_atr[i-1]*(InpATR-1)+tr)/InpATR; } //--- EMA of the close, seeded with the SMA of the first InpEMA closes if(i=InpRSI) { if(i==InpRSI) { double sg=0,sl=0; for(int k=1; k<=InpRSI; k++) { double ch=close[k]-close[k-1]; sg+=MathMax(ch,0.0); sl+=MathMax(-ch,0.0); } g_gain[i]=sg/InpRSI; g_loss[i]=sl/InpRSI; } else { double ch=close[i]-close[i-1]; g_gain[i]=(g_gain[i-1]*(InpRSI-1)+MathMax(ch,0.0))/InpRSI; g_loss[i]=(g_loss[i-1]*(InpRSI-1)+MathMax(-ch,0.0))/InpRSI; } if(g_loss[i]==0.0) g_rsi[i]=100.0; else if(g_gain[i]==0.0) g_rsi[i]=0.0; else g_rsi[i]=100.0-100.0/(1.0+g_gain[i]/g_loss[i]); } //--- SuperTrend bands and trend g_buy[i]=EMPTY_VALUE; g_sell[i]=EMPTY_VALUE; if(g_atr[i]==EMPTY_VALUE) { g_up[i]=EMPTY_VALUE; g_dn[i]=EMPTY_VALUE; g_trend[i]=EMPTY_VALUE; g_line[i]=EMPTY_VALUE; g_clr[i]=0; continue; } double src=(high[i]+low[i])/2.0; double up=src-InpMult*g_atr[i]; double dn=src+InpMult*g_atr[i]; bool first=(i==0 || g_up[i-1]==EMPTY_VALUE); double up1=(first ? up : g_up[i-1]); double dn1=(first ? dn : g_dn[i-1]); if(i>0 && Above(close[i-1],up1)) up=MathMax(up,up1); if(i>0 && Below(close[i-1],dn1)) dn=MathMin(dn,dn1); double trend=(first ? 1.0 : g_trend[i-1]); if(trend==-1.0 && Above(close[i],dn1)) trend=1.0; else if(trend==1.0 && Below(close[i],up1)) trend=-1.0; g_up[i]=up; g_dn[i]=dn; g_trend[i]=trend; g_line[i]=(trend==1.0 ? up : dn); g_clr[i]=(trend==1.0 ? 0 : 1); //--- signals: the trend flips; only on closed bars if(first || i>rates_total-2) continue; bool buy=(trend==1.0 && g_trend[i-1]==-1.0); bool sell=(trend==-1.0 && g_trend[i-1]==1.0); if(InpUseEMA) { buy=buy && g_ema[i]!=EMPTY_VALUE && close[i]>g_ema[i]; sell=sell && g_ema[i]!=EMPTY_VALUE && close[i]50.0; sell=sell && g_rsi[i]!=EMPTY_VALUE && g_rsi[i]<50.0; } if(buy) { g_buy[i]=low[i]; if(i==rates_total-2) SignalAlert(PRODUCT,"BUY, trend up from "+DoubleToString(close[i],_Digits),time[i],prev_calculated>0); } if(sell) { g_sell[i]=high[i]; if(i==rates_total-2) SignalAlert(PRODUCT,"SELL, trend down from "+DoubleToString(close[i],_Digits),time[i],prev_calculated>0); } } return(rates_total); } //+------------------------------------------------------------------+