[Pt] TICK + Heikin Ashi RSI Indicator
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © PtGambler

//@version=5
indicator("[Pt] TICK + Heikin Ashi RSI Indicator", shorttitle="[Pt] TICK + HARSI", overlay=false)

t1 = time(timeframe.period, "0930-1600:23456", "America/New_York")
tableLocation = input.string(defval='Bottom', options=['Top', 'Bottom'], title='Info Table Location', tooltip='Place information table on the top of the pane or the bottom of the pane.  Put on bottom if you like the headers for your indicators visible as they will overlap otherwise.')

// ***************************************************** TICK Indictor *****************************************************
tick_symbol = input.string("USI:TICK", "Symbol", options=['USI:TICK', 'USI:TICKQ', 'USI:TICKA'], group = "TICK")
tickMA_len = input.int(7, title = "TICK EMA length", group = "TICK")
tick_col = input.color(color.new(color.white,0), "TICK Color", group = "TICK", inline = 'tick')
show_tick = input.bool(true,"Show", inline = 'tick', group = "TICK")
tickEMA_col = input.color(color.rgb(161, 255, 250,0), "TICK EMA Color", group = "TICK", inline = 'tickema')
show_tickema = input.bool(true,"Show", inline = 'tickema', group = "TICK")
neutralH = input.int(200, title="Neutral zone +/- from 0", minval = 0, step=10, group = "TICK")
neutralL = -neutralH
BullishH = input.int(800, title="Trend zone +/- from 0", minval = 0, step=10, group = "TICK")
BearishL = -BullishH
OverH = input.int(1000, title="OB/OS extremes +/- from 0", minval = 0, step=10, group = "TICK")
OverL = -OverH

tickC = request.security(tick_symbol, timeframe.period, close)
tickEMA = ta.ema(tickC, tickMA_len)

//----------------------------------------------- TICK Divergence -------------------------------

lbR = input(title='Pivot Lookback Right', defval=2, group = "TICK Divergence")
lbL = input(title='Pivot Lookback Left', defval=2, group = "TICK Divergence")

rangeUpper = input(title='Max of Lookback Range', defval=60, group = "TICK Divergence")
rangeLower = input(title='Min of Lookback Range', defval=5, group = "TICK Divergence")
plotBull = input(title='Plot Bullish', defval=true, group = "TICK Divergence")
plotHiddenBull = input(title='Plot Hidden Bullish', defval=true, group = "TICK Divergence")
plotBear = input(title='Plot Bearish', defval=true, group = "TICK Divergence")
plotHiddenBear = input(title='Plot Hidden Bearish', defval=true, group = "TICK Divergence")

bearColor = color.red 
bullColor = color.green
hiddenBullColor = color.new(color.green, 80)
hiddenBearColor = color.new(color.red, 80)
textColor = color.white
noneColor = color.new(color.white, 100)

plFound = na(ta.pivotlow(tickC, lbL, lbR)) ? false : true
phFound = na(ta.pivothigh(tickC, lbL, lbR)) ? false : true

_inRange(cond) =>
    bars = ta.barssince(cond == true)
    rangeLower <= bars and bars <= rangeUpper

// Regular Bullish

// Osc: Higher low
oscHL = tickC[lbR] > ta.valuewhen(plFound, tickC[lbR], 1) and _inRange(plFound[1])

// Price: Lower low
priceLL = low[lbR] < ta.valuewhen(plFound, low[lbR], 1) 

bullCond = plotBull and priceLL and oscHL and plFound

plot(plFound ? tickC[lbR] : na, offset=-lbR, title='Regular Bullish', linewidth=2, color=bullCond ? bullColor : noneColor)

plotshape(bullCond ? tickC[lbR] : na, offset=-lbR, title='Regular Bullish Label', text=' Bull ', style=shape.labelup, location=location.absolute, color=color.new(bullColor, 0), textcolor=color.new(textColor, 0))

//------------------------------------------------------------------------------
// Hidden Bullish

// Osc: Lower low
oscLL = tickC[lbR] < ta.valuewhen(plFound, tickC[lbR], 1) and _inRange(plFound[1])

