Relative Strength
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © WebPro_Expert

//@version=5
indicator("Relative Strength")
f_barssince(_cond, _count) =>
    _barssince = int(math.max(1, nz(bar_index - ta.valuewhen(_cond, bar_index, _count))))
    _barssince

var int dec = str.length(str.tostring(syminfo.mintick))-2

// Input
showRsnhbp      = input(true, 'Show RSNHBP')
showRsnh        = input(true, 'Show RSNH')
alert           = input(true, 'Alert')

tf              = input.string('3M', 'Timeframe', ['3M', '6M', '1Y'])
correlationPair = input.symbol('SPX', 'Correlation Pair')

emaLen1     = input(4, 'RS Line EMA 1 Length')
emaLen2     = input(21, 'RS Line EMA 2 Length')

labCol      = input.color(color.white, 'Label Color')
texCol      = input.color(color.black, 'Text Color')


// Establish look back length:
Length = tf=='3M' ? 63 : tf=='6M' ? 126 : 252
//
cpOpen      = request.security(correlationPair, 'D', open , lookahead= barmerge.lookahead_on)
cpClose     = request.security(correlationPair, 'D', close, lookahead= barmerge.lookahead_on)
cpHigh      = request.security(correlationPair, 'D', high , lookahead= barmerge.lookahead_on)
cpLow       = request.security(correlationPair, 'D', low  , lookahead= barmerge.lookahead_on)

fFormatNumber(x)=> x<1?x*10 : x<0.1?x*100 : x<0.01? x*1000 : x<0.001? x*10000  : x<0.0001? x*100000 : x

rsOpen      = fFormatNumber(open  / cpOpen ) 
rsClose     = fFormatNumber(close / cpClose)
rsHigh      = fFormatNumber(high  / cpHigh )
rsLow       = fFormatNumber(low   / cpLow  )

// barcount notmalize ath atl
rsLine      = rsClose
highestRs   = ta.highest(rsClose, Length)

rsnhbpCond  = rsClose >= highestRs and close < ta.highest(close, Length)? highestRs : na
rsnhCond    = rsnhbpCond==na and rsClose==highestRs ? highestRs : na
rsnhbp      = rsnhbpCond? highestRs : na
rsnh        = rsnhCond  ? highestRs : na 

// -------
// EMA rsLine
emaRsLine1  = ta.ema(rsLine, emaLen1)
emaRsLine2  = ta.ema(rsLine, emaLen2)

// ------------
var barCount    = 0

if na(close)
    if na(barCount[1])
        barCount    := 1
    else
        barCount    := barCount[1] + 1
else
    barCount    = barCount[1]
    
// Normalize Relative Strength
newRngMax   = 99
newRngMin   = 1
var sinceFBar   = 0
sinceFBar  := request.security(syminfo.tickerid, "1M", f_barssince(na(rsClose[1]) and not na(rsClose), 0))

fGetHighest(dataSeries) =>
    var float highestHigh = 0
    if dataSeries > highestHigh
        highestHigh := dataSeries
    highestHigh

fATH(dataSeries) =>
    a = request.security(syminfo.tickerid, "", fGetHighest(dataSeries))
    
fGetLowest(dataSeries) =>
    var float lowestLow = 9999999
    if dataSeries < lowestLow
        lowestLow := dataSeries
    lowestLow

fATL(dataSeries) =>
    a = request.security(syminfo.tickerid, "", fGetLowest(dataSeries))

hhRsOpen    = fATH(rsOpen )
llRsOpen    = fATL(rsOpen )
hhRsClose   = fATH(rsClose)
llRsClose   = fATL(rsClose)
hhRsHigh    = fATH(rsHigh )
llRsHigh    = fATL(rsHigh )
hhRsLow     = fATH(rsLow  )
llRsLow     = fATL(rsLow  )

fNormalize(x__, hx, lx)=> int(((((newRngMax-newRngMin)*(x__-lx)) / (hx-lx)) + newRngMin))

normalizeRsClose    = fNormalize(rsClose, hhRsClose, llRsClose)
normalizeRsOpen     = fNormalize(rsOpen , hhRsOpen , llRsOpen )
normalizeRsHigh     = fNormalize(rsHigh , hhRsHigh , llRsHigh )
normalizeRsLow      = fNormalize(rsLow  , hhRsLow  , llRsLow  )

textLabel   = 'RS: ' + str.tostring(normalizeRsClose)
rsLabel     = label.new(bar_index, rsClose, textLabel, style=label.style_label_left, color=labCol, textcolor=texCol)
label.delete(rsLabel[1])

plot(normalizeRsClose, 'RS', color=color.new(color.red, 100), display=display.none)
plot(rsClose, 'RS Close'  , color=rsClose>rsClose[1]? #2b98f2 : #e358fb)
plot(emaRsLine1, 'EMA RS 1', color=#decfb8)
plot(emaRsLine2, 'EMA RS 2', color=#6fff2b)
plot(showRsnhbp? rsnhbp:na , 'RSNHBP', style=plot.style_circles, color=#c45ee1, linewidth=3)
plot(showRsnh  ? rsnh:na   , 'RSNH'  , style=plot.style_circles, color=color.green, linewidth=3)

if alert and rsnhbpCond
    alert("Relative Strength Line New Highs Before Price", alert.freq_once_per_bar_close)
if alert and rsnhCond
    alert("Relative Strength Line New Highs", alert.freq_once_per_bar_close)