Playing w/RSI Break outs and Open Interest – The Parrot Backtest Party episode 8

Open interest script

//@version=5
indicator("Open Interest", "OI", format = format.volume)

bool overwriteSymbolInput = input.bool(false, "Override symbol", inline = "Override symbol")
string tickerInput = input.symbol("", "", inline = "Override symbol")

string symbolOnly = syminfo.ticker(tickerInput)
string userSymbol = overwriteSymbolInput ? symbolOnly : syminfo.prefix + ":" + syminfo.ticker
string openInterestTicker = str.format("{0}_OI", userSymbol)
string timeframe = syminfo.type == "futures" and timeframe.isintraday ? "1D" : timeframe.period
[oiOpen, oiHigh, oiLow, oiClose, oiColorCond] = request.security(openInterestTicker, timeframe, [open, high, low, close, close > close[1]], ignore_invalid_symbol = true)
oiOpen := oiOpen ? oiOpen : na
oiHigh := oiHigh ? oiHigh : na
oiLow := oiLow ? oiLow : na

if barstate.islastconfirmedhistory and na(oiClose)
    runtime.error(str.format("No Open Interest data found for the `{0}` symbol.", userSymbol))

hasOHLC = ta.cum(oiOpen)
color openInterestColor = oiColorCond ? color.teal : color.red
// plot(hasOHLC ? na : oiClose, "Futures Open Interest", openInterestColor, style = plot.style_stepline, linewidth = 4)
// plotcandle(oiOpen, oiHigh, oiLow, hasOHLC ? oiClose : na, "Crypto Open Interest", color = openInterestColor, wickcolor = openInterestColor, bordercolor = openInterestColor)

// hline(30)
// hline(70)
// plot(ta.rsi(oiClose, 14), "rsi", color.white)


