Aroon Oscillator

Parameters: length = 14

Overview

The Aroon Oscillator simplifies trend analysis by combining Aroon Up and Aroon Down into a single line that oscillates between -100 and +100, calculated as Aroon Up minus Aroon Down. Positive values emerge when recent highs occur more frequently than recent lows, signaling upward momentum with strength proportional to the distance from zero. Conversely, negative readings indicate bearish conditions where new lows dominate the lookback window. The oscillator reaches extreme values near +100 when price consistently makes new highs while avoiding new lows, confirming powerful uptrends worth riding. Zero line crosses provide clear trend change signals without the ambiguity of watching two separate lines converge. Traders use the Aroon Oscillator to filter trades by only taking long positions above zero and shorts below, while avoiding sideways markets when the oscillator fluctuates near zero. The time calculation makes it particularly effective for catching trends early, as it reacts to the frequency of new extremes rather than waiting for price distance confirmations.

Implementation Examples

Get started with the Aroon Oscillator in just a few lines:

use vectorta::indicators::aroonosc::{aroon_osc, AroonOscInput, AroonOscParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};

// High/low slices must be the same length
let high = vec![
    101.2, 102.4, 103.8, 104.6, 105.3, 106.1, 107.0, 106.2,
    105.5, 106.8, 107.9, 108.4, 109.1, 108.6, 107.8, 108.9
];
let low = vec![
    99.7, 100.5, 101.4, 102.1, 103.0, 104.2, 104.9, 104.0,
    103.2, 104.6, 105.7, 106.3, 107.1, 106.4, 105.6, 106.8
];

let params = AroonOscParams { length: Some(14) };
let input = AroonOscInput::from_slices_hl(&high, &low, params);
let output = aroon_osc(&input)?;

// Access the oscillator values
for (idx, value) in output.values.iter().enumerate() {
    println!("{idx}: {value}");
}

// Using Candles with defaults (length = 14)
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = AroonOscInput::with_default_candles(&candles);
let output = aroon_osc(&input)?;

API Reference

Input Methods
// From parallel high/low slices
AroonOscInput::from_slices_hl(&[f64], &[f64], AroonOscParams) -> AroonOscInput

// From Candles (uses high/low columns internally)
AroonOscInput::from_candles(&Candles, AroonOscParams) -> AroonOscInput

// Convenience with default params (length = 14)
AroonOscInput::with_default_candles(&Candles) -> AroonOscInput
Parameters Structure
pub struct AroonOscParams {
    pub length: Option<usize>, // Default: 14
}
Output Structure
pub struct AroonOscOutput {
    pub values: Vec<f64>, // Oscillator values in [-100, 100]
}
Validation, Warmup & NaNs
  • length > 0 else AroonOscError::InvalidLength.
  • Inputs must be same length; otherwise AroonOscError::MismatchedArrayLengths.
  • Requires at least length + 1 valid points after the first finite high/low; otherwise AroonOscError::NotEnoughData.
  • Warmup: indices [0 .. first + length) are NaN. First finite output occurs at first + length.
  • Range guarantee: oscillator values are clamped to [-100, 100].
  • Streaming: AroonOscStream::update returns None until the window fills, then Some(value) thereafter.
Error Handling
use vectorta::indicators::aroonosc::AroonOscError;

match aroon_osc(&input) {
    Ok(output) => process(output.values),
    Err(AroonOscError::InvalidLength { length }) =>
        eprintln!("length must be > 0, got {length}"),
    Err(AroonOscError::MismatchedArrayLengths { high_len, low_len }) =>
        eprintln!("high/low slices differ: {high_len} vs {low_len}"),
    Err(AroonOscError::NotEnoughData { required, found }) =>
        eprintln!("need {required} observations after warmup, but only {found}"),
    Err(AroonOscError::EmptyData) =>
        eprintln!("no data available (empty or all non-finite)"),
    Err(AroonOscError::InvalidKernel) =>
        eprintln!("invalid or non-batch kernel for batch call"),
    Err(AroonOscError::InvalidOutputLen { expected, got }) =>
        eprintln!("output slice length mismatch: expected {expected}, got {got}"),
    Err(e) => eprintln!("Aroon Oscillator failed: {e}"),
}
CUDA Acceleration

CUDA support for Aroon Oscillator is currently under development. The API will follow the same pattern as other CUDA-enabled indicators.

# Coming soon: CUDA-accelerated Aroon Oscillator
# Planned batch API will mirror other indicators in this library.

Python Bindings

Python bindings coming soon.

JavaScript/WASM Bindings

Basic Usage

Compute the oscillator from browser or Node.js environments:

import { aroonosc_js } from 'vectorta-wasm';

const high = new Float64Array([/* recent highs */]);
const low = new Float64Array([/* matching lows */]);

// length defaults to 14 if omitted
const values = aroonosc_js(high, low, 20);
console.log('Aroon Oscillator values:', values);
Memory-Efficient Operations

Use the zero-copy helpers when integrating with WebAssembly memory directly:

import { aroonosc_alloc, aroonosc_free, aroonosc_into, memory } from 'vectorta-wasm';

const high = new Float64Array([/* highs */]);
const low = new Float64Array([/* lows */]);
const length = high.length;

const highPtr = aroonosc_alloc(length);
const lowPtr = aroonosc_alloc(length);
const outPtr = aroonosc_alloc(length);

const highView = new Float64Array(memory.buffer, highPtr, length);
const lowView = new Float64Array(memory.buffer, lowPtr, length);
highView.set(high);
lowView.set(low);

aroonosc_into(
  highPtr,  // input high pointer
  lowPtr,   // input low pointer
  outPtr,   // output pointer
  length,   // number of samples
  14        // length parameter
);

const result = new Float64Array(memory.buffer, outPtr, length);
console.log(result);

// Free allocations when finished
aroonosc_free(highPtr, length);
aroonosc_free(lowPtr, length);
aroonosc_free(outPtr, length);
Batch Processing

Evaluate multiple length windows without leaving WASM:

import {
  aroonosc_batch_js,
  aroonosc_batch_metadata_js,
  aroonosc_batch as aroonosc_batch_unified
} from 'vectorta-wasm';

const high = new Float64Array([/* highs */]);
const low = new Float64Array([/* lows */]);

// Legacy flat-array batch helpers
const metadata = aroonosc_batch_metadata_js(10, 40, 5); // [10, 15, 20, 25, 30, 35, 40]
const flatResults = aroonosc_batch_js(high, low, 10, 40, 5);

// Structured API returning values + metadata together
const config = { length_range: [10, 40, 5] };
const { values, combos, rows, cols } = aroonosc_batch_unified(high, low, config);

console.log('rows x cols:', rows, cols);
console.log('first combo length:', combos[0].length);

Performance Analysis

Comparison:
View:

Across sizes, Rust CPU runs about 1.08× slower than Tulip C in this benchmark.

Loading chart...

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

CUDA note

In our benchmark workload, the Rust CPU implementation is faster than CUDA for this indicator. Prefer the Rust/CPU path unless your workload differs.

Related Indicators