Goertzel Cycle Composite Wave

Parameters: max_period = 120 | start_at_cycle = 1 | use_top_cycles = 2 | bar_to_calculate = 1 | detrend_mode = hodrick_prescott_detrending

Overview

Goertzel Cycle Composite Wave is a spectral cycle tool that scans a rolling price sample for dominant periodic components, ranks those cycles by amplitude, and then reconstructs a composite wave from the strongest selected cycles. Before the scan, the input window can be smoothed or detrended with Hodrick-Prescott, zero-lag, or regression-based preprocessing so the cycle extraction focuses on oscillatory structure rather than raw trend.

The indicator is configurable enough to behave as either a broad composite-cycle reader or a stricter significance-filtered tool. Optional Bartels filtering can reject statistically weak cycles, the cycle list can be sorted by Bartels significance, and the final wave can use cosine or sine reconstruction, squared or raw amplitudes, and optional noise subtraction from the remaining lower-ranked cycles.

Defaults: Goertzel Cycle Composite Wave uses `max_period = 120`, `start_at_cycle = 1`, `use_top_cycles = 2`, `bar_to_calculate = 1`, `detrend_mode = "hodrick_prescott_detrending"`, `filter_bartels = false`, `squared_amp = true`, `use_cosine = true`, `subtract_noise = false`, and `use_cycle_strength = true`.

Implementation Examples

Compute the composite cycle wave from a price slice or from candle closes.

use vector_ta::indicators::goertzel_cycle_composite_wave::{
    goertzel_cycle_composite_wave,
    GoertzelCycleCompositeWaveInput,
    GoertzelCycleCompositeWaveParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

let close = vec![100.0, 101.1, 100.4, 102.0, 101.3, 103.2, 102.5];

let output = goertzel_cycle_composite_wave(&GoertzelCycleCompositeWaveInput::from_slice(
    &close,
    GoertzelCycleCompositeWaveParams::default(),
))?;

let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_output = goertzel_cycle_composite_wave(
    &GoertzelCycleCompositeWaveInput::with_default_candles(&candles),
)?;

println!("latest wave = {:?}", output.values.last());
println!("series length = {}", candle_output.values.len());

API Reference

Input Methods
// From candles with an explicit source
GoertzelCycleCompositeWaveInput::from_candles(&Candles, &str, GoertzelCycleCompositeWaveParams)
    -> GoertzelCycleCompositeWaveInput

// From a raw slice
GoertzelCycleCompositeWaveInput::from_slice(&[f64], GoertzelCycleCompositeWaveParams)
    -> GoertzelCycleCompositeWaveInput

// From candles with default source and parameters
GoertzelCycleCompositeWaveInput::with_default_candles(&Candles)
    -> GoertzelCycleCompositeWaveInput
Parameters Structure
pub struct GoertzelCycleCompositeWaveParams {
    pub max_period: Option<usize>,
    pub start_at_cycle: Option<usize>,
    pub use_top_cycles: Option<usize>,
    pub bar_to_calculate: Option<usize>,
    pub detrend_mode: Option<GoertzelDetrendMode>,
    pub dt_zl_per1: Option<usize>,
    pub dt_zl_per2: Option<usize>,
    pub dt_hp_per1: Option<usize>,
    pub dt_hp_per2: Option<usize>,
    pub dt_reg_zl_smooth_per: Option<usize>,
    pub hp_smooth_per: Option<usize>,
    pub zlma_smooth_per: Option<usize>,
    pub filter_bartels: Option<bool>,
    pub bart_no_cycles: Option<usize>,
    pub bart_smooth_per: Option<usize>,
    pub bart_sig_limit: Option<usize>,
    pub sort_bartels: Option<bool>,
    pub squared_amp: Option<bool>,
    pub use_cosine: Option<bool>,
    pub subtract_noise: Option<bool>,
    pub use_cycle_strength: Option<bool>,
}
Output Structure
pub struct GoertzelCycleCompositeWaveOutput {
    pub values: Vec<f64>,
}
Validation, Warmup & NaNs
  • The input series must be non-empty and contain at least one finite value.
  • Core positive parameters such as start_at_cycle, use_top_cycles, and the smoothing lengths must all be greater than 0.
  • Hodrick-Prescott periods that drive HP smoothing or detrending must be at least 2.
  • The indicator requires a contiguous valid run large enough to cover the entire rolling sample implied by max_period, bar_to_calculate, and Bartels settings.
  • One-shot and batch outputs are NaN-prefixed until the full sample window is available.
  • Streaming resets on non-finite input and restarts its rolling sample warmup.
  • Batch mode validates the range axes and rejects unsupported kernels through InvalidKernelForBatch.
Builder, Streaming & Batch APIs
// Builder
GoertzelCycleCompositeWaveBuilder::new()
    .params(GoertzelCycleCompositeWaveParams)
    .max_period(usize)
    .start_at_cycle(usize)
    .use_top_cycles(usize)
    .kernel(Kernel)
    .apply(&Candles)

GoertzelCycleCompositeWaveBuilder::new()
    .apply_slice(&[f64])

GoertzelCycleCompositeWaveBuilder::new()
    .into_stream()

// Stream
GoertzelCycleCompositeWaveStream::try_new(GoertzelCycleCompositeWaveParams)
GoertzelCycleCompositeWaveStream::update(f64) -> Option<f64>
GoertzelCycleCompositeWaveStream::reset()
GoertzelCycleCompositeWaveStream::get_warmup_period() -> usize

// Batch
GoertzelCycleCompositeWaveBatchBuilder::new()
    .kernel(Kernel)
    .max_period_range((usize, usize, usize))
    .start_at_cycle_range((usize, usize, usize))
    .use_top_cycles_range((usize, usize, usize))
    .params(GoertzelCycleCompositeWaveParams)
    .apply_slice(&[f64])
Error Handling
pub enum GoertzelCycleCompositeWaveError {
    EmptyInputData,
    AllValuesNaN,
    InvalidParameter { name: &'static str, value: usize },
    NotEnoughValidData { needed: usize, valid: usize },
    OutputLengthMismatch { expected: usize, got: usize },
    InvalidRange { start: usize, end: usize, step: usize },
    InvalidKernelForBatch(Kernel),
    MismatchedOutputLen { dst_len: usize, expected_len: usize },
    InvalidInput { msg: String },
    InvalidDetrendMode(String),
}

Python Bindings

Python exposes a scalar price-series function, a streaming class, and a batch sweep. The scalar path returns one NumPy composite-wave array. Streaming returns one floating-point wave value or `None`, while batch returns the flattened matrix plus the tested `max_period`, `start_at_cycle`, and `use_top_cycles` combinations together with output dimensions.

import numpy as np
from vector_ta import (
    goertzel_cycle_composite_wave,
    goertzel_cycle_composite_wave_batch,
    GoertzelCycleCompositeWaveStream,
)

data = np.asarray(close_values, dtype=np.float64)

values = goertzel_cycle_composite_wave(
    data,
    max_period=120,
    start_at_cycle=1,
    use_top_cycles=2,
    detrend_mode="hodrick_prescott_detrending",
    kernel="auto",
)

stream = GoertzelCycleCompositeWaveStream(
    max_period=96,
    start_at_cycle=1,
    use_top_cycles=3,
    detrend_mode="zero_lag_detrending",
)
print(stream.update(data[-1]))

batch = goertzel_cycle_composite_wave_batch(
    data,
    max_period_range=(80, 120, 20),
    start_at_cycle_range=(1, 2, 1),
    use_top_cycles_range=(1, 3, 1),
    detrend_mode="hodrick_prescott_detrending",
    kernel="auto",
)

print(batch["values"].shape)
print(batch["max_periods"])
print(batch["use_top_cycles"])

JavaScript/WASM Bindings

The WASM layer exposes a config-driven scalar function, a batch function, and raw allocation and into-buffer helpers. The scalar binding returns a single composite-wave array. The batch binding returns the flattened values matrix plus the tested parameter combinations and matrix dimensions.

import init, {
  goertzel_cycle_composite_wave_js,
  goertzel_cycle_composite_wave_batch_js,
} from "@vectoralpha/vector_ta";

await init();

const values = goertzel_cycle_composite_wave_js(close, {
  max_period: 120,
  start_at_cycle: 1,
  use_top_cycles: 2,
  detrend_mode: "hodrick_prescott_detrending",
  filter_bartels: false,
});

console.log(values);

const batch = goertzel_cycle_composite_wave_batch_js(close, {
  max_period_range: [80, 120, 20],
  start_at_cycle_range: [1, 2, 1],
  use_top_cycles_range: [1, 3, 1],
  base: {
    detrend_mode: "hodrick_prescott_detrending",
    filter_bartels: true,
    bart_sig_limit: 55,
  },
});

console.log(batch.values);
console.log(batch.combos);
console.log(batch.rows, batch.cols);

CUDA Bindings (Rust)

Additional details for the CUDA bindings can be found inside the VectorTA repository.

Performance Analysis

Comparison:
View:
Placeholder data (no recorded benchmarks for this indicator)

Across sizes, Rust CPU runs about 1.14× faster than Tulip C in this benchmark.

Loading chart...

AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU)

Related Indicators