Hybrid, Zero lag, Adaptive cycle 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("Hybrid, Zero lag, Adaptive cycle MACD [Loxx]", shorttitle = "HZLACMACD [Loxx]", timeframe="", timeframe_gaps=true, max_bars_back = 5000)

RMA(x, t) =>
    EMA1 = x
    EMA1 := na(EMA1[1]) ? x : (x - nz(EMA1[1])) * (1/t) + nz(EMA1[1])
    EMA1

EMA(x, t) =>
    EMA1 = x
    EMA1 := na(EMA1[1]) ? x : (x - nz(EMA1[1])) * (2 / (t + 1)) + nz(EMA1[1])
    EMA1

_bpDom(len, bpw, mult) =>
    HP = 0.0
    BP = 0.0
    Peak = 0.0
    Real = 0.0
    counter = 0.0
    DC = 0.0
    alpha2 = (math.cos(0.25 * bpw * 2 * math.pi / len) + math.sin(0.25 * bpw * 2 * math.pi  / len) - 1) / math.cos(0.25 * bpw * 2 * math.pi / len)
    HP := (1 + alpha2 / 2) * (close - nz(close[1])) + (1 - alpha2) * nz(HP[1])
    beta1 = math.cos(2 * math.pi / len)
    gamma1 = 1 / math.cos(2 *  math.pi * bpw / len)
    alpha1 = gamma1 - math.sqrt(gamma1 * gamma1 - 1)
    BP := 0.5 * (1 - alpha1) * (HP - nz(HP[2])) + beta1 * (1 + alpha1) * nz(BP[1]) - alpha1 * nz(BP[2])
    BP := bar_index == 1 or bar_index == 2  ? 0 : BP
    Peak := 0.991 * Peak
    Peak := math.abs(BP) > Peak ? math.abs(BP) : Peak
    Real := Peak != 0 ?  BP / Peak : Real
    DC := nz(DC[1])
    DC := DC < 6 ? 6 : DC
    counter := counter[1] + 1
    if ta.crossover(Real, 0) or ta.crossunder(Real, 0)
        DC := 2 * counter
        if 2 * counter > 1.25 * nz(DC[1])
            DC := 1.25 * DC[1]
        if 2 * counter < 0.8 * nz(DC[1])
            DC := 0.8 * nz(DC[1])
        counter := 0
    temp_out = mult * DC
    temp_out


ZL = "Zero lag"
R = "Regular"

macd_type = input.string(ZL, title='MACD Type', options=[ZL, R], group='MACD')
calc_type = input.string("Fixed", title='Calculation Type', options=["Band-pass Dominant Cycle", "Fixed"], group='MACD', tooltip = "Default is Fixed, this is the regular calculation for MACD and signal length inputs. If you choose Band-pass, then all fixed length inputs are ignored and the Band-pass Dominant Cycle measure will be used instead. You can see the Band-pass cycle lengths in the info window to fine-tune the signal.")

macdSrc = input.source(close, title='Source', group='MACD')
f_length_i = input.int(12, title="Fast Length", group='MACD')
s_length_i = input.int(24, title='Slow Length', group='MACD')
signalLen = input.int(9, title='Signal Length', group='MACD')

bp_period = input.int(13, "Band-pass Period", minval = 1, group = "Band-pass")
bp_width = input.float(0.20, "Band-pass Width", step = 0.1, group = "Band-pass")
cycle_len = input.float(100, "MACD Percent of Dominant Cycle (%)", step = 1.0, group = "Band-pass", tooltip ="View info window to see how this changes the value of the MACD MA length inputs")/100

efi_reduction = input.float(75, "Signal Percent of Dominant Cycle (%) ", step = 1.0, group = "Band-pass", tooltip ="View info window to see how this changes the value of the MACD MA length inputs")/100
slMult = input.float(2.0, "MACD Slow-to-Fast Multiple", step = 0.1, group = "Band-pass", tooltip = "The multiple of Slow-to-Fast used to calculate the dynamic lenth of the MACD slow and fast MA inputs. For example, regular MACD is 12 and 24, fast and slow. So a multiple of 2 would mean the following: Slow length = (Fast length X 2).")


macd_ma_type = input.string("EMA", title='Oscillator MA Type', options=["ALMA", "DEMA", "EMA", "LSMA", "RMA", "SMA", "TEMA", "TRIMA", "VWMA", "WMA"], group='MACD')
sig_type = input.string("EMA", title='Signal Line MA Type', options=["ALMA", "DEMA", "EMA", "LSMA", "RMA", "SMA", "TEMA", "TRIMA", "VWMA", "WMA"], group='MACD')

