Sumitx369/Paper_Trading_Backtesting
2
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 