MA Bollinger Bands + RSI 
// This close code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// Special credits: ChartArt / Matthew J. Slabosz / Zen & The Art of Trading 
// Scipt Author: © LucasVivien
//@version=5

strategy('MA Bollinger Bands + RSI (Strategy)', shorttitle='MABB+RSI (Strat)', calc_on_order_fills=true,  overlay=true, initial_capital=10000, default_qty_type=strategy.cash, default_qty_value=10000, commission_value=0.1)

//==============================================================================
//================================   INPUTS   ==================================
//==============================================================================

var g_trades = '     Trade Parameters'
longTradesON     = input.bool (title='Long trades'         , defval=true , group=g_trades, inline='a', tooltip='')
shortTradesON    = input.bool (title='Short trades'        , defval=true , group=g_trades, inline='a', tooltip='Switch on/off long and short trades')
useTP            = input.bool (title='Use Take Profit'     , defval=false, group=g_trades, inline='' , tooltip='Fixed Take Profit value')
useSL            = input.bool (title='Use Stop Loss'       , defval=false, group=g_trades, inline='' , tooltip='Fixed Stop Loss value')
useTSL           = input.bool (title='Use Trailing Stop'   , defval=true , group=g_trades, inline='' , tooltip='ATR Trailing Stop Loss value ')
reEnterAfterSLTP = input.bool (title='Re-Entry after SL/TP', defval=true , group=g_trades, inline='' , tooltip='Allows to re-enter trades in the same direction as previous trade if previous trade\'s stop loss or take profit was hit')
TSLlookback      = input.int  (title='Trailing lookback'   , defval=2    , group=g_trades, inline='' , tooltip='How many bars back will trailing stops look for a swing low (longs) or sing high (short) to get a starting point', minval=0, maxval=1000, step=1)
atrMult          = input.float(title='ATR Mult'            , defval=9.0  , group=g_trades, inline='' , tooltip='Increase/decrease to set stops and/or targets further/closer to trade entry price', minval=0.1)
atrLen           = input.int  (title='ATR Length'          , defval=14   , group=g_trades, inline='' , tooltip='Average of the \'True Range\' over x past bars', minval=0)
rr               = input.float(title='Risk:Reward'         , defval=1    , group=g_trades, inline='' , tooltip='Multiplies the take profit distance by this number ', minval=0, maxval=100, step=0.1)

var g_volatility = '     Volatility Filters'
UseVolHigh = input.bool (title='High Volatility'   , defval=true , group=g_volatility, inline='b', tooltip='')
UseVolLow  = input.bool (title='Low Volatility'    , defval=true , group=g_volatility, inline='b', tooltip='Filters out trade signals during high volatility / low volatility or both.')
BBvolX     = input.float(title='Volatility Factor' , defval=5.0  , group=g_volatility, inline='' , tooltip='Lower this number to filter out more trades when volatility at extremes', maxval=10, minval=0.1, step=0.1)
AddVol     = input.bool (title='Volatility Visuals', defval=false, group=g_volatility, inline='' , tooltip='Plots additionnal graphs on the chart to illustrate how extreme levels of volatility are defined (how Bollinger Bands are colored)')

var g_MABB = '     Moving Average & Bollinger Bands'
MAtype = input.string(title='MA Type', defval='SMA', group=g_MABB, inline='c', tooltip='Type of moving average used for standard deviation', options=['SMA', 'EMA', 'WMA', 'VWMA', 'HMA'])
MAlen  = input.int   (title='MA Length', defval=200, group=g_MABB, inline='c', tooltip='Moving average lookback')
BBX    = input.float (title=' BB Mult', defval=2.0 , group=g_MABB, inline='d', tooltip='Set upper & lower bands closer / appart', step=0.01, minval=0.001)
BBlen  = input.int   (title='BB Length', defval=200, group=g_MABB, inline='d', tooltip='Bollinger bands, standard deviation lookback')

var g_RSI = '     Relative Strength Index'
RSINlen = input.int(title='RSI Cross Loockback ', defval=10, group=g_RSI, tooltip='How many bars back (from price crossing-over lower bound or crossing-under upper bound) to look for corresponding RSI neutral crossover/under', minval=0, maxval=1000)
RSIN    = input.int(title='RSI Neutral'         , defval=50, group=g_RSI, tooltip='Defines the value at wich RSI neutral crossover or crossunder occurs')
RSIlen  = input.int(title='RSI Length'          , defval=6 , group=g_RSI, tooltip='Relative Strenght Index lookback')

