Monotonicity Index
length = 20 | mode = efficiency | index_smooth = 5 Overview
Monotonicity Index evaluates each rolling window by fitting both a non-decreasing and a non-increasing
monotone shape with PAVA and choosing the fit with lower mean squared error. In
efficiency mode, the raw score is the fitted start-to-end move divided by the total absolute price
path, scaled to 0..100. In complexity mode, the raw score is the number of fitted pool
transitions relative to the maximum possible transitions, also scaled to 0..100.
The raw score is then smoothed with an SMA of length index_smooth. The indicator returns the
smoothed index, a running cumulative_mean of that smoothed index, and an
upper_bound equal to cumulative_mean * 2.0. Candle-based input defaults to the
close source.
Defaults: length = 20, mode = "efficiency",
index_smooth = 5, candle source default close.
Implementation Examples
Compute the indicator from a slice or from candle data using the default source:
use vector_ta::indicators::monotonicity_index::{
monotonicity_index,
MonotonicityIndexInput,
MonotonicityIndexMode,
MonotonicityIndexParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
let data = vec![101.0, 102.0, 103.0, 102.8, 103.5, 104.2, 105.0];
let input = MonotonicityIndexInput::from_slice(
&data,
MonotonicityIndexParams {
length: Some(20),
mode: Some(MonotonicityIndexMode::Efficiency),
index_smooth: Some(5),
},
);
let result = monotonicity_index(&input)?;
println!("{:?}", result.index.last());
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = MonotonicityIndexInput::with_default_candles(&candles);
let result = monotonicity_index(&input)?;
println!("{:?}", result.upper_bound.last()); API Reference
Input Methods ▼
MonotonicityIndexInput::from_slice(&[f64], MonotonicityIndexParams)
MonotonicityIndexInput::from_candles(&Candles, source: &str, MonotonicityIndexParams)
MonotonicityIndexInput::with_default_candles(&Candles) // uses "close" Parameters Structure ▼
pub struct MonotonicityIndexParams {
pub length: Option<usize>, // default 20
pub mode: Option<MonotonicityIndexMode>, // default Efficiency
pub index_smooth: Option<usize>, // default 5
} lengthmust be at least2.index_smoothmust be at least1.modesupportsefficiencyandcomplexity.- Needed valid run length is
length + index_smooth - 1.
Output Structure ▼
pub struct MonotonicityIndexOutput {
pub index: Vec<f64>,
pub cumulative_mean: Vec<f64>,
pub upper_bound: Vec<f64>,
}
pub struct MonotonicityIndexBatchOutput {
pub index: Vec<f64>,
pub cumulative_mean: Vec<f64>,
pub upper_bound: Vec<f64>,
pub combos: Vec<MonotonicityIndexParams>,
pub rows: usize,
pub cols: usize,
} Validation, Warmup & NaNs ▼
- Empty input returns
EmptyInputData; all-NaN input returnsAllValuesNaN. - The indicator requires a consecutive valid run of at least
length + index_smooth - 1. - Single-run warmup is
first_valid + length + index_smooth - 2. - Streaming warmup period reported by
get_warmup_period()islength + index_smooth - 2. - Non-finite streaming input resets the rolling window, smoothing state, and cumulative statistics.
monotonicity_index_into_sliceschecks all three output slice lengths.- Batch APIs require a batch kernel; non-batch kernels return
InvalidKernelForBatch.
Error Handling ▼
use vector_ta::indicators::monotonicity_index::{
monotonicity_index,
MonotonicityIndexError,
};
match monotonicity_index(&input) {
Ok(output) => println!("Computed {} values", output.index.len()),
Err(MonotonicityIndexError::InvalidLength { length }) =>
eprintln!("Invalid length {}", length),
Err(MonotonicityIndexError::InvalidIndexSmooth { index_smooth }) =>
eprintln!("Invalid smoothing {}", index_smooth),
Err(MonotonicityIndexError::NotEnoughValidData { needed, valid }) =>
eprintln!("Need {} valid points, found {}", needed, valid),
Err(e) => eprintln!("Monotonicity Index error: {}", e),
} Python Bindings
Basic Usage ▼
The Python function returns a 3-tuple of NumPy arrays:
import numpy as np
from vector_ta import monotonicity_index
index, cumulative_mean, upper_bound = monotonicity_index(
np.asarray(data, dtype=np.float64),
length=20,
mode="efficiency",
index_smooth=5,
kernel="auto",
) Streaming Real-time Updates ▼
The Python stream class exposes both updates and the warmup period:
from vector_ta import MonotonicityIndexStream
stream = MonotonicityIndexStream(length=20, mode="efficiency", index_smooth=5)
print(stream.warmup_period)
for value in price_feed:
point = stream.update(value)
if point is not None:
index, cumulative_mean, upper_bound = point Batch Processing ▼
Batch output returns the row-major matrices plus combo metadata:
import numpy as np
from vector_ta import monotonicity_index_batch
result = monotonicity_index_batch(
np.asarray(data, dtype=np.float64),
length_range=(10, 30, 10),
index_smooth_range=(3, 7, 2),
mode="efficiency",
kernel="auto",
)
index = result["index"]
cumulative_mean = result["cumulative_mean"]
upper_bound = result["upper_bound"]
lengths = result["lengths"]
modes = result["modes"]
index_smooths = result["index_smooths"]
rows = result["rows"]
cols = result["cols"] JavaScript/WASM Bindings
Basic Usage ▼
The high-level WASM binding returns an object with the three output arrays:
import { monotonicity_index_js } from 'vectorta-wasm';
const result = monotonicity_index_js(
new Float64Array(data),
20,
"efficiency",
5
);
console.log(result.index);
console.log(result.upper_bound); Memory-Efficient Operations ▼
Use the low-level exports to write directly into preallocated output buffers:
import {
monotonicity_index_alloc,
monotonicity_index_free,
monotonicity_index_into,
memory,
} from 'vectorta-wasm';
const input = new Float64Array(data);
const len = input.length;
const inPtr = monotonicity_index_alloc(len);
const indexPtr = monotonicity_index_alloc(len);
const meanPtr = monotonicity_index_alloc(len);
const upperPtr = monotonicity_index_alloc(len);
new Float64Array(memory.buffer, inPtr, len).set(input);
monotonicity_index_into(inPtr, indexPtr, meanPtr, upperPtr, len, 20, "efficiency", 5);
const index = new Float64Array(memory.buffer, indexPtr, len).slice();
const cumulativeMean = new Float64Array(memory.buffer, meanPtr, len).slice();
const upperBound = new Float64Array(memory.buffer, upperPtr, len).slice();
monotonicity_index_free(inPtr, len);
monotonicity_index_free(indexPtr, len);
monotonicity_index_free(meanPtr, len);
monotonicity_index_free(upperPtr, len); Batch Processing ▼
Batch mode provides both object-returning and pointer-based WASM entry points:
import { monotonicity_index_batch_js } from 'vectorta-wasm';
const result = monotonicity_index_batch_js(new Float64Array(data), {
length_range: [10, 30, 10],
index_smooth_range: [3, 7, 2],
mode: "efficiency",
});
console.log(result.rows, result.cols);
console.log(result.combos);
console.log(result.index); CUDA Bindings (Rust)
Additional details for the CUDA bindings can be found inside the VectorTA repository.
Performance Analysis
Across sizes, Rust CPU runs about 1.14× faster than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU)