MACD Chebyshev (CMACD)
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © peacefulLizard50262

//@version=5
indicator("MACD Chebyshev (CMACD)", "CMACD", false)
import lastguru/DominantCycle/2 as d

j(source, delay)=>
    3 * source-2 * delay

diff(src, N) =>
    switch N
        1 => src - src[1]
        2 => (src - src[2]) / 2
        3 => (src + src[1] - src[2] - src[3]) / 4
        4 => (src + 2 * src[1] - 2 * src[3] - src[4]) / 8
        5 => (src + 3 * src[1] + 2 * src[2] - 2 * src[3] - 3 * src[4] - src[5]) / 16
        6 => (src + 4 * src[1] + 5 * src[2] - 5 * src[4] - 4 * src[5] - src[6]) / 32
        7 => (src + 5 * src[1] + 9 * src[2] + 5 * src[3] - 5 * src[4] - 9 * src[5] - 5 * src[6] - src[7]) / 64
        8 => (src + 6 * src[1] + 14 * src[2] + 14 * src[3] - 14 * src[5] - 14 * src[6] - 6 * src[7] - src[8]) / 128
        9 => (src + 7 * src[1] + 20 * src[2] + 28 * src[3] + 14 * src[4] - 14 * src[5] - 28 * src[6] - 20 * src[7] - 7 * src[8] - src[9]) / 256
        10 => (src + 8 * src[1] + 27 * src[2] + 48 * src[3] + 42 * src[4] - 42 * src[6] - 48 * src[7] - 27 * src[8] - 8 * src[9] - src[10]) / 512

// Custom cosh function
cosh(float x) =>
    (math.exp(x) + math.exp(-x)) / 2

// Custom acosh function
acosh(float x) =>
    x < 1 ? na : math.log(x + math.sqrt(x * x - 1))

// Custom sinh function
sinh(float x) =>
    (math.exp(x) - math.exp(-x)) / 2

// Custom asinh function
asinh(float x) =>
    math.log(x + math.sqrt(x * x + 1))

// Custom inverse tangent function
atan(float x) =>
    math.pi / 2 - math.atan(1 / x)

// Chebyshev Type I Moving Average
chebyshevI(float src, float len, float ripple) =>
    a = 0.
    b = 0.
    g = 0.
    chebyshev = 0.
    
    a := cosh(1 / len * acosh(1 / (1 - ripple)))
    b := sinh(1 / len * asinh(1 / ripple))
    g := (a - b) / (a + b)
    chebyshev := (1 - g) * src + g * nz(chebyshev[1])
    chebyshev

// Chebyshev Type II Moving Average
chebyshevII(float src, float len, float ripple) =>
    a = 0.
    b = 0.
    g = 0.
    chebyshev = 0.
    
    a := cosh(1 / len * acosh(1 / ripple))
    b := sinh(1 / len * asinh(ripple))
    g := (a - b) / (a + b)
    chebyshev := (1 - g) * src + g * nz(chebyshev[1], src)
    chebyshev

noise_gate(signal, ratio, level, knee_type) =>
    // Calculate the absolute value of the signal
    abs_signal = math.abs(signal)

    // Check the value of the knee_type parameter
    if knee_type == "hard"
        // If the knee_type is "hard", apply a hard knee
        if abs_signal > level
            out = signal
        else
            out = signal / ratio
    else
        // If the knee_type is not "hard", apply a soft knee
        if (abs_signal > level) or level == 0
            // If the absolute value is above the threshold, return the signal as is
            out = signal
        else
            // If the absolute value is below the threshold, calculate the soft knee ratio
            soft_knee_ratio = 1 - (level - abs_signal) / level
            // Reduce the amplitude of the signal by the soft knee ratio
            out = signal * soft_knee_ratio

// adjust the ripple value based on your requirement (between 0 and 1)

chebyshev(float src, float length, float ripple, bool style) =>
    not style ?
     chebyshevI(src, length, ripple) :
     chebyshevII(src, length, ripple)

source = input.source(close)
length_diff = input.int(1, "Slow Line Delay", 1, 10)
ripple = input.float(0.3, "Ripple", 0.01, 1, 0.01)

gate_level = input.int(25, "Percent Rank for the gate signal level", 0, 100)
gate_length = input.int(100, "Percent Rank Length", 10)
gate_ratio = input.int(100, "Gate Ratio")

enable_j = input.bool(false, "Enable KDJ Style J Line")

length = d.mamaPeriod(source, 8, 2048)
knee_type = "hard"

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(#ef5350, "Fall", group="Histogram", inline="Below")

cheb = chebyshev(source - chebyshev(source, length, 0.3, false), length, ripple, true) 
delay = cheb[length_diff]

macd = diff(cheb, length_diff)
level = ta.percentile_nearest_rank(math.abs(macd), gate_length, gate_level)
hist = noise_gate(macd, gate_ratio, level, knee_type)
j_line = j(cheb, delay)

colour = hist >= 0 ? (hist[1] < hist ? col_grow_above : col_fall_above) : (hist[1] < hist ? col_grow_below : col_fall_below)

plot(cheb, "Fast", color.blue, 1)
plot(delay, "Slow", color.orange, 1)
plot(hist, "Histogram", colour, style = plot.style_columns)
plot(enable_j ? j_line : na, "J Line", color.purple)
plot(0, color = color.gray)

