RSI-VWAP
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Xaviz

//#####©ÉÉÉÉ¶N###############################################
//####*..´´´´´´,,,»ëN########################################
//###ë..´´´´´´,,,,,,''%©#####################################
//###'´´´´´´,,,,,,,'''''?¶###################################
//##o´´´´´´,,,,,,,''''''''*©#################################
//##'´´´´´,,,,,,,'''''''^^^~±################################
//#±´´´´´,,,,,,,''''''''^í/;~*©####æ%;í»~~~~;==I±N###########
//#»´´´´,,,,,,'''''''''^;////;»¶X/í~~/~~~;=~~~~~~~~*¶########
//#'´´´,,,,,,''''''''^^;////;%I^~/~~/~~~=~~~;=?;~~~~;?ë######
//©´´,,,,,,,''''''''^^~/////X~/~~/~~/~~»í~~=~~~~~~~~~~^;É####
//¶´,,,,,,,''''''''^^^;///;%;~/~~;í~~»~í?~?~~~?I/~~~~?*=íÑ###
//N,,,,,,,'''''''^^^^^///;;o/~~;;~~;£=»í»;IX/=~~~~~~^^^^'*æ##
//#í,,,,,''''''''^^^^^;;;;;o~»~~~~íX//~/»~;í?IíI»~~^/*?'''=N#
//#%,,,'''''''''^^^^^^í;;;;£;~~~//»I»/£X/X/»í*&~~~^^^^'^*~'É#
//#©,,''''''''^^^^^^^^~;;;;&/~/////*X;í;o*í»~=*?*===^'''''*£#
//##&''''''''^^^^^^^^^^~;;;;X=í~~~»;;;/~;í»~»±;^^^^^';=''''É#
//##N^''''''^^^^^^^^^^~~~;;;;/£;~~/»~~»~~///o~~^^^^''''?^',æ#
//###Ñ''''^^^^^^^^^^^~~~~~;;;;;í*X*í»;~~IX?~~^^^^/?'''''=,=##
//####X'''^^^^^^^^^^~~~~~~~~;;íííííí~~í*=~~~~Ií^'''=''''^»©##
//#####£^^^^^^^^^^^~~~~~~~~~~~íííííí~~~~~*~^^^;/''''='',,N###
//######æ~^^^^^^^^~~~~~~~~~~~~~~íííí~~~~~^*^^^'=''''?',,§####
//########&^^^^^^~~~~~~~~~~~~~~~~~~~~~~~^^=^^''=''''?,íN#####
//#########N?^^~~~~~~~~~~~~~~~~~~~~~~~~^^^=^''^?''';í@#######
//###########N*~~~~~~~~~~~~~~~~~~~~~~~^^^*'''^='''/É#########
//##############@;~~~~~~~~~~~~~~~~~~~^^~='''~?'';É###########
//#################É=~~~~~~~~~~~~~~^^^*~'''*~?§##############
//#####################N§£I/~~~~~~»*?~»o§æN##################

//@version=4
strategy("RSI-VWAP #STRATEGY#", overlay=true, initial_capital = 1000, currency = "USD", pyramiding = 10, default_qty_type = strategy.cash, default_qty_value = 1000, commission_value = 0.04)

//Uncomment for alerts
//study("RSI-VWAP INDICATOR", overlay=true)

// ================================================================================================================================================================================
// VARIABLES
// ================================================================================================================================================================================

var bool long = na, var bool short = na
var bool longCondition = na, var bool shortCondition = na 
var bool Xlong = na, var bool Xshort = na,
var int CondIni_long = 0, var int CondIni_short = 0
var bool XlongCondition = na, var bool XshortCondition = na
var float last_open_longCondition = na, var float last_open_shortCondition = na
var int last_longCondition = 0, var int last_shortCondition = 0
var bool in_longCondition = na, var bool in_shortCondition = na
var int last_long_sl = na, var int last_short_sl = na
var bool CondIni_long_sl = 0, var bool CondIni_short_sl = 0
var int nLongs = na, var int nShorts = na, var int pyr = na
var float sum_long = 0.0, var float sum_short = 0.0
var float Position_Price = 0.0, Position_Price := nz(Position_Price[1])
var bool Final_Long_sl = na, var bool Final_Short_sl = na, var bool Act_sl = na, var float sl = na
var int last_long_tp = na, var int last_short_tp = na
var bool CondIni_long_tp = 0, var bool CondIni_short_tp = 0
var float Quantity = na, var float Increase = na
var float sum_qty_l = na, var float sum_qty_s = na

