Band Based Trend Filter
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © HeWhoMustNotBeNamed

//   __    __            __       __  __                  __       __                        __      __    __              __      _______             __    __                                          __ 
//  /  |  /  |          /  |  _  /  |/  |                /  \     /  |                      /  |    /  \  /  |            /  |    /       \           /  \  /  |                                        /  |
//  $$ |  $$ |  ______  $$ | / \ $$ |$$ |____    ______  $$  \   /$$ | __    __   _______  _$$ |_   $$  \ $$ |  ______   _$$ |_   $$$$$$$  |  ______  $$  \ $$ |  ______   _____  ____    ______    ____$$ |
//  $$ |__$$ | /      \ $$ |/$  \$$ |$$      \  /      \ $$$  \ /$$$ |/  |  /  | /       |/ $$   |  $$$  \$$ | /      \ / $$   |  $$ |__$$ | /      \ $$$  \$$ | /      \ /     \/    \  /      \  /    $$ |
//  $$    $$ |/$$$$$$  |$$ /$$$  $$ |$$$$$$$  |/$$$$$$  |$$$$  /$$$$ |$$ |  $$ |/$$$$$$$/ $$$$$$/   $$$$  $$ |/$$$$$$  |$$$$$$/   $$    $$< /$$$$$$  |$$$$  $$ | $$$$$$  |$$$$$$ $$$$  |/$$$$$$  |/$$$$$$$ |
//  $$$$$$$$ |$$    $$ |$$ $$/$$ $$ |$$ |  $$ |$$ |  $$ |$$ $$ $$/$$ |$$ |  $$ |$$      \   $$ | __ $$ $$ $$ |$$ |  $$ |  $$ | __ $$$$$$$  |$$    $$ |$$ $$ $$ | /    $$ |$$ | $$ | $$ |$$    $$ |$$ |  $$ |
//  $$ |  $$ |$$$$$$$$/ $$$$/  $$$$ |$$ |  $$ |$$ \__$$ |$$ |$$$/ $$ |$$ \__$$ | $$$$$$  |  $$ |/  |$$ |$$$$ |$$ \__$$ |  $$ |/  |$$ |__$$ |$$$$$$$$/ $$ |$$$$ |/$$$$$$$ |$$ | $$ | $$ |$$$$$$$$/ $$ \__$$ |
//  $$ |  $$ |$$       |$$$/    $$$ |$$ |  $$ |$$    $$/ $$ | $/  $$ |$$    $$/ /     $$/   $$  $$/ $$ | $$$ |$$    $$/   $$  $$/ $$    $$/ $$       |$$ | $$$ |$$    $$ |$$ | $$ | $$ |$$       |$$    $$ |
//  $$/   $$/  $$$$$$$/ $$/      $$/ $$/   $$/  $$$$$$/  $$/      $$/  $$$$$$/  $$$$$$$/     $$$$/  $$/   $$/  $$$$$$/     $$$$/  $$$$$$$/   $$$$$$$/ $$/   $$/  $$$$$$$/ $$/  $$/  $$/  $$$$$$$/  $$$$$$$/ 
//                                                                                                                                                                                                          
//                                                                                                                                                                                                          
//
//@version=5
indicator("Band Based Trend Filter")
import HeWhoMustNotBeNamed/ta/1 as eta
import HeWhoMustNotBeNamed/arrays/1 as pa

timeframe = input.timeframe("", "Timeframe", group="Bands", inline="tf", tooltip = 'Timeframe for band calculation')
bandType = input.string('Bollinger Bands', '', ['Bollinger Bands', 'Keltner Channel', 'Donchian Channel'], group='Bands', inline='b1')
maType = input.string('sma', '', options=['sma', 'ema', 'hma', 'rma', 'wma', 'vwma', 'highlow', 'linreg', 'median'], inline = 'b1', group='Bands')
maLength = input.int(20, '', minval = 5, step=5, inline = 'b1', group='Bands')
multiplier = input.float(3.0, '', step=0.5, minval=0.5, group='Bands', inline='b1', tooltip = 'Band parameters let you select type of band/channel, moving average base, length and multiplier')
useTrueRange = input.bool(true, 'Use True Range (For KC only)', group='Bands', tooltip = 'Used only for keltener channel calculation')
sticky = input.bool(true, 'Sticky', group='Bands', tooltip = 'Sticky bands avoids changing the band unless there is breach. Meaning, band positions only change when price is outside the band.')

trendConfirmationCount = input.int(3, 'Trend Confirmation Count', group='Trend', tooltip = 'Trend is defined only after reaching certain count')
inverseTrendDirection = input.bool(false, 'Inverse Trend', group='Trend', tooltip = 'Reverse trend direction - select this to be bearish when sentiment is bullish and vice versa')
colorCandles = input.bool(false, 'Color Bars', group='Trend', tooltip = 'If selected, colors bar based on trend')

float upper = 0.0
float lower = 0.0
float middle = 0.0

indexHighTF = barstate.isrealtime ? 1 : 0
indexCurrTF = barstate.isrealtime ? 0 : 1
[bmiddle, bupper, blower] = request.security(syminfo.tickerid, timeframe, 
                         eta.bb(close[indexHighTF], maType, maLength, multiplier, sticky), lookahead=barmerge.lookahead_on)
[kmiddle, kupper, klower] = request.security(syminfo.tickerid, timeframe,
                         eta.kc(close[indexHighTF], maType, maLength, multiplier, useTrueRange, sticky), lookahead=barmerge.lookahead_on)
[dmiddle, dupper, dlower] = request.security(syminfo.tickerid, timeframe,
                         eta.dc(maLength, false, close, sticky), lookahead=barmerge.lookahead_on)
if(bandType == 'Bollinger Bands')
    upper := bupper[indexCurrTF]
    lower := blower[indexCurrTF]
    middle := bmiddle[indexCurrTF]

if(bandType == 'Keltner Channel')
    upper := kupper[indexCurrTF]
    lower := klower[indexCurrTF]
    middle := kmiddle[indexCurrTF]

if(bandType == 'Donchian Channel')
    upper := dupper[indexCurrTF]
    lower := dlower[indexCurrTF]
    middle := dmiddle[indexCurrTF]

var flag = true
flag := flag or ta.crossover(close, middle) or ta.crossunder(close, middle)

var uptrendCount = 0
var downtrendCount = 0

closeAboveTop = close >= upper
closeBelowBottom = close <= lower
if(flag)
    if(closeAboveTop)
        downtrendCount := 0
        uptrendCount := uptrendCount + 1
    if(closeBelowBottom)
        uptrendCount := 0
        downtrendCount := downtrendCount+1

uptrend = plot(uptrendCount, "uptrend", color=color.green)
downtrend = plot(downtrendCount, "downtrend", color=color.red)
fillColor = uptrendCount>downtrendCount? color.green : color.red
fill(plot1 = uptrend, plot2= downtrend, top_value = 10, bottom_value = 0, top_color = color.new(fillColor, 60), bottom_color = color.new(color.silver, 90))

trend = uptrendCount >= trendConfirmationCount? 1: downtrendCount >= trendConfirmationCount? -1 : 0
inverseTrend = uptrendCount >= trendConfirmationCount? -1 : downtrendCount >= trendConfirmationCount? 1 : 0
barcolor(colorCandles ? ((inverseTrendDirection? inverseTrend : trend) > 0? color.green : trend < 0? color.red : color.silver) : na)
plot(inverseTrendDirection?inverseTrend:trend, "Trend", display = display.data_window)