Ehlers Data Sampling Relative Strength Indicator
length = 14 Overview
Ehlers Data Sampling Relative Strength Indicator takes the usual RSI idea and applies it to two slightly different price streams. The first output is the normal RSI of close. The second output is an RSI built from the midpoint of open and close for each bar, which effectively samples the bar differently and can change how quickly short-term momentum shifts appear in the oscillator.
The third output is not another RSI line. It is a discrete signal state derived from the slope of the midpoint
RSI. Positive acceleration states are encoded as 1 or 2, negative acceleration states
as -1 or -2, and flat transitions as 0. That gives the indicator both a
side-by-side comparison between the original and sampled RSI readings and a compact regime label for whether the
sampled RSI is strengthening or weakening.
Defaults: Ehlers Data Sampling Relative Strength Indicator uses `length = 14` and reads candle `open` plus `close`.
Implementation Examples
Compute the midpoint RSI, the original close RSI, and the discrete signal state from open/close data.
use vector_ta::indicators::ehlers_data_sampling_relative_strength_indicator::{
ehlers_data_sampling_relative_strength_indicator,
EhlersDataSamplingRelativeStrengthIndicatorInput,
EhlersDataSamplingRelativeStrengthIndicatorParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
let output = ehlers_data_sampling_relative_strength_indicator(
&EhlersDataSamplingRelativeStrengthIndicatorInput::from_slices(
&open,
&close,
EhlersDataSamplingRelativeStrengthIndicatorParams { length: Some(14) },
)
)?;
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_output = ehlers_data_sampling_relative_strength_indicator(
&EhlersDataSamplingRelativeStrengthIndicatorInput::with_default_candles(&candles)
)?;
println!("ds_rsi = {:?}", output.ds_rsi.last());
println!("original_rsi = {:?}", output.original_rsi.last());
println!("signal = {:?}", candle_output.signal.last()); API Reference
Input Methods ▼
// From candles
EhlersDataSamplingRelativeStrengthIndicatorInput::from_candles(
&Candles,
EhlersDataSamplingRelativeStrengthIndicatorParams,
) -> EhlersDataSamplingRelativeStrengthIndicatorInput
// From open/close slices
EhlersDataSamplingRelativeStrengthIndicatorInput::from_slices(
&[f64],
&[f64],
EhlersDataSamplingRelativeStrengthIndicatorParams,
) -> EhlersDataSamplingRelativeStrengthIndicatorInput
// From candles with default parameters
EhlersDataSamplingRelativeStrengthIndicatorInput::with_default_candles(&Candles)
-> EhlersDataSamplingRelativeStrengthIndicatorInput Parameters Structure ▼
pub struct EhlersDataSamplingRelativeStrengthIndicatorParams {
pub length: Option<usize>, // default 14
} Output Structure ▼
pub struct EhlersDataSamplingRelativeStrengthIndicatorOutput {
pub ds_rsi: Vec<f64>,
pub original_rsi: Vec<f64>,
pub signal: Vec<f64>,
} Validation, Warmup & NaNs ▼
- Open and close inputs must both be non-empty and have identical lengths.
lengthmust be greater than zero and no larger than the input length.- The longest contiguous run where both open and close are finite must be at least
lengthbars. - Warmup lasts for
lengthbars in the streaming API. - Streaming resets on non-finite open or close input and returns
Noneuntil all three outputs become finite again. - The signal output is a discrete state derived from the slope of
ds_rsi, not a separate RSI calculation. - Batch mode rejects invalid integer ranges and unsupported kernels.
Builder, Streaming & Batch APIs ▼
// Builder
EhlersDataSamplingRelativeStrengthIndicatorBuilder::new()
.length(usize)
.kernel(Kernel)
.apply_slices(&[f64], &[f64])
EhlersDataSamplingRelativeStrengthIndicatorBuilder::new()
.apply(&Candles)
EhlersDataSamplingRelativeStrengthIndicatorBuilder::new()
.into_stream()
// Stream
EhlersDataSamplingRelativeStrengthIndicatorStream::try_new(
EhlersDataSamplingRelativeStrengthIndicatorParams
)
EhlersDataSamplingRelativeStrengthIndicatorStream::update(open: f64, close: f64)
-> Option<(f64, f64, f64)>
EhlersDataSamplingRelativeStrengthIndicatorStream::reset()
EhlersDataSamplingRelativeStrengthIndicatorStream::get_warmup_period() -> usize
// Batch
EhlersDataSamplingRelativeStrengthIndicatorBatchBuilder::new()
.length_range(start, end, step)
.length_static(usize)
.kernel(Kernel)
.apply_slices(&[f64], &[f64])
EhlersDataSamplingRelativeStrengthIndicatorBatchBuilder::new()
.apply_candles(&Candles) Error Handling ▼
pub enum EhlersDataSamplingRelativeStrengthIndicatorError {
EmptyInputData,
InputLengthMismatch { open_len: usize, close_len: usize },
AllValuesNaN,
InvalidLength { length: usize, data_len: 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 },
} Python Bindings
Python exposes a three-array single-run function, a streaming class, and a batch function. The single-run binding returns the midpoint RSI array, the original close RSI array, and the discrete signal array. Batch returns matrices for all three outputs plus the tested lengths and the rows and cols shape.
import numpy as np
from vector_ta import (
ehlers_data_sampling_relative_strength_indicator,
ehlers_data_sampling_relative_strength_indicator_batch,
EhlersDataSamplingRelativeStrengthIndicatorStream,
)
open_ = np.asarray(open_values, dtype=np.float64)
close = np.asarray(close_values, dtype=np.float64)
ds_rsi, original_rsi, signal = ehlers_data_sampling_relative_strength_indicator(
open_,
close,
length=14,
kernel="auto",
)
stream = EhlersDataSamplingRelativeStrengthIndicatorStream(length=14)
print(stream.update(open_[-1], close[-1]))
batch = ehlers_data_sampling_relative_strength_indicator_batch(
open_,
close,
length_range=(10, 20, 5),
kernel="auto",
)
print(batch["lengths"], batch["rows"], batch["cols"]) JavaScript/WASM Bindings
The WASM layer exposes an object-returning single-run wrapper, a batch wrapper, and pointer-oriented in-place
helpers. The single-run helper returns named ds_rsi, original_rsi, and
signal arrays. The batch wrapper adds rows, cols, and combos.
import init, {
ehlers_data_sampling_relative_strength_indicator_js,
ehlers_data_sampling_relative_strength_indicator_batch_js,
} from "/pkg/vector_ta.js";
await init();
const open_ = new Float64Array(openValues);
const close = new Float64Array(closeValues);
const single = ehlers_data_sampling_relative_strength_indicator_js(open_, close, 14);
console.log(single.ds_rsi, single.original_rsi, single.signal);
const batch = ehlers_data_sampling_relative_strength_indicator_batch_js(open_, close, {
length_range: [10, 20, 5],
});
console.log(batch.ds_rsi, batch.original_rsi, batch.signal, 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)