Description: Determines the period over which the linear regression is calculated. A longer period smooths the oscillator but may lag, while a shorter period is more responsive but may be noisier.
Description: Option to color the price bars based on the oscillator's value, providing a visual representation of market conditions. Bars turn cyan for positive oscillator values and blue for negative.
This indicator helps traders identify overbought and oversold conditions, potential mean reversions, and trend changes based on the linear regression of the closing prices over a specified look-back period.
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ChartPrime
//@version=5
indicator("Linear Regression Oscillator [ChartPrime]", overlay=false, max_labels_count = 500)
// ---------------------------------------------------------------------------------------------------------------------}
// 𝙐𝙎𝙀𝙍 𝙄𝙉𝙋𝙐𝙏𝙎
// ---------------------------------------------------------------------------------------------------------------------{
int length   = input.int(20, "Length")
float upper  = input.float(1.5,  "Upper Threshold", step = 0.1)
float lower  = input.float(-1.5, "Lower Threshold", step = 0.1)
bool candles = input.bool(false, "Plot Bar Color")
color col_up = #10cab8
color col_dn = color.blue
// Source
series float source = close[barstate.isconfirmed ? 0 : 1]
// Max and Min prices for Invalidation Levels (period 5 bars back)
var lowest              = array.new(5)
var highest             = array.new(5)
var series float points = na
// ---------------------------------------------------------------------------------------------------------------------}
// 𝙄𝙉𝘿𝙄𝘾𝘼𝙏𝙊𝙍 𝘾𝘼𝙇𝘾𝙐𝙇𝘼𝙏𝙄𝙊𝙉𝙎
// ---------------------------------------------------------------------------------------------------------------------{
//@function Calculation of slope and intercept
//@param length LookBack Period
//@returns  Linear Regression Oscillator
linear_regression_osc(int length)=>
    n      = length
    sum_x  = 0.0
    sum_y  = 0.0
    sum_xy = 0.0
    sum_x_squared = 0.0
    for i = 0 to n - 1
        sum_x         := sum_x + i
        sum_y         := sum_y + source[i]
        sum_xy        := sum_xy + i * source[i]
        sum_x_squared := sum_x_squared + i * i
        m = (n * sum_xy - sum_x * sum_y) / (n * sum_x_squared - sum_x * sum_x)
        c = (sum_y - m * sum_x) / n
        linear_regression = ((m * bar_index + c)*-1)
// Calculate linear regression Oscillator
linear_regression = linear_regression_osc(length)
// Normaliztion
linear_regression := (linear_regression - ta.sma(linear_regression, 100)) / ta.stdev(linear_regression, 100)
// Conditions of Mean Reversion and Trends
cond1  = ta.crossunder(linear_regression, 0)
cond2  = ta.crossover( linear_regression, 0)
cond_1 = ta.crossunder(linear_regression, linear_regression[2]) 
          and 
         linear_regression > upper ? linear_regression[1] : na
cond_2 = ta.crossover(linear_regression, linear_regression[2]) 
          and 
         linear_regression < lower ? linear_regression[1] : na
// Invalidation Price Levels 
lowest. push(low)
highest.push(high)
switch 
    lowest.size() > 5 => lowest.shift(), highest.shift()
switch 
    cond1 => points := highest.max()
    cond2 => points := lowest. min()
// ---------------------------------------------------------------------------------------------------------------------}
// 𝙑𝙄𝙎𝙐𝘼𝙇𝙄𝙕𝘼𝙏𝙄𝙊𝙉
// ---------------------------------------------------------------------------------------------------------------------{
// Defined Colors
color = linear_regression > 0 
         ? color.from_gradient(linear_regression, 0, 2, color(na), col_up) 
         : color.from_gradient(linear_regression, -2, 0, col_dn, color(na)) 
color1= linear_regression > 0 
         ? color.from_gradient(linear_regression, 0, 2, color(na), color.new(chart.fg_color, 50)) 
         : color.from_gradient(linear_regression, -2, 0, color.new(chart.fg_color, 50), color(na)) 