var g_datetime = '     Date & Time Filters'
UseDateFilter  = input.bool   (title='Enable Date Filter'   , defval=false                              , group=g_datetime, tooltip='Turns on/off date filter')
StartDate      = input.time   (title='Start Date Filter'    , defval=timestamp('1 Jan 2022 00:00 +0000'), group=g_datetime, tooltip='Date & time to start excluding trades')
EndDate        = input.time   (title='End Date Filter'      , defval=timestamp('1 Jan 2023 00:00 +0000'), group=g_datetime, tooltip='Date & time to stop excluding trades')
UseTimeFilter  = input.bool   (title='Enable Session Filter', defval=false                              , group=g_datetime, tooltip='Turns on/off time session filter')
TradingSession = input.session(title='Trading Session'      , defval='1000-2200:1234567'                , group=g_datetime, tooltip='No trades will be taken outside of this range')

var g_messages = '     Alert Messages'
openLongAlertMessage   = input.string(title='Open Long'  , defval='', group=g_messages, inline='e', tooltip='If you use 3 Commas, Paste \'\'Message for deal start signal\'\' (in Open Long) & \'\'Message to close order at Market Price\'\' (in Close Long) from your 3Commas long bot. \n\nOtherwise, you can dynamically change the alert text you wrote here by using Pinescript {{placeholders}} (Google: \'\'variables in alerts tradingview\'\' for more details)')
closeLongAlertMessage  = input.string(title='Close Long' , defval='', group=g_messages, inline='e', tooltip='')
openShortAlertMessage  = input.string(title='Open Short' , defval='', group=g_messages, inline='f', tooltip='If you use 3 Commas, Paste \'\'Message for deal start signal\'\' (in Open Short) & \'\'Message to close order at Market Price\'\' (in Close Short) from your 3Commas short bot. \n\nOtherwise, you can dynamically change the alert text you wrote here by using Pinescript {{placeholders}} (Google: \'\'variables in alerts tradingview\'\' for more details)')
closeShortAlertMessage = input.string(title='Close Short', defval='', group=g_messages, inline='f', tooltip='')


//==============================================================================
//================================   SIGNALS   =================================
//==============================================================================

//----------------------------   BOLLINGER BANDS   -----------------------------
BBdev = ta.stdev(close, BBlen) * BBX
MA = ta.sma(close, MAlen)
if MAtype == 'HMA'
    MA := ta.hma(close, MAlen)
if MAtype == 'WMA'
    MA := ta.wma(close, MAlen)
if MAtype == 'EMA'
    MA := ta.ema(close, MAlen)
if MAtype == 'VWMA'
    MA := ta.vwma(close, MAlen)

BBupper = MA + BBdev
BBlower = MA - BBdev
BBbull  = open < BBlower and close > BBlower
BBbear  = open > BBupper and close < BBupper


//----------------------------------   RSI   -----------------------------------
RSI           = ta.rsi(close, RSIlen)
RSIcrossover  = ta.crossover(RSI, RSIN)
RSIcrossunder = ta.crossunder(RSI, RSIN)

RSIbull = false
for i = 0 to RSINlen by 1
    if RSIcrossover[i]  == true
        RSIbull := true
        RSIbull

RSIbear = false
for i = 0 to RSINlen by 1
    if RSIcrossunder[i] == true
        RSIbear := true
        RSIbear


//------------------------------   VOLATILITY   --------------------------------
BBvol      = BBupper - BBlower
SignalLine = ta.sma(BBvol, 50)
BaseLine   = ta.sma(BBvol, 2000)
HighVolLvl = BaseLine + BaseLine * BBvolX / 10
LowVolLvl  = BaseLine - BaseLine * BBvolX / 10

var volExtrmHigh = false
if BBvol > HighVolLvl and UseVolHigh
    volExtrmHigh := true
    volExtrmHigh
else
    volExtrmHigh := false
    volExtrmHigh

var volExtrmLow  = false
if BBvol < LowVolLvl and UseVolLow
    volExtrmLow  := true
    volExtrmLow
else
    volExtrmLow  := false
    volExtrmLow