// Price: Higher low
priceHL = low[lbR] > ta.valuewhen(plFound, low[lbR], 1)

hiddenBullCond = plotHiddenBull and priceHL and oscLL and plFound

plot(plFound ? tickC[lbR] : na, offset=-lbR, title='Hidden Bullish', linewidth=2, color=hiddenBullCond ? hiddenBullColor : noneColor)

plotshape(hiddenBullCond ? tickC[lbR] : na, offset=-lbR, title='Hidden Bullish Label', text=' H Bull ', style=shape.labelup, location=location.absolute, color=color.new(bullColor, 0), textcolor=color.new(textColor, 0))


//------------------------------------------------------------------------------
// Regular Bearish

// Osc: Lower high
oscLH = tickC[lbR] < ta.valuewhen(phFound, tickC[lbR], 1) and _inRange(phFound[1])

// Price: Higher high
priceHH = high[lbR] > ta.valuewhen(phFound, high[lbR], 1)

bearCond = plotBear and priceHH and oscLH and phFound

plot(phFound ? tickC[lbR] : na, offset=-lbR, title='Regular Bearish', linewidth=2, color=bearCond ? bearColor : noneColor)

plotshape(bearCond ? tickC[lbR] : na, offset=-lbR, title='Regular Bearish Label', text=' Bear ', style=shape.labeldown, location=location.absolute, color=color.new(bearColor, 0), textcolor=color.new(textColor, 0))

//------------------------------------------------------------------------------
// Hidden Bearish

// Osc: Higher high
oscHH = tickC[lbR] > ta.valuewhen(phFound, tickC[lbR], 1) and _inRange(phFound[1])

// Price: Lower high
priceLH = high[lbR] < ta.valuewhen(phFound, high[lbR], 1)

hiddenBearCond = plotHiddenBear and priceLH and oscHH and phFound

plot(phFound ? tickC[lbR] : na, offset=-lbR, title='Hidden Bearish', linewidth=2, color=hiddenBearCond ? hiddenBearColor : noneColor)

plotshape(hiddenBearCond ? tickC[lbR] : na, offset=-lbR, title='Hidden Bearish Label', text=' H Bear ', style=shape.labeldown, location=location.absolute, color=color.new(bearColor, 0), textcolor=color.new(textColor, 0))


// **************************************************** HARSI *************************************************
rsi_source = close
rsi_len = input.int(7, "RSI length", group="RSI")
rsi_smoothing = input.int(1, "RSI smoothing", group="RSI")
rsi_col = input.color(color.new(color.yellow,0),"RSI color", group = "RSI", inline ='rsi')
show_rsi = input.bool(true, "Show", inline ='rsi', group = "RSI")

show_harsi = input.bool(true, "Show HARSI", group="HARSI")
HARSI_len = input.int(14, "HARSI length", group="HARSI")
HARSI_smoothing = input.int(1, "HARSI smoothing", group="HARSI")

//  RSI Heikin-Ashi generation function
f_rsiHeikinAshi( _length ) =>

    float _closeRSI = ta.rsi( close, _length )

    float _openRSI  = nz( _closeRSI[1], _closeRSI )

    float _highRSI_raw  = ta.rsi( high, _length )
    float _lowRSI_raw   = ta.rsi( low, _length )

    float _highRSI  = math.max( _highRSI_raw, _lowRSI_raw )
    float _lowRSI   = math.min( _highRSI_raw, _lowRSI_raw )

    float _close    = ( _openRSI + _highRSI + _lowRSI + _closeRSI ) / 4

    var float _open = na
    _open  := na( _open[ HARSI_smoothing ] ) ? ( _openRSI + _closeRSI ) / 2 :
              ( ( _open[1] * HARSI_smoothing ) + _close[1] ) / (HARSI_smoothing + 1 )

    float _high     = math.max( _highRSI, math.max( _open, _close ) )
    float _low      = math.min( _lowRSI,  math.min( _open, _close ) )

    [ _open, _high, _low, _close ]


RSI = ta.sma(ta.rsi(rsi_source, rsi_len),rsi_smoothing)