color2= linear_regression > 0 
         ? color.from_gradient(linear_regression, 0, 1, color(na), col_up) 
         : color.from_gradient(linear_regression, -1, 0, col_dn, color(na)) 
         
// Plot Oscillator
plot(linear_regression, color = color, style = plot.style_area)
// Zero Line
plot(0, color = color1, linewidth = 2)
// Upper and Lower Thresholds
p1 = plot(upper, display = display.none)
p3 = plot(lower, display = display.none)
p4 = plot(-4,    display = display.none)
p2 = plot(4,     display = display.none)
fill(p1, p2, 4, upper, na, color.new(col_up, 75))
fill(p3, p4, lower, -4, color.new(col_dn, 75), na)
if barstate.islast
    l1 = label.new(bar_index, upper, str.tostring(upper), 
               style = label.style_diamond, size = size.tiny, textcolor = chart.fg_color, color = col_up)
    label.delete(l1[1])
    l2 = label.new(bar_index, lower, str.tostring(lower), 
               style = label.style_diamond, size = size.tiny, textcolor = chart.fg_color, color = col_dn)
    label.delete(l2[1])
// Oscillator Mean Reversion above or below Thresholds
plotchar(cond_1, "", "◇", 
         color = col_dn, 
         location = location.absolute, 
         size = size.small, 
         offset = -1
         )
plotchar(cond_2, "", "◇", 
         color = col_up, 
         location = location.absolute, 
         size = size.small, 
         offset = -1
         )
// Oscillator Crosses zero Line
plotchar(cond1 ? 0 : na, "", "◆", 
         color = color.new(col_dn, 0),
         location = location.absolute, 
         size = size.tiny, 
         offset = -1
         )
plotchar(cond2 ? 0 : na, "", "◆",
         color = color.new(col_up, 0), 
         location = location.absolute, 
         size = size.tiny, 
         offset = -1
         )
// Trend Labels on the chart
switch
    cond2 => label.new(chart.point.from_index(bar_index, low), "▲", 
                       style         = label.style_label_up, 
                       textcolor     = col_up, 
                       size          = size.large, 
                       color         = color(na), 
                       force_overlay = true
                       )
    cond1 => label.new(chart.point.from_index(bar_index, high), "▽", 
                       style         = label.style_label_down, 
                       textcolor     = col_dn, 
                       size          = size.large, 
                       color         = color(na), 
                       force_overlay = true
                       )
// Meant Reversion Labels on the chart
switch
    cond_2 => label.new(chart.point.from_index(bar_index, low),
                       text          = "◆\nReversion",
                       style         = label.style_label_up, 
                       textcolor     = col_up, 
                       size          = size.normal, 
                       color         = color(na), 
                       force_overlay = true
                       )
    cond_1 => label.new(chart.point.from_index(bar_index, high), 
                       text          = "Reversion\n◆",
                       style         = label.style_label_down, 
                       textcolor     = col_dn, 
                       size          = size.normal, 
                       color         = color(na), 
                       force_overlay = true
                       )
// Invalidation Price Levels 
plot(not ta.change(points) ? points : na, 
         color          = color2, 
         linewidth      = 2, 
         style          = plot.style_linebr, 
         force_overlay  = true
         )
if ta.change(points)
    label.new(chart.point.from_index(bar_index, points[1]), 
                       text          = "Invalidation\nLevel",
                       style         = label.style_label_left, 
                       textcolor     = linear_regression < 0 ? col_up : col_dn, 
                       size          = size.small, 
                       color         = color(na), 
                       force_overlay = true
                       )
// Candles Color
candle_col = candles ? (linear_regression < 0 ? col_dn : col_up) : na
plotcandle(open, high, low, close,
             title = "Color Candles", 
             color = candle_col, 
             bordercolor = candle_col, 
             wickcolor = candle_col, 
             force_overlay= true
             )
barcolor(candle_col)
//◆ ♢ ❖ ◇ ⬖
// ---------------------------------------------------------------------------------------------------------------------}