STD-Stepped, CFB-Adaptive Jurik Filter w/ Variety Levels [Loxx]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © loxx

//@version=5
indicator("STD-Stepped, CFB-Adaptive Jurik Filter w/ Variety Levels [Loxx]",
     shorttitle='STDSCFBADJFVL [Loxx] [Loxx]', 
     overlay = true, 
     timeframe="", 
     timeframe_gaps = true)

import loxx/loxxjuriktools/1
import loxx/loxxexpandedsourcetypes/3
    
greencolor = #2DD204  
redcolor = #D2042D 

_filt(src, len, filter)=>
    price = src
    filtdev = filter * ta.stdev(src, len)
    price := math.abs(price - price[1]) < filtdev ? price[1] : price
    price

smthtype = input.string("Kaufman", "Heiken-Ashi Better Smoothing", options = ["AMA", "T3", "Kaufman"], group=  "Source Settings")

srcoption = input.string("HAB Trend Biased (Extreme)", "Source", group= "Source Settings", 
     options = 
     ["Close", "Open", "High", "Low", "Median", "Typical", "Weighted", "Average", "Average Median Body", "Trend Biased", "Trend Biased (Extreme)", 
     "HA Close", "HA Open", "HA High", "HA Low", "HA Median", "HA Typical", "HA Weighted", "HA Average", "HA Average Median Body", "HA Trend Biased", "HA Trend Biased (Extreme)",
     "HAB Close", "HAB Open", "HAB High", "HAB Low", "HAB Median", "HAB Typical", "HAB Weighted", "HAB Average", "HAB Average Median Body", "HAB Trend Biased", "HAB Trend Biased (Extreme)"])

phase = input.float(0, "Jurik Phase", group= "Basic Settings")
double = input.string("Single", "Jurik Smoothing Double", options = ["Single", "Double"], group= "Basic Settings")
doubleatr = input.string("Single", "Jurik ATR Adaption Smoothing Double", options = ["Single", "Double"], group= "Basic Settings")

filterop = input.string("Both", "Filter Options", options = ["Price", "Jurik Filter", "Both"], group=  "Filter Settings")
filter = input.float(0, "Filter Devaitions", minval = 0, group= "Filter Settings")
filterperiod = input.int(1, "Filter Period", minval = 0, group= "Filter Settings")

leveltype = input.string("Floating", "Levels Type", options = ["Floating", "Quantile"], group= "Levels Settings")
levelper = input.int(35, "Levels Period", minval = 0, group= "Levels Settings")
flLevelUp  = input.float(90, "Levels Up Level %", group = "Levels Settings")  
flLevelDown =  input.float(20, "Levels Down Level %", group = "Levels Settings")  

nlen = input.int(50, "CFB Normal Period", minval = 1, group = "CFB Ingest Settings")
cfb_len = input.int(10, "CFB Depth", maxval = 10, group = "CFB Ingest Settings")
smth = input.int(8, "CFB Smooth Period", minval = 1, group = "CFB Ingest Settings")
slim = input.int(10, "CFB Short Limit", minval = 1, group = "CFB Ingest Settings")
llim = input.int(20, "CFB Long Limit", minval = 1, group = "CFB Ingest Settings")
jcfbsmlen = input.int(10, "CFB Jurik Smooth Period", minval = 1, group = "CFB Ingest Settings")
jcfbsmph = input.float(0, "CFB Jurik Smooth Phase", group = "CFB Ingest Settings")

colorbars = input.bool(true, "Color bars?", group= "UI Options")
showfloat = input.bool(true, "Show Levels?", group = "UI Options")
showfill = input.bool(true, "Fill Levels?", group = "UI Options")
colorneut = input.bool(true, "Use neutral zones?", group = "UI Options")
showSigs = input.bool(true, "Show signals?", group= "UI Options")
showBg = input.bool(false, "Color background??", group= "UI Options")

kfl=input.float(0.666, title="* Kaufman's Adaptive MA (KAMA) Only - Fast End", group = "Moving Average Inputs")
ksl=input.float(0.0645, title="* Kaufman's Adaptive MA (KAMA) Only - Slow End", group = "Moving Average Inputs")
amafl = input.int(2, title="* Adaptive Moving Average (AMA) Only - Fast", group = "Moving Average Inputs")
amasl = input.int(30, title="* Adaptive Moving Average (AMA) Only - Slow", group = "Moving Average Inputs")

