[DSPrated] Modified EMD for swing trade
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © DSPrated

//@version=5
// Modified Ehlers EMD  for swing trade

indicator("[DSPrated] Modified EMD  for swing trade", shorttitle="EMD4swing", overlay=false)
cyc1 = input.int(18, "Period 1", minval=2)
cyc2 = input.int(22, "Period 2", minval=2)
src = input.source(close, "Source")
length = input.int(10, "Truncation length", minval=2)
//------------------------------------------------------------------------------
// bpf function Butterworth bandpass with truncated version {
bpf(source, P1, P2, type = "full", length = 10) => // Butterworth 2nd order Bandpass Filter
    var omega1 = math.tan(math.pi / P2)
    var omega2 = math.tan(math.pi / P1)
    var ww = omega1 * omega2
    var W = omega2 - omega1
    var a0 = 1 + W + ww
    var a1 = 2 * (ww - 1)
    var a2 = 1 - W + ww
    float out = 0
    if type == "full"
        float bandPass = na,  bandPass := (W * (source - source[2])
                                             - a1 * nz(bandPass[1])
                                             - a2 * nz(bandPass[2])) / a0
        out := bandPass                                 
    else
        trun = array.new_float(length+2, 0.0)
        for i = length - 1 to 0
            array.set(trun, i, (W*(nz(source[i]) - nz(source[i + 2]))
                                 - a1*array.get(trun, i + 1)
                                 - a2*array.get(trun, i + 2)) / a0)
        out := array.get(trun, 0)
    out    
    //} 
//------------------------------------------------------------------------------
// lpf function Butterworth lowpass with truncated version {
lpf(source, P1, type = "full", length = 10) => // Butterworth 2nd order Lowpass Filter
    var C = math.tan(math.pi / P1)
    var D = 1 + math.sqrt(2) * C + C * C
    var a1 = 2 * (C * C - 1) / D
    var a2 = (1 - math.sqrt(2) * C + C * C) / D
    var b0 = C * C / D
    var b1 = 2 * b0
    var b2 = b0
    float out = 0
    if type == "full"
        float lowPass = na,  lowPass := b0 * source + b1 * source[1] + b2 * source[2]
                                         - a1 * nz(lowPass[1]) - a2 * nz(lowPass[2])
        out := lowPass
    else
        trun = array.new_float(length+2, 0.0)
        for i = length - 1 to 0
            array.set(trun, i, b0*(nz(source[i]) + b1 *nz(source[i + 1]) + b2 * nz(source[i + 2]))
                                 - a1*array.get(trun, i + 1) - a2 * array.get(trun, i + 2))
        out := array.get(trun, 0)
    out
    //}   
//------------------------------------------------------------------------------
var fraction = 0.5
Peak = 0.0
Valley = 0.0
pos = 0
//------------------------------------------------------------------------------
bp_trunc = bpf(src, cyc1, cyc2, "trunc", length)
//------emd---------------------------------------------------------------------
lp_trunc = lpf(bp_trunc, 2 * cyc2)
Peak := (bp_trunc[1] > bp_trunc and bp_trunc[1] > bp_trunc[2]) ? bp_trunc[1] : nz(Peak[1])
Valley := (bp_trunc[1] < bp_trunc and bp_trunc[1] < bp_trunc[2]) ? bp_trunc[1] : nz(Valley[1]) 
lp_peak = fraction * lpf(Peak, 2.5 * cyc2)
lp_vall = fraction * lpf(Valley, 2.5 * cyc2)

pos := (lp_trunc > lp_peak) ? 1 : (lp_trunc < lp_vall) ? -1 : 0
colr = switch pos
    1  => color.green
    0  => color.black
    -1 => color.red
     
//  signals for swing trade
bool buy  = pos == 0 and ta.crossover( ta.change(bp_trunc),0) and bp_trunc < lp_vall
bool sell = pos == 0 and ta.crossunder(ta.change(bp_trunc),0) and bp_trunc > lp_peak

//------------------------------------------------------------------------------
psig = plot(bp_trunc, title='BandPass truncated filter', color=color.new(colr,30), linewidth=2)
plot(lp_trunc, title='Trend ', color=color.new(color.aqua,30), linewidth=1)
phi = plot(lp_peak, title='High Boundary', color=color.new(color.maroon,30), linewidth=1)
plo = plot(lp_vall, title='Low Boundary', color=color.new(color.maroon,30), linewidth=1)
fill(psig, plo, color.new(color.green, pos == 0 and bp_trunc < lp_vall ? 40 : 100) )
fill(psig, phi, color.new(color.red, pos == 0 and bp_trunc > lp_peak ? 40 : 100) )
// markers
if sell
    label.new (bar_index, bp_trunc, "S", color=color.new(color.maroon,60), textcolor=color.white, style=label.style_label_down, yloc=yloc.price, size=size.tiny)
if buy
    label.new (bar_index, bp_trunc, "B", color=color.new(color.lime,60), textcolor=color.white, style=label.style_label_up, yloc=yloc.price, size=size.tiny)