Gaussian Filter MACD [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("Gaussian Filter MACD [Loxx]",
     shorttitle="GFMACD [Loxx]",
     overlay = false, 
     timeframe="", 
     timeframe_gaps = true)

import loxx/loxxexpandedsourcetypes/4

greencolor = #2DD204  
redcolor = #D2042D 

SM01 = 'Zero Cross'
SM02 = 'Signal Cross'

_alpha(int period, int poles)=>
    w = 2.0 * math.pi / period
    float b = (1.0 - math.cos(w)) / (math.pow(1.414, 2.0 / poles) - 1.0)
    float a = - b + math.sqrt(b * b + 2.0 * b)
    a

_gsmth(float src, int poles, float alpha)=>
    float out = 0.
    out := switch poles
        1 => alpha * src + (1 - alpha) * 
             nz(out[1])
        2 => math.pow(alpha, 2) * 
		     src + 2 * 
		     (1 - alpha) * 
		     nz(out[1]) - math.pow(1 - alpha, 2) * 
		     nz(out[2])
        3 => math.pow(alpha, 3) * 
             src + 3 * (1 - alpha) * 
             nz(out[1]) - 3 *
             math.pow(1 - alpha, 2) * 
             nz(out[2]) + math.pow(1 - alpha, 3) * 
             nz(out[3])
        4 => math.pow(alpha, 4) * 
             src + 4 * (1 - alpha) * 
             nz(out[1]) - 6 *
             math.pow(1 - alpha, 2) * 
             nz(out[2]) + 4 *
             math.pow(1 - alpha, 3) * 
             nz(out[3]) - math.pow(1 - alpha, 4) * 
             nz(out[4])
	out
	
smthtype = input.string("Kaufman", "Heiken-Ashi Better Smoothing", options = ["AMA", "T3", "Kaufman"], group=  "Source Settings")
srcoption = input.string("Close", "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)"])

fper = input.int(12,'Fast Period', group = "Basic Settings")
sper = input.int(26,'Slow Period', group = "Basic Settings")
sigper = input.int(9,'Signal Period', group = "Basic Settings")

fpoles = input.int(4,'Fast Poles', group = "Basic Settings", minval = 1, maxval = 4)
spoles = input.int(4,'Slow Poles', group = "Basic Settings", minval = 1, maxval = 4)
sigpoles = input.int(4,'Signal Poles', group = "Basic Settings", minval = 1, maxval = 4)

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

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

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	

Fast_alfa = _alpha(fper, fpoles)
Slow_alfa = _alpha(sper, spoles)
Signal_alfa = _alpha(sigper, sigpoles)

fout =   _gsmth(src, fpoles, Fast_alfa)
sout =   _gsmth(src, spoles, Slow_alfa)

macd = fout - sout
sigout = _gsmth(macd, sigpoles, Signal_alfa)

state = 0., mid = 0
if sigtype == SM01
    if (macd < mid) 
        state :=-1
    if (macd > mid) 
        state := 1
else if sigtype == SM02
    if (macd < sigout) 
        state :=-1
    if (macd > sigout)
        state := 1

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

plot(macd, "MACD", color = colorout, linewidth = 2)
plot(sigout, "Signal", color = color.white, linewidth = 1)
plot(mid, "Middle", color = bar_index % 2 ? color.gray : na)

barcolor(colorbars ? colorout : na)

goLong =  sigtype == SM01 ? ta.crossover(macd, mid) : ta.crossover(macd, sigout) 
goShort = sigtype == SM01 ? ta.crossunder(macd, mid) : ta.crossunder(macd, sigout) 

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

alertcondition(goLong, title="Long", message="Gaussian Filter MACD [Loxx]: Long\nSymbol: {{ticker}}\nPrice: {{close}}")
alertcondition(goShort, title="Short", message="Gaussian Filter MACD [Loxx]]: Short\nSymbol: {{ticker}}\nPrice: {{close}}")



