Bollinger Bands (Nadaraya Smoothed) | Flux Charts
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © fluxchart

//@version=5
indicator("Bollinger Bands (Nadaraya Smoothed) | Flux Charts", overlay = true, max_lines_count = 500, max_bars_back = 500)
group_smoothing = "smoothing"
h = input.float(6, "Smoothing Factor", step = .5, tooltip = "The bandwith(h) used in the kernel of the Nadaraya-Watson estimator function." ,group = group_smoothing)
repaint = input.bool(false,"Repaint Smoothing", tooltip = "This setting allows for repainting of the estimation" , group = group_smoothing)
sens = 4

group_boll = "Bollinger Bands Settings (Short, Medium, Long)"
short_period = input.int(20, "Period", inline = "short", group = group_boll)
short_stdev = input.float(3, "Deviation", inline = "short", group = group_boll)
med_period = input.int(75, "Period", inline = "med", group = group_boll)
med_stdev = input.float(4, "Deviation", inline = "med", group = group_boll)
long_period = input.int(100, " Period", inline = "long", group = group_boll)
long_stdev = input.float(4.25, "Deviation", inline = "long", group = group_boll)

group_graphics = "Plots and Labels"
labels = input.bool(true, "Labels", inline = "label" , group = group_graphics)
plots = input.bool(true, "Plot Lines",  group = group_graphics)
plot_thickness = input.int(2, "Line Width", group = group_graphics)

bands_lvl1 = input.bool(true, "Level 1 Bands", inline = "bands", group = group_graphics)
bands_lvl2 = input.bool(true, "Level 2 Bands", inline = "bands", group = group_graphics)

grp = "Color Theme"
pallete_bear = input.color(color.red, "Bearish", inline = "theme", group = grp)
pallete_bull = input.color(color.green, "Bullish", inline = "theme", group = grp)
alpha1 = input.float(.90, "Transparency: Level 1 ", minval = .1, maxval = 1,inline = "alpha", step = .1)
alpha2 = input.float(.85, "Level 2", minval = .1, maxval = 1, inline = "alpha", step = .1)

grp_n = "Notifications"
notifs = input.bool(false, "Band Breaks", group = grp_n, tooltip = "Recieve notifications when price goes above or below the first level.")

type pallete 
    color bear
    color bull 
    color shade1_bear 
    color shade1_bull 
    color shade2_bear 
    color shade2_bull

create_pallete(color bear, color bull, float alpha1 = 1, float alpha2 = 2) =>
    float shade1 = 100 * alpha1
    float shade2 = 100 * alpha2
    color shade1_bear = color.new(bear, shade1)
    color shade1_bull = color.new(bull, shade1)
    color shade2_bear = color.new(bear, shade2)
    color shade2_bull = color.new(bull, shade2)
    pallete.new(bear, bull, shade1_bear, shade1_bull, shade2_bear, shade2_bull)
    
theme = create_pallete(pallete_bear, pallete_bull, alpha1, alpha2)

const bool bollinger_bands_lvl1 = true
const bool bollinger_bands_lvl2 = true
float tp = (high + low + close) /3

int n_first = 20 
int n_second = 75 
int n_third = 100

guass_w(x, h) => 
   math.exp (-1 *( (x*x) / (2*(h*h)) ))

bollingers(n, factor = 3) =>
    bolu = ta.sma(tp, n) + (factor * ta.stdev(tp, n))
    bold = ta.sma(tp, n) - (factor * ta.stdev(tp, n))
    [bolu, bold]

[BOLU_FIRST, BOLD_FIRST] = bollingers(n_first, short_stdev) 
float BOL_FIRST_GAP = BOLU_FIRST - BOLD_FIRST

[BOLU_SECOND, BOLD_SECOND] = bollingers(n_second, short_stdev) 
float BOL_SECOND_GAP = BOLU_SECOND - BOLD_SECOND

[BOLU_THIRD, BOLD_THIRD] = bollingers(n_third, med_stdev) 
float BOL_THIRD_GAP = BOLU_THIRD - BOLD_THIRD

[BOLU_FOURTH, BOLD_FOURTH] = bollingers(n_third, long_stdev) 

var pivots = array.new<float>()
var pivots2 = array.new<float>()

pivot_rad = sens

float pivot_high = ta.pivothigh(high, pivot_rad, pivot_rad)
float pivot_low = ta.pivotlow(low, pivot_rad, pivot_rad)


