Volume Weighted Exponential Moving Average Suite (VWEMA)
// 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("Advanced EMA", timeframe = "", overlay = true)
import RicardoSantos/JohnEhlersFourierTransform/4 as r
import lastguru/DominantCycle/2 as d
bes(float source = close, float length = 9, daily_reset = false, volume_weight = false, cumulative = false)=>

    alpha = 2 / (length + 1)

    var float smoothed = na
    var float vol = na
    var float counter = na
    Volume = volume_weight ? volume : 1
    counter := session.isfirstbar ? 1 : counter[1] + 1
    Alpha = (session.isfirstbar and daily_reset) ? (cumulative ? 2 / (counter + 1) : 1) : (cumulative ? 2 / (counter + 1) : alpha)
    vol := na(volume) or (session.isfirstbar and daily_reset) ? Volume : Alpha * Volume + (1 - Alpha) * nz(vol[1])
    smoothed := na(smoothed) or (session.isfirstbar and daily_reset) ? source * Volume : Alpha * (source * Volume) + (1 - Alpha) * nz(smoothed[1])
    out = smoothed/vol

dema(float source = close, float length = 9, daily_reset = false, volume_weight = false, cumulative = false)=>
    e1 = bes(source, length, daily_reset, volume_weight, cumulative)
    e2 = bes(e1, length, daily_reset, volume_weight, cumulative)
    dema = 2 * e1 - e2

tema(float source = close, float length = 9, daily_reset = false, volume_weight = false, cumulative = false) =>
    e1 = bes(source, length, daily_reset, volume_weight, cumulative)
    e2 = bes(e1, length, daily_reset, volume_weight, cumulative)
    e3 = bes(e2, length, daily_reset, volume_weight, cumulative)
    tema = 3 * (e1 - e2) + e3

ehma(float source = close, float length = 9, daily_reset = false, volume_weight = false, cumulative = false)=>
    ehma1 = bes(2 * bes(source, int(length/2), daily_reset, volume_weight, cumulative) - bes(source, length, daily_reset, volume_weight, cumulative), int(math.sqrt(length/2)), volume_weight, cumulative)

stdev(source, length, average)=>
    alpha = 2 / (length + 1)
    var float smoothed = na
    smoothed := alpha * math.pow(source-average, 2) + (1 - alpha) * nz(smoothed[1])
    estdev = math.sqrt(smoothed)

source = input.source(close, "Source")

style  = input.string("EMA", "Style", ["EMA","DEMA","TEMA","EHMA"])

select     = input.string("MAMA", "Dominant Cycle Style", ["MAMA","PA","Phase","DFT","DFT2"])
max_length = input.int(100, "Max Length", 2)
min_length = input.int(4, "Min Length", 1)

volume_weight = input.bool(true, "Volume Weighting")
daily_reset   = input.bool(false, "Daily Reset")
cumulative    = input.bool(false, "Cumulative Length", "Enable Daily Reset to enjoy this feature.")
manual_length = input.bool(false, "Manual Length", inline = "length")
length        = input.float(20.5, "", 0.5, 1000, 0.5, inline = "length")

showBand_1  = input(false, "", group="Standard Deviation Bands Settings", inline="band_1")
stdevMult_1 = input(1.0, "Bands Multiplier #1", group="Standard Deviation Bands Settings", inline="band_1")
showBand_2  = input(false, "", group="Standard Deviation Bands Settings", inline="band_2")
stdevMult_2 = input(2.0, "Bands Multiplier #2", group="Standard Deviation Bands Settings", inline="band_2")
showBand_3  = input(false, "", group="Standard Deviation Bands Settings", inline="band_3")
stdevMult_3 = input(3.0, "Bands Multiplier #3", group="Standard Deviation Bands Settings", inline="band_3")

if volume_weight and barstate.islast and ta.cum(volume) == 0
    runtime.error("No volume is provided by the data vendor.")

if max_length < min_length
    runtime.error("Max length must be greater than min length.")

// if max_length - min_length > 100
//     runtime.error("Max length minus min length must be less than 100.")

if manual_length and cumulative 
    runtime.error("You can not have Cumulative Weight and Manual Length enabled at the same time.")

if cumulative and not daily_reset
    runtime.error("To enable 'Cumulative' you must also enable Daily Reset.")

dom()=>
    if select == "DFT2"
        [dominant_cycle, db] = r.transformed_dft(source, min_length, max_length)
        switch select
            "DFT2"   => ta.cum(dominant_cycle) / (bar_index + 1)
    else
        switch select
            "MAMA"  => d.mamaPeriod(source, min_length, max_length)
            "PA"    => d.paPeriod(source, min_length, max_length)
            "Phase" => d.phasePeriod(source, min_length, max_length)
            "DFT"   => d.dftPeriod(source, min_length, max_length)

wave_l = manual_length ? length : dom()

ma()=>
    switch style
        "EMA"  => bes(source, wave_l, daily_reset, volume_weight, cumulative)
        "DEMA" => dema(source, wave_l, daily_reset, volume_weight, cumulative)
        "TEMA" => tema(source, wave_l, daily_reset, volume_weight, cumulative)
        "EHMA" => ehma(source, wave_l, daily_reset, volume_weight, cumulative)

basis = ma()

dev_1 = stdev(source, wave_l, basis) * stdevMult_1
dev_2 = stdev(source, wave_l, basis) * stdevMult_2
dev_3 = stdev(source, wave_l, basis) * stdevMult_3

center = plot(basis, "Cycle EMA", color.orange)

upperBandValue1 = showBand_1 ? basis + dev_1 : na
lowerBandValue1 = showBand_1 ? basis - dev_1 : na

upperBandValue2 = showBand_2 ? basis + dev_2 : na
lowerBandValue2 = showBand_2 ? basis - dev_2 : na

upperBandValue3 = showBand_3 ? basis + dev_3 : na
lowerBandValue3 = showBand_3 ? basis - dev_3 : na

upperBand_1 = plot(upperBandValue1, title="Upper Band #1", color=color.green)
lowerBand_1 = plot(lowerBandValue1, title="Lower Band #1", color=color.green)
fill(upperBand_1, lowerBand_1, title="Bands Fill #1", color= color.new(color.green, 95))

upperBand_2 = plot(upperBandValue2, title="Upper Band #2", color=color.olive)
lowerBand_2 = plot(lowerBandValue2, title="Lower Band #2", color=color.olive)
fill(upperBand_2, lowerBand_2, title="Bands Fill #2", color= color.new(color.olive, 95))

upperBand_3 = plot(upperBandValue3, title="Upper Band #3", color=color.teal)
lowerBand_3 = plot(lowerBandValue3, title="Lower Band #3", color=color.teal)
fill(upperBand_3, lowerBand_3, title="Bands Fill #3", color= color.new(color.teal, 95))