//---------------------------   DATE/TIME FILTER   -----------------------------
In(t)      => na(time(timeframe.period, t)) == false
TimeFilter = UseTimeFilter and not In(TradingSession) or not UseTimeFilter
DateFilter = time >= StartDate and time <= EndDate
DateTime   = (UseDateFilter ? not DateFilter : true) and (UseTimeFilter ? In(TradingSession) : true)


//--------------------------   SIGNALS VALIDATION   ----------------------------
validLong  = BBbull and RSIbull and not volExtrmHigh and not volExtrmLow and DateTime and barstate.isconfirmed
validShort = BBbear and RSIbear and not volExtrmHigh and not volExtrmLow and DateTime and barstate.isconfirmed



//==============================================================================
//========================   STOP LOSS & TAKE PROFIT   =========================
//==============================================================================

//------------------------   TRADE DIRECTION CHANGE   --------------------------
var lastsignalislong  = false
var lastsignalisshort = false
var newTradeDirection = false
if validLong
    lastsignalislong  := true
    lastsignalisshort := false
    lastsignalisshort
if validShort
    lastsignalislong  := false
    lastsignalisshort := true
    lastsignalisshort
if  lastsignalislong  == true and lastsignalislong[1]  == false
 or lastsignalisshort == true and lastsignalisshort[1] == false
    newTradeDirection := true
    newTradeDirection
else
    newTradeDirection := false
    newTradeDirection


//---------------------------   DATA & VARIABLES   -----------------------------
SPS = strategy.position_size
atr = ta.atr(atrLen)
var SLsaved = 0.0
var TPsaved = 0.0
var float TSLsaved = na
var float entryPrice = na


//----------------------------   STRAIGHT STOPS   ------------------------------
SLdist      = atr * atrMult
longSL      = close - SLdist
longSLDist  = close - longSL
longTP      = close + longSLDist * rr
shortSL     = close + SLdist
shortSLDist = shortSL - close
shortTP     = close - shortSLDist * rr

if validLong and SPS[1] <= 0 or validShort and SPS[1] >= 0
 or (validLong or validShort) and SPS[1] == 0 and reEnterAfterSLTP
    SLsaved := validLong ? longSL : validShort ? shortSL : na
    TPsaved := validLong ? longTP : validShort ? shortTP : na
    TPsaved


//----------------------------   TRAILING STOPS   ------------------------------
longTrailStart  = ta.lowest(low, TSLlookback) - atr * atrMult
shortTrailStart = ta.highest(high, TSLlookback) + atr * atrMult
if validLong and SPS[1] <= 0 or validShort and SPS[1] >= 0
 or (validLong or validShort) and SPS[1] == 0 and reEnterAfterSLTP
    TSLsaved := validLong ? longTrailStart : validShort ? shortTrailStart : na
    entryPrice := close
if SPS > 0
    TSLsaved := math.max(longTrailStart , TSLsaved, TSLsaved[1])
if SPS < 0
    TSLsaved := math.min(shortTrailStart, TSLsaved, TSLsaved[1])
if SPS[1] != 0 and SPS == 0
    TSLsaved := na


//------------------------------   SL TP HITS   --------------------------------
var longSLTPhit  = false
if SPS[1] > 0 and((useTP ? high >= TPsaved[1] : false)
 or (useSL  ? low  <= SLsaved[1]  : false)
 or (useTSL ? low  <= TSLsaved[1] : false)) 
    longSLTPhit  := true
else
    longSLTPhit  := false

var shortSLTPhit = false
if SPS[1] < 0 and ((useTP ? low  <= TPsaved[1] : false)
 or (useSL  ? high >= SLsaved[1]  : false)
 or (useTSL ? high >= TSLsaved[1] : false)) 
    shortSLTPhit := true
else
    shortSLTPhit := false


//==============================================================================
//=================================   PLOTS   ==================================
//==============================================================================

