multicolor Bollinger Bands (BB <-> KC)
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// multicolor Bollinger Bands (BB <-> KC) © by Indicator-Jones
// Concept: After every low volatile phase comes a high volatile phase and after every high volatile phase comes a low volatile phase.
//          If the Bollinger bands are smaller then the Keltner channel, the price action is low in volatility… meaning a breakout will happen soon ;)
// This script is a combination of the 2 standard indicators (Bollinger Bands & Keltner Channel) from TradingView. 
// If Bollinger bands > Keltner channel  = green
// If Bollinger bands < Keltner channel  = red
// If multicolor BB is disabled = blue (tradingview default color)
// customize colors to your liking under settings -> style

// To get alerts for all coins
// -------------------------------
// 1. visit » tradingview.com/crypto-screener
// 2. set the filter to »
// Bollinger Upper Band (20) below Keltner Channels Upper Band (20) 
// Bollinger Lower Band (20) above Keltner Channels Lower Bands (20)
// 3. add your own custom filters, like: exchange, marketcap, etc…
// 4. choose the timeframe you want
// 5. enable alerts

// last update: 01.03.2022 - added Alerts
//              14.02.2022 - added Vix Fix for marking highs and lows
//              13.02.2022 - changed 'Multiplier' inputs to float. now steps of 0.1 possible. 
//                           new default value of Keltner Multiplier now 1.5 + added comparison of BB width & KC width to make it highly accurate ;)

//@version=5
indicator('Explosive Bollinger Bands (BB <-> KC) multicolor', shorttitle="multicol BB<->KC", overlay=true, timeframe="", timeframe_gaps=false)

// ------ Keltner Channel ---------
showKC=input.bool(false, title="show Keltner Channel?", group='Keltner Channel')
lengthKC = input.int(20, minval=1, title="Length KC", group='Keltner Channel')
srcKC = input(close, title="Source KC", group='Keltner Channel')
multKC = input.float(1.5, "Multiplier", group='Keltner Channel', step=0.1, minval=0, maxval=100)
exp = input(true, "Use Exponential MA", group='Keltner Channel')
BandsStyle = input.string("Average True Range", options = ["Average True Range", "True Range", "Range"], title="Bands Style", group='Keltner Channel')
atrlength = input(10, "ATR Length", group='Keltner Channel')
esma(source, lengthKC)=>
    s = ta.sma(source, lengthKC)
    e = ta.ema(source, lengthKC)
    exp ? e : s
