StdDev Channels
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © jjustingreyy

//@version=5
indicator("StdDev Channels" , overlay=true)

price = input(close, "Source")
deviations = input(2.0, "Deviation Count")
fullRange = input(false, "Toggle Full Range (DefVal 500)")
length = input(153, "Channel 1 Length")
length2 = input(50, "Channel 2 Length") // Length for second channel

uppercolor1 = input(color.rgb(236, 59, 59), "Channel 1 Upper Line")
middlecolor1 = input(color.rgb(228, 228, 220), "Channel 1 Mid Line")
lowercolor1 = input(color.rgb(61, 231, 97), "Channel 1 Lower Line")

uppercolor2 = input(color.rgb(150, 150, 150), "Channel 2 Upper Line")
middlecolor2 = input(color.rgb(188, 187, 187), "Channel 2 Mid Line")
lowercolor2 = input(color.rgb(150, 150, 150), "Channel 2 Lower Line")

// Additional inputs for line width and style
width1 = input(1, "Channel 1 Line Width")
width2 = input(1, "Channel 2 Line Width")
style1 = input(line.style_solid, "Channel 1 Line Style")
style2 = input(line.style_dashed, "Channel 2 Line Style")

//-- change this variable to the maximum number of bars you want to cover. must be bigger then length  --//
//-- even if full range is off.
max_bars_back=500
//----------------------------------------------------------------------------//

max_bars_back(price, max_bars_back)

Sqr(x) => x*x

newlength = fullRange ? max_bars_back : length 
newlength2 = fullRange ? max_bars_back : length2  // New length for second channel

InertiaAll (y, n) =>
    var x = 0
    x := x + 1
    a = (n * math.sum(x * y, n) - math.sum(x, n) * math.sum(y, n) ) / ( n * math.sum(Sqr(x), n) - Sqr(math.sum(x, n)))
    b = (math.sum(Sqr(x), n) * math.sum(y, n) - math.sum(x, n) * math.sum(x * y, n) ) / ( n * math.sum(Sqr(x), n) - Sqr(math.sum(x, n)))
    InertiaTS = a * x + b
    [InertiaTS, x, a, b]

[regression, x1, a1, b1] = InertiaAll(price, newlength)
stdDeviation = ta.stdev(price, newlength)
[regression2, x2, a2, b2] = InertiaAll(price, newlength2) // Regression for second channel
stdDeviation2 = ta.stdev(price, newlength2) // Standard deviation for second channel

var UpperLine = line.new(0, low, 0, low, color=uppercolor1, extend=extend.right, width=width1, style=style1)
var MiddleLine = line.new(0, low, 0, low, color=middlecolor1, extend=extend.right, width=width1, style=style1)
var LowerLine = line.new(0, low, 0, low, color=lowercolor1, extend=extend.right, width=width1, style=style1)

var UpperLine2 = line.new(0, low, 0, low, color=uppercolor2, extend=extend.right, width=width2, style=style2)
var MiddleLine2 = line.new(0, low, 0, low, color=middlecolor2, extend=extend.right, width=width2, style=style2)
var LowerLine2 = line.new(0, low, 0, low, color=lowercolor2, extend=extend.right, width=width2, style=style2)

if barstate.islast 

    line.set_xy1(UpperLine, last_bar_index - newlength + 1, a1*x1[newlength - 1] +b1 + deviations * stdDeviation) 
    line.set_xy2(UpperLine, last_bar_index, a1*x1 +b1 + deviations * stdDeviation)    

    line.set_xy1(MiddleLine, last_bar_index - newlength + 1, a1*x1[newlength - 1] +b1) 
    line.set_xy2(MiddleLine, last_bar_index, a1*x1 +b1)    
    
    line.set_xy1(LowerLine, last_bar_index - newlength + 1, a1*x1[newlength - 1] +b1 - deviations * stdDeviation) 
    line.set_xy2(LowerLine, last_bar_index, a1*x1 +b1 - deviations * stdDeviation)    

    line.set_xy1(UpperLine2, last_bar_index - newlength2 + 1, a2*x2[newlength2 - 1] +b2 + deviations * stdDeviation2) // Lines for second channel
    line.set_xy2(UpperLine2, last_bar_index, a2*x2 +b2 + deviations * stdDeviation2)

    line.set_xy1(MiddleLine2, last_bar_index - newlength2 + 1, a2*x2[newlength2 - 1] +b2)
    line.set_xy2(MiddleLine2, last_bar_index, a2*x2 +b2)

    line.set_xy1(LowerLine2, last_bar_index - newlength2 + 1, a2*x2[newlength2 - 1] +b2 - deviations * stdDeviation2)
    line.set_xy2(LowerLine2, last_bar_index, a2*x2 +b2 - deviations * stdDeviation2)