Goertzel Cycle Composite Wave [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 Cycle Composite Wave [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 function for spectral analysis
// src: input float array containing the data to be analyzed
// forBar: index of the starting bar in the data array
// samplesize: the number of samples per cycle
// per: the maximum number of cycles to analyze
// squaredAmp: a flag indicating whether to use the squared amplitude of the cycles
// useAddition: a flag indicating whether to use addition or subtraction for the wave equation
// useCosine: a flag indicating whether to use cosine or sine for the wave equation
// UseCycleStrength: a flag indicating whether to calculate the cycle strength
// WindowSizePast: the number of past bars to use for wave analysis
// FilterBartels: a flag indicating whether to use Bartel's test to filter out insignificant cycles
// BartNoCycles: the number of cycles to use for Bartel's test
// BartSmoothPer: the number of periods to smooth for Bartel's test
// BartSigLimit: the significance limit for Bartel's test
// SortBartels: a flag indicating whether to sort the cycles by significance
// goeWorkPast: a matrix used to store the past cycles for wave analysis
// cyclebuffer: an output array containing the cycles
// amplitudebuffer: an output array containing the amplitudes of the cycles
// phasebuffer: an output array containing the phases of the cycles
// cycleBartelsBuffer: an output array containing the Bartel's significance values of the cycles

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, 
     simple bool FilterBartels,simple int BartNoCycles, simple int BartSmoothPer, simple int BartSigLimit, 
     simple bool SortBartels, matrix<float> goeWorkPast, float[] cyclebuffer, 
     float[] amplitudebuffer, float[] phasebuffer, float[] cycleBartelsBuffer)=>

    // Calculate the number of samples per cycle
    int sample = 2 * per

    // Initialize arrays
    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.) 

    // Calculate the first two temporary values
    float temp1 = array.get(src, forBar + sample - 1)  
    float temp2 = (array.get(src, forBar) - temp1) / (sample - 1)  
    float temp3 = 0. 

    // Fill goeWork4 and goeWork3 arrays
    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)

    // Calculate cycles

    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
        // 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))

        // Adjust phase
        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

                // add the wave to the matrix, using either sine or cosine function
                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))

    // return the number of cycles found
    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.

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

// 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 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 backbars = input.int(400, "Number of Bars to Render", group = "Basic Settings", tooltip ="How many bars to plot.The higher the number the slower the computation.")

string detrendornot = input.string(hpsmthdt, "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(false, "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 UseCycleStrength = input.bool(true, "Use Cycle Strength", group = "Miscellaneous Filter Settings")

colorbars = input.bool(true, "Color bars?", group = "UI Options")
showSigs = input.bool(true, "Show signals?", group = "UI Options")

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

if last_bar_index - bar_index < backbars
    WindowSizePast := math.max(WindowSizePast, 2 * MaxPer)
    matrix<float> goeWorkPast = matrix.new<float>(WindowSizePast, WindowSizePast, 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,
         FilterBartels, BartNoCycles, BartSmoothPer, BartSigLimit, 
         SortBartels, goeWorkPast, cyclebuffer, amplitudebuffer, phasebuffer, cycleBartelsBuffer)

    // epgoertzel = end pointed goertzel  
    float[] epgoertzel = array.new<float>(WindowSizePast + 1, 0)

    // past bar calc.  of composite wave
    for i = 0 to WindowSizePast - 1
        array.set(epgoertzel, i, 0) 
        for k = StartAtCycle to StartAtCycle + UseTopCycles - 1
            array.set(epgoertzel, i, array.get(epgoertzel, i) + matrix.get(goeWorkPast, 0, k))
        if SubtractNoise
            if number_of_cycles >= 1
                for k = StartAtCycle + UseTopCycles - 1 to number_of_cycles - 1
                    array.set(epgoertzel, i, array.get(epgoertzel, i) - matrix.get(goeWorkPast, 0, k))

    out := array.get(epgoertzel, 0)

float middle = 0
color colorout = out > middle ? greencolor : out < middle ? redcolor : color.gray

plot(last_bar_index - bar_index < backbars ? out : na, "Goertzel Cycle Composite Wave", color = colorout, linewidth = 2)

barcolor(last_bar_index - bar_index < backbars and colorbars ? colorout : na)

goLong = ta.crossover(out, middle)
goShort = ta.crossunder(out, middle)

plotshape(showSigs and goLong, title = "Long", color = color.yellow, textcolor = color.yellow, text = "L", style = shape.triangleup, location = location.bottom, size = size.auto)
plotshape(showSigs and goShort, title = "Short", color = color.fuchsia, textcolor = color.fuchsia, text = "S", style = shape.triangledown, location = location.top, size = size.auto)

alertcondition(goLong,  title = "Long",  message = "Goertzel Cycle Composite Wave [Loxx]: Long\nSymbol: {{ticker}}\nPrice: {{close}}")
alertcondition(goShort, title = "Short", message = "Goertzel Cycle Composite Wave [Loxx]: Short\nSymbol: {{ticker}}\nPrice: {{close}}")