ma = esma(srcKC, lengthKC)
rangema = BandsStyle == "True Range" ? ta.tr(true) : BandsStyle == "Average True Range" ? ta.atr(atrlength) : ta.rma(high - low, lengthKC)
upperKC = ma + rangema * multKC
lowerKC = ma - rangema * multKC
KCwidth = (upperKC-lowerKC)/ma
uKC = plot(showKC ? upperKC : na, color=color.new(#00bcd4,0), title="Upper KC")
plot(showKC ? ma : na, color=color.new(#00bcd4,0), title="Basis KC")
lKC = plot(showKC ? lowerKC : na, color=color.new(#00bcd4,0), title="Lower KC")
fill(uKC, lKC, color=color.rgb(0, 188, 212, 95), title="Background KC")

// -------- Bollinger Bands ------------
showBB=input.bool(true, title="Show Bolliniger Bands?", group='Bollinger Bands')
multicolor = input.bool(title="Multicolor Bands (BB < KC = red, BB > KC = green)", defval=true, group='Bollinger Bands')
fillBB=input.bool(true, title="Background color? (red zone = 💣💥 incoming!!!)", group='Bollinger Bands')
showAlerts=input.bool(true, title="Show Alerts? 🔺🔻", group='Bollinger Bands', tooltip='Right click on the indicator -> "Add alert on multicol BB" to create alerts')
lengthBB = input.int(20, minval=1, title="Length BB", group='Bollinger Bands')
srcBB = input(close, title="Source BB", group='Bollinger Bands')
multBB = input.float(2.0, step=0.1, minval=0, maxval=100, title="Multiplier", group='Bollinger Bands')
basis = ta.sma(srcBB, lengthBB)
dev = multBB * ta.stdev(srcBB, lengthBB)
upperBB = basis + dev
lowerBB = basis - dev
BBwidth = (upperBB-lowerBB)/basis
offset = input.int(0, "Offset", minval = -500, maxval = 500)
bool BBupGtKCup = upperBB > upperKC
plot(showBB ? basis : na, color=color.new(#FF6D00,0), offset = offset, title="Basis BB")
p1 = plot(showBB ? upperBB : na, color=multicolor ? (upperBB < upperKC ? color.red : color.green) : color.new(#2962FF,0), offset = offset, title="Upper BB")
p2 = plot(showBB ? lowerBB : na, color=multicolor ? (lowerBB > lowerKC ? color.red : color.green) : color.new(#2962FF,0), offset = offset, title="Upper BB")


redZone = upperBB < upperKC and lowerBB > lowerKC and BBwidth < KCwidth
greenZone = upperBB > upperKC and lowerBB < lowerKC and BBwidth > KCwidth
redZoneStart=redZone[1] == false and redZone[0] == true
redZoneEnd=redZone[1] == true and redZone[0] == false

fill(p1, p2, title = "Background BB", color=multicolor and fillBB ? ( redZone ? color.new(#FF5252,75) : color.new(#4CAF50,95)) : color.rgb(33, 150, 243, 95) )

plotshape(showAlerts ? redZoneStart : na, style=shape.triangledown, color=color.new(color.red, 0), location=location.top, textcolor=color.new(color.black, 0), text='', size=size.tiny)
plotshape(showAlerts ? redZoneEnd : na, style=shape.triangleup, color=color.new(color.green, 0), location=location.bottom, textcolor=color.new(color.black, 0), text='', size=size.tiny)

alertcondition(redZoneStart, title='🚨 low volatility alert (BB<KC)', message='🚨 low volatility alert (BB<KC)')
alertcondition(redZoneEnd, title='💣 high volatility alert (BB>KC)', message='💣 high volatility alert (BB>KC)')


// -------- Vix Fix ------------
// ++++++++++ INPUTS ++++++++++ //
VIXFix_length = input(20, title='VIX Fix Length', group='Vix Fix')
VIXFix_back = input(20, title='The number of periods among which to look for lows and highs', group='Vix Fix')
plotMarks = input(title='Plot high/low marks', defval=false, group='Vix Fix')

useFilter = input.bool(true, title='Use ADX filter?', group='Vix Fix')
adxMinVal = input.int(17, title='Do not show signals if ADX is below', group='Vix Fix', minval=0, maxval=100)
adxlen = input.int(14, title='ADX Smoothing (optional)', group='Vix Fix')
dilen = input.int(14, title='DI Length (optional)', group='Vix Fix')

// ++++++++++ LOGIC ++++++++++ //
// Vix current
VIXFix_classic = (ta.highest(close, VIXFix_length) - low) / ta.highest(close, VIXFix_length) * -100
VIXFix_reverse = (ta.lowest(close, VIXFix_length) - high) / ta.lowest(close, VIXFix_length) * -100

// ADX Filter
dirmov(len) =>
    up = ta.change(high)
    down = -ta.change(low)
    plusDM = na(up) ? na : up > down and up > 0 ? up : 0
    minusDM = na(down) ? na : down > up and down > 0 ? down : 0
    truerange = ta.rma(ta.tr, len)
    plus = fixnan(100 * ta.rma(plusDM, len) / truerange)
    minus = fixnan(100 * ta.rma(minusDM, len) / truerange)
    [plus, minus]
adx(dilen, adxlen) =>
    [plus, minus] = dirmov(dilen)
    sum = plus + minus
    adx = 100 * ta.rma(math.abs(plus - minus) / (sum == 0 ? 1 : sum), adxlen)
    adx
sig = adx(dilen, adxlen)

// Minimaxis
isMaxUp = ta.highest(VIXFix_reverse, VIXFix_back) == VIXFix_reverse  // Top peaks
isMaxDown = ta.lowest(VIXFix_classic, VIXFix_back) == VIXFix_classic  // Top bottoms
isMinUp = ta.lowest(VIXFix_reverse, VIXFix_back) == VIXFix_reverse  // Min peaks
isMinDown = ta.highest(VIXFix_classic, VIXFix_back) == VIXFix_classic  // Min bottoms

// Signals
buySignal = isMaxDown or isMinUp
sellSignal = isMinDown or isMaxUp

// Filtred signals
buySignalFiltred = buySignal and sig > adxMinVal
sellSignalFiltred = sellSignal and sig > adxMinVal

// ++++++++++ PLOT - Marks ++++++++++ //
plotshape((useFilter ? sellSignalFiltred : sellSignal) and plotMarks, title='Sell', color=color.new(color.red, 0), style=shape.circle, location=location.abovebar, size=size.tiny)
plotshape((useFilter ? buySignalFiltred : buySignal) and plotMarks, title='Buy', color=color.new(color.green, 0), style=shape.circle, location=location.belowbar, size=size.tiny)