Hodrick-Prescott 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("Hodrick-Prescott MACD [Loxx]", 
     shorttitle='HPMACD [Loxx]', 
     overlay = false, 
     timeframe="", 
     timeframe_gaps = true)

import loxx/loxxexpandedsourcetypes/4

greencolor = #2DD204
redcolor = #D2042D 

SM02 = 'Slope'
SM03 = 'Middle Crosses'
SM04 = 'Signal Crosses'

_HPFilter(src, lamb, per)=>
    H1 = 0., H2 = 0., H3 = 0., H4 = 0., H5 = 0., 
    HH1 = 0., HH2 = 0., HH3 = 0., HH5 = 0.
    HB= 0., HC= 0., Z= 0.
    
    a = array.new<float>(per, 0.)
    b = array.new<float>(per, 0.)
    c = array.new<float>(per, 0.)

    out = array.new<float>(per, 0.)
    for i = 0 to per - 1
        array.set(out, i, nz(src[i]))
        
    array.set(a, 0, 1.0 + lamb)
    array.set(b, 0, -2.0 * lamb)
    array.set(c, 0, lamb)
    
    for i = 1 to per - 3
        array.set(a, i, 6.0 * lamb + 1.0)
        array.set(b, i, -4.0 * lamb)
        array.set(c, i, lamb)
    
    array.set(a, 1, 5.0 * lamb + 1)
    array.set(a, per - 1, 1.0 + lamb)
    array.set(a, per - 2, 5.0 * lamb + 1.0)
    array.set(b, per - 2, -2.0 * lamb)
    array.set(b, per - 1, 0.)
    array.set(c, per - 2, 0.)
    array.set(c, per - 1, 0.)
    
    for i = 0 to per - 1 
        Z := array.get(a, i) - H4 * H1 - HH5 * HH2
        if (Z == 0) 
            break
            
        HB := array.get(b, i)
        HH1 := H1
        H1 := (HB - H4 * H2) / Z
        array.set(b, i, H1)
        
        HC := array.get(c, i)
        HH2 := H2
        H2 := HC / Z
        array.set(c, i, H2)
        
        array.set(a, i, (array.get(out, i) - HH3 * HH5 - H3 * H4) / Z)
        HH3 := H3
        H3 := array.get(a, i)
        H4 := HB - H5 * HH1
        HH5 := H5
        H5 := HC

    H2 := 0
    H1 := array.get(a, per - 1)
    array.set(out, per - 1, H1)
    
    for i = per - 2 to 0
        array.set(out, i, array.get(a, i) - array.get(b, i) * H1 - array.get(c, i) * H2)
        H2 := H1
        H1 := array.get(out, i)
    out

  
smthtype = input.string("Kaufman", "Heikin-Ashi Better Caculation Type", options = ["AMA", "T3", "Kaufman"], group = "Source Settings")
srcin = 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)"])


fastper = input.int(40, "Signal Period", group = "Basic Settings", minval = 3)
slowper = input.int(80, "Signal Period", group = "Basic Settings", minval = 3)
sigper = input.int(3, "Signal Period", group = "Basic Settings", minval = 3)

sigtype = input.string(SM03, "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
	
	
lambfast = 0.0625 / math.pow(math.sin(math.pi / fastper), 4) 
lambslow = 0.0625 / math.pow(math.sin(math.pi / slowper), 4) 
lambsig = 0.0625 / math.pow(math.sin(math.pi / sigper), 4) 

fast = _HPFilter(src, lambfast, fastper)
slow = _HPFilter(src, lambslow, slowper)

macd = array.get(fast, 0) - array.get(slow, 0)
macds = macd[1]

sig = _HPFilter(macd, lambsig, sigper)

sigout = array.get(sig, 0)
mid = 0

state = 0.
if sigtype == SM02
    if (macd<macds) 
        state :=-1
    if (macd>macds) 
        state := 1
else if sigtype == SM03
    if (macd<mid) 
        state :=-1
    if (macd>mid)
        state := 1
else if sigtype == SM04
    if (macd<sigout) 
        state :=-1
    if (macd>sigout)
        state := 1
        
colorout = state == -1 ? redcolor : state == 1 ? greencolor : color.gray

plot(sigout, "Signal", color = colorout, linewidth = 3)
plot(macd, "HP MACD", color = color.white)

plot(mid, "Middle", color =  bar_index % 2 ? color.gray : na)
barcolor(colorbars ? colorout : na)

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

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="Hodrick-Prescott MACD [Loxx]: Long\nSymbol: {{ticker}}\nPrice: {{close}}")
alertcondition(goShort, title="Short", message="Hodrick-Prescott MACD [Loxx]: Short\nSymbol: {{ticker}}\nPrice: {{close}}")



