Relative Strength Index (RSI)
period = 14 Overview
The Relative Strength Index (RSI) measures momentum by comparing the magnitude of recent gains to recent losses, oscillating between 0 and 100 to reveal whether bullish or bearish momentum dominates. J. Welles Wilder developed RSI in 1978 using a smoothed ratio of average gains to average losses over 14 periods, with his proprietary smoothing technique that weights recent data more heavily than simple averages. The calculation first separates positive and negative price changes, averages each using Wilder's smoothing method, then transforms the ratio into an oscillator bounded between 0 and 100. Readings above 70 traditionally signal overbought conditions where price has risen too far too fast, while values below 30 indicate oversold territory where selling pressure may have exhausted. Traders watch for divergences between RSI and price as early reversal warnings, such as price making new highs while RSI fails to exceed its previous peak. The 50 level acts as a momentum threshold, with sustained readings above confirming bullish bias and values below suggesting bearish control of the market.
Defaults: period = 14.
Implementation Examples
Get started with RSI in just a few lines:
use vector_ta::indicators::rsi::{rsi, RsiInput, RsiParams};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
// Using with a price slice
let prices = vec![100.0, 102.0, 101.0, 103.0, 104.5, 104.0];
let params = RsiParams { period: Some(14) }; // default is 14
let input = RsiInput::from_slice(&prices, params);
let result = rsi(&input)?;
// Using with Candles (defaults: period=14, source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = RsiInput::with_default_candles(&candles);
let result = rsi(&input)?;
// Access RSI values
for value in result.values {
println!("RSI: {}", value);
} API Reference
Input Methods ▼
// From price slice
RsiInput::from_slice(&[f64], RsiParams) -> RsiInput
// From candles with custom source
RsiInput::from_candles(&Candles, &str, RsiParams) -> RsiInput
// From candles with default params (close, period=14)
RsiInput::with_default_candles(&Candles) -> RsiInput Parameters Structure ▼
pub struct RsiParams {
pub period: Option<usize>, // Default: 14
} Output Structure ▼
pub struct RsiOutput {
pub values: Vec<f64>, // RSI values (0..=100), warmup as NaN
} Validation, Warmup & NaNs ▼
period > 0andperiod ≤ len(data); otherwiseRsiError::InvalidPeriod.- If all inputs are
NaN, returnsRsiError::AllValuesNaN. - Must have at least
periodvalid values after the first finite input; elseRsiError::NotEnoughValidData. - Warmup: indices before
first + periodareNaN; the first non-NaN is atfirst + period. - If
AvgGain + AvgLoss == 0at any step, RSI is50.0. rsi_into_slicerequiresdst.len() == data.len(), otherwiseRsiError::LengthMismatch.- Batch requires a batch kernel; otherwise
RsiError::UnsupportedKernel.
Error Handling ▼
use vector_ta::indicators::rsi::RsiError;
match rsi(&input) {
Ok(output) => process(output.values),
Err(RsiError::EmptyInputData) => println!("Input data is empty"),
Err(RsiError::AllValuesNaN) => println!("All input values are NaN"),
Err(RsiError::InvalidPeriod { period, data_len }) =>
println!("Invalid period {} for length {}", period, data_len),
Err(RsiError::NotEnoughValidData { needed, valid }) =>
println!("Need {} valid points, only {}", needed, valid),
Err(RsiError::LengthMismatch { dst, src }) =>
println!("Destination len {} != source len {}", dst, src),
Err(RsiError::UnsupportedKernel) => println!("Unsupported kernel for batch operation"),
} Python Bindings
Basic Usage ▼
Calculate RSI using NumPy arrays (default period=14):
import numpy as np
from vector_ta import rsi
prices = np.array([100.0, 102.0, 101.0, 103.0, 104.5])
# Default period (14)
values = rsi(prices, period=14)
# Select kernel ("auto", "scalar", "avx2", "avx512") if available on your platform
values = rsi(prices, period=14, kernel="auto")
print(values) Streaming Real-time Updates ▼
from vector_ta import RsiStream
stream = RsiStream(period=14)
for price in price_feed:
rsi_value = stream.update(price)
if rsi_value is not None:
print("RSI:", rsi_value) Batch Parameter Optimization ▼
Test multiple period values efficiently:
import numpy as np
from vector_ta import rsi_batch
prices = np.array([...], dtype=float)
# Define (start, end, step)
period_range = (5, 30, 5) # 5, 10, 15, 20, 25, 30
results = rsi_batch(prices, period_range, kernel="auto")
print(results["values"].shape) # (num_periods, len(prices))
print(results["periods"]) # array of tested periods CUDA Acceleration ▼
CUDA helpers are available when the Python package is built with CUDA support. Inputs must be float32; outputs are device arrays (DLPack / __cuda_array_interface__ compatible).
import numpy as np
from vector_ta import rsi_cuda_batch_dev, rsi_cuda_many_series_one_param_dev
# One series (float32)
data_f32 = np.asarray(load_data(), dtype=np.float32)
dev = rsi_cuda_batch_dev(
data_f32=data_f32,
period_range=(5, 30, 5),
device_id=0,
)
# Many series (time-major)
data_tm_f32 = np.asarray(load_data_time_major_matrix(), dtype=np.float32)
dev_tm = rsi_cuda_many_series_one_param_dev(
data_tm_f32=data_tm_f32,
period=14,
device_id=0,
) JavaScript/WASM Bindings
Basic Usage ▼
Calculate RSI with the WASM module:
import { rsi_js } from 'vectorta-wasm';
const prices = new Float64Array([100.0, 102.0, 101.0, 103.0]);
const values = rsi_js(prices, 14); // period=14
console.log('RSI:', values); Memory-Efficient Operations ▼
Use zero-copy operations for large datasets:
import { rsi_alloc, rsi_free, rsi_into, memory } from 'vectorta-wasm';
const prices = new Float64Array([/* your data */]);
const len = prices.length;
const inPtr = rsi_alloc(len);
const outPtr = rsi_alloc(len);
new Float64Array(memory.buffer, inPtr, len).set(prices);
// Args: in_ptr, out_ptr, len, period
rsi_into(inPtr, outPtr, len, 14);
const out = new Float64Array(memory.buffer, outPtr, len).slice();
rsi_free(inPtr, len);
rsi_free(outPtr, len);
console.log('RSI:', out); Batch Processing ▼
Test multiple period values with a single call:
import { rsi_batch } from 'vectorta-wasm';
const prices = new Float64Array([/* historical prices */]);
// config = { period_range: [start, end, step] }
const config = { period_range: [5, 30, 5] };
const res = rsi_batch(prices, config);
// res = { values: Float64Array, combos: RsiParams[], rows, cols }
// values are flattened row-major: rows=num_combos, cols=prices.length
console.log(res.rows, res.cols, res.combos); CUDA Bindings (Rust)
use vector_ta::cuda::CudaRsi;
use vector_ta::indicators::rsi::RsiBatchRange;
let cuda = CudaRsi::new(0)?;
let prices_f32: [f32] = /* ... */;
let sweep = RsiBatchRange::default();
let out = cuda.rsi_batch_dev(&prices_f32, &sweep)?;
let _ = out; Performance Analysis
Across sizes, Rust CPU runs about 2.98× faster than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-02-28