Normalized Resonator
period = 100 | delta = 0.5 | lookback_mult = 1 | signal_length = 9 Overview
Normalized Resonator runs a two-pole band-pass style filter over the selected series, then divides that response by the strongest absolute resonance seen in a rolling peak window. The resulting oscillator stays bounded and can be compared more cleanly across changing volatility regimes.
A short EMA of the normalized oscillator becomes the signal line. The default candle source is hl2,
the stream requires two valid samples before it emits values, and any non-finite update resets the internal state.
Defaults: `period = 100`, `delta = 0.5`, `lookback_mult = 1.0`, and `signal_length = 9`.
Implementation Examples
Use the default hl2 candle source or pass a custom numeric slice.
use vector_ta::indicators::normalized_resonator::{
normalized_resonator,
NormalizedResonatorInput,
NormalizedResonatorParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
let output = normalized_resonator(&NormalizedResonatorInput::from_slice(
&data,
NormalizedResonatorParams {
period: Some(100),
delta: Some(0.5),
lookback_mult: Some(1.0),
signal_length: Some(9),
},
))?;
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_output = normalized_resonator(
&NormalizedResonatorInput::with_default_candles(&candles),
)?;
println!("oscillator = {:?}", output.oscillator.last());
println!("signal = {:?}", candle_output.signal.last()); API Reference
Input Methods ▼
NormalizedResonatorInput::from_candles(
&Candles,
"hl2",
NormalizedResonatorParams,
) -> NormalizedResonatorInput
NormalizedResonatorInput::from_slice(&[f64], NormalizedResonatorParams)
-> NormalizedResonatorInput
NormalizedResonatorInput::with_default_candles(&Candles)
-> NormalizedResonatorInput Parameters Structure ▼
pub struct NormalizedResonatorParams {
pub period: Option<usize>, // default 100
pub delta: Option<f64>, // default 0.5
pub lookback_mult: Option<f64>, // default 1.0
pub signal_length: Option<usize>, // default 9
} Output Structure ▼
pub struct NormalizedResonatorOutput {
pub oscillator: Vec<f64>,
pub signal: Vec<f64>,
} Validation, Warmup & NaNs ▼
- The slice must not be empty and must contain at least one finite value.
periodmust be at least2.deltamust be finite and stay within(0, 1].lookback_multmust be finite and greater than0.signal_lengthmust be greater than0.- The longest consecutive finite run must contain at least
3samples, and the stream reportsget_warmup_period() -> 2. - Any non-finite streaming sample resets the internal state and returns
None. - Batch mode rejects invalid range tuples and non-batch kernels.
Builder, Streaming & Batch APIs ▼
NormalizedResonatorBuilder::new()
.period(usize)
.delta(f64)
.lookback_mult(f64)
.signal_length(usize)
.kernel(Kernel)
.apply(&Candles, "hl2")
.apply_slice(&[f64])
.into_stream()
NormalizedResonatorStream::try_new(params)
stream.update(f64) -> Option<(f64, f64)>
stream.reset()
stream.get_warmup_period() -> usize
NormalizedResonatorBatchBuilder::new()
.period_range(start, end, step)
.delta_range(start, end, step)
.lookback_mult_range(start, end, step)
.signal_length_range(start, end, step)
.apply_slice(&[f64])
.apply_candles(&Candles, "hl2") Python Bindings
Python exposes a scalar function, a stream class, and a batch helper. The scalar call returns oscillator and signal arrays, the stream yields one tuple per update after warmup, and the batch helper returns a dictionary with reshaped matrices plus the parameter axes that were swept.
from vector_ta import (
normalized_resonator,
normalized_resonator_batch,
NormalizedResonatorStream,
)
oscillator, signal = normalized_resonator(
data,
period=100,
delta=0.5,
lookback_mult=1.0,
signal_length=9,
)
stream = NormalizedResonatorStream(100, 0.5, 1.0, 9)
point = stream.update(data[-1])
batch = normalized_resonator_batch(
data,
period_range=(60, 100, 20),
delta_range=(0.3, 0.5, 0.1),
lookback_mult_range=(1.0, 2.0, 0.5),
signal_length_range=(5, 9, 2),
)
print(batch.keys())
# dict_keys(['oscillator', 'signal', 'periods', 'deltas',
# 'lookback_multipliers', 'signal_lengths', 'rows', 'cols']) JavaScript/WASM Bindings
The WASM surface includes a high-level scalar function, a batch function, and low-level allocation and into-buffer helpers. The scalar and batch calls return plain objects, while the low-level exports let callers reuse memory for oscillator and signal arrays.
import init, {
normalized_resonator_js,
normalized_resonator_batch_js,
normalized_resonator_alloc,
normalized_resonator_free,
normalized_resonator_into,
normalized_resonator_batch_into,
} from "vector-ta-wasm";
await init();
const out = normalized_resonator_js(data, 100, 0.5, 1.0, 9);
const batch = normalized_resonator_batch_js(data, {
period_range: [60, 100, 20],
delta_range: [0.3, 0.5, 0.1],
lookback_mult_range: [1.0, 2.0, 0.5],
signal_length_range: [5, 9, 2],
}); 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)