Range Oscillator

Parameters: length = 50 | mult = 2

Overview

Range Oscillator starts from a weighted moving center line, measures the largest recent deviation from that line, and then projects upper and lower bands around it using a configurable multiplier. The resulting state bundle does more than show one oscillator value: it also tracks whether price remains inside the active range, which direction the current regime favors, and whether a fresh upside or downside break has occurred.

In VectorTA the indicator returns the oscillator itself, the weighted mean, range width, in-range flag, trend state, and breakout markers. It supports candles or explicit high-low-close slices, streaming updates, and two-axis batch sweeps across both the lookback window and band multiplier.

Defaults: `length = 50` and `mult = 2.0`.

Implementation Examples

Run the indicator from candles or from explicit high, low, and close slices.

use vector_ta::indicators::range_oscillator::{
    range_oscillator,
    RangeOscillatorInput,
    RangeOscillatorParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

let direct = range_oscillator(&RangeOscillatorInput::from_slices(
    &high,
    &low,
    &close,
    RangeOscillatorParams {
        length: Some(50),
        mult: Some(2.0),
    },
))?;

let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let from_candles = range_oscillator(&RangeOscillatorInput::with_default_candles(&candles))?;

println!("osc = {:?}", direct.oscillator.last());
println!("in_range = {:?}", from_candles.in_range.last());

API Reference

Input Methods
RangeOscillatorInput::from_candles(&Candles, RangeOscillatorParams)
    -> RangeOscillatorInput

RangeOscillatorInput::from_slices(&[f64], &[f64], &[f64], RangeOscillatorParams)
    -> RangeOscillatorInput

RangeOscillatorInput::with_default_candles(&Candles)
    -> RangeOscillatorInput
Parameters Structure
pub struct RangeOscillatorParams {
    pub length: Option<usize>, // default 50
    pub mult: Option<f64>,     // default 2.0
}
Output Structure
pub struct RangeOscillatorOutput {
    pub oscillator: Vec<f64>,
    pub ma: Vec<f64>,
    pub upper_band: Vec<f64>,
    pub lower_band: Vec<f64>,
    pub range_width: Vec<f64>,
    pub in_range: Vec<f64>,
    pub trend: Vec<f64>,
    pub break_up: Vec<f64>,
    pub break_down: Vec<f64>,
}
Validation & Warmup
  • High, low, and close arrays must be non-empty, equal in length, and contain at least one valid triple.
  • length must be greater than 0.
  • mult must be finite and at least 0.1.
  • The vector path uses a long warmup driven by the larger of the chosen length and the internal ATR fallback period.
  • Non-finite stream input clears the ATR state, close history, and trend flag, then returns None.
  • Batch mode validates both sweep axes and rejects non-batch kernels.
Builder, Streaming & Batch APIs
RangeOscillatorBuilder::new()
    .length(usize)
    .mult(f64)
    .kernel(Kernel)
    .apply(&Candles)
    .apply_slices(&[f64], &[f64], &[f64])
    .into_stream()

RangeOscillatorStream::try_new(params)
stream.update(high, low, close) -> Option<RangeOscillatorStreamOutput>

RangeOscillatorBatchBuilder::new()
    .range(RangeOscillatorBatchRange)
    .kernel(Kernel)
    .apply(&Candles)
    .apply_slices(&[f64], &[f64], &[f64])

Python Bindings

Python exposes scalar and batch helpers that return dictionaries keyed by each output field, plus a stream class for incremental bar-by-bar updates.

from vector_ta import (
    range_oscillator,
    range_oscillator_batch,
    RangeOscillatorStream,
)

single = range_oscillator(high, low, close, length=50, mult=2.0)

stream = RangeOscillatorStream(length=50, mult=2.0)
point = stream.update(high[-1], low[-1], close[-1])

batch = range_oscillator_batch(
    high,
    low,
    close,
    length_range=(50, 70, 10),
    mult_range=(2.0, 3.0, 0.5),
)

print(single["oscillator"][-1], single["break_up"][-1])
print(batch["rows"], batch["cols"])

JavaScript/WASM Bindings

The WASM layer exposes object-returning scalar and batch helpers that cover every output series in the range state bundle.

import init, {
  range_oscillator_js,
  range_oscillator_batch,
} from "vector-ta-wasm";

await init();

const single = range_oscillator_js(high, low, close, 50, 2.0);

const batch = range_oscillator_batch(high, low, close, {
  length_range: [50, 70, 10],
  mult_range: [2.0, 3.0, 0.5],
});

console.log(single.oscillator, single.break_up, batch.rows);

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