Relative Strength Index (RSI)

Parameters: 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 vectorta::indicators::rsi::{rsi, RsiInput, RsiParams};
use vectorta::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 > 0 and period ≤ len(data); otherwise RsiError::InvalidPeriod.
  • If all inputs are NaN, returns RsiError::AllValuesNaN.
  • Must have at least period valid values after the first finite input; else RsiError::NotEnoughValidData.
  • Warmup: indices before first + period are NaN; the first non-NaN is at first + period.
  • If AvgGain + AvgLoss == 0 at any step, RSI is 50.0.
  • rsi_into_slice requires dst.len() == data.len(), otherwise RsiError::LengthMismatch.
  • Batch requires a batch kernel; otherwise RsiError::UnsupportedKernel.
Error Handling
use vectorta::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 vectorta 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 vectorta 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 vectorta 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 support for RSI is currently under development. The API will follow the same pattern as other CUDA-enabled indicators.

# Coming soon: CUDA-accelerated RSI batch operations
# Patterns will mirror other CUDA-enabled indicators in this project.

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);

Performance Analysis

Comparison:
View:

Across sizes, Rust CPU runs about 2.98× faster than Tulip C in this benchmark.

Loading chart...

AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05

Related Indicators