// ================================================================================================================================================================================
// RSI VWAP INDICATOR
// ================================================================================================================================================================================

// Initial inputs
Long_only = input(true, "🐮 ACTIVATE BULLS")
RSI_VWAP_length_long = input(17, "RSI-VWAP LENGTH", minval = 1, maxval = 99)
RSI_VWAP_overSold_long = input(19, "OVERSOLD (LONG)", type=input.float, minval = 1, maxval = 99)
RSI_VWAP_overBought_long = input(78, "OVERBOUGHT (XLONG)", type=input.float, minval = 1, maxval = 99)
RSI_VWAP_overSold_long2 = input(38, "OVERSOLD 2 (LONG)", type=input.float, minval = 1, maxval = 99)

Short_only = input(false, "🐻 ACTIVATE BEARS")
RSI_VWAP_length_short = input(17, "RSI-VWAP LENGTH", minval = 1, maxval = 99)
RSI_VWAP_overSold_short = input(19, "OVERSOLD (XSHORT)", type=input.float, minval = 1, maxval = 99)
RSI_VWAP_overBought_short = input(80, "OVERBOUGHT (SHORT)", type=input.float, minval = 1, maxval = 99)
RSI_VWAP_overBought_short2 = input(59, "OVERBOUGHT 2 (SHORT)", type=input.float, minval = 1, maxval = 99)

// RSI with VWAP as source
RSI_VWAP_long = rsi(vwap(close), RSI_VWAP_length_long)
RSI_VWAP_short = rsi(vwap(close), RSI_VWAP_length_short)

// ================================================================================================================================================================================
// STRATEGY
// ================================================================================================================================================================================

// Long/Short conditions, next entry always at better price
long := (((crossover(RSI_VWAP_long, RSI_VWAP_overSold_long2)) and nz(CondIni_long[1]) == -1) or (crossover(RSI_VWAP_long, RSI_VWAP_overSold_long))) and (nz(nLongs[1]) < pyr) and Long_only
longCondition := in_longCondition and nLongs > 0 ? long and (close < fixnan(Position_Price[1])) : long
short := (((crossunder(RSI_VWAP_short, RSI_VWAP_overBought_short2)) and nz(CondIni_short[1]) == -1) or (crossunder(RSI_VWAP_short, RSI_VWAP_overBought_short))) and (nz(nShorts[1]) < pyr) and Short_only   
shortCondition := in_shortCondition and nShorts > 0 ? short and (close > fixnan(Position_Price[1])) : short
   
// Xlong/Xshort Conditions, closing with profit only?
Xlong := (crossunder(RSI_VWAP_long, RSI_VWAP_overBought_long)) and Long_only and not Short_only
Xshort := (crossover(RSI_VWAP_short, RSI_VWAP_overSold_short)) and Short_only and not Long_only
CondIni_long := longCondition ? 1 : Xlong or shortCondition ? -1 : nz(CondIni_long[1])
CondIni_short := shortCondition ? 1 : Xshort or longCondition ? -1 : nz(CondIni_short[1])
XlongCondition := Xlong and nz(CondIni_long[1]) == 1
XshortCondition := Xshort and nz(CondIni_short[1]) == 1

// Get the price of the last opened long or short
last_open_longCondition := longCondition ? close : nz(last_open_longCondition[1])
last_open_shortCondition := shortCondition ? close : nz(last_open_shortCondition[1])

// Get the bar time of the last opened long or short
last_longCondition := longCondition ? time : nz(last_longCondition[1])
last_shortCondition := shortCondition ? time : nz(last_shortCondition[1])

// In long/short conditions
in_longCondition := last_longCondition > last_shortCondition
in_shortCondition := last_shortCondition > last_longCondition