[ O, H, L, C ] = f_rsiHeikinAshi( HARSI_len )

RSI_scaled = RSI*40 - 2000

O_scaled = O*40 - 2000
H_scaled = H*40 - 2000
L_scaled = L*40 - 2000
C_scaled = C*40 - 2000

//****************************************** Trend / Signal Conditions **********************************************

var trend = 0

bulltick = (tickC > neutralH and tickC < 1000) or (trend[1] == 1 and tickC[1] > neutralL and tickC > neutralL)
beartick = (tickC < neutralL and tickC > -1000) or (trend[1] == -1 and tickC[1] < neutralH and tickC < neutralH)

bulltickMA = (tickEMA > 0 and tickEMA < 1000) 
beartickMA = (tickEMA < 0 and tickEMA > -1000)

// Green or red HARSI candle
TICKHA_bull_0 = C > O and C >= C[1] 
TICKHA_bear_0 = C < O and C <= C[1] 

// Inside bar HARSI candle
TICKHA_bull_1 = C[1] < O[1] and C > C[1] 
TICKHA_bear_1 = C[1] > O[1] and C < C[1]

// trend continuation based on TICK, regardless of HARSI
TICKHA_bull_2 = trend[1] == 1 and tickC > neutralL 
TICKHA_bear_2 = trend[1] == -1 and tickC < neutralH 

// trend continuation before RSI and HARSI crossover
TICKHA_bull_3 = trend[1] == 1 and RSI > H
TICKHA_bear_3 = trend[1] == -1 and RSI < L

rsi_bull = RSI > 50 or RSI < 30
rsi_bear = RSI < 50 or RSI > 70

sub_bull = TICKHA_bull_0 or TICKHA_bull_1 or TICKHA_bull_2 or TICKHA_bull_3
sub_bear = TICKHA_bear_0 or TICKHA_bear_1 or TICKHA_bear_2 or TICKHA_bear_3

TICKHA_bull = sub_bull and rsi_bull and bulltick and bulltickMA
TICKHA_bear = sub_bear and rsi_bear and beartick and beartickMA

trend := not(t1) ? 0 : TICKHA_bull and not(TICKHA_bear) ? 1 : TICKHA_bear and not(TICKHA_bull) ? -1 : trend[1]
trend := trend == 1 and not(sub_bull) and sub_bear ? 0 : trend == -1 and not(sub_bear) and sub_bull ? 0 : trend

// *********************************************** Plots ************************************************************

OB          = hline(OverH, color=color.gray, linestyle=hline.style_dashed)
upperbull   = hline(BullishH, color=color.gray, linestyle=hline.style_dashed)
lowerbull   = hline(neutralH, color=color.gray, linestyle=hline.style_dashed)
median      = hline(0, color=color.orange, linestyle = hline.style_dotted,  linewidth = 2)
upperbear   = hline(neutralL, color=color.gray, linestyle=hline.style_dashed)
lowerbear   = hline(BearishL, color=color.gray, linestyle=hline.style_dashed)
OS          = hline(OverL, color=color.gray, linestyle=hline.style_dashed)

fill( upperbull, OB, color.new(color.green,90))
fill( lowerbull, upperbull, color.new(color.green,80))
fill( lowerbull, upperbear, color.new(color.gray,90))
fill( upperbear, lowerbear, color.new(color.red,80))
fill( lowerbear, OS, color.new(color.red,90))

color bodyColour    = C > O ? color.teal : color.red
color wickColour    = color.gray

plotcandle( O_scaled, H_scaled, L_scaled, C_scaled, "HARSI", show_harsi ? bodyColour : na, show_harsi ? wickColour : na, bordercolor = show_harsi ? bodyColour : na )

plot(show_tick ? tickC : na, title='TICK shadow', color = t1 ? color.rgb( 0, 0, 0, 50 ) : na , style=plot.style_linebr, linewidth = 4)
plot(show_tick ? tickC : na, title='TICK', color = t1 ? tick_col : na , style=plot.style_linebr, linewidth = 2)

