TrendCylinder (Expo)
// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/
// ~~ © Zeiierman {

//@version=5
indicator("TrendCylinder (Expo)", overlay = true)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ ToolTips {
t1 = "Volatility Period defines the length of the look-back period for calculating volatility. Higher values make the bands adapt more slowly to volatility changes. Lower values make them adapt more quickly."
t2 = "Trend Factor adjusts the sensitivity of the trend line to price movements. A higher value makes the trend line less sensitive and smoother. Lower values make it more sensitive and reactive to price changes."
t3 = "Trend Step controls how quickly the trend line adjusts to sudden price changes. Higher values cause slower adjustments, leading to smoother trend lines. Lower values result in quicker adjustments to sudden changes."
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Inputs {
volatilityPeriod   = input.int(100, title="Period", step=10, minval=2, maxval=1000, inline="vol", group="Volatility Settings", tooltip=t1)
trendFactor        = input.float(9, step=0.1, title='Factor', minval = 0.1, inline="", group="Trend Settings", tooltip=t2)
trendStep          = input.float(0.7, "Step", step=0.1,minval = 0.5, maxval = 5.0, inline="", group="Trend Settings", tooltip=t3)

color_trend        = input.color(color.navy, title="Trend Line  ", inline="trend", group="Style")
colorForUpperBand  = input.color(color.new(#862458, 10), title="Upper Band", inline="band", group="Style")
colorForLowerBand  = input.color(color.new(#493893, 10), title="Lower Band", inline="band", group="Style")
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~  Initialize Variables
var float currentTrend        = 0.0
var int trendDirection        = 0
averageTrueRange              = ta.atr(200)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~  Function to determine the trend direction
determineTrendDirection(direction) => direction - direction[1] > 0 ? 1 : (direction - direction[1] < 0 ? -1 : 0)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~  Calculate Trend Direction
closingPrice      = close
scaledStandardDev = (nz(averageTrueRange) * trendFactor)
trendDirection    := determineTrendDirection(currentTrend) * int(scaledStandardDev)
priceTrendDiff    = closingPrice - currentTrend > 0 ? closingPrice - currentTrend : currentTrend - closingPrice
reciprocalFactor  = (scaledStandardDev * (1 / trendFactor)) * 1 / math.pow(2, 100)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Calculate the Current Trend
trendAdjustment   = priceTrendDiff > scaledStandardDev * trendStep ? math.avg(closingPrice, currentTrend) : trendDirection * reciprocalFactor + currentTrend
currentTrend      := trendAdjustment
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~  Calculate Upper and Lower Bands
upperBand = currentTrend + scaledStandardDev - averageTrueRange - ta.ema(ta.stdev(closingPrice, volatilityPeriod), 200)
lowerBand = currentTrend - scaledStandardDev + averageTrueRange + ta.ema(ta.stdev(closingPrice, volatilityPeriod), 200)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Plot
isTrendConsistent = trendDirection == trendDirection[1]
colorForPlot      = trendDirection == 1 ? color_trend : color_trend

plotTrend   = plot(isTrendConsistent ? currentTrend : na, title="Trend Line", color=colorForPlot)
plotUpper   = plot(isTrendConsistent ? upperBand : na, title="Upper Band", color = color.new(color.black, 100))
plotLower   = plot(isTrendConsistent ? lowerBand : na, title="Lower Band", color = color.new(color.black, 100))

fill(plotUpper, plotTrend, top_color = colorForLowerBand, bottom_color =color.new(na,100), top_value = upperBand, bottom_value = currentTrend, title="Background Upper")
fill(plotTrend, plotLower, top_color = color.new(na,100), bottom_color = colorForUpperBand, top_value = currentTrend, bottom_value = lowerBand, title="Background Lower")
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}