// ================================================================================================================================================================================
// PRICE AVERAGE / PYRAMIDING
// ================================================================================================================================================================================

// Pyramiding
pyr := input(10, "MAX. PYRAMIDING 🎢" , minval = 1, maxval = 10)

// Counting long & short iterations
nLongs := nz(nLongs[1])
nShorts := nz(nShorts[1])

// Longs Counter
if longCondition or (Final_Long_sl and not Act_sl)
    nLongs := nLongs + 1
    nShorts := 0
    
// Shorts Counter
if shortCondition or (Final_Short_sl and not Act_sl)
    nLongs := 0
    nShorts := nShorts + 1

// Quantity Factor
QF_l = Quantity+(Increase*(nLongs-1))
QF_s = Quantity+(Increase*(nShorts-1))

// Price average of your position according to the quantities
if longCondition
    sum_long := nz(last_open_longCondition)*QF_l + nz(sum_long[1])
    sum_short := 0.0
    sum_qty_l := QF_l + nz(sum_qty_l[1])
    sum_qty_s := na
    
if Final_Long_sl and not Act_sl
    sum_long := ((1-(sl/100))*last_open_longCondition)*QF_l + nz(sum_long[1])
    sum_short := 0.0
    sum_qty_l := QF_l + nz(sum_qty_l[1])
    sum_qty_s := na
    
if shortCondition
    sum_short := nz(last_open_shortCondition)*QF_s + nz(sum_short[1])
    sum_long := 0.0
    sum_qty_s := QF_s + nz(sum_qty_s[1])
    sum_qty_l := na
    
if Final_Short_sl and not Act_sl
    sum_long := 0.0
    sum_short := ((1+(sl/100))*last_open_shortCondition)*QF_s + nz(sum_short[1])
    sum_qty_s := QF_s + nz(sum_qty_s[1])
    sum_qty_l := na

// Calculating and Plotting the price average
Position_Price := nz(Position_Price[1])
Position_Price := longCondition or (Final_Long_sl and not Act_sl) ? sum_long/(sum_qty_l) : shortCondition or (Final_Short_sl and not Act_sl) ? sum_short/(sum_qty_s) : na
plot(Position_Price[1], title = "Average Price", color = in_longCondition ? color.blue : color.red, linewidth = 2, style = plot.style_cross, transp = 0)

// ================================================================================================================================================================================
// STOP LOSS / RE-ENTRY
// ================================================================================================================================================================================

// SL initial inputs
Act_sl := input(false, "ACTIVATE SL / DEACTIVATE RE-ENTRY")
sl := input(10, "STOP LOSS / RE-ENTRY %", type = input.float, minval = 0, step = 0.5)

// Initial SL conditions
long_sl = crossunder(low, (1-(sl/100))*last_open_longCondition) and in_longCondition and not longCondition
short_sl = crossover(high, (1+(sl/100))*last_open_shortCondition) and in_shortCondition and not shortCondition

// Get the time of the last sl
last_long_sl := long_sl ? time : nz(last_long_sl[1])
last_short_sl := short_sl ? time : nz(last_short_sl[1])

// Sl counter
CondIni_long_sl := long_sl or XlongCondition ? 1 : longCondition ? -1 : nz(CondIni_long_sl[1])
CondIni_short_sl := short_sl or XshortCondition ? 1 : shortCondition ? -1 : nz(CondIni_short_sl[1])

// Final SL conditions
Final_Long_sl := long_sl and nz(CondIni_long_sl[1]) == -1 and in_longCondition and not longCondition
Final_Short_sl := short_sl and nz(CondIni_short_sl[1]) == -1 and in_shortCondition and not shortCondition

// ================================================================================================================================================================================
// TAKE PROFIT
// ================================================================================================================================================================================

// Take Profit input
Act_tp = input(false, "ACTIVATE TAKE PROFIT")
tp = input(5.0, "TAKE PROFIT %", type = input.float, minval = 0, step = 0.5)
qty_TP = input(50, "QUANTITY TO CLOSE TP %", minval = 0, maxval = 100)

