Range Based Signals and Alerts
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © serkany88

//@version=5
indicator("Range Based Signals and Alerts", shorttitle="RB S&A", overlay=true, precision=3)

//To reduce frequency of signals on repeaded conds to avoid flooding of alerts
f_ideal_TimesInLast(bool _cond, simple int _len) =>  math.sum(_cond ? 1 : 0, _len)

//MA Function
ma(simple string smt, float src, simple int len) =>
    switch smt
        "RMA" =>  ta.rma(src, len)
        "SMA" => ta.sma(src, len)
        "EMA" => ta.ema(src, len)
        "VWMA" => ta.vwma(src, len)
        "WMA" => ta.wma(src, len)
        "HMA" => ta.hma(src, len)
        "LSMA" => ta.linreg(src, len, 0)
        => na

// Calculating MACD
f_getmacd(float src, simple int macd_fast, simple int macd_slow, simple int macd_sig, simple string maType) =>
    _close = src[barstate.isrealtime ? 1 : 0]
    float[] macdArr = array.new<float>()
    fast_ma = ma(maType, _close, macd_fast)
    slow_ma = ma(maType, _close, macd_slow)
    macd = fast_ma - slow_ma
    sig = ma(maType, macd, macd_sig)
    hist = macd - sig
    macdArr.push(hist), macdArr.push(sig), macdArr.push(macd)
    macdArr

//Let's get our inputs
hi_lo_tf = input.timeframe("D", title="High-Low MTF", group="High-Low MTF", tooltip="For reliability make sure your choice is higher than your current chart timeframe")

ma_type = input.string("EMA", title="MA Type", options =["RMA", "SMA", "EMA", "VWMA", "WMA", "HMA", "LSMA"] ,group="MA")
ma_src = input.source(close, title="MA Source", group="MA" )
ma_length = input.int(20, title="MA Length", minval=1, group="MA")

macd_enb = input.bool(true, title="Enable MACD Trend", group="MTF Macd")
macd_tf = input.timeframe("D", title="MACD TF", group="MTF Macd", tooltip="For reliability make sure your choice is higher than your current chart timeframe")
macd_src = input.source(close, title="MACD Source", group="MTF Macd")
macd_fast = input.int(12, title="MACD Fast", minval=1, group="MTF Macd")
macd_slow = input.int(26, title="MACD Slow", minval=1, group="MTF Macd")
macd_sig = input.int(9, title="MACD Signal", minval=1, group="MTF Macd")
macd_ma_type = input.string("EMA", title="MACD Smoothing Type", options =["RMA", "SMA", "EMA", "VWMA", "WMA", "HMA", "LSMA"] ,group="MTF Macd")

//Let's get high and low
[_hi, _lo] = request.security(syminfo.tickerid, hi_lo_tf, [high[barstate.isrealtime ? 1 : 0], 
 low[barstate.isrealtime ? 1 : 0]])

//Let's get MACD
macdArr = request.security(syminfo.tickerid, macd_tf, f_getmacd(macd_src, macd_fast, macd_slow, macd_sig, macd_ma_type))

//Let's get our MA based on our choice
float ma = ma(ma_type, ma_src, ma_length)

//Get macd results from array
float macd = array.get(macdArr, 2)
float sig = array.get(macdArr, 1)
float hist = array.get(macdArr, 0) // We don't really use it but whatever

//Rules of signal production
bool longCond = (macd_enb ? macd > sig : true) and close < _lo and close > open and close > ma and open > ma and barstate.isconfirmed
bool shortCond = (macd_enb ? macd < sig : true) and close > _hi and close < open and close < ma and open < ma and barstate.isconfirmed

//Let's filter out repeated signals
longCond := f_ideal_TimesInLast(longCond, 7) > 1 ? false : longCond
shortCond := f_ideal_TimesInLast(shortCond, 7) > 1 ? false : shortCond

//Plots
plotshape(longCond, title="LongCond", style=shape.triangleup, color=color.green, size=size.small, location=location.belowbar)
plotshape(shortCond, title="shortCond", style=shape.triangledown, color=color.red, size=size.small, location=location.abovebar)

plot(ma, title="Moving Average", color=color.white)
plot(_hi, title="Daily High", color=color.red, linewidth = 2)
plot(_lo, title="Daily Low", color=color.green, linewidth= 2)

//Alerts
alertcondition(longCond, title="Long Signal", message="Long Signal Triggered")
alertcondition(shortCond, title="Short Signal", message="Short Signal Triggered")

//Functional Alert for Both condition
string alertString = str.format("{0} Signal on {1}\nTF: {2}", longCond ? "Long" : "Short" ,syminfo.tickerid, timeframe.period)
if longCond or shortCond
    alert(alertString, alert.freq_once_per_bar_close)