Absolute Strength Index Oscillator

Parameters: ema_length = 21 | signal_length = 34

Overview

Absolute Strength Index Oscillator tracks directional pressure by separating advancing moves, declining moves, and unchanged bars into running accumulators and collapsing them into a bounded absolute-strength ratio. That ratio is then smoothed with an EMA, and the final oscillator is the distance between the live ratio and its EMA. A second smoothing pass produces the signal line, while the histogram measures the spread between oscillator and signal.

In practice, the oscillator reacts to the balance between persistent advances and declines rather than to price level alone. Positive histogram expansion means the live strength ratio is outrunning its signal, while negative histogram expansion means the directional impulse is cooling. Because the implementation resets on invalid values and starts calculating as soon as the first finite bar appears, this indicator behaves more like a stateful breadth oscillator than a long warmup momentum study.

Defaults: Absolute Strength Index Oscillator uses `ema_length = 21` and `signal_length = 34`.

Implementation Examples

Compute the oscillator from a single source slice or from candle data with a chosen source field.

use vector_ta::indicators::absolute_strength_index_oscillator::{
    absolute_strength_index_oscillator,
    AbsoluteStrengthIndexOscillatorInput,
    AbsoluteStrengthIndexOscillatorParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

let close = vec![100.0, 101.4, 101.1, 102.8, 102.2, 103.6];
let params = AbsoluteStrengthIndexOscillatorParams {
    ema_length: Some(21),
    signal_length: Some(34),
};

let output = absolute_strength_index_oscillator(
    &AbsoluteStrengthIndexOscillatorInput::from_slice(&close, params)
)?;

let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_output = absolute_strength_index_oscillator(
    &AbsoluteStrengthIndexOscillatorInput::from_candles(
        &candles,
        "close",
        AbsoluteStrengthIndexOscillatorParams::default(),
    )
)?;

println!("{:?}", output.oscillator.last());
println!("{:?}", output.signal.last());
println!("{:?}", candle_output.histogram.last());

API Reference

Input Methods
// From candles with explicit source
AbsoluteStrengthIndexOscillatorInput::from_candles(
    &Candles,
    &str,
    AbsoluteStrengthIndexOscillatorParams,
) -> AbsoluteStrengthIndexOscillatorInput

// From a single source slice
AbsoluteStrengthIndexOscillatorInput::from_slice(
    &[f64],
    AbsoluteStrengthIndexOscillatorParams,
) -> AbsoluteStrengthIndexOscillatorInput

// From candles with defaults and close source
AbsoluteStrengthIndexOscillatorInput::with_default_candles(&Candles)
    -> AbsoluteStrengthIndexOscillatorInput
Parameters Structure
pub struct AbsoluteStrengthIndexOscillatorParams {
    pub ema_length: Option<usize>,    // default 21
    pub signal_length: Option<usize>, // default 34
}
Output Structure
pub struct AbsoluteStrengthIndexOscillatorOutput {
    pub oscillator: Vec<f64>,
    pub signal: Vec<f64>,
    pub histogram: Vec<f64>,
}
Validation, Warmup & NaNs
  • The input slice must not be empty, and there must be at least one finite value after any leading NaNs.
  • ema_length and signal_length must both be at least 1; invalid values raise InvalidEmaLength or InvalidSignalLength.
  • Leading invalid values remain NaN in the output. Once the first finite bar appears, the indicator begins producing values immediately.
  • Encountering a non-finite value later resets the running state in streaming mode, so the next valid bar starts a fresh accumulation.
  • Batch mode only accepts batch-capable kernels; otherwise it returns InvalidKernelForBatch.
Builder, Streaming & Batch APIs
// Builder
AbsoluteStrengthIndexOscillatorBuilder::new()
    .ema_length(usize)
    .signal_length(usize)
    .kernel(Kernel)
    .apply_slice(&[f64])

AbsoluteStrengthIndexOscillatorBuilder::new()
    .apply(&Candles, &str)

AbsoluteStrengthIndexOscillatorBuilder::new()
    .into_stream()

// Stream
AbsoluteStrengthIndexOscillatorStream::try_new(AbsoluteStrengthIndexOscillatorParams)
AbsoluteStrengthIndexOscillatorStream::update(f64)
    -> Option<(f64, f64, f64)>

// Batch
AbsoluteStrengthIndexOscillatorBatchBuilder::new()
    .ema_length_range(start, end, step)
    .signal_length_range(start, end, step)
    .kernel(Kernel)
    .apply_slice(&[f64])
Error Handling
pub enum AbsoluteStrengthIndexOscillatorError {
    EmptyInputData,
    AllValuesNaN,
    InvalidEmaLength { ema_length: usize },
    InvalidSignalLength { signal_length: usize },
    OutputLengthMismatch { expected: usize, oscillator_got: usize, signal_got: usize, histogram_got: usize },
    InvalidRange { start: String, end: String, step: String },
    InvalidKernelForBatch(Kernel),
}

Python Bindings

Python exposes a single-run function, a batch function, and a streaming class. The single-run call returns three NumPy arrays as a tuple. Batch returns a dictionary with 2D oscillator, signal, and histogram arrays plus the swept EMA and signal lengths. The streaming class returns a three-value tuple on each valid update and exposes a zero warmup period.

import numpy as np
from vector_ta import (
    absolute_strength_index_oscillator,
    absolute_strength_index_oscillator_batch,
    AbsoluteStrengthIndexOscillatorStream,
)

data = np.asarray(close_values, dtype=np.float64)

oscillator, signal, histogram = absolute_strength_index_oscillator(
    data,
    ema_length=21,
    signal_length=34,
    kernel="auto",
)

batch = absolute_strength_index_oscillator_batch(
    data,
    ema_length_range=(14, 28, 7),
    signal_length_range=(20, 40, 10),
    kernel="auto",
)

stream = AbsoluteStrengthIndexOscillatorStream(21, 34)
bar = stream.update(float(data[-1]))

JavaScript/WASM Bindings

The WASM layer exposes object-returning and pointer-oriented entry points. The normal JS call returns three typed arrays named oscillator, signal, and histogram. Batch returns those same families as flattened arrays plus combos, rows, and cols.

import init, {
  absolute_strength_index_oscillator_js,
  absolute_strength_index_oscillator_batch_js,
} from "/pkg/vector_ta.js";

await init();

const data = new Float64Array(closeValues);

const out = absolute_strength_index_oscillator_js(data, 21, 34);
console.log(out.oscillator.at(-1), out.signal.at(-1), out.histogram.at(-1));

const batch = absolute_strength_index_oscillator_batch_js(data, {
  ema_length_range: [14, 28, 7],
  signal_length_range: [20, 40, 10],
});

console.log(batch.rows, batch.cols, batch.oscillator.slice(0, batch.cols));

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