[Mad] Triple Bollinger Bands MTF
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © djmad
// Changelog (by Johnney):  Decimals autoadjust when changing Assets.
//                          Optimized rounding Algo.
//                          Trailing Zeroes fixed.
// Changelog (by djmad):    Added Bollinger width average , codeparts from ©The_Caretaker in the width calc

//@version=5
indicator(shorttitle='[Mad] BBx3 MTF', title='[Mad] Triple Bollinger Bands MTF_3x', overlay=true)

//Variables Inputs Basics{
TimeFrame                   =           input.timeframe('', title='TimeFrame',group='Data-source')

string ma_type              =           input.string( 'SMA', 'Basis Type', options=[ 'SMA', 'EMA', 'WMA', 'RMA', 'HMA', 'VWMA' ], group = 'Multiplicators')
int length                  =           input.int(20, minval=1,group='Multiplicators')
float mult1                 =           input.float(1.0, minval=0.001, maxval=10, step=0.2,group='Multiplicators')
float mult2                 =           input.float(2.0, minval=0.001, maxval=10, step=0.2,group='Multiplicators')
float mult3                 =           input.float(3.0, minval=0.001, maxval=10, step=0.2,group='Multiplicators')

string mode                 =           input.string('Band-crossin',title='Alert mode', options=['Band-outside', 'Band-crossin', 'Band-crossout', 'Trend'],group='Alerts')
bool showalerts_L1          =           input.bool(true, 'Show alerts L1',group='Alerts', inline='1a')
bool showalerts_L2          =           input.bool(true, 'Show L2',group='Alerts', inline='1a')
bool showalerts_L3          =           input.bool(true, 'Show L3',group='Alerts', inline='1a')

color basecolor             =           input.color(color.gray, 'Base Color',inline='11',group='static colors')
color multi1color           =           input.color(color.green, 'Multiplicator 1 Color',group='static colors')
color multi2color           =           input.color(color.orange, 'Multiplicator 2 Color',group='static colors')
color multi3color           =           input.color(color.red, 'Multiplicator 3 Color',group='static colors')
bool bgactive               =           input.bool(true,'Draw background',group='static colors', inline='2a')
color bgcolor               =           input.color(color.gray, 'Background color',group='static colors')