// Initial TP conditions
long_tp = crossover(high, (1+(tp/100))*fixnan(Position_Price)) and in_longCondition and not longCondition and not Final_Long_sl and Act_tp
short_tp = crossunder(low, (1-(tp/100))*fixnan(Position_Price)) and in_shortCondition and not shortCondition and not Final_Short_sl and Act_tp

// Get the time of the last tp
last_long_tp := long_tp ? time : nz(last_long_tp[1])
last_short_tp := short_tp ? time : nz(last_short_tp[1])

// Tp signal ordering
CondIni_long_tp := (Final_Long_sl and Act_sl) or XlongCondition ? 1 : longCondition ? -1 : nz(CondIni_long_tp[1])
CondIni_short_tp := Final_Short_sl and Act_sl ? 1 : shortCondition ? -1 : nz(CondIni_short_tp[1])

// Final tp condition
Final_Long_tp = long_tp and last_longCondition > nz(last_long_tp[1]) and nz(CondIni_long_tp[1]) == -1
Final_Short_tp = short_tp and last_shortCondition > nz(last_short_tp[1]) and nz(CondIni_short_tp[1]) == -1

if Final_Long_tp or (Final_Long_sl and Act_sl) or XlongCondition
    sum_long := 0.0
    nLongs := na
    CondIni_long_sl := 1
    sum_qty_l := na
    
if Final_Short_tp or (Final_Short_sl and Act_sl) or XshortCondition
    sum_short := 0.0
    nShorts := na
    CondIni_short_sl := 1
    sum_qty_s := na
    
// ================================================================================================================================================================================
// SIGNALS
// ================================================================================================================================================================================

// Longs
//label.new(
//   x = longCondition[1] ? time : na, 
//   y = na, 
//   text = 'LONG '+tostring(nLongs), 
//   color = color.blue, 
//   textcolor = color.black,  
//   style = label.style_labelup, 
//   xloc = xloc.bar_time, 
//   yloc = yloc.belowbar,
//   size = size.tiny
//   )

// Shorts
//label.new(
//   x = shortCondition[1] ? time : na, 
//   y = na, 
//   text = 'SHORT '+tostring(nShorts), 
//   color = color.red, 
//   textcolor = color.black,  
//   style = label.style_labeldown, 
//   xloc = xloc.bar_time, 
//   yloc = yloc.abovebar,
//   size = size.tiny
//   )

// XLongs
//label.new(
//   x = XlongCondition[1] ? time : na, 
//   y = na, 
//   text = 'XLONG', 
//   color = color.yellow, 
//   textcolor = color.black,  
//   style = label.style_labeldown, 
//   xloc = xloc.bar_time, 
//   yloc = yloc.abovebar,
//   size = size.tiny
//   )

// XShorts
//label.new(
//   x = XshortCondition[1] ? time : na, 
//   y = na, 
//   text = 'XSHORT', 
//   color = color.yellow, 
//   textcolor = color.black,  
//   style = label.style_labelup, 
//   xloc = xloc.bar_time, 
//   yloc = yloc.belowbar,
//   size = size.tiny
//   )
   
// Tp on longs
//label.new(
//   x = Final_Long_tp ? time : na, 
//   y = na, 
//   text = 'TP '+tostring(tp)+'%', 
//   color = color.orange, 
//   textcolor = color.black,  
//   style = label.style_labeldown, 
//   xloc = xloc.bar_time, 
//   yloc = yloc.abovebar,
//   size = size.tiny
//   ) 

//ltp = iff(Final_Long_tp, (fixnan(Position_Price)*(1+(tp/100))), na), plot(ltp, style=plot.style_cross, linewidth=3, color = color.white, editable = false)

// Tp on shorts
//label.new(
//   x = Final_Short_tp ? time : na, 
//   y = na, 
//   text = 'TP '+tostring(tp)+'%', 
//   color = color.orange, 
//   textcolor = color.black,  
//   style = label.style_labelup, 
//   xloc = xloc.bar_time, 
//   yloc = yloc.belowbar,
//   size = size.tiny
//   )
   
