Ehlers Autocorrelation Periodogram
min_period = 8 | max_period = 48 | avg_length = 3 | enhance = true Overview
Ehlers Autocorrelation Periodogram is not a trend oscillator in the usual sense. It is a cycle detector. The implementation high-pass filters and smooths the input series, measures how strongly that filtered signal correlates with lagged copies of itself, and then converts those lag relationships into a periodogram-like power surface across the candidate cycle lengths between the chosen minimum and maximum periods.
VectorTA distills that internal spectrum into two outputs. The dominant-cycle line is the smoothed winning cycle estimate, expressed in bars. The normalized-power line is the power value at the selected dominant-cycle bucket, which acts like a confidence read on how concentrated the spectral energy is around that chosen period. The optional enhance mode sharpens strong peaks by cubing normalized power before the final weighting step, making the dominant-cycle estimate less influenced by weaker candidate periods.
Defaults: Ehlers Autocorrelation Periodogram uses `min_period = 8`, `max_period = 48`, `avg_length = 3`, `enhance = true`, and defaults candle input to `close`.
Implementation Examples
Compute the dominant cycle and normalized power from a close series or a candle source.
use vector_ta::indicators::ehlers_autocorrelation_periodogram::{
ehlers_autocorrelation_periodogram,
EhlersAutocorrelationPeriodogramInput,
EhlersAutocorrelationPeriodogramParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
let output = ehlers_autocorrelation_periodogram(
&EhlersAutocorrelationPeriodogramInput::from_slice(
&close,
EhlersAutocorrelationPeriodogramParams {
min_period: Some(8),
max_period: Some(48),
avg_length: Some(3),
enhance: Some(true),
},
)
)?;
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_output = ehlers_autocorrelation_periodogram(
&EhlersAutocorrelationPeriodogramInput::with_default_candles(&candles)
)?;
println!("dominant cycle = {:?}", output.dominant_cycle.last());
println!("normalized power = {:?}", candle_output.normalized_power.last()); API Reference
Input Methods ▼
// From candles and a named source field
EhlersAutocorrelationPeriodogramInput::from_candles(
&Candles,
&str,
EhlersAutocorrelationPeriodogramParams,
) -> EhlersAutocorrelationPeriodogramInput
// From a raw slice
EhlersAutocorrelationPeriodogramInput::from_slice(
&[f64],
EhlersAutocorrelationPeriodogramParams,
) -> EhlersAutocorrelationPeriodogramInput
// From candles with default parameters
EhlersAutocorrelationPeriodogramInput::with_default_candles(&Candles)
-> EhlersAutocorrelationPeriodogramInput Parameters Structure ▼
pub struct EhlersAutocorrelationPeriodogramParams {
pub min_period: Option<usize>, // default 8
pub max_period: Option<usize>, // default 48
pub avg_length: Option<usize>, // default 3
pub enhance: Option<bool>, // default true
} Output Structure ▼
pub struct EhlersAutocorrelationPeriodogramOutput {
pub dominant_cycle: Vec<f64>,
pub normalized_power: Vec<f64>,
} Validation, Warmup & NaNs ▼
- The input slice must be non-empty and contain at least one finite value.
min_periodmust be at least3.max_periodmust be greater thanmin_period, and when real data length is known it cannot exceed that length.- The longest contiguous finite run must be at least
warmup_period + 1bars, wherewarmup_period = max_period + corr_window - 1. - Streaming resets on non-finite input and returns
Noneuntil warmup completes again. - The normalized-power output is the power at the selected dominant-cycle bucket, not the full spectrum.
- When
enhanceis enabled, normalized power is cubed before the dominant-cycle weighting step, making strong peaks dominate more aggressively.
Builder, Streaming & Batch APIs ▼
// Builder
EhlersAutocorrelationPeriodogramBuilder::new()
.min_period(usize)
.max_period(usize)
.avg_length(usize)
.enhance(bool)
.kernel(Kernel)
.apply_slice(&[f64])
EhlersAutocorrelationPeriodogramBuilder::new()
.apply(&Candles, &str)
EhlersAutocorrelationPeriodogramBuilder::new()
.into_stream()
// Stream
EhlersAutocorrelationPeriodogramStream::try_new(EhlersAutocorrelationPeriodogramParams)
EhlersAutocorrelationPeriodogramStream::update(f64) -> Option<(f64, f64)>
EhlersAutocorrelationPeriodogramStream::get_warmup_period() -> usize
// Batch
EhlersAutocorrelationPeriodogramBatchBuilder::new()
.min_period_range((usize, usize, usize))
.max_period_range((usize, usize, usize))
.avg_length_range((usize, usize, usize))
.enhance(bool)
.kernel(Kernel)
.apply_slice(&[f64])
EhlersAutocorrelationPeriodogramBatchBuilder::new()
.apply_candles(&Candles, &str) Error Handling ▼
pub enum EhlersAutocorrelationPeriodogramError {
EmptyInputData,
AllValuesNaN,
InvalidMinPeriod { min_period: usize },
InvalidMaxPeriod { max_period: usize, data_len: usize },
InvalidPeriodOrder { min_period: usize, max_period: usize },
NotEnoughValidData { needed: usize, valid: usize },
OutputLengthMismatch {
expected: usize,
dominant_cycle_got: usize,
normalized_power_got: usize,
},
InvalidRange { start: String, end: String, step: String },
InvalidKernelForBatch(Kernel),
} Python Bindings
Python exposes a two-array single-run function, a streaming class, and a batch function. The single-run binding returns the dominant-cycle array together with the normalized-power array. Batch returns both matrices plus the tested min periods, max periods, averaging lengths, enhance flags, and the rows and cols shape.
import numpy as np
from vector_ta import (
ehlers_autocorrelation_periodogram,
ehlers_autocorrelation_periodogram_batch,
EhlersAutocorrelationPeriodogramStream,
)
data = np.asarray(close_values, dtype=np.float64)
dominant_cycle, normalized_power = ehlers_autocorrelation_periodogram(
data,
min_period=8,
max_period=48,
avg_length=3,
enhance=True,
kernel="auto",
)
stream = EhlersAutocorrelationPeriodogramStream(
min_period=8,
max_period=48,
avg_length=3,
enhance=True,
)
print(stream.update(data[-1]))
print(stream.warmup_period)
batch = ehlers_autocorrelation_periodogram_batch(
data,
min_period_range=(8, 12, 2),
max_period_range=(36, 48, 12),
avg_length_range=(3, 5, 2),
enhance=True,
kernel="auto",
)
print(batch["min_periods"], batch["enhance_flags"], batch["rows"], batch["cols"]) JavaScript/WASM Bindings
The WASM layer exposes an object-returning single-run wrapper, pointer-oriented in-place helpers, and a batch
wrapper that returns both outputs together with parameter metadata. The single-run helper returns named
dominant_cycle and normalized_power arrays. The batch helper adds combos, parameter
vectors, rows, and cols.
import init, {
ehlers_autocorrelation_periodogram_js,
ehlers_autocorrelation_periodogram_batch_js,
} from "/pkg/vector_ta.js";
await init();
const data = new Float64Array(closeValues);
const single = ehlers_autocorrelation_periodogram_js(data, 8, 48, 3, true);
console.log(single.dominant_cycle, single.normalized_power);
const batch = ehlers_autocorrelation_periodogram_batch_js(data, {
min_period_range: [8, 12, 2],
max_period_range: [36, 48, 12],
avg_length_range: [3, 5, 2],
enhance: true,
});
console.log(
batch.dominant_cycle,
batch.normalized_power,
batch.min_periods,
batch.enhance_flags,
batch.rows,
batch.cols
); CUDA Bindings (Rust)
Additional details for the CUDA bindings can be found inside the VectorTA repository.
Performance Analysis
Across sizes, Rust CPU runs about 1.14× faster than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU)
Related Indicators
High-Low Correlation
Technical analysis indicator
Correlation Cycle
Technical analysis indicator
Deviation
Technical analysis indicator
Ehlers Error-Correcting EMA (ECEMA)
Moving average indicator
Ehlers Instantaneous Trendline
Moving average indicator
Ehlers Kaufman Adaptive Moving Average
Moving average indicator