Price-Filtered Spearman Rank Correl. w/ Floating 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("Price-Filtered Spearman Rank Correl. w/ Floating Levels [Loxx]",
     shorttitle= "PFSRCFL [Loxx]", 
     overlay = false, 
     timeframe="", 
     timeframe_gaps = true)

import loxx/loxxexpandedsourcetypes/3

greencolor = #2DD204
redcolor = #D2042D

SM02 = 'Slope'
SM03 = 'Middle Crossover'
SM04 = 'Levels Crossover'

variant(type, src, len) =>
    sig = 0.0
    if type == "SMA"
        sig := ta.sma(src, len) 
    else if type == "EMA"
        sig := ta.ema(src, len) 
    else if type == "WMA"
        sig := ta.wma(src, len)   
    else if type == "RMA"
        sig := ta.rma(src, len)  
    sig
    
_spearman(src, rank, coeff)=>
    var m = matrix.new<float>(rank, 2, 0.)
    for k = 0 to rank - 1
        matrix.set(m, k, 0, nz(src[k]))
        matrix.set(m, k, 1, k)
    matrix.sort(m, 0, order.descending)
    sum = 0.0
    for k = 0 to rank - 1
        sum += math.pow(matrix.get(m, k, 1) - k, 2)
    out = 1 - 6.00 * sum / coeff
    out
    
smthtype = input.string("Kaufman", "Heikin-Ashi Better Caculation Type", options = ["AMA", "T3", "Kaufman"], group = "Basic Settings")

srcin = input.string("HA Median", "Source", group= "Basic 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)"])

type = input.string("SMA", "Source Filter Type", options = ["EMA", "WMA", "RMA", "SMA"], group = "Basic Settings")
smth = input.int(1, "Source Smoothing Period", group = "Basic Settings", minval = 1)

rank = input.int(32, "Rank", group = "Basic Settings")

inpFlPeriod = input.int(32, "Floating Levels Period", group = "Floating Settings", minval = 1)
inpFlLevelUp = input.float(80 , "Level Up", group = "Floating Levels Settings")
inpFlLevelDown = input.float(20 , "Level Down", group = "Floating Levels Settings")

sigtype = input.string(SM04, "Signal type", options = [SM02, SM03, SM04], group = "Signal Settings")

colorbars = input.bool(true, "Color bars?", group = "UI Options")
showsignals = input.bool(true, "Show signals?", 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)

src = switch srcin
	"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
    	
filtsrc = variant(type, src, smth)
coeff = math.pow(rank, 3) - rank
out1 = _spearman(filtsrc, rank, coeff)
out2 = out1[1]

state = 0.

_min   = ta.lowest(out1, inpFlPeriod) 
_max   = ta.highest(out1, inpFlPeriod) 
_range = (_max-_min)/100.0

lvlup = _min + inpFlLevelUp *_range
lvldn = _min + inpFlLevelDown * _range
mid = _min + 50.0 * _range
            
if sigtype == SM02
    if (out1<out2) 
        state :=-1
    if (out1>out2) 
        state := 1
else if sigtype == SM03
    if (out1<mid) 
        state :=-1
    if (out1>mid)
        state := 1
else if sigtype == SM04
    if (out1<lvldn) 
        state :=-1
    if (out1>lvlup)
        state := 1

colorout = state == -1 ? redcolor : state == 1 ? greencolor : color.gray

outpl = plot(out1, color = colorout, title="Fisher", linewidth = 2)

lvldnpl = plot(lvldn, "High Level", color = color.gray)
lvluppl = plot(lvlup, "Low Level" ,color = color.gray)
plot(mid, "Middle", color = bar_index % 2 ? color.gray : na)

barcolor(colorbars ? colorout : na)

goLong = sigtype == SM02 ? ta.crossover(out1, out2) : sigtype == SM03 ? ta.crossover(out1, mid) : ta.crossover(out1, lvlup)
goShort = sigtype == SM02 ? ta.crossunder(out1, out2) : sigtype == SM03 ? ta.crossunder(out1, mid) :  ta.crossunder(out1, lvldn)

plotshape(goLong and showsignals, title = "Long", color = color.yellow, textcolor = color.yellow, text = "L", style = shape.triangleup, location = location.bottom, size = size.auto)
plotshape(goShort and showsignals, title = "Short", color = color.fuchsia, textcolor = color.fuchsia, text = "S", style = shape.triangledown, location = location.top, size = size.auto)

alertcondition(goLong, title="Long", message="Price-Filtered Spearman Rank Correl. w/ Floating Levels [Loxx]: Long\nSymbol: {{ticker}}\nPrice: {{close}}")
alertcondition(goShort, title="Short", message="Price-Filtered Spearman Rank Correl. w/ Floating Levels [Loxx]: Short\nSymbol: {{ticker}}\nPrice: {{close}}")


