Noski - Rob Hoffman_Inventory Retracement Bar
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © noski1

//@version=5
indicator(title='Noski - Rob Hoffman_Inventory Retracement Bar', shorttitle='Noski HM', precision=2, overlay=true)


// Inputs
z = input.int(45, title='Inventory Retracement Percentage %', maxval=100, group="IRB")
src = input(title='Source', defval=close, group="Angle of EMA")
guide_pos = input.float(title='Guides Position', defval=45, group="Angle of EMA")
guide_neg = input(title='Guides Position', defval=-45, group="Angle of EMA")
price2bar_ratio = input(title='Price To Bar Ratio', defval=20.0, group="Angle of EMA") 
threshold = input(title='Threshold', defval=1.0, group="Angle of EMA")
smal = input(title='Average angle over how many bars', defval=20, group="Angle of EMA")
emafilter   = input.int(title="EMA length", defval=20, group= "EMA")

// Strategy Settings
var g_strategy      = "Strategy Settings"
stopMultiplier      = input.float(title="Stop Loss ATR", defval=1.0, group=g_strategy, tooltip="Stop loss multiplier (x ATR)")
rr                  = input.float(title="R:R", defval=1.0, group=g_strategy, tooltip="Risk:Reward profile")

// Filter Settings
var g_filter        = "Filter Settings"
atrMinFilterSize    = input.float(title=">= ATR Filter", defval=0.0, minval=0.0, group=g_filter, tooltip="Minimum size of entry candle compared to ATR")
atrMaxFilterSize    = input.float(title="<= ATR Filter", defval=3.0, minval=0.0, group=g_filter, tooltip="Maximum size of entry candle compared to ATR")




// --------------------------------------------------------------------------------
//------- IRB--------//
// --------------------------------------------------------------------------------
// Candle Range
a = math.abs(high - low)
// Candle Body
b = math.abs(close - open)
// Percent to Decimal
c = z / 100

// Range Verification 
rv = b < c * a

// Price Level for Retracement
x = low + c * a
y = high - c * a

// IRB Buy/Sell Filter
irbb = rv == 1 and high > y and close < y and open < y   //triangle down
irbs = rv == 1 and low < x and close > x and open > x    //triangle up

// Line Definition
li = irbb ? y : irbs ? x : (x + y) / 2

// --------------------------------------------------------------------------------
// EMA Angle Functions
// --------------------------------------------------------------------------------
ema = ta.ema(close, emafilter)
get_slope(ema, price2bar_ratio) =>
    180.0 / (2 * math.asin(1)) * math.atan(ta.change(ema) / price2bar_ratio)

// Logic

slope = get_slope(ema, price2bar_ratio)

rise = false
rise := slope - slope[1] > threshold ? true : slope - slope[1] < -threshold ? false : nz(rise[1])

prefall = false
prefall := not rise or slope - slope[1] > 0 ? false : rise and slope - slope[1] < 0 ? true : nz(prefall[1])

prerise = false
prerise := rise or slope - slope[1] < 0 ? false : not rise and slope - slope[1] > 0 ? true : nz(prerise[1])

sma = ta.sma(slope, smal)
atr = ta.atr(14)

// Angle Buy Sell Filter
emapos = sma > guide_pos
emaneg = sma < guide_neg

// --------------------------------------------------------------------------------
// ATR Settings
// --------------------------------------------------------------------------------

// Check ATR filter
atrMinFilter = high - low >= (atrMinFilterSize * atr) or atrMinFilterSize == 0.0
atrMaxFilter = high - low <= (atrMaxFilterSize * atr) or atrMaxFilterSize == 0.0
atrFilter = atrMinFilter and atrMaxFilter and not na(atr)


// Calculate long stops & targets
longStop = low - (atr * stopMultiplier) 
longStopDistance = close - longStop 
longTarget = high + (longStopDistance * rr)

// Calculate short stops & targets
shortStop = high + (atr * stopMultiplier) 
shortStopDistance = shortStop - close 
shortTarget = low - (shortStopDistance * rr) 

var int inTrade = 0
// --------------------------------------------------------------------------------
// Combined Buy and Sell signals
// --------------------------------------------------------------------------------
buy = irbb and emapos and atrFilter and barstate.isconfirmed and inTrade == 0
sell = irbs and emaneg and atrFilter and barstate.isconfirmed and inTrade == 0


// Save stops & targets
var float t_stop = na
var float t_target = na
if (buy or sell) and inTrade == 0
    t_stop := buy ? longStop : shortStop
    t_target := buy ? longTarget : shortTarget
    inTrade := buy ? 1 : -1

// Check if long stop or target is hit
if inTrade == 1
    if high >= t_target or low <= t_stop
        inTrade := 0

// Check if short stop or target is hit
if inTrade == -1
    if high >= t_stop or low <= t_target
        inTrade := 0 


// Plot Statement

plotshape(buy, style=shape.triangleup, location=location.abovebar, color=color.new(color.green, 0), text = "Long", title='Long IRB', textcolor = color.green)
plotshape(sell, style=shape.triangledown, location=location.belowbar, color=color.new(color.red, 0), text = "Short", title='Short IRB', textcolor = color.red)

bgcolor(sma > guide_pos ? color.new(color.green, 85) : na)  // highlighting bg when ema angle > 45
bgcolor(sma < guide_neg ? color.new(color.red, 85) : na)

plot(inTrade != 0 ? t_stop : na, style=plot.style_linebr, color=color.red, title="Trade Stop")
plot(inTrade != 0 ? t_target : na, style=plot.style_linebr, color=color.green, title="Trade Target")
plot(ema, title="EMA", color=color.yellow, linewidth=2)
// Trigger alerts
alertcondition(buy, "Buy")
alertcondition(sell, "Sell")