//--------------------------------   SIGNALS   ---------------------------------
plotchar(validLong , title='Long Signal' , char='⬆',
 location=location.belowbar, size=size.tiny, color=color.new(#3064fc, 0))
plotchar(validShort, title='Short Signal', char='⬇',
 location=location.abovebar, size=size.tiny, color=color.new(#fc1049, 0))



//----------------------------   STRAIGHT STOPS   ------------------------------
plot(useTP and SPS != 0 and not newTradeDirection ? TPsaved : na,
 color=color.new(color.green, 0), style=plot.style_linebr)
plot(useSL and SPS != 0 and not newTradeDirection ? SLsaved : na,
 color=color.new(color.red, 0), style=plot.style_linebr)


//----------------------------   TRAILING STOPS   ------------------------------
TSLcolor = SPS > 0 and entryPrice > TSLsaved ? color.red : SPS > 0 and entryPrice < TSLsaved ? color.green :
           SPS < 0 and entryPrice < TSLsaved ? color.red : SPS < 0 and entryPrice > TSLsaved ? color.green : na
plot(useTSL and SPS != 0 and not newTradeDirection ? TSLsaved : na, color=TSLcolor, style=plot.style_linebr)


//----------------------------   BOLLINGER BANDS   -----------------------------
plot(MA, title='Moving Average', color=color.new(color.white, 50))
PriceUpperLine = plot(BBupper, title='BBprice Upper', color=color.new(color.gray, transp=60))
PriceLowerLine = plot(BBlower, title='BBprice Lower', color=color.new(color.gray, transp=60))

fill(PriceUpperLine, PriceLowerLine, title='BBprice Fill', color=
 volExtrmHigh and BBvol > BBvol[1] ? color.new(#ff1010, 70) :
 volExtrmHigh and BBvol < BBvol[1] ? color.new(#ff1010, 75) : 
 volExtrmLow  and BBvol < BBvol[1] ? color.new(#10ff10, 70) : 
 volExtrmLow  and BBvol > BBvol[1] ? color.new(#10ff10, 75) : 
 color.new(color.white, 90))


//------------------------------   VOLATILITY   --------------------------------
plot((UseVolHigh or UseVolLow) and AddVol ? BBvol      : na, title='BBvol'      , color=color.new(color.blue   , 10))
plot((UseVolHigh or UseVolLow) and AddVol ? SignalLine : na, title='Signal Line', color=color.new(color.fuchsia, 10))
plot((UseVolHigh or UseVolLow) and AddVol ? BaseLine   : na, title='Base Line'  , color=color.new(color.yellow , 10))
VolUpperLine = plot((UseVolHigh or UseVolLow) and AddVol ? HighVolLvl : na, title='BBvol Upper', color=color.new(color.yellow, 70))
VolLowerLine = plot((UseVolHigh or UseVolLow) and AddVol ? LowVolLvl  : na, title='BBvol Lower', color=color.new(color.yellow, 70))
fill(VolUpperLine, VolLowerLine, title='BBvol Fill', color=color.new(color.yellow, 98))


//---------------------------   DATE/TIME FILTER   -----------------------------
bgcolor(DateFilter and UseDateFilter ? color.rgb(255, 70, 70, 85) : na, title='Date Filter')
bgcolor(TimeFilter and UseTimeFilter ? color.rgb(255, 70, 70, 85) : na, title='Time Filter')


//==============================================================================
//===========================   STRATEGY & ALERTS    ===========================
//==============================================================================

//---------------------------------   LONGS   ----------------------------------
if  longTradesON and validLong and newTradeDirection
 or longTradesON and validLong and SPS[1] == 0 and reEnterAfterSLTP 
 and not (validLong and longSLTPhit)
    strategy.entry(id='Long', direction=strategy.long)
    alert(openLongAlertMessage  , alert.freq_once_per_bar_close)

strategy.exit(id='Long exit', from_entry='Long',
 stop  = useSL ? SLsaved : useTSL ? TSLsaved : newTradeDirection ? BBupper : na,
 limit = useTP ? TPsaved : na,
 when  = SPS > 0)

if longSLTPhit or (shortTradesON and validShort and newTradeDirection)
    alert(closeLongAlertMessage , alert.freq_once_per_bar)


//--------------------------------   SHORTS   ----------------------------------
if  shortTradesON and validShort and newTradeDirection
 or shortTradesON and validShort and SPS[1] == 0 and reEnterAfterSLTP 
 and not (validShort and shortSLTPhit)
    strategy.entry(id='Short', direction=strategy.short)
    alert(openShortAlertMessage , alert.freq_once_per_bar_close)

strategy.exit(id='Short exit', from_entry='Short',
 stop  = useSL ? SLsaved : useTSL ? TSLsaved : newTradeDirection ? BBlower : na,
 limit = useTP ? TPsaved : na,
 when  = SPS < 0)

if shortSLTPhit or (longTradesON and validLong and newTradeDirection)
    alert(closeShortAlertMessage, alert.freq_once_per_bar)