smoothK = input.int(3, "K", minval=1)
smoothD = input.int(3, "D", minval=1)
lengthRSI = input.int(14, "RSI Length", minval=1)
lengthStoch = input.int(14, "Stochastic Length", minval=1)
src = oiClose
rsi1 = ta.rsi(src, lengthRSI)
k = ta.sma(ta.stoch(rsi1, rsi1, rsi1, lengthStoch), smoothK)
d = ta.sma(k, smoothD)
plot(k, "K", color=#2962FF)
plot(d, "D", color=#FF6D00)
h0 = hline(80, "Upper Band", color=#787B86)
hline(50, "Middle Band", color=color.new(#787B86, 50))
h1 = hline(20, "Lower Band", color=#787B86)
fill(h0, h1, color=color.rgb(33, 150, 243, 90), title="Background")


rsi2 = ta.rsi(close, lengthRSI)
k2 = ta.sma(ta.stoch(rsi2, rsi2, rsi2, lengthStoch), smoothK)
d2 = ta.sma(k2, smoothD)

plotshape(ta.crossover(k2,d2) and k2 < 20 and k > 80, title = "cross over", style = shape.labelup, location = location.bottom, text = "S", textcolor = color.white, color=color.green)
plotshape(ta.crossunder(k2,d2) and k2 > 80 and k > 80, title = "cross over", style = shape.labeldown, location = location.top, text = "S", textcolor = color.white, color=color.red)

RSI Trendline breakouts tweaks

UPDATE 1: Apologies but this script still has a problem to filter out trend lines that I wasn’t able to solve.

UPDATE 2: script has been fixed! it now can properly filter

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// ยฉ HoanGhetti

//@version=5
indicator("RSI Trendlines with Breakouts [HG]", precision = 2, max_labels_count = 500, max_lines_count = 500)
import HoanGhetti/SimpleTrendlines/3 as tl

g_trendlines    = 'Trendline Settings', g_conditions = 'Conditions',  g_styling = 'Styling', g_timeframe = 'Timeframe'
input_timeframe = input.timeframe(defval = '', title = 'Timeframe', group = g_timeframe)
input_pLen      = input.int(defval = 4, title = 'Lookback Range', minval = 1, group = g_trendlines, tooltip = 'How many bars to determine when a swing high/low is detected.')
input_rLen      = input.int(defval = 14, title = 'RSI Length' , minval = 1, group = g_trendlines)
input_rSrc      = input.source(defval = close, title = 'RSI Source', group = g_trendlines)
input_repaint   = input.string(defval = 'On', title = 'Repainting', group = g_conditions, options = ['On', 'Off: Bar Confirmation'], tooltip = 'Bar Confirmation: Generates alerts when candle closes. (1 Candle Later)')
input_minRsiDiff= input.int(defval = 3, title = 'min RSI Difference', group = g_conditions, tooltip = 'The difference between the current RSI value and the breakout value.\n\nHow much higher in value should the current RSI be compared to the breakout value in order to detect a breakout?')

input_maxRsiDiff= input.int(defval = 10, title = 'max RSI Difference', group = g_conditions, tooltip = 'The difference between the current RSI value and the breakout value.\n\nThis parameter will limit the max difference')

input_rsiCol    = input.color(defval = color.blue, title = 'RSI Color', group = g_styling)
input_width     = input.int(defval = 2, title = 'Line Width', minval = 1, group = g_styling)
input_lblType   = input.string(defval = 'Simple', title = 'Label Type', group = g_styling, options = ['Full', 'Simple'])
input_lblSize   = input.string(defval = size.small, title = 'Label Size', group = g_styling, options = [size.huge, size.large, size.normal, size.small, size.tiny])
input_pLowCol   = input.color(defval = color.red, title = 'Pivot Low', inline = 'col', group = g_styling)
input_pHighCol  = input.color(defval = #089981, title = 'Pivot High', inline = 'col', group = g_styling)
input_override  = input.bool(defval = false, title = 'Override Text Color', group = g_styling, inline = 'override')
input_overCol   = input.color(defval = color.white, title = ' ', group = g_styling, inline = 'override')


shortRsiMin = input(20, tooltip = "it won't trigger short breakouts on rsi values below this")
longRsiMax = input(80, tooltip = "it won't trigger long breakouts on rsi values above this")

lblText = switch input_lblType
    'Simple' => 'Br'
    'Full'   => 'Break'
repaint = switch input_repaint
    'On' => true
    'Off: Bar Confirmation' => false

rsi_v = ta.rsi(input_rSrc, input_rLen) 
rsi = input_timeframe == '' ? rsi_v : request.security(syminfo.tickerid, input_timeframe, rsi_v, lookahead = barmerge.lookahead_on)

pl = fixnan(ta.pivotlow(rsi, 1, input_pLen))
ph = fixnan(ta.pivothigh(rsi, 1, input_pLen))

minSlope = input(0)
maxSlope = input(90)


pivot(float pType) =>
    pivot = pType == pl ? pl : ph
    xAxis = ta.valuewhen(ta.change(pivot), bar_index, 0) - ta.valuewhen(ta.change(pivot), bar_index, 1)
    prevPivot = ta.valuewhen(ta.change(pivot), pivot, 1)
    pivotCond = ta.change(pivot) and (pType == pl ? pivot > prevPivot : pivot < prevPivot)
    pData = tl.new(x_axis = xAxis, offset = input_pLen, strictMode = true, strictType = pType == pl ? 0 : 1)
    pData.drawLine(pivotCond, prevPivot, pivot, rsi)
    pData




breakout(tl.Trendline this, float pType) =>
    var bool hasCrossed = false
    if ta.change(this.lines.startline.get_y1())
        hasCrossed := false
    this.drawTrendline(not hasCrossed)
    condType = (pType == pl ? rsi < this.lines.trendline.get_y2() - input_minRsiDiff : rsi > this.lines.trendline.get_y2() + input_minRsiDiff) 
        // and (pType == pl ? input_maxRsiDiff > this.lines.trendline.get_y2()  - rsi : input_maxRsiDiff > rsi - this.lines.trendline.get_y2() ) 
         and not hasCrossed
    condition = repaint ? condType : condType and barstate.isconfirmed

    x1 = this.lines.trendline.get_x1()
    y1 = this.lines.trendline.get_y1()
    x2 = this.lines.trendline.get_x2()
    y2 = this.lines.trendline.get_y2()

    m = math.atan( (y2-y1)/(x2-x1)) * (180 / math.pi)
   
    bo_diff = math.abs(y2 - rsi)

    if condition
        hasCrossed :=true
        this.lines.startline.set_xy2(this.lines.trendline.get_x2(), this.lines.trendline.get_y2())
        this.lines.trendline.set_xy2(na, na)
        this.lines.startline.copy()
       
        label.new(
             bar_index, 
             this.lines.startline.get_y2(), 
            //  text = lblText, color = pType == pl ? color.new(input_pLowCol, 50) : color.new(input_pHighCol, 50), 
             text = lblText + "\nbo diff "+ str.tostring(bo_diff,"#.#")+ "\nSlope " + str.tostring(m,"#.#") + "\nRSI "+str.tostring(rsi,"#.#"), color = pType == pl ? color.new(input_pLowCol, 50) : color.new(input_pHighCol, 50), 
             size = input_lblSize, style = pType == pl ? label.style_label_lower_left : label.style_label_upper_left, 
             textcolor = pType == pl ? (input_override ? input_overCol : input_pLowCol) : input_override ? input_overCol : input_pHighCol)
    [hasCrossed, m , bo_diff]

method style(tl.Trendline this, color col) =>
    this.lines.startline.set_color(col)
    this.lines.startline.set_width(input_width)
    this.lines.trendline.set_color(col)
    this.lines.trendline.set_width(input_width)
    this.lines.trendline.set_style(line.style_dashed)

plData = pivot(pl)
phData = pivot(ph)
plData.style(input_pLowCol)
phData.style(input_pHighCol)
[cu, m_fu, bo_diff_fu] = breakout(plData, pl)
[co, m_fo, bo_diff_fo] = breakout(phData, ph)

hline(70, title = 'Overbought', color = input_pHighCol, linestyle = hline.style_dotted)
hline(30, title = 'Oversold', color = input_pLowCol, linestyle = hline.style_dotted)
plot(rsi, title = 'Relative Strength Index', linewidth = 2, color = input_rsiCol)
alertcondition(ta.change(plData.lines.startline.get_y1()), 'New Pivot Low Trendline')
alertcondition(ta.change(cu) and cu, 'Pivot Low Breakout')
alertcondition(ta.change(phData.lines.startline.get_y1()), 'New Pivot High Trendline')
alertcondition(ta.change(co) and co, 'Pivot High Breakout')

buyCondition = ta.change(co) and co
sellCondition = ta.change(cu) and cu


confirm(bool long, m, bo_diff) =>

    lowSlope = long ? -1 * maxSlope : minSlope
    highSlope = long ? -1 * minSlope : maxSlope

    signal =  bo_diff < input_maxRsiDiff and m < highSlope and m > lowSlope

    if long
        signal and rsi < longRsiMax
    else 
        signal and rsi > shortRsiMin

buyConditionFiltered = false
sellConditionFiltered = false


if buyCondition
    buyConditionFiltered := confirm(true, m_fo, bo_diff_fo)
else if sellCondition
    sellConditionFiltered := confirm(false, m_fu, bo_diff_fu)

plot(buyCondition ? 1 : sellCondition  ? 2 : na , "signal", color=na)
plotshape(buyConditionFiltered, "buy", shape.labelup, location = location.bottom,color=color.green, text="b", textcolor = color.white)
plotshape(sellConditionFiltered, "sell", shape.labeldown, location = location.top,color=color.red, text="s", textcolor = color.white)

plot(buyConditionFiltered ? 1 : sellConditionFiltered  ? 2 : na , "signal filtered", color=na)

Featured products and TTP memberships