Andean Oscillator

Parameters: length = 50 | signal_length = 9

Overview

The Andean Oscillator is a two-sided pressure study built from open and close rather than high and low. It recursively tracks rising and falling envelopes, converts those envelopes into bullish and bearish dispersion measures, and then smooths the stronger side into a signal line. That gives you separate bull and bear components instead of compressing both sides into one zero-centered oscillator.

In practice, the bull series expands when upward pressure dominates the evolving envelope structure, the bear series expands when downward pressure dominates, and the signal line follows whichever side is stronger at the moment. Because the implementation initializes from the first valid open/close pair and immediately begins the recursive process, the earliest finite bars are usable but still represent the least-settled part of the series.

Defaults: Andean Oscillator uses `length = 50` and `signal_length = 9`.

Implementation Examples

Compute the oscillator from open/close slices or from a candle container.

use vector_ta::indicators::andean_oscillator::{
    andean_oscillator,
    AndeanOscillatorInput,
    AndeanOscillatorParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

let open = vec![100.0, 101.2, 102.0, 101.4, 103.3, 104.0];
let close = vec![100.8, 102.1, 101.5, 102.7, 104.1, 103.6];

let output = andean_oscillator(&AndeanOscillatorInput::from_slices(
    &open,
    &close,
    AndeanOscillatorParams {
        length: Some(50),
        signal_length: Some(9),
    },
))?;

let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_output = andean_oscillator(
    &AndeanOscillatorInput::with_default_candles(&candles)
)?;

println!("Latest bull: {:?}", output.bull.last());
println!("Latest bear: {:?}", output.bear.last());
println!("Latest signal: {:?}", candle_output.signal.last());

API Reference

Input Methods
// From candles
AndeanOscillatorInput::from_candles(&Candles, AndeanOscillatorParams)
    -> AndeanOscillatorInput

// From open/close slices
AndeanOscillatorInput::from_slices(&[f64], &[f64], AndeanOscillatorParams)
    -> AndeanOscillatorInput

// From candles with default parameters
AndeanOscillatorInput::with_default_candles(&Candles)
    -> AndeanOscillatorInput
Parameters Structure
pub struct AndeanOscillatorParams {
    pub length: Option<usize>,        // default 50
    pub signal_length: Option<usize>, // default 9
}
Output Structure
pub struct AndeanOscillatorOutput {
    pub bull: Vec<f64>,
    pub bear: Vec<f64>,
    pub signal: Vec<f64>,
}
Validation, Warmup & NaNs
  • open.len() == close.len(); otherwise the function returns LengthMismatch.
  • Empty input returns EmptyInputData. If every open/close pair is non-finite, the function returns AllValuesNaN.
  • length and signal_length must both be greater than zero.
  • Leading non-finite pairs are preserved as NaN in the output. Once the first valid pair is reached, the recursive state initializes and the first finite bull, bear, and signal values are emitted immediately.
  • Batch range expansion requires valid ascending integer ranges. Invalid batch kernels return InvalidKernelForBatch.
Builder, Streaming & Batch APIs
// Builder
AndeanOscillatorBuilder::new()
    .length(usize)
    .signal_length(usize)
    .kernel(Kernel)
    .apply_slices(&[f64], &[f64])

AndeanOscillatorBuilder::new()
    .apply(&Candles)

AndeanOscillatorBuilder::new()
    .into_stream()

// Stream
AndeanOscillatorStream::try_new(AndeanOscillatorParams)
AndeanOscillatorStream::update(open, close) -> (f64, f64, f64)

// Batch
AndeanOscillatorBatchBuilder::new()
    .length_range((usize, usize, usize))
    .signal_length_range((usize, usize, usize))
    .kernel(Kernel)
    .apply_slices(&[f64], &[f64])
Error Handling
pub enum AndeanOscillatorError {
    EmptyInputData,
    LengthMismatch { open_len: usize, close_len: usize },
    AllValuesNaN,
    InvalidLength { length: usize },
    InvalidSignalLength { signal_length: usize },
    OutputLengthMismatch { expected: usize, got: usize },
    InvalidRange { start: String, end: String, step: String },
    InvalidKernelForBatch(Kernel),
}

Python Bindings

Python exposes a dictionary-returning single-run function, a streaming class, and a batch function. The single-run binding returns NumPy arrays for bull, bear, and signal. Batch returns 2D matrices for each output plus the length axes and matrix shape metadata.

import numpy as np
from vector_ta import (
    andean_oscillator,
    andean_oscillator_batch,
    AndeanOscillatorStream,
)

open_ = np.asarray(open_values, dtype=np.float64)
close = np.asarray(close_values, dtype=np.float64)

result = andean_oscillator(
    open_,
    close,
    length=50,
    signal_length=9,
    kernel="auto",
)

print(result["bull"][-1], result["bear"][-1], result["signal"][-1])

batch = andean_oscillator_batch(
    open_,
    close,
    length_range=(34, 50, 8),
    signal_length_range=(7, 11, 2),
    kernel="auto",
)

stream = AndeanOscillatorStream(50, 9)
print(stream.update(open_[-1], close[-1]))

JavaScript/WASM Bindings

The WASM wrapper exposes object-returning single-run and batch functions plus lower-level allocation and in-place APIs. The high-level JavaScript path takes open and close typed arrays, then returns bull, bear, and signal arrays. Batch accepts two three-element ranges in its config object and returns flattened output buffers along with the parameter lists and final shape.

import init, {
  andean_oscillator_js,
  andean_oscillator_batch_js,
} from "/pkg/vector_ta.js";

await init();

const open = new Float64Array(openValues);
const close = new Float64Array(closeValues);

const result = andean_oscillator_js(open, close, 50, 9);
console.log(result.bull.at(-1), result.bear.at(-1), result.signal.at(-1));

const batch = andean_oscillator_batch_js(open, close, {
  length_range: [34, 50, 8],
  signal_length_range: [7, 11, 2],
});

console.log(batch.rows, batch.cols, batch.lengths, batch.signal_lengths);

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