L2 Ehlers Signal To Noise
source = hl2 | smooth_period = 10 Overview
L2 Ehlers Signal To Noise produces a single signal-to-noise series from a price source and the bar range. The implementation smooths high-low range into a noise estimate, builds Ehlers-style smoothed, detrended, in-phase, and quadrature components from the selected source, estimates dominant cycle period, and then computes a decibel-like power-to-noise ratio before recursively smoothing the final values series.
Defaults: candle source = "hl2" and smooth_period = 10. The Rust path needs the chosen source plus high and low.
Implementation Examples
Build the indicator from candles or explicit source/high/low slices:
use vector_ta::indicators::l2_ehlers_signal_to_noise::{
l2_ehlers_signal_to_noise,
L2EhlersSignalToNoiseInput,
L2EhlersSignalToNoiseParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
let source = vec![100.0, 100.8, 101.2, 101.0, 102.1, 102.9, 103.2];
let high = vec![100.6, 101.1, 101.8, 101.5, 102.8, 103.4, 103.8];
let low = vec![99.6, 100.3, 100.7, 100.5, 101.4, 102.1, 102.7];
let input = L2EhlersSignalToNoiseInput::from_slices(
&source,
&high,
&low,
L2EhlersSignalToNoiseParams::default(),
);
let out = l2_ehlers_signal_to_noise(&input)?;
// Candles use a selectable source field, defaulting to hl2
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_input = L2EhlersSignalToNoiseInput::with_default_candles(&candles);
let candle_out = l2_ehlers_signal_to_noise(&candle_input)?;
println!("{:?}", out.values.last()); API Reference
Input Methods ▼
// From candles with selectable source
L2EhlersSignalToNoiseInput::from_candles(
&Candles,
&str,
L2EhlersSignalToNoiseParams,
) -> L2EhlersSignalToNoiseInput
// From slices
L2EhlersSignalToNoiseInput::from_slices(
&[f64],
&[f64],
&[f64],
L2EhlersSignalToNoiseParams,
) -> L2EhlersSignalToNoiseInput
// Default candles source is "hl2"
L2EhlersSignalToNoiseInput::with_default_candles(&Candles)
-> L2EhlersSignalToNoiseInput Parameters and Output ▼
pub struct L2EhlersSignalToNoiseParams {
pub smooth_period: Option<usize>, // default 10
}
pub struct L2EhlersSignalToNoiseOutput {
pub values: Vec<f64>,
} Builder, Stream, and Batch Types ▼
L2EhlersSignalToNoiseBuilder::new()
.source(&'static str)
.smooth_period(usize)
.kernel(Kernel)
.apply(&Candles) -> Result<L2EhlersSignalToNoiseOutput, _>
L2EhlersSignalToNoiseBuilder::new()
.apply_slices(&[f64], &[f64], &[f64]) -> Result<L2EhlersSignalToNoiseOutput, _>
L2EhlersSignalToNoiseBuilder::new()
.into_stream() -> Result<L2EhlersSignalToNoiseStream, _>
L2EhlersSignalToNoiseStream::update(source, high, low) -> f64
L2EhlersSignalToNoiseBatchBuilder::new()
.source(&'static str)
.smooth_period_range((usize, usize, usize))
.kernel(Kernel)
.apply(&Candles) -> Result<L2EhlersSignalToNoiseBatchOutput, _>
L2EhlersSignalToNoiseBatchBuilder::new()
.apply_slices(&[f64], &[f64], &[f64]) -> Result<L2EhlersSignalToNoiseBatchOutput, _> Warmup, NaNs, and Validation ▼
- Inputs must be non-empty equal-length
source,high, andlowarrays. - The first valid bar requires all three values to be finite. If none are finite, the indicator returns
AllValuesNaN. smooth_periodmust be non-zero.- The batch and scalar validators require at least
MIN_WARMUP_BARS + 1valid bars after the first valid triple, so at least7valid bars. - The scalar path allocates a NaN prefix of
first_valid + 6bars. - The stream returns a plain
f64, notOption. Invalid inputs and warmup bars yieldNaN. - The low-level core also returns
NaNuntilvalid_count > MIN_WARMUP_BARS.
Calculation Notes and Batch Output ▼
range_1is recursively smoothed as0.1 * (high - low) + 0.9 * previous_range_1.- The core uses a 4-bar weighted source smoother, 7-slot rings for detrender / I / Q components, and a period multiplier of
0.075 * smooth_period + 0.54. - Dominant cycle period is clamped to
[6.0, 50.0]and then recursively smoothed. - The final signal-to-noise estimate uses
10 * log10(power / noise) + 6and is recursively smoothed as0.25 * raw + 0.75 * prev. - Batch output is `L2EhlersSignalToNoiseBatchOutput` with `values`, `combos`, `rows`, and `cols`, and the values buffer is flattened row-major.
- Batch range is only
smooth_period: (start, end, step). Whenstep == 0,startmust equalend.
Error Handling ▼
use vector_ta::indicators::l2_ehlers_signal_to_noise::L2EhlersSignalToNoiseError;
// Common errors:
// - EmptyInputData
// - AllValuesNaN
// - InconsistentSliceLengths
// - InvalidSmoothPeriod
// - NotEnoughValidData
// - OutputLengthMismatch
// - InvalidRange
// - InvalidKernelForBatch Python Bindings
Basic Usage ▼
The Python scalar function returns one NumPy array:
import numpy as np
from vector_ta import l2_ehlers_signal_to_noise
values = l2_ehlers_signal_to_noise(
source,
high,
low,
smooth_period=10,
kernel="auto",
)
print(values.shape) Streaming Real-time Updates ▼
The Python stream wrapper also returns a raw float each update:
from vector_ta import L2EhlersSignalToNoiseStream
stream = L2EhlersSignalToNoiseStream(smooth_period=10)
for src, hi, lo in live_points:
value = stream.update(src, hi, lo)
if np.isfinite(value):
print(value) Batch Processing ▼
Batch output keys are values, smooth_periods, rows, and cols:
from vector_ta import l2_ehlers_signal_to_noise_batch
result = l2_ehlers_signal_to_noise_batch(
source,
high,
low,
smooth_period_range=(10, 20, 5),
kernel="auto",
)
values = result["values"]
smooth_periods = result["smooth_periods"]
rows = result["rows"]
cols = result["cols"] JavaScript/WASM Bindings
Basic Usage ▼
The scalar WASM export returns a single Float64Array:
import { l2_ehlers_signal_to_noise_js } from 'vectorta-wasm';
const values = l2_ehlers_signal_to_noise_js(source, high, low, 10);
console.log(values); Host Buffer API ▼
The low-level API writes one output array of length len:
import {
l2_ehlers_signal_to_noise_alloc,
l2_ehlers_signal_to_noise_free,
l2_ehlers_signal_to_noise_into,
} from 'vectorta-wasm';
const ptr = l2_ehlers_signal_to_noise_alloc(source.length);
try {
l2_ehlers_signal_to_noise_into(sourcePtr, highPtr, lowPtr, ptr, source.length, 10);
} finally {
l2_ehlers_signal_to_noise_free(ptr, source.length);
} Batch Processing ▼
The JS batch config must provide smooth_period_range as a 3-element array:
import { l2_ehlers_signal_to_noise_batch_js } from 'vectorta-wasm';
const batch = l2_ehlers_signal_to_noise_batch_js(source, high, low, {
smooth_period_range: [10, 20, 5],
}) as {
values: number[];
combos: Array<{ smooth_period?: number }>;
rows: number;
cols: number;
};
console.log(batch.rows, batch.cols);
console.log(batch.combos); 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)