Ehlers Data Sampling Relative Strength Indicator

Parameters: 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.
  • length must 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 length bars.
  • Warmup lasts for length bars in the streaming API.
  • Streaming resets on non-finite open or close input and returns None until 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

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