Hey there, thanks!
I've setup tests overnight and will review the results in the morning!
Code: Select all
//@version=5
indicator("RSI Bull_Div Alert MTF")
enable_tf1 = true
enable_tf2 = true
enable_tf3 = true
alert_tf1 = true
alert_tf2 = true
alert_tf3 = true
tf1_col = color.blue
tf2_col = color.yellow
tf3_col = color.green
timeframe1 = "15"
timeframe2 = "30"
timeframe3 = "60"
lookback = 90
lengthRSI = 14
// ---------------------------------------------------------------------------------------------- //
cutLastDigit(str) =>
s = str + ';'
r = str.replace_all(s, '1;', '')
if r != s
[r, 1]
else
r := str.replace_all(s, '2;', '')
if r != s
[r, 2]
else
r := str.replace_all(s, '3;', '')
if r != s
[r, 3]
else
r := str.replace_all(s, '4;', '')
if r != s
[r, 4]
else
r := str.replace_all(s, '5;', '')
if r != s
[r, 5]
else
r := str.replace_all(s, '6;', '')
if r != s
[r, 6]
else
r := str.replace_all(s, '7;', '')
if r != s
[r, 7]
else
r := str.replace_all(s, '8;', '')
if r != s
[r, 8]
else
r := str.replace_all(s, '9;', '')
if r != s
[r, 9]
else
r := str.replace_all(s, '0;', '')
if r != s
[r, 0]
strToNumInt(str) =>
integer = 0 // integer part of the number
s_new = str
position = 0.0 // handled position of the number.
sign = 1 // sign of the number. 1.0 is PLUS and -1.0 is MINUS.
for i = 0 to 30 by 1
[s, digit] = cutLastDigit(s_new) // here we'll cut the digits by one from the string till the string is empty.
integer += digit * int(math.pow(10, position)) // it's just a regular digit.
position += 1
if s == ''
break
s_new := s // If we are here, then there are more digits in the string. Let's handle the next one!
s_new
sign * integer // We've exited from the loop. Build the returning value.
calculateTimeDividedBy(res) =>
timeDividiedBy = time(timeframe.period)
if strToNumInt(res) < 1440
timeDividiedBy := strToNumInt(res) * 60 * 1000
timeDividiedBy
for i = 1 to 50 by 1
if res == str.tostring(i) + 'D' or res == 'D'
timeDividiedBy := i * 1 * 86400000
break
else if res == str.tostring(i) + 'W' or res == 'W'
timeDividiedBy := i * 7 * 86400000
break
else if res == str.tostring(i) + 'M' or res == 'M'
timeDividiedBy := i * 30 * 86400000
break
timeDividiedBy
tf1_isNewPeriod = ta.change(time(timeframe1))
tf2_isNewPeriod = ta.change(time(timeframe2))
tf3_isNewPeriod = ta.change(time(timeframe3))
tf1_multiplier = calculateTimeDividedBy(timeframe1) / calculateTimeDividedBy(timeframe.period)
tf2_multiplier = calculateTimeDividedBy(timeframe2) / calculateTimeDividedBy(timeframe.period)
tf3_multiplier = calculateTimeDividedBy(timeframe3) / calculateTimeDividedBy(timeframe.period)
//////////////////////////////////////////////////////////////
rsi = ta.rsi(close, lengthRSI)
len = 14 //input(14, minval=1, title="RSI Length")
ob = 70 //input(defval=70, title="Overbought", type=input.integer, minval=0, maxval=100)
os = 30 //input(defval=30, title="Oversold", type=input.integer, minval=0, maxval=100)
hline(50, title='Fifty-Line', color=color.gray, linestyle=hline.style_solid)
seventy = hline(ob, color=color.gray, linestyle=hline.style_dashed)
thirty = hline(os, color=color.gray, linestyle=hline.style_dashed)
fill(thirty, seventy, color.new(color.purple, 90))
pl_rsi = plot(rsi, title='RSI Oscillator', color=color.new(color.purple, 0), linewidth=1)
// Inputs
scalePercentage = input.int(100, "Vertical %", step = 10, maxval = 100)
lookBack = input.int(100, "Last Bars to Look", minval = 2, step = 20)
scaleFactor = 100 / scalePercentage
//plot(volume, color = color.orange, title="Volume", style=plot.style_columns, transp=0)
hi_limit = ta.highest(rsi, lookBack)
lo_limit = ta.lowest(rsi, lookBack)
high_div =hi_limit * scaleFactor
low_div = lo_limit * scaleFactor
plot(high_div, "High", #00000000)
plot(low_div, "Low", #00000000)
/////////////////////////////////////
// Find Divergence
///////////////////////////////////
find_divergence(price_close, oscillator, lookback, isReal) =>
highest_bar = math.abs(ta.highestbars(oscillator, lookback)) // Finds bar with highest value in last X bars
lowest_bar = math.abs(ta.lowestbars(oscillator, lookback)) // Finds bar with lowest value in last X bars
// Defining variable
max_price = float(na)
max_osc = float(na)
min_price = float(na)
min_osc = float(na)
pivoth = bool(na)
pivotl = bool(na)
divbear = bool(na)
divbull = bool(na)
// If bar with lowest / highest is current bar, use it's value
max_price := highest_bar == 0 ? price_close : na(max_price[1]) ? price_close : max_price[1]
max_osc := highest_bar == 0 ? oscillator : na(max_osc[1]) ? oscillator : max_osc[1]
min_price := lowest_bar == 0 ? price_close : na(min_price[1]) ? price_close : min_price[1]
min_osc := lowest_bar == 0 ? oscillator : na(min_osc[1]) ? oscillator : min_osc[1]
// Compare high of current bar being examined with previous bar's high
// If curr bar high is higher than the max bar high in the lookback window range
if price_close > max_price // we have a new high
max_price := price_close // change variable "max" to use current bar's high value
max_price
if oscillator > max_osc // we have a new high
max_osc := oscillator // change variable "max_rsi" to use current bar's RSI value
max_osc
if price_close < min_price // we have a new low
min_price := price_close // change variable "min" to use current bar's low value
min_price
if oscillator < min_osc // we have a new low
min_osc := oscillator // change variable "min_rsi" to use current bar's RSI value
min_osc
// Finds pivot point with at least 2 right candles with lower value
pivoth := max_osc == max_osc[2] and max_osc[2] != max_osc[3] ? true : na
pivotl := min_osc == min_osc[2] and min_osc[2] != min_osc[3] ? true : na
// Detects divergences between price and indicator with 1 candle delay so it filters out repeating divergences
if max_price[1] > max_price[2] and oscillator[1] < max_osc and oscillator <= oscillator[1]
divbear := true
divbear
if min_price[1] < min_price[2] and oscillator[1] > min_osc and oscillator >= oscillator[1]
divbull := true
divbull
[divbull, divbear, time, isReal]
[tf1_divbull, tf1_divbear, tf1_time, tf1_real] = request.security(syminfo.ticker, timeframe1, find_divergence(close, rsi, lookback, barstate.isrealtime))
[tf2_divbull, tf2_divbear, tf2_time, tf2_real] = request.security(syminfo.ticker, timeframe2, find_divergence(close, rsi, lookback, barstate.isrealtime))
[tf3_divbull, tf3_divbear, tf3_time, tf3_real] = request.security(syminfo.ticker, timeframe3, find_divergence(close, rsi, lookback, barstate.isrealtime))
////////////////////////////
// Draw Labels
/////////////////////////
if enable_tf1 and not tf1_real// and tf1_isNewPeriod
tf1_divergence = (tf1_divbear ? label.new(bar_index - 1 * tf1_multiplier, high_div, timeframe1, color=barstate.islast and not barstate.isconfirmed ? color.new(tf1_col, 80) : tf1_col, textcolor=color.black, style=label.style_label_down, yloc=yloc.price, size=size.normal) : tf1_divbull ? label.new(bar_index - 1 * tf1_multiplier, low_div, timeframe1, color=barstate.islast and not barstate.isconfirmed ? color.new(tf1_col, 80) : tf1_col, textcolor=color.black, style=label.style_label_up, yloc=yloc.price, size=size.normal) : na)
if enable_tf2 and not tf2_real// and tf2_isNewPeriod
tf2_divergence = (tf2_divbear ? label.new(bar_index - 1 * tf2_multiplier, high_div+10, timeframe2, color=barstate.islast and not barstate.isconfirmed ? color.new(tf2_col, 80) : tf2_col, textcolor=color.black, style=label.style_label_down, yloc=yloc.price, size=size.normal) : tf2_divbull ? label.new(bar_index - 1 * tf2_multiplier, low_div-10, timeframe2, color=barstate.islast and not barstate.isconfirmed ? color.new(tf2_col, 80) : tf2_col, textcolor=color.black, style=label.style_label_up, yloc=yloc.price, size=size.normal) : na)
if enable_tf3 and not tf3_real //and tf3_isNewPeriod
tf3_divergence = (tf3_divbear ? label.new(bar_index - 1 * tf3_multiplier, high_div+20, timeframe3, color=barstate.islast and not barstate.isconfirmed ? color.new(tf3_col, 80) : tf3_col, textcolor=color.black, style=label.style_label_down, yloc=yloc.price, size=size.normal) : tf3_divbull ? label.new(bar_index - 1 * tf3_multiplier, low_div-20, timeframe3, color=barstate.islast and not barstate.isconfirmed ? color.new(tf3_col, 80) : tf3_col, textcolor=color.black, style=label.style_label_up, yloc=yloc.price, size=size.normal) : na)
//////////////////////////
// Create Alerts
///////////////////////
if alert_tf1 and not tf1_real// and tf1_isNewPeriod and (time >= time_close(timeframe1)-(time_close-time))
if tf1_divbull
alert(syminfo.ticker + ' Bullish Divergence TESTING - Price: ' + str.tostring(close) + ' - Timeframe: ' + timeframe1, alert.freq_once_per_bar_close)
if tf1_divbear
alert(syminfo.ticker + ' Bearish Divergence TESTING - Price: ' + str.tostring(close) + ' - Timeframe: ' + timeframe1, alert.freq_once_per_bar_close)
if alert_tf2 and not tf2_real// and tf2_isNewPeriod and (time >= time_close(timeframe2)-(time_close-time))
if tf2_divbull
alert(syminfo.ticker + ' Bullish Divergence TESTING - Price: ' + str.tostring(close) + ' - Timeframe: ' + timeframe2, alert.freq_once_per_bar_close)
if tf2_divbear
alert(syminfo.ticker + ' Bearish Divergence TESTING - Price: ' + str.tostring(close) + ' - Timeframe: ' + timeframe2, alert.freq_once_per_bar_close)
if alert_tf3 and not tf3_real //and tf3_isNewPeriod and (time >= time_close(timeframe3)-(time_close-time))
if tf3_divbull
alert(syminfo.ticker + ' Bullish Divergence TESTING - Price: ' + str.tostring(close) + ' - Timeframe: ' + timeframe3, alert.freq_once_per_bar_close)
if tf3_divbear
alert(syminfo.ticker + ' Bearish Divergence TESTING - Price: ' + str.tostring(close) + ' - Timeframe: ' + timeframe3, alert.freq_once_per_bar_close)
//yyy = calculateTimeDividedBy(time)
//var label xxx = na
//if ((not tf1_real and (tf1_divbull or tf1_divbear)) or (not tf1_real and (tf2_divbull or tf2_divbear)) or (not tf1_real and (tf3_divbull or tf3_divbear)) )
// xxx := label.new(bar_index, high, str.tostring(tf1_time) + '-' + str.tostring(tf2_time) + '-' + str.tostring(tf3_time) + '\n' + str.tostring(tf1_divbull) + ':' + str.tostring(tf1_divbear)+ '\n' + str.tostring(tf2_divbull)+ ':' + str.tostring(tf2_divbear)+ '\n' + str.tostring(tf3_divbull)+ ':' + str.tostring(tf3_divbear))
//if barstate.islast
// label.delete(xxx[1])
//xxx := label.new(bar_index, high, str.tostring(tf1_isNewPeriod) + '-' + str.tostring(tf2_isNewPeriod) +'\n' + str.tostring(time(timeframe2)) + '\n' + str.tostring(time(timeframe3))+ '\n' + str.tostring(time))
//plot(tf1_time,display = display.none)
//DEBUGS
plot(tf1_divbear?-1:na,"tf1_divbear",color=color.red, linewidth=3)
plot(tf1_divbull?-1:na,"tf1_divbull",color=color.blue, linewidth=3)
plot(tf1_real?-1:na,"real")
plot(tf2_divbear?-3:na,"tf2_divbear",color=color.purple, linewidth=3)
plot(tf2_divbull?-3:na,"tf2_divbull",color=color.black, linewidth=3)
plot(tf2_real?-3:na,"real")
plot(tf3_divbear?-5:na,"tf3_divbear",color=color.olive, linewidth=3)
plot(tf3_divbull?-5:na,"tf3_divbull",color=color.orange, linewidth=3)
plot(tf3_real?-5:na,"real")
var label zzz = na
var label zzz2 = na
var label zzz3 = na
if (tf1_divbear and not tf1_divbear[1]) or (tf1_divbull and not tf1_divbull[1])
zzz := label.new(bar_index, 80, 'TimeF 1: ' +str.format("@{0,time,HH:mm}",tf1_time)+' Bear-'+str.tostring(tf1_divbear)+' Bull-'+str.tostring(tf1_divbull),color=color.green, textcolor=color.yellow)
if (tf2_divbear and not tf2_divbear[1]) or (tf2_divbull and not tf2_divbull[1])
zzz2 := label.new(bar_index, 90, 'TimeF 2: ' + str.format("@{0,time,HH:mm}",tf2_time)+' Bear-'+str.tostring(tf2_divbear)+' Bull-'+str.tostring(tf3_divbull),color=color.green, textcolor=color.yellow)
if (tf3_divbear and not tf3_divbear[1]) or (tf3_divbull and not tf3_divbull[1])
zzz3 := label.new(bar_index, 100, 'TimeF 3: ' + str.format("@{0,time,HH:mm}",tf3_time)+' Bear-'+str.tostring(tf3_divbear)+' Bull-'+str.tostring(tf3_divbull),color=color.green, textcolor=color.yellow)
//plot(tf2_time/1000,"tf2_time",display=display.none)
//plot(tf3_time/1000,"tf3_time",display=display.none)
//plot(tf1_multiplier,"multiplier", display = display.none)