add_cols(mat, h_n = 1) =>
    sum_array = array.new<float>()
    for i=0 to matrix.rows(mat)-1
        array.push(sum_array, array.sum(matrix.row(mat, i))/h_n)
    sum_array

nadaraya(src, color) =>
    smoothed = array.new<float>() 
    if barstate.islast and repaint
        for i=0 to 499
            sum = 0.
            gk = array.new<float>()
            for y =0 to 499
                gk.push(guass_w(y - i, h))
            gk_sum = gk.sum()
            for y =0 to 499
                sum += src[y]*(gk.get(y)/gk_sum)
            smoothed.push(sum)
            if i%2 == 0 and i != 0
                line.new(bar_index[i-1], smoothed.get(i-1), bar_index[i], smoothed.get(i), color = color, width = 2)
    smoothed

running_nadaraya(src, n)=>
    var gk = array.new<float>(0)
    var gk_sum =  0.
    var src_matrix = matrix.new<float>()
    smoothed = 0.
    if barstate.isfirst and not repaint
        for i=0 to n
            gk.push(guass_w(i, h))
        gk_sum := gk.sum()
    if not repaint
        for i=n to 0
            smoothed += src[i] * (gk.get(i)/gk_sum)
    smoothed 

n = 499


smoothed_bolu_1 = running_nadaraya(BOLU_FIRST, n)
smoothed_bold_1 = running_nadaraya(BOLD_FIRST, n)

smoothed_bolu_2 = running_nadaraya(BOLU_SECOND, n)
smoothed_bold_2 = running_nadaraya(BOLD_SECOND, n)

smoothed_bolu_3 = running_nadaraya(BOLU_THIRD, n)
smoothed_bold_3 = running_nadaraya(BOLD_THIRD, n)

smoothed_bolu_4 = running_nadaraya(BOLU_FOURTH, n)
smoothed_bold_4 = running_nadaraya(BOLD_FOURTH, n)

BOLU_FIRST_PLOT = plot(smoothed_bolu_1, display = display.none)
BOLD_FIRST_PLOT = plot(smoothed_bold_1, display = display.none)

BOLU_SECOND_PLOT = plot(smoothed_bolu_2, display = display.none)
BOLD_SECOND_PLOT = plot(smoothed_bold_2, display = display.none)

BOLU_THIRD_PLOT = plot(smoothed_bolu_3, display = display.none)
BOLD_THIRD_PLOT = plot(smoothed_bold_3, display = display.none)

BOLU_FOURTH_PLOT = plot(smoothed_bolu_4, display = display.none)
BOLD_FOURTH_PLOT = plot(smoothed_bold_4, display = display.none)

if repaint
    nadaraya(BOLU_FIRST, theme.bear)
    nadaraya(BOLD_FIRST, theme.bull)
    
spacing = ta.atr(300)

upper_band_test = pivot_high  >= smoothed_bolu_1[sens] and not repaint ? pivot_high + spacing * 1.01  : na
lower_band_test = pivot_low   <= smoothed_bold_1[sens] and not repaint ? pivot_low - spacing * 1.01  : na

if notifs and close > smoothed_bolu_1
    alert("Upper Band Crossed on " + syminfo.ticker, alert.freq_once_per_bar_close)
else if notifs and close < smoothed_bold_1
    alert("Lower Band Crossed on " + syminfo.ticker, alert.freq_once_per_bar_close)

plotshape(labels ? upper_band_test : na, style = shape.triangledown, location = location.absolute, color = theme.bear, offset = -1*sens, size = size.tiny)
plotshape(labels ? lower_band_test : na, style = shape.triangleup, location = location.absolute, color = theme.bull, offset = -1*sens, size = size.tiny)

plot(not repaint and plots ? smoothed_bolu_1 : na, linewidth = plot_thickness, color = theme.bear)
plot(not repaint and plots ? smoothed_bold_1 : na, linewidth = plot_thickness, color = theme.bull)

fill(BOLU_FIRST_PLOT, BOLU_SECOND_PLOT, theme.shade1_bear, display = bands_lvl1 ? display.all: display.none)
fill(BOLD_FIRST_PLOT, BOLD_SECOND_PLOT, theme.shade1_bull, display = bands_lvl1 ? display.all: display.none)
fill(BOLU_SECOND_PLOT, BOLU_THIRD_PLOT, theme.shade2_bear, display = bands_lvl2 ? display.all: display.none)
fill(BOLD_SECOND_PLOT, BOLD_THIRD_PLOT, theme.shade2_bull, display = bands_lvl2 ? display.all: display.none)
