Goertzel Browser [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("Goertzel Browser [Loxx]", overlay = false, max_lines_count = 500)

color greencolor = #2DD204
color redcolor = #D2042D 

string hpsmth = "Hodrick-Prescott Filter Smoothing"
string zlagsmth = "Zero-lag Moving Average Smoothing"

string hpsmthdt = "Hodrick-Prescott Filter Detrending"
string zlagsmthdt = "Zero-lag Moving Average Detrending"
string logZlagRegression = "Logarithmic Zero-lag Moving Average Regression Detrending"

string none = "None"

// Zero-lag moving average
zeroLagMA(float[] src, int SmoothPer, int BarsTaken)=>
    float sum = 0
    float sumw = 0
    float weight = 0
    float[] lwma1 = array.new<float>(BarsTaken, 0)
    float[] output = array.new<float>(BarsTaken, 0)
    for i = BarsTaken - 1 to 0
        for k = 0 to SmoothPer - 1
            if i + k >= 0 and i + k < BarsTaken - 1
                weight := SmoothPer - k
                sumw += weight
                sum += weight * array.get(src, i + k)
        if sumw != 0
            array.set(lwma1, i, sum / sumw)
        else        
            array.set(lwma1, i, 0)
    sum := 0
    sumw := 0
    weight := 0
    for i = 0 to BarsTaken - 1
        for k = 0 to SmoothPer - 1
            if i - k >= 0  
                weight := SmoothPer - k
                sumw += weight
                sum += weight * array.get(lwma1, i - k)
        if sumw != 0
            array.set(output, i, sum / sumw)
        else        
            array.set(output, i, 0)
    output

// Bartels probability
bartelsProb(int n, int N, Bvalues)=>
    float AvgCoeffA = 0
    float AvgCoeffB = 0
    float AvgIndAmplit = 0
    float AvgAmpl = 0
    float ExptAmpl = 0
    float ARatio = 0
    float BP = 0
    float[] teta = array.new<float>(n, 0)
    float[] vsin = array.new<float>(n, 0)
    float[] vcos = array.new<float>(n, 0)
    float[] CoeffA = array.new<float>(N, 0)
    float[] CoeffB = array.new<float>(N, 0)
    float[] IndAmplit = array.new<float>(N, 0)
    for i = 0 to n - 1
        array.set(teta, i, 1.0 * (i + 1) / n * 2 * math.pi)
        array.set(vsin, i, math.sin(array.get(teta, i)))
        array.set(vcos, i, math.cos(array.get(teta, i)))
    for t = 0 to N - 1
        for i = 0 to n - 1
            array.set(CoeffA, t, array.get(CoeffA, t) + array.get(vsin, i) * array.get(Bvalues, t * n + i))
            array.set(CoeffB, t, array.get(CoeffB, t) + array.get(vcos, i) * array.get(Bvalues, t * n + i))
        array.set(IndAmplit, t, math.pow(array.get(CoeffA, t), 2) + math.pow(array.get(CoeffB, t), 2))
    for t = 0 to N - 1
        AvgCoeffA += array.get(CoeffA, t)
        AvgCoeffB += array.get(CoeffB, t)
        AvgIndAmplit += array.get(IndAmplit, t)
    AvgCoeffA := AvgCoeffA / N
    AvgCoeffB := AvgCoeffB / N
    AvgAmpl := math.sqrt(math.pow(AvgCoeffA, 2) + math.pow(AvgCoeffB, 2)) 
    AvgIndAmplit := math.sqrt(AvgIndAmplit / N)
    ExptAmpl := AvgIndAmplit / math.sqrt(1.0 * N)
    ARatio := AvgAmpl / ExptAmpl
    BP := 1 / math.exp(math.pow(ARatio, 2))
    BP

// Detrend Logrithmic Zero-lag Regression
detrendLnZeroLagRegression(float[] src, int SmoothPer, int BarsTaken)=>
    float[] RegValue = array.new<float>(BarsTaken, 0)
    float[] output = array.new<float>(BarsTaken, 0)
    float[] calcValues = zeroLagMA(src, SmoothPer, BarsTaken)
    for i = 0 to BarsTaken - 1
        array.set(calcValues, i, math.log( array.get(calcValues, i) ) * 100)
    float val1 = 0
    float val2 = 0
    float val3 = 0
    float sumy = 0
    float sumx = 0
    float sumxy = 0
    float sumx2 = 0
    for i = 0 to BarsTaken - 1
        sumy += array.get(calcValues, i)
        sumx += i
        sumxy += i * array.get(calcValues, i)
        sumx2 += i * i
    val3 := sumx2 * BarsTaken - sumx * sumx

    if val3 != 0.0 
        val2 := (sumxy * BarsTaken - sumx * sumy) / val3
        val1 := (sumy - sumx * val2) / BarsTaken
        for i = 0 to BarsTaken - 1
            array.set(RegValue, i, val1 + val2 * i)
        for i = 0 to BarsTaken - 1
            array.set(output, i, array.get(calcValues, i) - array.get(RegValue, i))

    output

// Bartels cycle significance test
bartelsCycleTest(float[] src, int G, float[] cyclebuffer, float[] BartelsProb, BartNoCycles, BartSmoothPer)=>
    for k = 0 to G - 1
        int bpi = math.round(array.get(cyclebuffer, k))
        if bpi > 0 
            bval = detrendLnZeroLagRegression(src, BartSmoothPer, bpi * BartNoCycles)
            array.set(BartelsProb, k, (1 - bartelsProb(bpi, BartNoCycles, bval)) * 100)
    BartelsProb

// Goertzel Browser
goertzel(float[] src, simple int forBar, simple int samplesize, simple int per, simple bool squaredAmp, simple bool useAddition, 
     simple bool useCosine, simple bool UseCycleStrength, int WindowSizePast, 
     int WindowSizeFuture, simple bool FilterBartels, 
     simple int BartNoCycles, simple int BartSmoothPer, simple int BartSigLimit, 
     simple bool SortBartels, matrix<float> goeWorkPast, matrix<float> goeWorkFuture, float[] cyclebuffer, 
     float[] amplitudebuffer, float[] phasebuffer, float[] cycleBartelsBuffer)=>

    int sample = 2 * per
    float[] goeWork1 = array.new_float(sample + 1, 0.)  
    float[] goeWork2 = array.new_float(sample + 1, 0.)  
    float[] goeWork3 = array.new_float(sample + 1, 0.)  
    float[] goeWork4 = array.new_float(sample + 1, 0.) 

    float temp1 = array.get(src, forBar + sample - 1)  
    float temp2 = (array.get(src, forBar) - temp1) / (sample - 1)  
    float temp3 = 0. 
    
    for k = sample - 1 to 1 
        float temp = array.get(src, forBar + k - 1)  - (temp1 + temp2 * (sample - k))
        array.set(goeWork4, k, temp)
        array.set(goeWork3, k, 0.)

    array.set(goeWork3, 0, 0)

    for k = 2 to per 
        float w = 0
        float x = 0
        float y = 0
        float z = math.pow(k, -1)
        
        temp1 := 2.0 * math.cos(2.0 * math.pi * z)
        
        for i = sample to 1  
            w := temp1 * x - y + nz(array.get(goeWork4, i))
            y := x
            x := w

        temp2 := x - y / 2.0 * temp1 
        if temp2 == 0.0
            temp2 := 0.0000001
        
        temp3 := y * math.sin(2.0 * math.pi * z) 

        //Cycle Strength  = Cycle Amplitude/ Cycle Length
        //as described in “Decoding the Hidden Market Rhythm. 
        //For trading it is more important to know which cycle 
        //has the biggest influence to drive the price per bar, 
        //and not only which cycle has the highest amplitude

        if UseCycleStrength
            if squaredAmp 
                array.set(goeWork1, k, (math.pow(temp2, 2) + math.pow(temp3, 2)) / k) 
            else 
                array.set(goeWork1, k, (math.sqrt(math.pow(temp2, 2) + math.pow(temp3, 2))) / k) 
            array.set(goeWork2, k, math.atan(temp3 / temp2))
        else 
            if squaredAmp 
                array.set(goeWork1, k, math.pow(temp2, 2) + math.pow(temp3, 2)) 
            else 
                array.set(goeWork1, k, math.sqrt(math.pow(temp2, 2) + math.pow(temp3, 2))) 
            array.set(goeWork2, k, math.atan(temp3 / temp2))

        if temp2 < 0.0
            array.set(goeWork2, k, nz(array.get(goeWork2, k)) + math.pi)
        else
            if temp3 < 0.0
                array.set(goeWork2, k, nz(array.get(goeWork2, k)) + 2.0 * math.pi)
                
    for k = 3 to per - 1
        if (nz(array.get(goeWork1, k)) > nz(array.get(goeWork1, k + 1)) and nz(array.get(goeWork1, k)) > nz(array.get(goeWork1, k - 1)))
            array.set(goeWork3, k, k * math.pow(10, -4))
        else 
            array.set(goeWork3, k, 0.0)

    // extract cycles
    int number_of_cycles = 0
    for i = 0 to per + 1  
        if nz(array.get(goeWork3, i)) > 0.0
            number_of_cycles += 1
            array.set(cyclebuffer, number_of_cycles, math.round(10000.0 * array.get(goeWork3, i)))
            array.set(amplitudebuffer, number_of_cycles, array.get(goeWork1, i))
            array.set(phasebuffer, number_of_cycles, array.get(goeWork2, i))

    // order cycles acc. largest amplitude or cycle strength  
    if number_of_cycles >= 1
        for i = 1 to number_of_cycles - 1
            for k = i + 1 to number_of_cycles 
                if array.get(amplitudebuffer, k) > array.get(amplitudebuffer, i)
                    y = array.get(amplitudebuffer, i)
                    w = array.get(cyclebuffer, i)
                    x = array.get(phasebuffer, i)
                    array.set(amplitudebuffer, i, array.get(amplitudebuffer, k))
                    array.set(cyclebuffer, i, array.get(cyclebuffer, k))
                    array.set(phasebuffer, i, array.get(phasebuffer, k))
                    array.set(amplitudebuffer, k, y)
                    array.set(cyclebuffer, k, w)
                    array.set(phasebuffer, k, x)

    // Execute Bartels test for cycle significance
        if FilterBartels 
            bartelsCycleTest(src, number_of_cycles, cyclebuffer, cycleBartelsBuffer, BartNoCycles, BartSmoothPer)
            int no_Bcycles = 0
            float v = 0
            //Filter significant cycles
            for i = 0 to number_of_cycles - 1
                if array.get(cycleBartelsBuffer, i) > BartSigLimit
                    array.set(amplitudebuffer, no_Bcycles, array.get(amplitudebuffer, i))
                    array.set(cyclebuffer, no_Bcycles, array.get(cyclebuffer, i))
                    array.set(phasebuffer,  no_Bcycles, array.get(phasebuffer, i))
                    array.set(cycleBartelsBuffer,no_Bcycles, array.get(cycleBartelsBuffer, i))
                    no_Bcycles += 1   
        
            number_of_cycles := no_Bcycles == 0 ? 0 : no_Bcycles

            //Sort Bartels
            if SortBartels and number_of_cycles >= 1
                for i = 1 to number_of_cycles - 1
                    for k = i + 1 to number_of_cycles 
                        if array.get(cycleBartelsBuffer, k) > array.get(cycleBartelsBuffer, i) 
                            y = array.get(amplitudebuffer, i) 
                            w = array.get(cyclebuffer, i) 
                            x = array.get(phasebuffer, i) 
                            v := array.get(cycleBartelsBuffer, i) 
                            array.set(amplitudebuffer, i, array.get(amplitudebuffer, k))
                            array.set(cyclebuffer, i, array.get(cyclebuffer, k))
                            array.set(phasebuffer, i, array.get(phasebuffer, k))
                            array.set(cycleBartelsBuffer, i, array.get(cycleBartelsBuffer, k))
                            array.set(amplitudebuffer, k, y)
                            array.set(cyclebuffer, k, w)
                            array.set(phasebuffer, k, x)
                            array.set(cycleBartelsBuffer, k, v)
        // calculate waves
        for i = 1 to number_of_cycles 
            float amplitude = array.get(amplitudebuffer, i)
            float phase = array.get(phasebuffer, i)
            float cycle = array.get(cyclebuffer, i)
            float sign = 1
            if not useAddition
                sign := -1
            for k = 0 to WindowSizePast - 1
                if useCosine
                    matrix.set(goeWorkPast, k, i, amplitude * math.cos(phase + sign * k * 2.0 * math.pi / cycle))
                else 
                    matrix.set(goeWorkPast, k, i, amplitude * math.sin(phase + sign * k * 2.0 * math.pi / cycle))
            sign *= -1
            for k = 0 to WindowSizeFuture - 1
                if useCosine
                    matrix.set(goeWorkFuture, WindowSizeFuture - k - 1, i, amplitude * math.cos(phase + sign * k * 2.0 * math.pi / cycle))
                else 
                    matrix.set(goeWorkFuture, WindowSizeFuture - k - 1, i, amplitude * math.sin(phase + sign * k * 2.0 * math.pi / cycle))
    number_of_cycles

// Hodrick-Prescott Filter
hodrickPrescottFilter(float[] src, float lamb, int 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.
    float[] a = array.new<float>(per, 0.)
    float[] b = array.new<float>(per, 0.)
    float[] c = array.new<float>(per, 0.)
    float[] output = array.new<float>(per, 0.)
    for i = 0 to per - 1
        array.set(output, i, array.get(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(src, 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(output, per - 1, H1)
    for i = per - 2 to 0
        array.set(output, i, array.get(a, i) - array.get(b, i) * H1 - array.get(c, i) * H2)
        H2 := H1
        H1 := array.get(output, i)
    output

// Detrending options
detrendCenteredMA(float[] src, int period1, int period2, int calcBars, string DTmethod)=>
    if DTmethod == hpsmthdt
        calcValues1 = hodrickPrescottFilter(src, 0.0625 / math.pow(math.sin(math.pi / period1), 4), calcBars)
        calcValues2 = hodrickPrescottFilter(src, 0.0625 / math.pow(math.sin(math.pi / period2), 4), calcBars)
        for i = 0 to calcBars - 1
            array.set(src, i, array.get(calcValues1, i) - array.get(calcValues2, i))
    if DTmethod == zlagsmthdt
        calcValues1 = zeroLagMA(src, period1, calcBars)
        calcValues2 = zeroLagMA(src, period2, calcBars)
        for i = 0 to calcBars - 1
            array.set(src, i, array.get(calcValues1, i) - array.get(calcValues2, i))

// BarToCalculate: This setting determines the starting bar for cycle calculations. 
// Set it to 0 for the current (open) bar, or any number > 0 for closed bars 
// (specific bar depends on the value entered).

// UseCosineForWaves: Choose between sine or cosine for wave reconstruction. 
// Cosine is the preferred method for Goertzel calculations.

// UseAdditionForSteps: Determines how previous bar phases are reconstructed. 
// If set to true, it adds steps to the current phase. If set to false, it 
// subtracts steps from the current phase.

// UseSquaredAmp: Useful for adding many cycles, but may be misleading 
// with 2 or 3 cycles. Recommended usage.

// UseTopCycles: Sorts by largest amplitude or cycle strength. Not necessarily the 
// waves with the largest Bartels cycle significance, but often show significant values. 
// Use cycle strength and Bartels >50 and select cycles with strength >1. Do not 
// use more than 10 cycles.

// WindowSizeFuture: The size in bars to extend into the future.

// Cycle List: If true, it will use up to 5 chosen cycles. Non-consecutive cycles 
// can be used, e.g., 1st, 3rd, and 5th cycles.

// Subtract Noise: Only works when UseTopCycles < max. shown cycles in cycle list.

// Bartels Cycle Significance Test: Applied to every extracted Goertzel cycle.

// Smoothing: Original time series data can be smoothed with Hodrick 
// Prescott filter or Absolutely No Lag LWMA.

// Detrending: Various methods are available, including Absolutely 
// No Lag LWMA, a linear regression of the log-transformed 
// smoothed time series data, and the HP algorithm.

// SampleSize: Calculated as BartNoCycles * MaxCycLength + BarToCalculate. 
// WindowSizePast must be >= SampleSize.

// UseCycleStrength: Used as an alternative to amplitude before the Bartels test.

float src = input.source(close, "Source", group = "Basic Settings")
int MaxPer = input.int(120, "Max Period", minval = 2, group = "Basic Settings")
int WindowSizePast = input.int(100, "Window Size Past", group = "Basic Settings")
int WindowSizeFuture = input.int(100, "Window Size Future", group = "Basic Settings")
int StartAtCycle = input.int(1, "Start Cycle At", group = "Basic Settings")
int UseTopCycles = input.int(2, "Use Top Cycles", group = "Basic Settings")
int BarToCalculate = input.int(1, "Bar to Calculate", group = "Basic Settings")

int Cycle1 = input.int(1, "Cycle 1", group = "Compound Cycle Settings")
int Cycle2 = input.int(1, "Cycle 2", group = "Compound Cycle Settings")
int Cycle3 = input.int(1, "Cycle 3", group = "Compound Cycle Settings")
int Cycle4 = input.int(1, "Cycle 4", group = "Compound Cycle Settings")
int Cycle5 = input.int(1, "Cycle 5", group = "Compound Cycle Settings")

string detrendornot = input.string(zlagsmth, "Smoothing Mode", options = [none, hpsmth, zlagsmth, hpsmthdt, zlagsmthdt, logZlagRegression], group = "Source Price Detrending/Smoothing Settings")

int DT_ZLper1 = input.int(10, "Zero-lag Moving Average Fast Period", group = "Source Price Detrending Settings")
int DT_ZLper2 = input.int(40, "Zero-lag Moving Average Slow Period", group = "Source Price Detrending Settings")
int DT_HPper1 = input.int(20, "Hodrick-Prescott Filter Fast Period", group = "Source Price Detrending Settings")
int DT_HPper2 = input.int(80, "Hodrick-Prescott Filter Slow Period", group = "Source Price Detrending Settings")
int DT_RegZLsmoothPer = input.int(5, "Logarithmic Zero-lag Moving Average Regression Period", group = "Source Price Detrending Settings")

int HPsmoothPer = input.int(20, "Hodrick-Prescott Filter Period",  group = "Source Price Smoothing Settings")
int ZLMAsmoothPer = input.int(10, "Zero-lag Moving Average Period", group = "Source Price Smoothing Settings")

bool FilterBartels = input.bool(true, "Filter Bartels", group = "Bartels Cycle Significance Settings")
int BartNoCycles = input.int(5, "Bartel Number of Cycles", group = "Bartels Cycle Significance Settings")
int BartSmoothPer = input.int(2, "Bartel Smoothing Period", group = "Bartels Cycle Significance Settings")
int BartSigLimit = input.int(50, "Bartel Signal Limit", group = "Bartels Cycle Significance Settings")
bool SortBartels = input.bool(false, "Sort Bartels", group = "Bartels Cycle Significance Settings")

bool squaredAmp = input.bool(true, "Squared Amplitude",group =  "Miscellaneous Filter Settings")
bool useAddition = input.bool(false, "Use Addition", group = "Miscellaneous Filter Settings")
bool useCosine = input.bool(true, "Use Cosine", group = "Miscellaneous Filter Settings")
bool SubtractNoise = input.bool(false, "Subtract Noise", group = "Miscellaneous Filter Settings")
bool UseCycleList = input.bool(false, "Use Cycle List", group = "Miscellaneous Filter Settings")
bool UseCycleStrength = input.bool(true, "Use Cycle Strength", group = "Miscellaneous Filter Settings")

bool showTable = input.bool(true, "Show Table", group = "UI Options")

var pvlines = array.new_line(0)
var fvlines = array.new_line(0)

plot(0, "Zero-line", color = color.gray)

if barstate.isfirst
    for i = 0 to 250 - 1
        array.push(pvlines, line.new(na, na, na, na))
        array.push(fvlines, line.new(na, na, na, na))

if barstate.islastconfirmedhistory

    WindowSizePast := math.max(WindowSizePast, 2 * MaxPer)
    WindowSizeFuture := math.max(WindowSizeFuture, 2 * MaxPer)

    matrix<float> goeWorkPast = matrix.new<float>(WindowSizePast, WindowSizePast, 0)
    matrix<float> goeWorkFuture = matrix.new<float>(WindowSizeFuture, WindowSizeFuture, 0)

    SampleSize = BartNoCycles * MaxPer + BarToCalculate

    float[] cyclebuffer = array.new<float>(MaxPer + 1, 0)
    float[] amplitudebuffer = array.new<float>(MaxPer + 1, 0)
    float[] phasebuffer = array.new<float>(MaxPer + 1, 0)
    float[] cycleBartelsBuffer = array.new<float>(MaxPer * 3, 0)
    float[] srcVal = array.new<float>(SampleSize, 0)

    for i = 0 to SampleSize - 1
        array.set(srcVal, i, nz(src[i]))

    if detrendornot == hpsmthdt
        detrendCenteredMA(srcVal, DT_HPper1, DT_HPper2, SampleSize, detrendornot)
    if detrendornot == zlagsmthdt
        detrendCenteredMA(srcVal, DT_ZLper1, DT_ZLper2, SampleSize, detrendornot)
    if detrendornot == logZlagRegression
        srcVal := detrendLnZeroLagRegression(srcVal, DT_RegZLsmoothPer, SampleSize)

    if detrendornot == hpsmth
        srcVal := hodrickPrescottFilter(srcVal, 0.0625/math.pow(math.sin(math.pi / HPsmoothPer), 4), SampleSize)
    if detrendornot == zlagsmth
        srcVal := zeroLagMA(srcVal, ZLMAsmoothPer, SampleSize)
            
    int number_of_cycles = goertzel(srcVal, BarToCalculate, SampleSize, MaxPer, squaredAmp, useAddition, useCosine, UseCycleStrength, WindowSizePast, 
         WindowSizeFuture, FilterBartels, BartNoCycles, BartSmoothPer, BartSigLimit, 
         SortBartels, goeWorkPast, goeWorkFuture, cyclebuffer, amplitudebuffer, phasebuffer, cycleBartelsBuffer)

    // epgoertzel = end pointed goertzel goertzel is non-endpointed goertzelFuture is goertzel projection into the future 
    float[] epgoertzel = array.new<float>(WindowSizePast + 1, 0)
    float[] goertzel = array.new<float>(WindowSizePast + 1, 0)
    float[] goertzelFuture = array.new<float>(WindowSizeFuture + 1, 0)

    // past bar calc.  of composite wave
    for i = 0 to WindowSizePast - 1
        array.set(goertzel, i, 0) 
        if UseCycleList
            if Cycle1 > 0
                array.set(goertzel, i, array.get(goertzel, i) + matrix.get(goeWorkPast, i, Cycle1))
            if Cycle2 > 0
                array.set(goertzel, i, array.get(goertzel, i) + matrix.get(goeWorkPast, i, Cycle2))
            if Cycle3 > 0
                array.set(goertzel, i, array.get(goertzel, i) + matrix.get(goeWorkPast, i, Cycle3))
            if Cycle4 > 0
                array.set(goertzel, i, array.get(goertzel, i) + matrix.get(goeWorkPast, i, Cycle4))
            if Cycle5 > 0
                array.set(goertzel, i, array.get(goertzel, i) + matrix.get(goeWorkPast, i, Cycle5))
        else
            for k = StartAtCycle to StartAtCycle + UseTopCycles - 1
                array.set(goertzel, i, array.get(goertzel, i) + matrix.get(goeWorkPast, i, k))
            if SubtractNoise
                if number_of_cycles >= 1
                    for k = StartAtCycle + UseTopCycles - 1 to number_of_cycles - 1
                        array.set(goertzel, i, array.get(goertzel, i) - matrix.get(goeWorkPast, i, k))

     // future bar calc. of composite wave
    for i = 0 to WindowSizePast - 1
        array.set(goertzelFuture, i, 0) 
        if UseCycleList
            if Cycle1 > 0
                array.set(goertzelFuture, i, array.get(goertzelFuture, i) + matrix.get(goeWorkFuture, i, Cycle1))
            if Cycle2 > 0
                array.set(goertzelFuture, i, array.get(goertzelFuture, i) + matrix.get(goeWorkFuture, i, Cycle2))
            if Cycle3 > 0
                array.set(goertzelFuture, i, array.get(goertzelFuture, i) + matrix.get(goeWorkFuture, i, Cycle3))
            if Cycle4 > 0
                array.set(goertzelFuture, i, array.get(goertzelFuture, i) + matrix.get(goeWorkFuture, i, Cycle4))
            if Cycle5 > 0
                array.set(goertzelFuture, i, array.get(goertzelFuture, i) + matrix.get(goeWorkFuture, i, Cycle5))
        else
            for k = StartAtCycle  to StartAtCycle + UseTopCycles - 1
                array.set(goertzelFuture, i, array.get(goertzelFuture, i) + matrix.get(goeWorkFuture, i, k))
            if SubtractNoise
                if number_of_cycles >= 1
                    for k = StartAtCycle + UseTopCycles to number_of_cycles  
                        array.set(goertzelFuture, i, array.get(goertzelFuture, i) - matrix.get(goeWorkFuture, i, k))


    float[] pv = goertzel
    int npast = array.size(pv)

    for i = 0 to npast - 2 
        pvline = array.get(pvlines, i)
        colorout = i < array.size(pv) - 2 ? array.get(pv, i) > array.get(pv, i + 1) ? greencolor : redcolor: na
        line.set_xy1(pvline, bar_index - i - 1, array.get(pv, i + 1))
        line.set_xy2(pvline, bar_index - i, array.get(pv, i))
        line.set_color(pvline, colorout)
        line.set_style(pvline, line.style_solid)
        line.set_width(pvline, 3)

    float[] fv = goertzelFuture
    int nfut = array.size(fv)
    array.reverse(fv)

    for i = 1 to nfut - 3
        fvline = array.get(fvlines, i - 1)
        colorout = i < array.size(fv) - 2 ? array.get(fv, i) > array.get(fv, i + 1) ? color.fuchsia : color.yellow : na
        line.set_xy1(fvline, bar_index + i, array.get(fv, i))
        line.set_xy2(fvline, bar_index + i + 1, array.get(fv, i + 1))
        line.set_color(fvline, colorout)
        line.set_style(fvline, line.style_dotted)
        line.set_width(fvline, 2)

    if number_of_cycles >= 1 and showTable
        var table3 = table.new(position = position.top_right, columns = 10, rows = number_of_cycles + 2, bgcolor = color.yellow, border_width = 1)

        string Amp = "Amplitude"
        if UseCycleStrength 
            Amp := "Cycle Strength"

        float fmax   = array.max(amplitudebuffer)
        float coeff = math.max(math.ceil(math.log(fmax) / math.log(10)) -2, -4)

        table.cell(table_id = table3, column = 0, row = 0, text = "Rank")
        table.cell(table_id = table3, column = 1, row = 0, text = "Period")
        table.cell(table_id = table3, column = 2, row = 0, text = "Bartel")
        table.cell(table_id = table3, column = 3, row = 0, text = Amp)
        table.cell(table_id = table3, column = 4, row = 0, text = "Phase")

        for i = 1 to number_of_cycles - 2
            buffer = array.get(cyclebuffer, i)
            amp = array.get(amplitudebuffer, i) / math.pow(10, coeff) * 10
            phase = (array.get(phasebuffer, i) % 2 * math.pi) * 180 / math.pi
            bartel = array.get(cycleBartelsBuffer, i)
            temparr = array.new<float>(5, 0)
            array.set(temparr, 0, i)
            array.set(temparr, 1, buffer)
            array.set(temparr, 2, bartel)
            array.set(temparr, 3, amp)
            array.set(temparr, 4, phase)

            for k = 0 to 4
                tempout = array.get(temparr, k)
                table.cell(table_id = table3, column = k, row = i + 1, text = str.tostring(tempout, "#.###"))