haclose = request.security(ticker.heikinashi(syminfo.tickerid), timeframe.period, close)
haopen = request.security(ticker.heikinashi(syminfo.tickerid), timeframe.period, open)
hahigh = request.security(ticker.heikinashi(syminfo.tickerid), timeframe.period, high)
halow = request.security(ticker.heikinashi(syminfo.tickerid), timeframe.period, low)
hamedian = request.security(ticker.heikinashi(syminfo.tickerid), timeframe.period, hl2)
hatypical = request.security(ticker.heikinashi(syminfo.tickerid), timeframe.period, hlc3)
haweighted = request.security(ticker.heikinashi(syminfo.tickerid), timeframe.period, hlcc4)
haaverage = request.security(ticker.heikinashi(syminfo.tickerid), timeframe.period, ohlc4)

float src = switch srcoption
	"Close" => loxxexpandedsourcetypes.rclose()
	"Open" => loxxexpandedsourcetypes.ropen()
	"High" => loxxexpandedsourcetypes.rhigh()
	"Low" => loxxexpandedsourcetypes.rlow()
	"Median" => loxxexpandedsourcetypes.rmedian()
	"Typical" => loxxexpandedsourcetypes.rtypical()
	"Weighted" => loxxexpandedsourcetypes.rweighted()
	"Average" => loxxexpandedsourcetypes.raverage()
    "Average Median Body" => loxxexpandedsourcetypes.ravemedbody()
	"Trend Biased" => loxxexpandedsourcetypes.rtrendb()
	"Trend Biased (Extreme)" => loxxexpandedsourcetypes.rtrendbext()
	"HA Close" => loxxexpandedsourcetypes.haclose(haclose)
	"HA Open" => loxxexpandedsourcetypes.haopen(haopen)
	"HA High" => loxxexpandedsourcetypes.hahigh(hahigh)
	"HA Low" => loxxexpandedsourcetypes.halow(halow)
	"HA Median" => loxxexpandedsourcetypes.hamedian(hamedian)
	"HA Typical" => loxxexpandedsourcetypes.hatypical(hatypical)
	"HA Weighted" => loxxexpandedsourcetypes.haweighted(haweighted)
	"HA Average" => loxxexpandedsourcetypes.haaverage(haaverage)
    "HA Average Median Body" => loxxexpandedsourcetypes.haavemedbody(haclose, haopen)
	"HA Trend Biased" => loxxexpandedsourcetypes.hatrendb(haclose, haopen, hahigh, halow)
	"HA Trend Biased (Extreme)" => loxxexpandedsourcetypes.hatrendbext(haclose, haopen, hahigh, halow)
	"HAB Close" => loxxexpandedsourcetypes.habclose(smthtype, amafl, amasl, kfl, ksl)
	"HAB Open" => loxxexpandedsourcetypes.habopen(smthtype, amafl, amasl, kfl, ksl)
	"HAB High" => loxxexpandedsourcetypes.habhigh(smthtype, amafl, amasl, kfl, ksl)
	"HAB Low" => loxxexpandedsourcetypes.hablow(smthtype, amafl, amasl, kfl, ksl)
	"HAB Median" => loxxexpandedsourcetypes.habmedian(smthtype, amafl, amasl, kfl, ksl)
	"HAB Typical" => loxxexpandedsourcetypes.habtypical(smthtype, amafl, amasl, kfl, ksl)
	"HAB Weighted" => loxxexpandedsourcetypes.habweighted(smthtype, amafl, amasl, kfl, ksl)
	"HAB Average" => loxxexpandedsourcetypes.habaverage(smthtype, amafl, amasl, kfl, ksl)
    "HAB Average Median Body" => loxxexpandedsourcetypes.habavemedbody(smthtype, amafl, amasl, kfl, ksl)
	"HAB Trend Biased" => loxxexpandedsourcetypes.habtrendb(smthtype, amafl, amasl, kfl, ksl)
	"HAB Trend Biased (Extreme)" => loxxexpandedsourcetypes.habtrendbext(smthtype, amafl, amasl, kfl, ksl)
	=> haclose

