Relative Strength Xtra (RSX)
period = 14 Overview
Relative Strength Xtra refines the classic RSI calculation by adding multiple stages of exponential smoothing to reduce noise without sacrificing responsiveness to genuine price movements. RSX employs a proprietary chain of weighted filters that progressively smooth the momentum signal, eliminating the choppy behavior that often plagues standard RSI during ranging markets. The calculation maintains the familiar 0 to 100 scale with 50 as the neutral midpoint, but produces cleaner swings that better reflect underlying momentum shifts. Values above 70 suggest strong bullish momentum without the false signals common in traditional RSI, while readings below 30 indicate sustained bearish pressure. The enhanced smoothing makes RSX particularly effective for reducing whipsaw trades in volatile conditions, as the indicator filters out minor fluctuations while still responding quickly to meaningful trend changes. Traders appreciate RSX for generating more reliable divergence signals and producing fewer false overbought or oversold readings during strong trending markets.
Default: period = 14.
Implementation Examples
Compute RSX from a price slice or candles:
use vectorta::indicators::rsx::{rsx, RsxInput, RsxParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// Using a price slice
let prices = vec![100.0, 102.0, 101.5, 103.0, 105.0, 104.5];
let params = RsxParams { period: Some(14) }; // default = 14
let input = RsxInput::from_slice(&prices, params);
let result = rsx(&input)?; // RsxOutput { values: Vec<f64> }
// Using Candles with defaults (period=14; source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = RsxInput::with_default_candles(&candles);
let result = rsx(&input)?;
// Access RSX values
for v in result.values {
println!("RSX: {}", v);
} API Reference
Input Methods ▼
// From price slice
RsxInput::from_slice(&[f64], RsxParams) -> RsxInput
// From candles with custom source
RsxInput::from_candles(&Candles, &str, RsxParams) -> RsxInput
// From candles with default params (close prices, period=14)
RsxInput::with_default_candles(&Candles) -> RsxInput Parameters Structure ▼
#[derive(Debug, Clone)]
pub struct RsxParams {
pub period: Option<usize>, // Default: 14
} Output Structure ▼
#[derive(Debug, Clone)]
pub struct RsxOutput {
pub values: Vec<f64>, // RSX in [0, 100]
} Validation, Warmup & NaNs ▼
period > 0andperiod ≤ data_len; otherwiseRsxError::InvalidPeriod.- Requires at least
periodvalid points after the first finite value; elseRsxError::NotEnoughValidData. - If all inputs are
NaN:RsxError::AllValuesNaN. Empty input yieldsRsxError::EmptyInputData. - Warmup: indices
< first + period − 1are filled withNaN. First valid occurs at that index or next. - Constant data converges to
50.0; general range is[0, 100]. - Slice writer
rsx_into_slicechecks destination length; otherwiseRsxError::SizeMismatch.
Error Handling ▼
use vectorta::indicators::rsx::RsxError;
match rsx(&input) {
Ok(out) => use_values(out.values),
Err(RsxError::EmptyInputData) =>
eprintln!("Input data is empty"),
Err(RsxError::AllValuesNaN) =>
eprintln!("All input values are NaN"),
Err(RsxError::InvalidPeriod { period, data_len }) =>
eprintln!("Invalid period {period} for data length {data_len}"),
Err(RsxError::NotEnoughValidData { needed, valid }) =>
eprintln!("Need {needed} valid points, only {valid} available"),
Err(RsxError::SizeMismatch { dst, src }) =>
eprintln!("Destination len {dst} != source len {src}"),
Err(e) => eprintln!("RSX error: {}", e)
} Python Bindings
Basic Usage ▼
Compute RSX from a NumPy array:
import numpy as np
from vectorta import rsx
prices = np.array([100.0, 102.0, 101.5, 103.0, 105.0], dtype=float)
# period is required; kernel is optional (e.g., "auto", "avx2")
values = rsx(prices, period=14, kernel="auto")
print(values[-3:]) Streaming ▼
from vectorta import RsxStream
stream = RsxStream(period=14)
for price in price_stream:
out = stream.update(price)
if out is not None:
use(out) Batch Parameter Sweep ▼
import numpy as np
from vectorta import rsx_batch
prices = np.asarray([...], dtype=float)
# (start, end, step) for period
res = rsx_batch(prices, (5, 20, 5), kernel="auto")
# res['values'] is a 2D array [rows, len]; res['periods'] lists each row's period
print(res['periods']) CUDA Acceleration ▼
CUDA support for RSX is coming soon.
JavaScript/WASM Bindings
Basic Usage ▼
Calculate RSX from a Float64Array:
import { rsx_js } from 'vectorta-wasm';
const prices = new Float64Array([100, 102, 101.5, 103, 105]);
const values = rsx_js(prices, 14);
console.log(values.slice(-3)); Memory-Efficient Operations ▼
Use zero-copy operations for large datasets:
import { rsx_alloc, rsx_free, rsx_into, memory } from 'vectorta-wasm';
const prices = new Float64Array([/* your data */]);
const n = prices.length;
// Allocate WASM memory for input and output
const inPtr = rsx_alloc(n);
const outPtr = rsx_alloc(n);
// Copy input data into WASM memory
new Float64Array(memory.buffer, inPtr, n).set(prices);
// Compute RSX directly into allocated memory
rsx_into(inPtr, outPtr, n, 14);
// Read results (slice to copy out)
const rsxValues = new Float64Array(memory.buffer, outPtr, n).slice();
// Free when done
rsx_free(inPtr, n);
rsx_free(outPtr, n); Batch Processing ▼
Test multiple period values efficiently:
import { rsx_batch } from 'vectorta-wasm';
const prices = new Float64Array([/* historical prices */]);
// Unified batch API: pass a config object
const res = rsx_batch(prices, { period_range: [5, 20, 5] });
// res: { values: Float64Array, combos: RsxParams[], rows: number, cols: number }
// Extract a row for a specific period
const { values, rows, cols, combos } = res;
const idx = combos.findIndex(c => (c.period ?? 14) === 10);
const row10 = values.slice(idx * cols, (idx + 1) * cols); Performance Analysis
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05
CUDA note
In our benchmark workload, the Rust CPU implementation is faster than CUDA for this indicator. Prefer the Rust/CPU path unless your workload differs.