col_macd = input(#2962FF, "MACD Line  ", group="Color Settings", inline="MACD")
col_signal = input(#FF6D00, "Signal Line  ", group="Color Settings", inline="Signal")
col_grow_above = input(#26A69A, "Above   Grow", group="Histogram", inline="Above")
col_fall_above = input(#B2DFDB, "Fall", group="Histogram", inline="Above")
col_grow_below = input(#FFCDD2, "Below Grow", group="Histogram", inline="Below")
col_fall_below = input(#FF5252, "Fall", group="Histogram", inline="Below")

alma_offset = input.float(defval=0.85, title="* Arnaud Legoux Moving Average (ALMA) Only - Offset", group = "Moving Average Inputs")
alma_sigma = input.int(defval=6, title="* Arnaud Legoux Moving Average (ALMA) Only - Sigma", group = "Moving Average Inputs")
lsma_offset = input.int(defval=0, title="* Least Squares Moving Average (LSMA) Only - Offset", group = "Moving Average Inputs")


variant(type, src, len) =>
    sig = 0.0
    if type == "ALMA"
        sig := ta.alma(src, len, alma_offset, alma_sigma) 
    else if type == "SMA"
        sig := ta.sma(src, len) 
    else if type == "EMA"
        sig := EMA(src, len) 
    else if type == "DEMA"
        sig := 2 * EMA(src, len) - EMA(EMA(src, len), len) 
    else if type == "TEMA"
        sig := 3 * (EMA(src, len) - EMA(EMA(src, len), len)) + EMA(EMA(EMA(src, len), len), len)  
    else if type == "WMA"
        sig := ta.wma(src, len)   
    else if type == "TRIMA"
        sig := ta.sma(ta.sma(src, math.ceil(len / 2)), math.floor(len / 2) + 1) 
    else if type == "RMA"
        sig := RMA(src, len)  
    else if type == "VWMA"
        sig := ta.vwma(src, len)  
    else if type == "LSMA"
        sig := ta.linreg(src, len, lsma_offset) 
    sig

_macd(src, m_type, ma_type, s_type, f_len, s_len, sig_len, sig_type_in) =>
    fast_MA1 = variant(ma_type, src, f_len)
    fast_MA2 = variant(ma_type, fast_MA1, f_len) 
    diff_fast = fast_MA1 - fast_MA2
    zlag_fast= fast_MA1 + diff_fast
    slow_MA1 = variant(ma_type, src, s_len)
    slow_MA2 = variant(ma_type, slow_MA1, s_len)
    diff_slow = slow_MA1 - slow_MA2
    zlag_slow= slow_MA1 + diff_slow
    macd = 0.0
    sig = 0.0
    hist = 0.0
    if (m_type == ZL)
        macd := zlag_fast - zlag_slow
        ema1 = variant(sig_type_in, macd, sig_len)
        ema2= variant(sig_type_in, ema1, sig_len)
        diff = ema1 - ema2
        sig := ema1 + diff
        hist := macd - sig
    else
        macd := fast_MA1 - slow_MA1
        sig_t= variant(sig_type_in, macd, sig_len)
        sig := sig_t
        hist := macd - sig
    [macd, sig, hist]

len_out_macd = int(nz(_bpDom(bp_period, bp_width, cycle_len), 1)) < 1 ? 1 : int(nz(_bpDom(bp_period, bp_width, cycle_len), 1))

len_out_signal = int(nz(_bpDom(bp_period, bp_width, efi_reduction), 1)) < 1 ? 1 : int(nz(_bpDom(bp_period, bp_width, efi_reduction), 1))


specFL = calc_type == "Band-pass Dominant Cycle" ? len_out_macd: f_length_i
specSL = calc_type == "Band-pass Dominant Cycle" ? int(len_out_macd * slMult)  : s_length_i
specSig = calc_type == "Band-pass Dominant Cycle" ? len_out_signal : signalLen

[macd, signal, hist] = _macd(macdSrc, macd_type, macd_ma_type, macd_ma_type, specFL, specSL, specSig, sig_type) 

plot(0, "Zero Line", color=color.new(#787B86, 50))

plot(hist, title="Histogram", style=plot.style_columns, color=(hist>=0 ? (hist[1] < hist ? col_grow_above : col_fall_above) : (hist[1] < hist ? col_grow_below : col_fall_below)))
plot(macd, title="MACD", color=col_macd)
plot(signal, title="Signal", color=col_signal)


plotchar(len_out_macd, title = "MACD Fast BP Cycle Length", char = "", location = location.top)
plotchar(int(len_out_macd * slMult) , title = "MACD Slow BP Cycle Length", char = "", location = location.top)
plotchar(len_out_signal, title = "Signal BP Cycle Length", char = "", location = location.top)




