cfb_draft = loxxjuriktools.jcfb(src, cfb_len, smth)
cfb_pre = doubleatr == 
     "Double" ? loxxjuriktools.jurik_filt(loxxjuriktools.jurik_filt(cfb_draft, jcfbsmlen, jcfbsmph), jcfbsmlen, jcfbsmph) :
     loxxjuriktools.jurik_filt(cfb_draft, jcfbsmlen, jcfbsmph)

max = ta.highest(cfb_pre, nlen)
min = ta.lowest(cfb_pre, nlen)
denom = max - min
ratio = (denom > 0) ? (cfb_pre - min) / denom : 0.5
len_out_cfb = math.ceil(slim + ratio * (llim - slim))

price = filterop == "Both" or filterop == "Price" and filter > 0 ? _filt(src, filterperiod, filter) : src

jmaout = double == 
     "Double" ? loxxjuriktools.jurik_filt(loxxjuriktools.jurik_filt(price, len_out_cfb, phase), len_out_cfb, phase) : 
     loxxjuriktools.jurik_filt(price, len_out_cfb, phase)
     
out = filterop == "Both" or filterop == "Jurik Filter" and filter > 0 ? _filt(jmaout, filterperiod, filter) : jmaout

mini = ta.lowest(out, levelper)
maxi = ta.highest(out, levelper)

rrange = maxi-mini

maxq = ta.percentile_linear_interpolation(out, levelper, flLevelUp) 
minq = ta.percentile_linear_interpolation(out, levelper, flLevelDown) 
midq = (maxq + minq)/2

flu = leveltype == "Floating" ? mini + flLevelUp * rrange/100.0 : maxq
fld = leveltype == "Floating" ? mini + flLevelDown * rrange/100.0 : minq
flm = leveltype == "Floating" ? mini + 0.5 * rrange : midq

top = plot(showfloat ? flu : na, "Top level", color = color.new(greencolor, 50), linewidth = 1)
bot = plot(showfloat ? fld : na, "Bottom level", color = color.new(redcolor, 50), linewidth = 1)
mid = plot(showfloat ? flm : na, "Mid level", color = color.new(color.white, 10), linewidth = 1)

fill(top, mid, title = "Top level fill color", color = showfill ? color.new(greencolor, 95) : na)
fill(bot, mid,title = "Bottom level fill color",  color = showfill ?  color.new(redcolor, 95) : na)

coloroutneut = 
     out > out[1] and out > flu ? greencolor : 
     out < out[1] and out < fld ? redcolor :
     color.gray

colorout = 
     out > out[1] ? greencolor : 
     redcolor

plot(out,"Adaptive Jurik Filter", color = colorneut ? coloroutneut : colorout, linewidth = 3)

barcolor(colorbars ? colorneut ? coloroutneut : colorout : na)


goLong_pre = colorneut ? ta.crossover(out, flu) : ta.crossover(out, out[1])
goShort_pre = colorneut ? ta.crossunder(out, fld) : ta.crossunder(out, out[1])


contSwitch = 0
contSwitch := nz(contSwitch[1])
contSwitch := goLong_pre ? 1 : goShort_pre ? -1 : contSwitch

goLong = goLong_pre and ta.change(contSwitch)
goShort = goShort_pre and ta.change(contSwitch)


plotshape(showSigs and goLong, title = "Long", color = color.yellow, textcolor = color.yellow, text = "L", style = shape.triangleup, location = location.belowbar, size = size.small)
plotshape(showSigs and goShort, title = "Short", color = color.fuchsia, textcolor = color.fuchsia, text = "S", style = shape.triangledown, location = location.abovebar, size = size.small)

alertcondition(goLong, title="Long", message="Ehlers Step OTF: Long\nSymbol: {{ticker}}\nPrice: {{close}}")
alertcondition(goShort, title="Short", message="Ehlers Step OTF: Short\nSymbol: {{ticker}}\nPrice: {{close}}")

coloroutneutbg = 
     out > out[1] and out > flu ? color.new(greencolor, 95) : 
     out < out[1] and out < fld ? color.new(redcolor, 95) :
     na

coloroutbg = 
     out > out[1] ? color.new(greencolor, 95) : 
     color.new(redcolor, 95)


bgcolor(showBg ? colorneut ? coloroutneutbg : coloroutbg : na)

















