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

//@version=5
// @description B Bands with some squeese indicating additions
library('raf_BollingerBandsSqueezy', overlay=true)

// inputs
color bbbgcolor = input(color.new(#673ab7, 95), title='BB Background')
color cFillUpperExits = input(color.new(#00ff00, 50), title='Fill this color when prise above UPPER')
color cFillLowerExits = input(color.new(#ff0000, 50), title='Fill this color when prise below LOWER')


// these need to stay constant or be changed only from code, since strategies depend on these
// the commended out "input" is for finding the parameters more easily, then they should be frozen again
float __src__ =   close           // input(close, title='Price input')
int     length = 15     // input.int(15, minval=1)
float   mult = 1.3      // input.float(1.3, minval=0.001, maxval=50, step=0.05, title='StdDev')
bool    is_exponential = true   // input(true, title='Exponential MA?')
int     len_sqz_sma = 100       // input.int(100, 'BB Relative Squeeze Length', minval=5)
float   sqz_threshold = 0.5     // input.float(0.5, 'BB Squeeze Threshold', maxval=1, step=0.05)
int     len_fast_ma = 3         // input.int(3, 'Fast MA Length', minval=1, step=1)

// @function Calcs BB
// @returns the tree lines, upper, basis and lower
export bbands_lines() => 
    ema_line = ta.ema(__src__, length)
    sma_line = ta.sma(__src__, length)
    bb_basis = is_exponential ? ema_line : sma_line
    bb_dev   = mult * ta.stdev(__src__, length)
    bb_upper = bb_basis + bb_dev
    bb_lower = bb_basis - bb_dev
    
    // Calculate BB spread and average spread
    spread = bb_upper - bb_lower
    avgspread = ta.sma(spread, len_sqz_sma)

    // squeeze upper and lower
    bb_sqz_upper = bb_basis + avgspread * sqz_threshold 
    bb_sqz_lower = bb_basis - avgspread * sqz_threshold
    [bb_upper, bb_basis, bb_lower, bb_sqz_upper, bb_sqz_lower]
    


// @function calcs the fast moving average, to be used to compare how prise is positioned against BB
// @returns the fast EMA line, and the difference between it and the BB basis line
export bbands_fast_ma() =>
    ta.ema(__src__, len_fast_ma)
    
// render
[bb_upper, bb_basis, bb_lower, bb_sqz_upper, bb_sqz_lower] = bbands_lines()

plot(bb_basis, 'Basis', color=color.new(#4a148c, 70), linewidth=3)
p1 = plot(bb_upper, 'Upper', color=color.new(#ce93d8, 50), linewidth=2)
p2 = plot(bb_lower, 'Lower', color=color.new(#ce93d8, 50), linewidth=2)
fill(p1, p2, title='Background', color=bbbgcolor)

psqz_u = plot(bb_sqz_upper, 'Squeeze Upper', color=color.new(color.orange, 50), linewidth=2)
psqz_l = plot(bb_sqz_lower, 'Squeeze Lower', color=color.new(color.orange, 50), linewidth=2)
fill(psqz_u, psqz_l, color=color.new(color.orange, 85))

psrc = plot(close, title='Price bar close', display=display.none)
fill(psrc, p1, color=close > bb_upper ? cFillUpperExits : na)
fill(psrc, p2, color=close < bb_lower ? cFillLowerExits : na)

fast_ma_line = bbands_fast_ma()
plot(fast_ma_line, 'Fast MA line', color=color.new(color.blue, 0), linewidth=2)

// important events happening in this indicator
// export indicator_signals() =>
//     // enter
//     hasEnteredFromAbove = src < upper and src[1] >= upper
//     hasEnteredFromBelow = src >= lower and src[1] < lower
//     hasEnteredFromAboveToAboveMid = hasEnteredFromAbove and src > basis
//     hasEnteredFromAboveToBelowMid = hasEnteredFromAbove and src <= basis
//     hasEnteredFromBelowToAboveMid = hasEnteredFromBelow and src > basis
//     hasEnteredFromBelowToBelowMid = hasEnteredFromBelow and src <= basis
//     // exit
//     hasExitedFromAbove = src > upper and src[1] <= upper
//     hasExitedFromBelow = src < lower and src[1] >= lower
//     // go through like no care
//     hasGoneThroughFromBelow = src > upper and src[1] < lower
//     hasGoneThroughFromAbove = src < lower and src[1] > upper


// ////////////////////////
// for strategies:
// export strategic_signals_please() =>
//     // helpful vars
//     candle_head = math.max(open, close)
//     candle_ass = math.min(open, close)

//     bool ssig_candle_body_inside = candle_head <= upper and candle_ass >= lower
//     bool ssig_candle_pokes_above = ssig_candle_body_inside and high > upper
//     bool ssig_candle_pokes_below = ssig_candle_body_inside and lower > low
//     bool ssig_candle_sticks_head_out = candle_head > upper and upper >= candle_ass
//     bool cssig_andle_sticks_ass_out = candle_head >= lower and lower > candle_ass
//     bool ssig_candle_body_above = candle_ass > upper
//     bool ssig_candle_body_below = lower > candle_head
//     bool ssig_candle_gone_fly = ssig_candle_body_above and low > upper
//     bool ssig_candle_gone_dive = ssig_candle_body_below and lower > high
//     bool ssig_bb_shrinks = upper - lower < upper[1] - lower[1]

//     basis_slope_line = basis - basis[1]
//     bool ssig_continuing_positive_bb_basis_line_uptrend = 
//          basis_slope_line > 0 and basis_slope_line >= basis_slope_line[1] 
//          and basis_slope_line[1] > 0 and basis_slope_line[1] >= basis_slope_line[2] 
//          and basis_slope_line[2] > 0 and basis_slope_line[2] >= basis_slope_line[3] 
//          and basis_slope_line[3] > 0 and basis_slope_line[3] >= basis_slope_line[4]
//          //  and basis_slope_line[4] > 0 and basis_slope_line[4] >= basis_slope_line[5]
//          //  and basis_slope_line[5] > 0 and basis_slope_line[5] >= basis_slope_line[6]
//          //  and basis_slope_line[6] > 0 and basis_slope_line[6] >= basis_slope_line[7]
//          //  and basis_slope_line[7] > 0 and basis_slope_line[7] >= basis_slope_line[8]