//stp = iff(Final_Short_tp, (fixnan(Position_Price)*(1-(tp/100))), na), plot(stp, style=plot.style_cross, linewidth=3, color = color.white, editable = false)

// Sl on Longs
//label.new(
//   x = Final_Long_sl ? time : na, 
//   y = na, 
//  text = Act_sl ? ('SL '+tostring(sl)+'%') : ('RE '+tostring(sl)+'%'), 
//   color = color.green, 
//   textcolor = color.black,  
//   style = label.style_labelup, 
//   xloc = xloc.bar_time, 
//   yloc = yloc.belowbar,
//   size = size.tiny
//   )
   
// Sl on Longs dot   
//lsl = iff(Final_Long_sl, (last_open_longCondition*(1-(sl/100))), na), plot(lsl, style=plot.style_cross, linewidth=3, color = color.white, editable = false)

// Sl on Shorts
//label.new(
//   x = Final_Short_sl ? time : na, 
//   y = na, 
//   text = Act_sl ? ('SL '+tostring(sl)+'%') : ('RE '+tostring(sl)+'%'), 
//   color = color.maroon, 
//   textcolor = color.black,  
//   style = label.style_labeldown, 
//   xloc = xloc.bar_time, 
//   yloc = yloc.abovebar,
//   size = size.tiny
//   ) 

// Sl on Shorts dot
//ssl = iff(Final_Short_sl, (last_open_shortCondition*(1+(sl/100))), na), plot(ssl, style=plot.style_cross, linewidth=3, color = color.white, editable = false)

// ================================================================================================================================================================================
// BACKTEST
// ================================================================================================================================================================================

// Backtest inputs
Act_BT = input(true, "BACKTEST 💹")
contracts_or_cash = input("CASH", "CONTRACTS ₿ / CASH $", options = ["CONTRACTS","CASH"])
cc_factor = (contracts_or_cash == "CASH") ? close : 1
Quantity := input(1000, "$ QUANTITY 1ST ENTRY", minval = 0)/cc_factor
Increase := input(500, "$ INCREASE NEXT ENTRY", minval = 0)/cc_factor

// Backtest Period inputs
testStartYear = input(2019, "BACKTEST START YEAR ⏲️", minval = 1980, maxval = 2222) 
testStartMonth = input(01, "BACKTEST START MONTH", minval = 1, maxval = 12)
testStartDay = input(01, "BACKTEST START DAY", minval = 1, maxval = 31)
testPeriodStart = timestamp(testStartYear,testStartMonth,testStartDay,0,0)
testStopYear = input(2222, "BACKTEST STOP YEAR", minval=1980, maxval = 2222)
testStopMonth = input(12, "BACKTEST STOP MONTH", minval=1, maxval=12)
testStopDay = input(31, "BACKTEST STOP DAY", minval=1, maxval=31)
testPeriodStop = timestamp(testStopYear, testStopMonth, testStopDay, 0, 0)

// Backtest Condition
testPeriod = time >= testPeriodStart and time <= testPeriodStop ? true : false

// Backtest entries
if (Act_BT and testPeriod)
    strategy.entry("Long", strategy.long, qty = QF_l, when = longCondition or (Final_Long_sl and not Act_sl))
    strategy.close("Long", when = XlongCondition)
    strategy.entry("Short", strategy.short, qty = QF_s, when = shortCondition or (Final_Short_sl and not Act_sl))
    strategy.close("Short", when = XshortCondition)
    strategy.exit("TPl", "Long", qty_percent = qty_TP, limit = Act_tp ? (fixnan(Position_Price)*(1+(tp/100))) : na)
    strategy.close("Long", when = Act_sl and Final_Long_sl)
    strategy.exit("TPs", "Short", qty_percent = qty_TP, limit = Act_tp ? (fixnan(Position_Price)*(1-(tp/100))) : na)
    strategy.close("Short", when = Act_sl and Final_Short_sl)

// ================================================================================================================================================================================
// ALERTS
// ================================================================================================================================================================================

// LONGS

alertcondition((longCondition[1] or (Final_Long_sl and not Act_sl)), title="All Longs Alert", 
   message = "LONG")

