LNRSI Single TF

//@version=5 // Combined: Normalized RS with Adaptive Laguerre Signal & Stats + Multi-Timeframe + BG Shading indicator("Adaptive Laguerre NormRS Single TF (BG Shade)", shorttitle= "LNRSI - Single BG", format=format.price, precision=3)

// --- Inputs --- // 1. Timeframe Selection tfSelection = input.timeframe("", title="Resolution (Leave empty for Chart)", group="Data Settings")

// 2. Basic Settings benchmarkTicker = input.symbol("SPY", title="Benchmark Ticker", group="Data Settings") lookback = input.int(50, title="Normalization Lookback", minval=1, group="Data Settings")

// 3. Laguerre & Fractals Settings useFractals = input.bool(true, title="Use Fractals Energy?", group="Laguerre Settings") feLength = input.int(13, title="Fractals Length", minval=1, group="Laguerre Settings") baseAlpha = input.float(0.7, title="Base Alpha (if Fractals Off)", minval=0.01, maxval=1.0, step=0.1, group="Laguerre Settings")

// 4. Visual Settings (Simplified) shadeOn = input.bool(true, "Show Background Shading?", group="Visual Settings")

// --- Calculations ---

// Logic: Use the user's selected timeframe. If empty, default to the current chart's timeframe. targetTF = (tfSelection == "") ? timeframe.period : tfSelection

// 1. Get Price Data (MTF Enabled) priceCurrent = request.security(syminfo.tickerid, targetTF, close) priceBenchmark = request.security(benchmarkTicker, targetTF, close)

// 2. Calculate the Ratio ratio = priceCurrent / priceBenchmark

// 3. Normalize the Ratio highestRatio = ta.highest(ratio, lookback) lowestRatio = ta.lowest(ratio, lookback) rangeVal = highestRatio - lowestRatio normalizedValue = rangeVal == 0 ? 0.5 : (ratio - lowestRatio) / rangeVal

// 4. Calculate Fractals Energy r_high = ta.highest(ratio, 2) r_low = ta.lowest(ratio, 2)

feNum = math.sum((r_high - r_low), feLength) feDenom = ta.highest(r_high, feLength) - ta.lowest(r_low, feLength) feRatio = (feDenom != 0) ? feNum / feDenom : 1

gamma = math.log(feRatio) / math.log(feLength) dynamicAlpha = useFractals ? gamma : baseAlpha

// 5. Laguerre Filter var float L0 = 0.0 var float L1 = 0.0 var float L2 = 0.0 var float L3 = 0.0

alpha_calc = dynamicAlpha L0 := alpha_calc * normalizedValue + (1 - alpha_calc) * nz(L0[1]) L1 := -(1 - alpha_calc) * L0 + nz(L0[1]) + (1 - alpha_calc) * nz(L1[1]) L2 := -(1 - alpha_calc) * L1 + nz(L1[1]) + (1 - alpha_calc) * nz(L2[1]) L3 := -(1 - alpha_calc) * L2 + nz(L2[1]) + (1 - alpha_calc) * nz(L3[1])

signalLine = (L0 + 2*L1 + 2*L2 + L3) / 6

// --- Plotting --- normPlot = plot(normalizedValue, title="Normalized RS", color=color.new(color.blue, 0), linewidth=2) sigPlot = plot(signalLine, title="Laguerre Signal", color=color.new(color.orange, 0), linewidth=2)

// Threshold Lines hline(0.8, "Upper Threshold", color=color.red, linestyle=hline.style_dashed) hline(0.5, "Midline", color=color.gray, linestyle=hline.style_dotted) hline(0.2, "Lower Threshold", color=color.green, linestyle=hline.style_dashed)

// --- Background Shading Logic --- // Green (50% transp) if NRS > Signal, Red (50% transp) if NRS < Signal bgColor = normalizedValue >= signalLine ? color.new(color.green, 50) : color.new(color.red, 50)

// Apply Background Color if enabled bgcolor(shadeOn ? bgColor : na, title="Trend Background")

// --- Stats Table --- var totalDaysAbove = 0.0 var numberOfStreaks = 0 isAbove = normalizedValue > 0.8 wasBelow = not (normalizedValue[1] > 0.8)

if isAbove and wasBelow numberOfStreaks += 1 if isAbove totalDaysAbove += 1

averageDuration = numberOfStreaks > 0 ? (totalDaysAbove / numberOfStreaks) : 0

var table statsTable = table.new(position.top_right, 2, 1) if barstate.islast table.cell(statsTable, 0, 0, "Avg. Duration: " + str.tostring(averageDuration, "0.00"), bgcolor = color.new(color.green, 20), text_color=color.white) table.cell(statsTable, 1, 0, "Current Alpha: " + str.tostring(dynamicAlpha, "0.00"), bgcolor = color.new(color.blue, 20), text_color=color.white)