dynamic_color         =                 input.bool(false,'Dynamic Colors', group='Dynamic colors')
dynamic_color_bull          =           input.color(color.green,'Color bull',      group='Dynamic colors', inline='1a')
dynamic_bear                =           input.color(color.red,'Color bear',        group='Dynamic colors', inline='1b')
dynamic_neut                =           input.color(color.new(#daff52, 80),'Color neut',  group='Dynamic colors', inline='1a')

int trans                   =           input.int(90,'Transparency background',group='global colors', inline='2a')
// Input definitions

bool tableactive            =           input.bool(false,'Draw table', group='Bollinger width table')
int lookbacktime            =           input.int( 500, 'Lookback time',minval=1, group='Bollinger width table')
string Position             =           input.string(title='Position', defval=position.bottom_right, options=[position.top_left, position.top_center, position.top_right, position.middle_left, position.middle_center, position.middle_right, position.bottom_left, position.bottom_center, position.bottom_right], group='Bollinger width table',inline='2')
string Size                 =           input.string(title='Size', defval=size.auto, options=[size.tiny, size.small, size.normal, size.large, size.huge, size.auto], group='Bollinger width table',inline='2')
color bg_color              =           input.color(title='Background', defval=color.white, group='Bollinger width table')
color text_color            =           input.color(title='Text', defval=color.black, group='Bollinger width table')

var i_decimals_array        =           array.from('#', '0.0', '0.00', '0.000', '0.0000', '0.00000', '0.000000', '0.0000000', '0.00000000              ')

i_decimals_s                =           input.string('Asset',title='Decimals', options=['Asset', '0 ', '0.1', '0.01', '0.001', '0.0001', '0.00001', '0.000001', '0.0000001'],group='labels and lines')

labelcolor                  =           input.color(color.white,'label-color', group='labels and lines')

show_pricelines             =           input(true,title='show lines', group='labels and lines', inline='1a')
lineshift                   =           input(0,title='- shift lines', group='labels and lines', inline='1a')

show_labels                 =           input(true,title='show labels', group='labels and lines', inline='2a')
displayshift                =           input(35,title='- shift labels ', group='labels and lines', inline='2a')
//}

// Variables {
var int i_decimals = 2
bollarray                   =           array.from(0.0,0.0,0.0,0.0,0.0,0.0,0.0)
if not bgactive
    trans := 100

var float bbu3 = na
var float bbu2 = na
var float bbu1 = na
var float bbm_ = na
var float bbd1 = na
var float bbd2 = na
var float bbd3 = na


//}

//functions{
//orig roundTo(_value) => str.tostring(math.round(_value * math.pow(10, i_decimals)) / math.pow(10, i_decimals))
//new1 roundTo(_value) => str.tostring(math.round(_value * math.pow(10, i_decimals)) / math.pow(10, i_decimals), '0.000')
//new2 roundTo(_value) => str.tostring(math.round(_value, i_decimals),'#.0000')
roundTo(_value) => str.tostring(_value, array.get(i_decimals_array,i_decimals)) // + ' Debug : ' + 'i_decimals = ' + str.tostring(i_decimals) + ' Original value = ' + str.tostring(_value)

shifting(_value) =>
    var string output = ''
    output := ''
    for i = 0 to _value by 1
        output := output + ' '


f_name_2_price(value_of_indicator) =>
    value_of_indicator == bbu3 ?  + shifting(displayshift) + ' +3 - ' + str.tostring(roundTo(bbu3)) :
     value_of_indicator == bbu2 ? + shifting(displayshift) + ' +2 - ' + str.tostring(roundTo(bbu2)) :
     value_of_indicator == bbu1 ? + shifting(displayshift) + ' +1 - ' + str.tostring(roundTo(bbu1)) :
     value_of_indicator == bbm_ ? + shifting(displayshift) + 'BB0 - ' + str.tostring(roundTo(bbm_)) :
     value_of_indicator == bbd1 ? + shifting(displayshift) + ' -1 - ' + str.tostring(roundTo(bbd1)) :
     value_of_indicator == bbd2 ? + shifting(displayshift) + ' -2 - ' + str.tostring(roundTo(bbd2)) :
     value_of_indicator == bbd3 ? + shifting(displayshift) + ' -3 - ' + str.tostring(roundTo(bbd3)) :
     na

f_delete_all() =>     
    a_allLines = line.all
    if array.size(a_allLines) > 0
        for i = 0 to array.size(a_allLines) - 1
            line.delete(array.get(a_allLines, i))
    a_allLabel = label.all
    if array.size(a_allLabel) > 0
        for i = 0 to array.size(a_allLabel) - 1
            label.delete(array.get(a_allLabel, i))

f_draw(value_of_indicator, offset, c_rs) =>    
    T1 = bar_index[1] + lineshift
    T2 = bar_index + lineshift
    M1 = xloc.bar_index

    if barstate.islast or barstate.isrealtime
        var label lb1 =     na
        var line ln1  =     na

        if show_labels
            lb1 := label.new(time + (time - time[1]) * 1, 
             value_of_indicator,
             f_name_2_price(value_of_indicator), xloc=xloc.bar_time, textcolor=c_rs , style=label.style_none, size=size.small)
        if show_pricelines
            ln1 := line.new(T1, value_of_indicator, T2, 
             value_of_indicator,
             width=1, extend=extend.right, xloc=M1, color=color.gray)

f_calc_ma(_src, _len, _type) =>
    _ma = float(na)
    if _type == 'SMA'
        _ma := ta.sma(_src, _len)
    else if _type == 'EMA'
        _ma := ta.ema(_src, _len)
    else if _type == 'WMA'
        _ma := ta.wma(_src, _len)
    else if _type == 'RMA'
        _ma := ta.rma(_src, _len)
    else if _type == 'HMA'
        _ma := ta.hma(_src, _len)
    else
        _ma := ta.vwma(_src, _len)
    _ma

f_boll(_src, _ma, _length, mult1, mult2, mult3) =>
    basis = _ma
    dev = ta.stdev(_src, _length)
    transferarray = array.from(
     basis + dev * mult3,
     basis + dev * mult2,
     basis + dev * mult1,
     basis,
     basis - dev * mult1,
     basis - dev * mult2,
     basis - dev * mult3
     )

    transferarray

// original from ©The_Caretaker, little modded
f_bbwp(_src, _BB_length, _lookbacktime, _type) =>
    _basis = f_calc_ma(_src, _BB_length, _type)
    _dev = ta.stdev(_src, _BB_length)
    _BB_width = 2 * _dev / _basis    
    _BB_summarized = 0.0
    _len = math.min(bar_index, _lookbacktime)
    for _i = 1 to _len by 1
        _BB_summarized := _BB_summarized + (_BB_width[_i] > _BB_width ? 0 : 1)
    _return = bar_index >= _BB_length ? (_BB_summarized / _len) * 100 : na
    _return
//}

//Init Vars (we only need it once at start)
if barstate.isfirst
    i_decimals := str.length(str.tostring( (i_decimals_s == 'Asset') ? str.tostring (syminfo.mintick) : i_decimals_s)) -2

//Plotting Bollinger {
bollarray := request.security(syminfo.tickerid, TimeFrame, f_boll(close, f_calc_ma(close, length, ma_type   ) ,length, mult1, mult2, mult3), barmerge.gaps_off, barmerge.lookahead_off)

if na(bollarray)
    bollarray := array.from(na,na,na,na,na,na,na)

color coloroff = color.new(#000000, 100)
colorbull = dynamic_color_bull
colorbaer = dynamic_bear
colorneut = dynamic_neut

f_color(float upper_2,float upper_1, float current, float lower_1,float lower_2, float src, float index) =>
    color mycolor = na  
    color coloron = na    

    if src < (upper_1+current)/2 and src > (lower_1+current)/2
        coloron := colorneut
    else if src < index
        coloron := colorbaer
    else if src > index
        coloron := colorbull
        

    if src > current and src < upper_2
        mycolor := color.from_gradient(src, (current+upper_1)/2, upper_2 , coloron, coloroff)

    else if src < current and src > lower_2
        mycolor := color.from_gradient(src, lower_2, (current+lower_1)/2 , coloroff, coloron)

    else
        mycolor := coloroff

    mycolor


bbu3 := array.get(bollarray,0)
bbu2 := array.get(bollarray,1)
bbu1 := array.get(bollarray,2)
bbm_ := array.get(bollarray,3)
bbd1 := array.get(bollarray,4)
bbd2 := array.get(bollarray,5)
bbd3 := array.get(bollarray,6)


p3a = plot((not dynamic_color or coloroff != (f_color(upper_2 = 99999999,      upper_1 = 99999999, current = bbu3, lower_1 = bbu2,         lower_2 = bbu1,         src = ta.sma(close,3),  index = bbm_))) ? bbu3:na,display=display.all, linewidth=2,      color=not dynamic_color ? multi3color : f_color(upper_2 = 99999999,      upper_1 = 99999999, current = bbu3, lower_1 = bbu2,         lower_2 = bbu1,         src = ta.sma(close,3),  index = bbm_), style=plot.style_linebr)
p2a = plot((not dynamic_color or coloroff != (f_color(upper_2 = 99999999,      upper_1 = bbu3 ,    current = bbu2, lower_1 = bbu1,         lower_2 = bbm_,         src = ta.sma(close,3),  index = bbm_))) ? bbu2:na,display=display.all, linewidth=2,      color=not dynamic_color ? multi2color : f_color(upper_2 = 99999999,      upper_1 = bbu3 ,    current = bbu2, lower_1 = bbu1,         lower_2 = bbm_,         src = ta.sma(close,3),  index = bbm_), style=plot.style_linebr)
p1a = plot((not dynamic_color or coloroff != (f_color(upper_2 = bbu3,          upper_1 = bbu2 ,    current = bbu1, lower_1 = bbm_,         lower_2 = bbd1,         src = ta.sma(close,3),  index = bbm_))) ? bbu1:na,display=display.all, linewidth=2,      color=not dynamic_color ? multi1color : f_color(upper_2 = bbu3,          upper_1 = bbu2 ,    current = bbu1, lower_1 = bbm_,         lower_2 = bbd1,         src = ta.sma(close,3),  index = bbm_), style=plot.style_linebr)
p00 = plot((not dynamic_color or coloroff != (f_color(upper_2 = bbu2,          upper_1 = bbu1 ,    current = bbm_, lower_1 = bbd1,         lower_2 = bbd2,         src = ta.sma(close,3),  index = bbm_))) ?  bbm_:na,title='Middle'  , linewidth=2,        color=not dynamic_color ? basecolor   : f_color(upper_2 = bbu2,          upper_1 = bbu1 ,    current = bbm_, lower_1 = bbd1,         lower_2 = bbd2,         src = ta.sma(close,3),  index = bbm_), style=plot.style_linebr)
p1b = plot((not dynamic_color or coloroff != (f_color(upper_2 = bbu1,          upper_1 = bbm_ ,    current = bbd1, lower_1 = bbd2,         lower_2 = bbd3,         src = ta.sma(close,3),  index = bbm_))) ? bbd1:na,display=display.all, linewidth=2,      color=not dynamic_color ? multi1color : f_color(upper_2 = bbu1,          upper_1 = bbm_ ,    current = bbd1, lower_1 = bbd2,         lower_2 = bbd3,         src = ta.sma(close,3),  index = bbm_), style=plot.style_linebr)
p2b = plot((not dynamic_color or coloroff != (f_color(upper_2 = bbm_,          upper_1 = bbd1 ,    current = bbd2, lower_1 = bbd3,         lower_2 = 00000000,     src = ta.sma(close,3),  index = bbm_))) ? bbd2:na,display=display.all, linewidth=2,      color=not dynamic_color ? multi2color : f_color(upper_2 = bbm_,          upper_1 = bbd1 ,    current = bbd2, lower_1 = bbd3,         lower_2 = 00000000,     src = ta.sma(close,3),  index = bbm_), style=plot.style_linebr)
p3b = plot((not dynamic_color or coloroff != (f_color(upper_2 = bbd1,          upper_1 = bbd2 ,    current = bbd3, lower_1 = 00000000,     lower_2 = 00000000,     src = ta.sma(close,3),  index = bbm_))) ? bbd3:na,display=display.all, linewidth=2,      color=not dynamic_color ? multi3color : f_color(upper_2 = bbd1,          upper_1 = bbd2 ,    current = bbd3, lower_1 = 00000000,     lower_2 = 00000000,     src = ta.sma(close,3),  index = bbm_), style=plot.style_linebr)


fill(p2a, p3a, color=not dynamic_color ? color.new(bgcolor, trans):color.new(f_color(upper_2 = 99999999, upper_1 = 99999999, current = bbu3,    lower_1 = bbd2,     lower_2 = bbu1,      src = ta.sma(close,3),  index = bbm_),trans))
fill(p1a, p3a, color=not dynamic_color ? color.new(bgcolor, trans):color.new(f_color(upper_2 = 99999999, upper_1 = bbu3,     current = bbd2,    lower_1 = bbu1,     lower_2 = bbm_,      src = ta.sma(close,3),  index = bbm_),trans))
fill(p3a, p3b, color=not dynamic_color ? color.new(bgcolor, trans):na)
fill(p1b, p3b, color=not dynamic_color ? color.new(bgcolor, trans):color.new(f_color(upper_2 = bbm_,     upper_1 = bbd1,     current = bbd2,    lower_1 = bbd3,     lower_2 = 00000000,  src = ta.sma(close,3),  index = bbm_),trans))
fill(p2b, p3b, color=not dynamic_color ? color.new(bgcolor, trans):color.new(f_color(upper_2 = bbd1,     upper_1 = bbd2,     current = bbd3,    lower_1 = 00000000, lower_2 = 00000000,  src = ta.sma(close,3),  index = bbm_),trans))
//}

//Plotting of lines and prices {

f_delete_all()

if array.size(bollarray) > 0
    for i1 = 0 to array.size(bollarray) - 1 by 1
        f_draw(array.get(bollarray, i1), 7, labelcolor)

//}

//Plotting of table {

bw1 = 
 request.security(syminfo.tickerid, TimeFrame, 
 tableactive?f_bbwp(close, length, lookbacktime, ma_type   ):na)

// Create table
if tableactive
    t = table.new(position=Position, rows=2, columns=1, border_width=1)
    table.cell(t, 0, 0, 'BB-W', bgcolor=bg_color, text_color=text_color, text_size = Size)
    table.cell(t, 0, 1, str.tostring(bw1, '##.####')+'%', bgcolor=bg_color, text_color=text_color, text_size = Size)

//}

// Creating the Alarms Start {
//************************************************************************************************************
bool    a_L1_long      = false
bool    a_L1_short     = false
bool    a_L2_long      = false
bool    a_L2_short     = false
bool    a_L3_long      = false
bool    a_L3_short     = false


if mode == 'Band-outside'
    a_L1_long  :=   bbd1   >   close
    a_L1_short   :=   bbu1   <   close
    a_L2_long  :=   bbd2   >   close
    a_L2_short   :=   bbd2   <   close
    a_L3_long  :=   bbd3   >   close
    a_L3_short   :=   bbu3   <   close

if mode == 'Band-crossin'
    a_L1_long  :=   ta.crossover(close,    bbd1)
    a_L1_short   :=   ta.crossunder(close,   bbu1)
    a_L2_long  :=   ta.crossover(close,    bbd2)
    a_L2_short   :=   ta.crossunder(close,   bbd2)
    a_L3_long  :=   ta.crossover(close,    bbd3)
    a_L3_short   :=   ta.crossunder(close,   bbu3)

if mode == 'Band-crossout'
    a_L1_long  :=   ta.crossunder(close,   bbd1)
    a_L1_short   :=   ta.crossover(close,    bbu1)
    a_L2_long  :=   ta.crossunder(close,   bbd2)
    a_L2_short   :=   ta.crossover(close,    bbd2)
    a_L3_long  :=   ta.crossunder(close,   bbd3)
    a_L3_short   :=   ta.crossover(close,    bbu3)

if mode == 'Trend'
    a_L3_long   :=  bbm_   <   close 
    a_L3_short  :=  bbm_   >   close 

alertcondition(a_L3_long, 'BBx3 -3 Band Alert',     'BBx3 -3 Band Alert'  )
alertcondition(a_L2_long, 'BBx3 -2 Band Alert',     'BBx3 -2 Band Alert'  )
alertcondition(a_L1_long, 'BBx3 -1 Band Alert',     'BBx3 -1 Band Alert'  )
alertcondition(a_L1_short, 'BBx3 +1 Band Alert',    'BBx3 +1 Band Alert'  )
alertcondition(a_L3_short, 'BBx3 +2 Band Alert',    'BBx3 +2 Band Alert'  )
alertcondition(a_L3_short, 'BBx3 +3 Band Alert',    'BBx3 +3 Band Alert'  )

//}

// Plotting of Alarms {

plotshape(showalerts_L1? a_L1_long:    na  ,
 style=shape.triangleup, location=location.belowbar, color=color.new(#ebff00, 60), size=size.tiny)
plotshape(showalerts_L1? a_L1_short:   na  ,
 style=shape.triangledown, location=location.abovebar, color=color.new(#ebff00, 60), size=size.tiny)

plotshape(showalerts_L2? a_L2_long:    na  ,
 style=shape.triangleup, location=location.belowbar, color=color.new(#00ff20, 30), size=size.small)
plotshape(showalerts_L2? a_L2_short:   na  ,
 style=shape.triangledown, location=location.abovebar, color=color.new(#ff0000, 30), size=size.small)

plotshape(showalerts_L3? a_L3_long:    na  ,
 style=shape.triangleup, location=location.belowbar, color=color.new(#00ff20, 0), size=size.small)
plotshape(showalerts_L3? a_L3_short:   na  ,
 style=shape.triangledown, location=location.abovebar, color=color.new(#ff0000, 0), size=size.small)
//}

// SIGNAL Daisychain {

string  inputtype           =   input.string('NoInput' , title='Signal Type', group='Multibit signal config', options=['MultiBit', 'MultiBit_pass', 'NoInput'], tooltip='Multibit Daisychain with and without infusing\nMutlibit is the Signal-Type used in my Backtestsystem',inline='3a')
float   inputModule         =   input(title='Select L1 Indicator Signal', group='Multibit signal config', defval=close, inline='3a')

Signal_Channel_Line1=   input.int(-1,   'L1 long channel',   minval=-1,   maxval=15,group='Multibit',inline='1a')
Signal_Channel_Line2=   input.int(-1,   'L1 short channel',  minval=-1,   maxval=15,group='Multibit',inline='1a')
Signal_Channel_Line3=   input.int(-1,   'L2 long channel',   minval=-1,   maxval=15,group='Multibit',inline='1b')
Signal_Channel_Line4=   input.int(-1,   'L2 short channel',  minval=-1,   maxval=15,group='Multibit',inline='1b')
Signal_Channel_Line5=   input.int(-1,   'L3 long channel',   minval=-1,   maxval=15,group='Multibit',inline='1c')
Signal_Channel_Line6=   input.int(-1,   'L3 short channel',  minval=-1,   maxval=15,group='Multibit',inline='1c')

//*********** Simplesignal Implementation

signalout = 0
signalout := a_L3_long ? 1 : a_L3_short ? -1 : 0
BM_color_signal = a_L3_long ? #4C9900 : a_L3_short ? #CC0000 : color.black
L_digital_signal = plot(signalout, title='Digitalsignal', color=BM_color_signal, style=plot.style_columns, display=display.none)

//*********** MULTIBIT Implementation
import djmad/Signal_transcoder_library/7 as transcode
bool [] Multibit = array.new<bool>(16,false)
if inputtype == 'MultiBit' or inputtype == 'MultiBit_pass'
    Multibit := transcode._16bit_decode(inputModule)

if inputtype != 'MultiBit_pass'
    transcode.f_infuse_signal(Signal_Channel_Line1, a_L1_long, Signal_Channel_Line2, a_L1_short, Signal_Channel_Line3, a_L2_long, Signal_Channel_Line4, a_L2_short, Signal_Channel_Line5, a_L3_long, Signal_Channel_Line6, a_L3_short, Multibit)

float plot_output = transcode._16bit_encode(Multibit)

plot(plot_output,title='MultiBit Signal',display=display.none)

//}


