// © Julien_Eche //@version=5 indicator("Adaptive Trend Finder (log)", overlay=true, max_bars_back=1200) confidence(pearsonR) => switch pearsonR < 0.2 => "Extremely Weak" pearsonR < 0.3 => "Very Weak" pearsonR < 0.4 => "Weak" pearsonR < 0.5 => "Mostly Weak" pearsonR < 0.6 => "Somewhat Weak" pearsonR < 0.7 => "Moderately Weak" pearsonR < 0.8 => "Moderate" pearsonR < 0.9 => "Moderately Strong" pearsonR < 0.92 => "Mostly Strong" pearsonR < 0.94 => "Strong" pearsonR < 0.96 => "Very Strong" pearsonR < 0.98 => "Exceptionally Strong" => "Ultra Strong" getTablePosition(string pos) => switch pos "Bottom Right" => position.bottom_right "Bottom Center" => position.bottom_center "Bottom Left" => position.bottom_left "Top Right" => position.top_right "Top Left" => position.top_left "Top Center" => position.top_center "Middle Right" => position.middle_right => position.middle_left // "Middle Left" - default // Calculate deviations for given length calcDev(float source, int length) => float logSource = math.log(source) var int period_1 = length - 1 if barstate.islast float sumX = 0.0 float sumXX = 0.0 float sumYX = 0.0 float sumY = 0.0 for int i=1 to length float lSrc = logSource[i-1] sumX += i sumXX += i * i sumYX += i * lSrc sumY += lSrc float slope = nz((length * sumYX - sumX * sumY) / (length * sumXX - sumX * sumX)) float average = sumY / length float intercept = average - (slope * sumX / length) + slope float sumDev = 0.0 float sumDxx = 0.0 float sumDyy = 0.0 float sumDyx = 0.0 float regres = intercept + slope * period_1 * 0.5 float sumSlp = intercept for int i=0 to period_1 float lSrc = logSource[i] float dxt = lSrc - average float dyt = sumSlp - regres lSrc -= sumSlp sumSlp += slope sumDxx += dxt * dxt sumDyy += dyt * dyt sumDyx += dxt * dyt sumDev += lSrc * lSrc float unStdDev = math.sqrt(sumDev / period_1) // unbiased float divisor = sumDxx * sumDyy float pearsonR = nz(sumDyx / math.sqrt(divisor)) [unStdDev, pearsonR, slope, intercept] else [na, na, na, na] string t1 = "In Long-Term Channel mode, if the channel is not visible, scroll back on the chart for additional historical data." string t2 = "Pearson's R, a statistical measure in Adaptive Trend Finder, gauges the linear relationship between price and trend projection. A value closer to 1 indicates a strong positive correlation, reinforcing confidence in the trend direction based on historical price movements." sourceInput = input.source(close, title="Source") string group0 = "CHANNEL SETTINGS" bool periodMode = input.bool ( false, "Use Long-Term Channel", group=group0, tooltip=t1) float devMultiplier = input.float ( 2.0, "Deviation Multiplier:", group=group0, step=0.1) color colorInput = input.color ( color.gray, "", group=group0, inline=group0) string lineStyle1 = input.string( "Solid", "", group=group0, inline=group0, options=["Solid", "Dotted", "Dashed"]) string extendStyle = input.string("Extend Right", "", group=group0, inline=group0, options=["Extend Right", "Extend Both", "Extend None", "Extend Left"]) int fillTransparency = input.int ( 93, "Fill Transp:", group=group0, inline="mid", minval=0, maxval=100, step=1) int channelTransparency = input.int ( 40, "Line Transp:", group=group0, inline="mid", minval=0, maxval=100, step=1) string group1 = "MIDLINE SETTINGS" int transpInput = input.int ( 100, "Transp:", group=group1, inline=group1, minval=0, maxval=100, step=10) int lineWidth = input.int ( 1, "Line Width:", group=group1, inline=group1) string midLineStyle = input.string("Solid", "", group=group1, inline=group1, options=["Dotted", "Solid", "Dashed"]) string group2 = "TABLE SETTINGS" string tablePositionInput = input.string("Bottom Right", "Table Position", options=["Bottom Right", "Bottom Left", "Middle Right", "Middle Left", "Top Right", "Top Left", "Top Center", "Bottom Center"], group=group2) bool showPearsonInput = input.bool ( false, "Show Pearson's R instead of Projection Confidence Level", group=group2, tooltip=t2) string textSizeInput = input.string( "Normal", "Text Size", options=["Normal", "Large"], group=group2) var string EXTEND_STYLE = switch extendStyle "Extend Right" => extend.right "Extend Both" => extend.both "Extend None" => extend.none => extend.left // Length Inputs var array Periods = periodMode ? array.from(na,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000) : array.from(na,20,30,40,50,60,70,80,90,100,110,120,130,140,150,160,170,180,190,200) // Calculate deviations, correlation, slope, and intercepts for different lengths [stdDev01, pearsonR01, slope01, intercept01] = calcDev(sourceInput, Periods.get( 1)) [stdDev02, pearsonR02, slope02, intercept02] = calcDev(sourceInput, Periods.get( 2)) [stdDev03, pearsonR03, slope03, intercept03] = calcDev(sourceInput, Periods.get( 3)) [stdDev04, pearsonR04, slope04, intercept04] = calcDev(sourceInput, Periods.get( 4)) [stdDev05, pearsonR05, slope05, intercept05] = calcDev(sourceInput, Periods.get( 5)) [stdDev06, pearsonR06, slope06, intercept06] = calcDev(sourceInput, Periods.get( 6)) [stdDev07, pearsonR07, slope07, intercept07] = calcDev(sourceInput, Periods.get( 7)) [stdDev08, pearsonR08, slope08, intercept08] = calcDev(sourceInput, Periods.get( 8)) [stdDev09, pearsonR09, slope09, intercept09] = calcDev(sourceInput, Periods.get( 9)) [stdDev10, pearsonR10, slope10, intercept10] = calcDev(sourceInput, Periods.get(10)) [stdDev11, pearsonR11, slope11, intercept11] = calcDev(sourceInput, Periods.get(11)) [stdDev12, pearsonR12, slope12, intercept12] = calcDev(sourceInput, Periods.get(12)) [stdDev13, pearsonR13, slope13, intercept13] = calcDev(sourceInput, Periods.get(13)) [stdDev14, pearsonR14, slope14, intercept14] = calcDev(sourceInput, Periods.get(14)) [stdDev15, pearsonR15, slope15, intercept15] = calcDev(sourceInput, Periods.get(15)) [stdDev16, pearsonR16, slope16, intercept16] = calcDev(sourceInput, Periods.get(16)) [stdDev17, pearsonR17, slope17, intercept17] = calcDev(sourceInput, Periods.get(17)) [stdDev18, pearsonR18, slope18, intercept18] = calcDev(sourceInput, Periods.get(18)) [stdDev19, pearsonR19, slope19, intercept19] = calcDev(sourceInput, Periods.get(19)) if barstate.islast // Find the highest Pearson's R float highestPearsonR = math.max(pearsonR01, pearsonR02, pearsonR03, pearsonR04, pearsonR05, pearsonR06, pearsonR07, pearsonR08, pearsonR09, pearsonR10, pearsonR11, pearsonR12, pearsonR13, pearsonR14, pearsonR15, pearsonR16, pearsonR17, pearsonR18, pearsonR19) // Determine selected length, slope, intercept, and deviations int detectedPeriod = na float detectedSlope = na float detectedIntrcpt = na float detectedStdDev = na switch highestPearsonR pearsonR01 => detectedPeriod := Periods.get(1) detectedSlope := slope01 detectedIntrcpt := intercept01 detectedStdDev := stdDev01 pearsonR02 => detectedPeriod := Periods.get(2) detectedSlope := slope02 detectedIntrcpt := intercept02 detectedStdDev := stdDev02 pearsonR03 => detectedPeriod := Periods.get(3) detectedSlope := slope03 detectedIntrcpt := intercept03 detectedStdDev := stdDev03 pearsonR04 => detectedPeriod := Periods.get(4) detectedSlope := slope04 detectedIntrcpt := intercept04 detectedStdDev := stdDev04 pearsonR05 => detectedPeriod := Periods.get(5) detectedSlope := slope05 detectedIntrcpt := intercept05 detectedStdDev := stdDev05 pearsonR06 => detectedPeriod := Periods.get(6) detectedSlope := slope06 detectedIntrcpt := intercept06 detectedStdDev := stdDev06 pearsonR07 => detectedPeriod := Periods.get(7) detectedSlope := slope07 detectedIntrcpt := intercept07 detectedStdDev := stdDev07 pearsonR08 => detectedPeriod := Periods.get(8) detectedSlope := slope08 detectedIntrcpt := intercept08 detectedStdDev := stdDev08 pearsonR09 => detectedPeriod := Periods.get(9) detectedSlope := slope09 detectedIntrcpt := intercept09 detectedStdDev := stdDev09 pearsonR10 => detectedPeriod := Periods.get(10) detectedSlope := slope10 detectedIntrcpt := intercept10 detectedStdDev := stdDev10 pearsonR11 => detectedPeriod := Periods.get(11) detectedSlope := slope11 detectedIntrcpt := intercept11 detectedStdDev := stdDev11 pearsonR12 => detectedPeriod := Periods.get(12) detectedSlope := slope12 detectedIntrcpt := intercept12 detectedStdDev := stdDev12 pearsonR13 => detectedPeriod := Periods.get(13) detectedSlope := slope13 detectedIntrcpt := intercept13 detectedStdDev := stdDev13 pearsonR14 => detectedPeriod := Periods.get(14) detectedSlope := slope14 detectedIntrcpt := intercept14 detectedStdDev := stdDev14 pearsonR15 => detectedPeriod := Periods.get(15) detectedSlope := slope15 detectedIntrcpt := intercept15 detectedStdDev := stdDev15 pearsonR16 => detectedPeriod := Periods.get(16) detectedSlope := slope16 detectedIntrcpt := intercept16 detectedStdDev := stdDev16 pearsonR17 => detectedPeriod := Periods.get(17) detectedSlope := slope17 detectedIntrcpt := intercept17 detectedStdDev := stdDev17 pearsonR18 => detectedPeriod := Periods.get(18) detectedSlope := slope18 detectedIntrcpt := intercept18 detectedStdDev := stdDev18 => // pearsonR19 detectedPeriod := Periods.get(19) detectedSlope := slope19 detectedIntrcpt := intercept19 detectedStdDev := stdDev19 var line upperLine = na, var linefill upperFill = na var line baseLine = na var line lowerLine = na, var linefill lowerFill = na // Calculate start and end price based on detected slope and intercept float startPrice = math.exp(detectedIntrcpt + detectedSlope * (detectedPeriod - 1)) float endPrice = math.exp(detectedIntrcpt) int startAtBar = bar_index - detectedPeriod + 1 var color ChannelColor = color.new(colorInput, channelTransparency) if na(baseLine) baseLine := line.new(startAtBar, startPrice, bar_index, endPrice, width=lineWidth, extend=EXTEND_STYLE, color=color.new(colorInput, transpInput), style=midLineStyle == "Dotted" ? line.style_dotted : midLineStyle == "Dashed" ? line.style_dashed : line.style_solid) else line.set_xy1(baseLine, startAtBar, startPrice) line.set_xy2(baseLine, bar_index, endPrice) float upperStartPrice = startPrice * math.exp(devMultiplier * detectedStdDev) float upperEndPrice = endPrice * math.exp(devMultiplier * detectedStdDev) if na(upperLine) upperLine := line.new(startAtBar, upperStartPrice, bar_index, upperEndPrice, width=1, extend=EXTEND_STYLE, color=ChannelColor, style=lineStyle1 == "Dotted" ? line.style_dotted : lineStyle1 == "Dashed" ? line.style_dashed : line.style_solid) else line.set_xy1 (upperLine, startAtBar, upperStartPrice) line.set_xy2 (upperLine, bar_index, upperEndPrice) line.set_color(upperLine, colorInput) float lowerStartPrice = startPrice / math.exp(devMultiplier * detectedStdDev) float lowerEndPrice = endPrice / math.exp(devMultiplier * detectedStdDev) if na(lowerLine) lowerLine := line.new(startAtBar, lowerStartPrice, bar_index, lowerEndPrice, width=1, extend=EXTEND_STYLE, color=ChannelColor, style=lineStyle1 == "Dotted" ? line.style_dotted : lineStyle1 == "Dashed" ? line.style_dashed : line.style_solid) else line.set_xy1 (lowerLine, startAtBar, lowerStartPrice) line.set_xy2 (lowerLine, bar_index, lowerEndPrice) line.set_color(lowerLine, colorInput) if na(upperFill) upperFill := linefill.new(upperLine, baseLine, color=color.new(colorInput, fillTransparency)) if na(lowerFill) lowerFill := linefill.new(baseLine, lowerLine, color=color.new(colorInput, fillTransparency)) var table t = table.new(getTablePosition(tablePositionInput), 3, 2) string text1 = periodMode ? "Auto-Selected Period (Long Term): " + str.tostring(detectedPeriod) : "Auto-Selected Period: " + str.tostring(detectedPeriod) var colorInputLight = color.new(colorInput, 40) table.cell(t, 0, 0, text1, text_color=colorInputLight, text_size=textSizeInput == "Large" ? size.large : size.normal) if showPearsonInput table.cell(t, 1, 0, "Pearson's R: " + str.tostring(detectedSlope > 0.0 ? -highestPearsonR : highestPearsonR, "#.###"), text_color=colorInput, text_size=textSizeInput == "Large" ? size.large : size.normal) else table.cell(t, 1, 0, "Projection Confidence: " + confidence(highestPearsonR), text_color=colorInput, text_size=textSizeInput == "Large" ? size.large : size.normal)