Rate of Change Ratio (ROCR)
period = 10 Overview
The Rate of Change Ratio (ROCR) presents momentum as a simple price ratio centered at 1.0, dividing the current value by the value from n periods earlier. This multiplicative perspective differs from additive ROC and fractional ROCP by showing relative price relationships directly. When ROCR equals 1.0, prices are unchanged over the lookback window; values above 1.0 indicate cumulative gains, and values below 1.0 reflect losses. For example, a ROCR of 1.08 means current price is 8% higher than n periods ago, while 0.95 indicates a 5% decline. This ratio format proves particularly useful for compounding calculations and geometric mean computations in quantitative strategies. Traders monitor ROCR for trend strength assessment, with sustained readings above 1.0 confirming uptrends and readings below 1.0 validating downtrends. The implementation returns 0.0 when encountering zero or NaN in the historical lookback, preventing division errors while maintaining a valid numeric output series. The default 10-period window provides a practical balance between short term noise and meaningful momentum measurement.
Implementation Examples
Get started with ROCR in just a few lines:
use vectorta::indicators::rocr::{rocr, RocrInput, RocrParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// Using with price data slice
let prices = vec![100.0, 102.0, 101.5, 103.0, 105.0, 104.5];
let params = RocrParams { period: Some(10) }; // default = 10
let input = RocrInput::from_slice(&prices, params);
let result = rocr(&input)?;
// Using with Candles data structure (defaults: period=10; source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = RocrInput::with_default_candles(&candles);
let result = rocr(&input)?;
// Access the ROCR values (centered at 1.0)
for value in result.values {
println!("ROCR: {}", value);
} API Reference
Input Methods ▼
// From price slice
RocrInput::from_slice(&[f64], RocrParams) -> RocrInput
// From candles with custom source
RocrInput::from_candles(&Candles, &str, RocrParams) -> RocrInput
// From candles with default params (close prices, period=10)
RocrInput::with_default_candles(&Candles) -> RocrInput Parameters Structure ▼
pub struct RocrParams {
pub period: Option<usize>, // Default: 10
} Output Structure ▼
pub struct RocrOutput {
pub values: Vec<f64>, // ROCR values (centered at 1.0; 0.0 when past==0 or NaN)
} Validation, Warmup & NaNs ▼
period > 0andperiod ≤ len(data); elseRocrError::InvalidPeriod.- There must be at least
periodvalid points after the first finite value; otherwiseRocrError::NotEnoughValidData. - If all values are NaN:
RocrError::AllValuesNaN. Empty input:RocrError::EmptyData. - Warmup: indices before
first_non_nan + periodare set toNaN. - Division edge case: when the past value is
0.0orNaN, the output at that index is0.0.
Error Handling ▼
use vectorta::indicators::rocr::RocrError;
match rocr(&input) {
Ok(output) => process_results(output.values),
Err(RocrError::EmptyData) =>
println!("Input data is empty"),
Err(RocrError::InvalidPeriod { period, data_len }) =>
println!("Invalid period {} for data length {}", period, data_len),
Err(RocrError::NotEnoughValidData { needed, valid }) =>
println!("Need {} data points, only {} valid after first non-NaN", needed, valid),
Err(RocrError::AllValuesNaN) =>
println!("All input values are NaN"),
} Python Bindings
Basic Usage ▼
Calculate ROCR using NumPy arrays (default period = 10):
import numpy as np
from vectorta import rocr
# Prepare price data as NumPy array
prices = np.array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5])
# Calculate ROCR with defaults (period=10)
result = rocr(prices)
# Or specify custom parameters
result = rocr(prices, period=14)
# Optionally specify kernel ("auto", "scalar", "avx2", "avx512")
result = rocr(prices, period=10, kernel="auto")
# Result is a NumPy array matching input length
print(f"ROCR values: {result}") Streaming Real-time Updates ▼
Process real-time price updates efficiently:
from vectorta import RocrStream
# Initialize streaming ROCR calculator
stream = RocrStream(period=10)
# Process real-time price updates
for price in price_feed:
rocr_value = stream.update(price)
if rocr_value is not None:
# ROCR value is ready (None during warmup period)
print(f"Current ROCR: {rocr_value}") Batch Parameter Optimization ▼
Test multiple period values for optimization:
import numpy as np
from vectorta import rocr_batch
# Your price data
prices = np.array([...]) # Your historical prices
# Define period range to test: (start, end, step)
period_range = (5, 20, 5) # Test: 5, 10, 15, 20
# Run batch calculation
results = rocr_batch(
prices,
period_range=period_range,
kernel="auto" # Auto-select best kernel
)
# Access results
print(f"Values shape: {results['values'].shape}") # (num_combinations, len(prices))
print(f"Periods tested: {results['periods']}") CUDA Acceleration ▼
CUDA support for ROCR is currently under development. The API will follow the same pattern as other CUDA-enabled indicators.
# Coming soon: CUDA-accelerated ROCR calculations JavaScript/WASM Bindings
Basic Usage ▼
Calculate ROCR in JavaScript/TypeScript:
import { rocr_js } from 'vectorta-wasm';
// Price data as Float64Array or regular array
const prices = new Float64Array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5]);
// Calculate ROCR with specified period
const result = rocr_js(prices, 10); // period=10
// Result is a Float64Array
console.log('ROCR values:', result); Memory-Efficient Operations ▼
Use zero-copy operations for better performance with large datasets:
import { rocr_alloc, rocr_free, rocr_into, memory } from 'vectorta-wasm';
// Prepare your price data
const prices = new Float64Array([/* your data */]);
const length = prices.length;
// Allocate WASM memory for input and output
const inPtr = rocr_alloc(length);
const outPtr = rocr_alloc(length);
// Copy input data into WASM memory
new Float64Array(memory.buffer, inPtr, length).set(prices);
// Calculate ROCR directly into allocated memory
// Args: in_ptr, out_ptr, len, period
rocr_into(inPtr, outPtr, length, 10);
// Read results from WASM memory (slice() to copy out)
const rocrValues = new Float64Array(memory.buffer, outPtr, length).slice();
// Free allocated memory when done
rocr_free(inPtr, length);
rocr_free(outPtr, length);
console.log('ROCR values:', rocrValues); Batch Processing ▼
Test multiple period values efficiently:
import { rocr_batch } from 'vectorta-wasm';
// Your price data
const prices = new Float64Array([/* historical prices */]);
// Define parameter sweep ranges via config object
const config = { period_range: [5, 20, 5] }; // start, end, step
// Calculate all combinations
const results = rocr_batch(prices, config);
// results = { values: Float64Array (flattened), combos: RocrParams[], rows, cols }
console.log('Rows (num combos):', results.rows);
console.log('Cols (series length):', results.cols); Performance Analysis
Across sizes, Rust CPU runs about 7.42× faster than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05