Team Ai
Apppublic

Sumitx369/Paper_Trading_Backtesting

sourceHugging Faceupdated 4mo agoView on Hugging Face
2likes
RB_Indicator.pine186 linesDownload Raw Back to root
1//@version=62// =============================================================================3// Rob Booker - Knoxville Divergence4// -----------------------------------------------------------------------------5// The Knoxville Divergence combines TWO conditions that must occur together:6//   1) Price/Momentum divergence over a lookback window7//        - Bullish: price makes a LOWER low, but Momentum makes a HIGHER low8//        - Bearish: price makes a HIGHER high, but Momentum makes a LOWER high9//   2) RSI confirmation at the extreme10//        - Bullish requires RSI to have been OVERSOLD   (<= rsiLower)11//        - Bearish requires RSI to have been OVERBOUGHT (>= rsiUpper)12// When both align, a line is drawn between the two price extremes and a13// label (KD) is plotted. Bearish = above bars (sell), Bullish = below (buy).14// =============================================================================15 16indicator("Knoxville Divergence (Rob Booker)", shorttitle="KD", overlay=true, max_lines_count=500, max_labels_count=500)17 18// ----------------------------- Inputs ---------------------------------------19grpD       = "Divergence"20lookback   = input.int(30,  "Divergence Lookback (bars)", minval=5,  maxval=200, group=grpD, tooltip="Window used to search for the prior price extreme to compare against.")21minBars    = input.int(5,   "Min Bars Between Pivots",    minval=1,  maxval=100, group=grpD, tooltip="Two extremes closer together than this are ignored.")22 23grpM       = "Momentum"24momLen     = input.int(20,  "Momentum Length",            minval=1,  group=grpM)25 26grpR       = "RSI Filter"27rsiLen     = input.int(14,  "RSI Length",                 minval=1,  group=grpR)28rsiUpper   = input.int(70,  "RSI Overbought",             minval=50, maxval=100, group=grpR)29rsiLower   = input.int(30,  "RSI Oversold",               minval=0,  maxval=50,  group=grpR)30 31grpS       = "Style"32bullCol    = input.color(color.new(color.green, 0), "Bullish Color", group=grpS)33bearCol    = input.color(color.new(color.red,   0), "Bearish Color", group=grpS)34lineW      = input.int(2, "Line Width", minval=1, maxval=5, group=grpS)35showLabels = input.bool(true, "Show KD Labels", group=grpS)36 37// ----------------------------- Calculations ---------------------------------38mom = ta.mom(close, momLen)          // momentum = close - close[momLen]39rsi = ta.rsi(close, rsiLen)40 41// --- BEARISH: current bar is the highest high of the lookback window ---------42// price higher high vs the prior high inside the window, momentum lower high,43// and RSI was overbought somewhere across the window.44isHighPivot = high == ta.highest(high, lookback)45 46// Find the prior swing high (the highest high strictly before minBars ago,47// inside the lookback window) to compare against.48priorHigh      = ta.highest(high[minBars], lookback - minBars)49priorHighOff   = ta.highestbars(high[minBars], lookback - minBars) * -1 + minBars  // bars back to that prior high50priorHighMom   = mom[priorHighOff]51 52bearishDiv = isHighPivot and high > priorHigh and mom < priorHighMom and ta.highest(rsi, lookback) >= rsiUpper53 54// --- BULLISH: current bar is the lowest low of the lookback window -----------55isLowPivot = low == ta.lowest(low, lookback)56 57priorLow       = ta.lowest(low[minBars], lookback - minBars)58priorLowOff    = ta.lowestbars(low[minBars], lookback - minBars) * -1 + minBars59priorLowMom    = mom[priorLowOff]60 61bullishDiv = isLowPivot and low < priorLow and mom > priorLowMom and ta.lowest(rsi, lookback) <= rsiLower62 63// -------------------- Stochastic RSI Confirmation (both sides) ----------------64// A BEARISH KD only counts when Stoch RSI rolls DOWN at the top — blue %K has65// crossed (or is already) below red %D, with both lines falling/flat.66// A BULLISH KD (mirror) only counts when Stoch RSI rolls UP at the bottom — blue67// %K has crossed (or is already) above red %D, with both lines rising/flat.68// The roll-over may happen up to N bars after the KD (see window). If the lines69// are still moving the wrong way (momentum not turning), the KD is suppressed.70grpStoch = "Stoch RSI Confirmation"71useStoch = input.bool(true, "Confirm KD with Stoch RSI (both sides)", group=grpStoch)72stochWin = input.int(5, "Confirm within N bars of KD", minval=0, maxval=30, group=grpStoch, tooltip="The Stoch RSI usually rolls over a few bars AFTER the high that makes the KD. 0 = must roll over on the KD bar itself (very few signals). 5 = allow the cross-down within 5 bars after the KD (many more signals). Raise for more, lower for stricter.")73stRsiLen = input.int(14, "RSI Length",         minval=1, group=grpStoch)74stLen    = input.int(14, "Stochastic Length",  minval=1, group=grpStoch)75stKsm    = input.int(3,  "%K Smoothing (blue)", minval=1, group=grpStoch)76stDsm    = input.int(3,  "%D Smoothing (red)",  minval=1, group=grpStoch)77 78stochSrc = ta.rsi(close, stRsiLen)79kLine    = ta.sma(ta.stoch(stochSrc, stochSrc, stochSrc, stLen), stKsm)   // blue %K80dLine    = ta.sma(kLine, stDsm)                                           // red  %D81 82// Stoch rolling DOWN (for bearish): blue crossed/below red, both falling/flat.83stochRollDown = (ta.crossunder(kLine, dLine) or kLine < dLine) and (kLine <= kLine[1] and dLine <= dLine[1])84// Stoch rolling UP (for bullish, mirror): blue crossed/above red, both rising/flat.85stochRollUp   = (ta.crossover(kLine, dLine)  or kLine > dLine) and (kLine >= kLine[1] and dLine >= dLine[1])86 87// --- Bearish: remember the high, confirm when Stoch rolls DOWN within window ---88var float kdHigh     = na89var int   kdHighIdx  = na90var float kdPrior    = na91var int   kdPriorIdx = na92var int   barsSinceKD = 100000093var bool  kdFired     = false94if bearishDiv95    kdHigh     := high96    kdHighIdx  := bar_index97    kdPrior    := priorHigh98    kdPriorIdx := bar_index - priorHighOff99    barsSinceKD := 0100    kdFired := false101else102    barsSinceKD += 1103showBearKD = useStoch ? (barsSinceKD <= stochWin and stochRollDown and not kdFired) : bearishDiv104if showBearKD and useStoch105    kdFired := true106 107// --- Bullish: remember the low, confirm when Stoch rolls UP within window ------108var float kdLow       = na109var int   kdLowIdx    = na110var float kdPriorL    = na111var int   kdPriorLIdx = na112var int   barsSinceBullKD = 1000000113var bool  kdBullFired = false114if bullishDiv115    kdLow       := low116    kdLowIdx    := bar_index117    kdPriorL    := priorLow118    kdPriorLIdx := bar_index - priorLowOff119    barsSinceBullKD := 0120    kdBullFired := false121else122    barsSinceBullKD += 1123showBullKD = useStoch ? (barsSinceBullKD <= stochWin and stochRollUp and not kdBullFired) : bullishDiv124if showBullKD and useStoch125    kdBullFired := true126 127// -------------------- Mean Reversion Confirmation (visual) -------------------128// LeafAlgo "Adaptive Mean Reversion" plotted as a VISUAL confirmation layer.129// The KD signals are NOT auto-filtered here — every divergence still prints, and130// YOU confirm manually using the zones:131//   GREEN zone  (price > upper band + RSI extreme) = top    -> confirms BEARISH KD132//   FUCHSIA zone(price < lower band + RSI extreme) = bottom -> confirms BULLISH KD133// Rule of thumb: trust a KD when its zone is active, or ended just 1 candle ago.134grpMR        = "Mean Reversion Confirmation"135useAtrRegime = input.bool(true, "ATR Regime Switch (on/off)", group=grpMR, tooltip="ON = auto-switch between Trending and Ranging parameters using ATR. OFF = always use the Ranging parameters (regime detection disabled).")136volPct       = input.float(1.5, "Volatility Threshold (% of price)", minval=0.0, step=0.1, group=grpMR, tooltip="DYNAMIC threshold: ATR(14) above this percentage of price = 'trending'. Because it is a % of price it scales automatically with the market price, so the same setting works on a $5 stock and a $5000 one — no manual retuning.")137lbTrend      = input.int(40,  "Lookback (Trending)", minval=2, group=grpMR)138lbRange      = input.int(20,  "Lookback (Ranging)",  minval=2, group=grpMR)139thTrend      = input.float(2.0, "Threshold (Trending)", step=0.1, group=grpMR)140thRange      = input.float(1.5, "Threshold (Ranging)",  step=0.1, group=grpMR)141showBands    = input.bool(true, "Show MR Bands", group=grpMR)142showZone     = input.bool(true, "Shade Reversal Zones", group=grpMR)143 144// Dynamic ATR threshold: a % of current price, so it auto-scales per symbol.145atr14        = ta.atr(14)146dynThreshold = close * volPct / 100.0147isTrending   = useAtrRegime and atr14 > dynThreshold148mrLookback   = isTrending ? lbTrend : lbRange149mrThreshold  = isTrending ? thTrend : thRange150 151mrMean = ta.sma(close, mrLookback)152mrDev  = ta.stdev(close, mrLookback)153// Ranging regime tightens the bands to 0.75x (matches the source script).154mrMult  = isTrending ? mrThreshold : mrThreshold * 0.75155mrUpper = mrMean + mrDev * mrMult156mrLower = mrMean - mrDev * mrMult157 158mrConfluence = rsi >= rsiUpper or rsi <= rsiLower159greenZone = close > mrUpper and mrConfluence   // TOP    -> confirm bearish KD160pinkZone  = close < mrLower and mrConfluence    // BOTTOM -> confirm bullish KD161 162plot(showBands ? mrMean  : na, "MR Mean",  color=color.new(color.aqua,    0))163plot(showBands ? mrUpper : na, "MR Upper", color=color.new(color.lime,    0))164plot(showBands ? mrLower : na, "MR Lower", color=color.new(color.fuchsia, 0))165bgcolor(showZone and greenZone ? color.new(color.lime,    85) : na, title="Top Reversal Zone")166bgcolor(showZone and pinkZone  ? color.new(color.fuchsia, 85) : na, title="Bottom Reversal Zone")167 168// ----------------------------- Drawing ---------------------------------------169// Bearish KD shows ONLY when Stoch RSI confirms (rolling down). Bullish unchanged.170if showBearKD171    line.new(kdPriorIdx, kdPrior, kdHighIdx, kdHigh, color=bearCol, width=lineW)172    if showLabels173        label.new(kdHighIdx, kdHigh, "KD", style=label.style_label_down, color=bearCol, textcolor=color.white, size=size.small)174 175if showBullKD176    line.new(kdPriorLIdx, kdPriorL, kdLowIdx, kdLow, color=bullCol, width=lineW)177    if showLabels178        label.new(kdLowIdx, kdLow, "KD", style=label.style_label_up, color=bullCol, textcolor=color.white, size=size.small)179 180plotshape(showBearKD and not showLabels, title="Bearish marker", style=shape.triangledown, location=location.abovebar, color=bearCol, size=size.tiny)181plotshape(showBullKD and not showLabels, title="Bullish marker", style=shape.triangleup,   location=location.belowbar, color=bullCol, size=size.tiny)182 183// ----------------------------- Alerts ---------------------------------------184alertcondition(showBearKD, "Bearish Knoxville Divergence", "Bearish KD (Stoch RSI confirmed)")185alertcondition(showBullKD, "Bullish Knoxville Divergence", "Bullish KD (Stoch RSI confirmed)")186