plot(show_tickema ? tickEMA : na, title='TICK EMA shadow', color = t1 ? color.rgb( 0, 0, 0, 50 ) : na , style=plot.style_linebr, linewidth = 4)
plot(show_tickema ? tickEMA : na, title='TICK EMA', color = t1 ? tickEMA_col : na , style=plot.style_linebr, linewidth = 2)

plot(show_rsi ? RSI_scaled : na, title='RSI shadow', color = color.rgb( 0, 0, 0, 50 ) , style=plot.style_linebr, linewidth = 4)
plot(show_rsi ? RSI_scaled : na, title='RSI', color = rsi_col , style=plot.style_linebr, linewidth = 2)

plotshape(TICKHA_bull_0,"Bull 0", color=color.new(color.green,70), style=shape.circle, location = location.bottom, size = size.tiny )
plotshape(TICKHA_bear_0,"Bear 0", color=color.new(color.red,70), style=shape.circle, location = location.top, size = size.tiny )
plotshape(TICKHA_bull_1,"Bull 1", color=color.new(color.green,70), style=shape.circle, location = location.bottom, size = size.tiny )
plotshape(TICKHA_bear_1,"Bear 1", color=color.new(color.red,70), style=shape.circle, location = location.top, size = size.tiny )
plotshape(TICKHA_bull_2,"Bull 2", color=color.new(color.green,70), style=shape.circle, location = location.bottom, size = size.tiny )
plotshape(TICKHA_bear_2,"Bear 2", color=color.new(color.red,70), style=shape.circle, location = location.top, size = size.tiny )
plotshape(TICKHA_bull_3,"Bull 3", color=color.new(color.green,70), style=shape.circle, location = location.bottom, size = size.tiny )
plotshape(TICKHA_bear_3,"Bear 3", color=color.new(color.red,70), style=shape.circle, location = location.top, size = size.tiny )

plotshape(TICKHA_bull,"Bull", color=color.new(color.green,0), style=shape.circle, location = location.bottom, size = size.tiny )
plotshape(TICKHA_bear,"Bear", color=color.new(color.red,0), style=shape.circle, location = location.top, size = size.tiny )

bgcolor(not(t1) ? color.new(color.white,95) : na)
bgcolor(trend == 1 ? color.new(color.green, 85) : trend == -1 ? color.new(color.red, 85) : na)

// ------------------------------------------ Stats Display -------------------------------------------------------------
 
tablePosition = tableLocation == 'Top' ? position.top_right : position.bottom_right
var table displayTable = table.new(tablePosition, 2, 1, border_width=3)

f_fillCell(_column, _cellText, _c_color) =>
    table.cell(displayTable, _column, 0, _cellText, bgcolor=color.new(_c_color, 75), text_color=_c_color)

posColor = color.new(color.green,0)
negColor = color.new(color.red,0)
posDeColor = color.new(color.blue,0)
negDeColor = color.new(color.orange,0)
neuColor = color.new(color.gray,0)

// --- TICK stats ---
tick_neutral = tickEMA < neutralH and tickEMA > neutralL
tick_bull_ext = tickC > 800
tick_bear_ext = tickC < -800
tick_bull = trend > 0 and not(tick_neutral) and not(tick_bull_ext)
tick_bear = trend < 0 and not(tick_neutral) and not(tick_bear_ext)
tick_NeuBull = trend > 0 and tick_neutral
tick_NeuBear = trend < 0 and tick_neutral

if barstate.islast
    f_fillCell(0, "TICK trend: " + (tick_bull ? "Bullish" : tick_bear ? "Bearish" : tick_NeuBull ? "Neutral w/ Bullish bias" : tick_NeuBear ? "Neutral, Bearish bias" : tick_bull_ext ? "Bullish, Extended" : tick_bear_ext ? "Bearish, Extended" : "Neutral" ), trend > 0 ? posColor : trend < 0 ? negColor : neuColor)
    f_fillCell(1, "RSI: " + (RSI > 50 ? "Bullish" : RSI < 50 ? "Bearish" : "Neutral"), RSI > 50 ? posColor : RSI < 50 ? negColor : neuColor)
 