//alertcondition((longCondition[1] or (Final_Long_sl and not Act_sl)) and nLongs == 1, title="Long 1 Alert", 
//   message = "LONG1")
//alertcondition((longCondition[1] or (Final_Long_sl and not Act_sl)) and nLongs == 2, title="Long 2 Alert", 
//   message = "LONG2")
//alertcondition((longCondition[1] or (Final_Long_sl and not Act_sl)) and nLongs == 3, title="Long 3 Alert", 
//   message = "LONG3")
//alertcondition((longCondition[1] or (Final_Long_sl and not Act_sl)) and nLongs == 4, title="Long 4 Alert", 
//   message = "LONG4")
//alertcondition((longCondition[1] or (Final_Long_sl and not Act_sl)) and nLongs == 5, title="Long 5 Alert", 
//   message = "LONG5")
//alertcondition((longCondition[1] or (Final_Long_sl and not Act_sl)) and nLongs == 6, title="Long 1 Alert", 
//   message = "LONG6")
//alertcondition((longCondition[1] or (Final_Long_sl and not Act_sl)) and nLongs == 7, title="Long 1 Alert", 
//   message = "LONG7")
//alertcondition((longCondition[1] or (Final_Long_sl and not Act_sl)) and nLongs == 8, title="Long 1 Alert", 
//   message = "LONG8")
//alertcondition((longCondition[1] or (Final_Long_sl and not Act_sl)) and nLongs == 9, title="Long 1 Alert", 
//   message = "LONG9")
//alertcondition((longCondition[1] or (Final_Long_sl and not Act_sl)) and nLongs == 10, title="Long 1 Alert", 
//   message = "LONG10")

alertcondition(Final_Long_tp, title="TPL Alert",
   message = "TPL")
   
alertcondition(XlongCondition[1] or (Final_Long_sl and Act_sl), title="Close Long / SL Alert", 
   message = "XL/SLL")

// SHORTS

alertcondition((shortCondition[1] or (Final_Short_sl and not Act_sl)), title="All Shorts Alert", 
   message = "SHORT")

//alertcondition((shortCondition[1] or (Final_Short_sl and not Act_sl)) and nShorts == 1, title="Short 1 Alert", 
//   message = "SHORT1")
//alertcondition((shortCondition[1] or (Final_Short_sl and not Act_sl)) and nShorts == 2, title="Short 2 Alert", 
//   message = "SHORT2")
//alertcondition((shortCondition[1] or (Final_Short_sl and not Act_sl)) and nShorts == 3, title="Short 3 Alert", 
//   message = "SHORT3")
//alertcondition((shortCondition[1] or (Final_Short_sl and not Act_sl)) and nShorts == 4, title="Short 4 Alert", 
//   message = "SHORT4")
//alertcondition((shortCondition[1] or (Final_Short_sl and not Act_sl)) and nShorts == 5, title="Short 5 Alert", 
//   message = "SHORT5")
//alertcondition((shortCondition[1] or (Final_Short_sl and not Act_sl)) and nShorts == 6, title="Short 6 Alert", 
//   message = "SHORT6")
//alertcondition((shortCondition[1] or (Final_Short_sl and not Act_sl)) and nShorts == 7, title="Short 7 Alert", 
//   message = "SHORT7")
//alertcondition((shortCondition[1] or (Final_Short_sl and not Act_sl)) and nShorts == 8, title="Short 8 Alert", 
//   message = "SHORT8")
//alertcondition((shortCondition[1] or (Final_Short_sl and not Act_sl)) and nShorts == 9, title="Short 9 Alert", 
//   message = "SHORT9")
//alertcondition((shortCondition[1] or (Final_Short_sl and not Act_sl)) and nShorts == 10, title="Short 10 Alert", 
//   message = "SHORT10")

alertcondition(Final_Short_tp, title="TPS/SLS Alert", 
   message = "TPS")

alertcondition(XshortCondition[1] or (Final_Short_sl and Act_sl), title="Close Long / SL Alert", 
   message = "XS/SLS")
   
// by Xaviz
