Momentum Ratio Oscillator

Parameters: source = close | period = 50

Overview

Momentum Ratio Oscillator operates on a single source series. For each valid bar it updates an EMA, compares that EMA to the previous EMA, and treats the ratio differently depending on whether it is below or above 1.0. Those lower and upper ratio components are smoothed again and combined into the final line value with 2 * ratioa / (ratioa + ratiob * emaa) - 1 when the denominator stays finite and non-zero. The companion signal output is the prior line value, so this implementation exposes both the current oscillator and its one-bar lag.

Defaults: period = 50. Candle helpers and builder candle input default to close.

Implementation Examples

Use explicit slices or the default candle helper on close:

use vector_ta::indicators::momentum_ratio_oscillator::{
    momentum_ratio_oscillator,
    MomentumRatioOscillatorInput,
    MomentumRatioOscillatorParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

let data = vec![100.0, 101.2, 100.8, 102.1, 103.5, 102.9];

let input = MomentumRatioOscillatorInput::from_slice(
    &data,
    MomentumRatioOscillatorParams::default(),
);
let out = momentum_ratio_oscillator(&input)?;

// Default candle helper uses close
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_out = momentum_ratio_oscillator(
    &MomentumRatioOscillatorInput::with_default_candles(&candles),
)?;

println!("{:?}", out.line.last());
println!("{:?}", out.signal.last());

API Reference

Input Methods
// From candles
MomentumRatioOscillatorInput::from_candles(
    &Candles,
    &str,
    MomentumRatioOscillatorParams,
) -> MomentumRatioOscillatorInput

// From a source slice
MomentumRatioOscillatorInput::from_slice(
    &[f64],
    MomentumRatioOscillatorParams,
) -> MomentumRatioOscillatorInput

// Default candles helper
MomentumRatioOscillatorInput::with_default_candles(&Candles)
    -> MomentumRatioOscillatorInput
Parameters and Outputs
pub struct MomentumRatioOscillatorParams {
    pub period: Option<usize>,   // default 50
}

pub struct MomentumRatioOscillatorOutput {
    pub line: Vec<f64>,
    pub signal: Vec<f64>,
}
Builder, Stream, and Batch Surface
MomentumRatioOscillatorBuilder::new()
    .period(usize)
    .source(&str)
    .kernel(Kernel)
    .apply(&Candles) -> Result<MomentumRatioOscillatorOutput, _>

MomentumRatioOscillatorBuilder::new()
    .apply_slice(&[f64]) -> Result<MomentumRatioOscillatorOutput, _>

MomentumRatioOscillatorBuilder::new()
    .into_stream() -> Result<MomentumRatioOscillatorStream, _>

MomentumRatioOscillatorStream::update(value) -> Option<(f64, f64)>
MomentumRatioOscillatorStream::update_reset_on_nan(value) -> Option<(f64, f64)>

MomentumRatioOscillatorBatchBuilder::new()
    .kernel(Kernel)
    .period_range(start, end, step)
    .period_static(period)
    .run_on_slice(&[f64]) -> Result<MomentumRatioOscillatorBatchOutput, _>
Validation, Warmup, and NaNs
  • The input slice must be non-empty and contain at least one finite value.
  • period must be greater than 0 and no larger than the data length.
  • The scalar and batch validators require at least 2 finite values from the first valid bar onward.
  • Scalar warmup prefixes are first_valid + 1 for line and first_valid + 2 for signal.
  • In the slice and batch compute paths, any non-finite source value writes NaN for that index and resets EMA state.
  • The stream also resets on non-finite input and returns None until a new finite oscillator value is available.
  • The first finite stream result can carry signal = NaN because it is the prior line.
Calculation and Batch Output
  • The implementation uses alpha = 2.0 / period for the main EMA and both ratio-side EMA tracks.
  • ratioa is the ratio of the current EMA to the previous EMA.
  • Values of ratioa < 1.0 feed emaa; values of ratioa > 1.0 feed emab.
  • ratiob is ratioa / (ratioa + emab) when that ratio is valid.
  • The published outputs are line = val and signal = previous val.
  • Batch defaults are period = (50, 50, 0).
  • Rust batch output is MomentumRatioOscillatorBatchOutput with flattened line and signal buffers plus combos, rows, and cols.
Error Handling
use vector_ta::indicators::momentum_ratio_oscillator::MomentumRatioOscillatorError;

// Common errors:
// - EmptyInputData
// - AllValuesNaN
// - InvalidPeriod
// - NotEnoughValidData
// - OutputLengthMismatch
// - InvalidRange
// - InvalidKernelForBatch

Python Bindings

Basic Usage

The Python scalar function returns the oscillator line and one-bar signal arrays:

from vector_ta import momentum_ratio_oscillator

line, signal = momentum_ratio_oscillator(
    data,
    period=50,
    kernel="auto",
)
Streaming Real-time Updates

The Python stream wrapper exposes the same per-value update contract:

from vector_ta import MomentumRatioOscillatorStream

stream = MomentumRatioOscillatorStream(period=50)

for value in live_values:
    result = stream.update(value)
    if result is not None:
        line, signal = result
Batch Processing

Python batch returns reshaped output matrices plus the swept period column:

from vector_ta import momentum_ratio_oscillator_batch

result = momentum_ratio_oscillator_batch(
    data,
    period_range=(20, 60, 20),
    kernel="auto",
)

line = result["line"]
signal = result["signal"]
periods = result["periods"]
rows = result["rows"]
cols = result["cols"]

JavaScript/WASM Bindings

Basic Usage

The scalar JS/WASM export returns an object with line and signal arrays:

import { momentum_ratio_oscillator_js } from 'vectorta-wasm';

const result = momentum_ratio_oscillator_js(data, 50) as {
  line: number[];
  signal: number[];
};

console.log(result.line);
console.log(result.signal);
Host Buffer API

Low-level WASM allocates one packed buffer of length len * 2, split into line then signal:

import {
  momentum_ratio_oscillator_alloc,
  momentum_ratio_oscillator_free,
  momentum_ratio_oscillator_into_host,
} from 'vectorta-wasm';

const len = data.length;
const outPtr = momentum_ratio_oscillator_alloc(len);

try {
  momentum_ratio_oscillator_into_host(data, outPtr, 50);
} finally {
  momentum_ratio_oscillator_free(outPtr, len);
}
Batch Processing

The JS batch config takes a 3-element period_range and returns output arrays plus parameter combos:

import { momentum_ratio_oscillator_batch_js } from 'vectorta-wasm';

const batch = momentum_ratio_oscillator_batch_js(data, {
  period_range: [20, 60, 20],
}) as {
  line: number[];
  signal: number[];
  rows: number;
  cols: number;
  combos: Array<{ period?: number }>;
};

console.log(batch.rows, batch.cols);
console.log(batch.combos);

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