Kairi Relative Index

Parameters: length = 50 | ma_type = SMA

Overview

Kairi Relative Index measures how far the current source value has moved above or below a selected moving average, expressed as a percentage of that moving average. The Rust implementation computes the percent distance between the source and the chosen moving-average baseline once that baseline has enough valid data.

The indicator accepts either candle data plus a source field or raw source and volume slices. Volume is always passed through the API because the VWMA mode needs it; other moving-average modes ignore the volume values except for length matching. The default candle source is close.

Defaults: length = 50, ma_type = "SMA", and candle source = "close".

Implementation Examples

Get started with source/volume slices or with candles using the default close source:

use vector_ta::indicators::kairi_relative_index::{
    kairi_relative_index, KairiRelativeIndexInput, KairiRelativeIndexParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

let source = vec![100.0, 101.0, 102.0, 101.5, 103.0, 104.0];
let volume = vec![1200.0, 1100.0, 1300.0, 1250.0, 1400.0, 1500.0];

let input = KairiRelativeIndexInput::from_slices(
    &source,
    &volume,
    KairiRelativeIndexParams {
        length: Some(5),
        ma_type: Some("EMA".to_string()),
    },
);
let out = kairi_relative_index(&input)?;
println!("{:?}", out.values);

// Default candles helper uses source = "close"
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let out = kairi_relative_index(&KairiRelativeIndexInput::with_default_candles(&candles))?;

API Reference

Input Methods
KairiRelativeIndexInput::from_candles(&Candles, &str, KairiRelativeIndexParams) -> KairiRelativeIndexInput
KairiRelativeIndexInput::from_slices(&[f64], &[f64], KairiRelativeIndexParams) -> KairiRelativeIndexInput
KairiRelativeIndexInput::with_default_candles(&Candles) -> KairiRelativeIndexInput // source = "close"
Parameters Structure
pub struct KairiRelativeIndexParams {
    pub length: Option<usize>,
    pub ma_type: Option<String>,
}

// Defaults
// length = 50
// ma_type = "SMA"

// Supported ma_type values:
// "SMA", "EMA", "WMA", "TMA", "VIDYA", "WWMA",
// "ZLEMA", "TSF", "HMA" (or "HULL"), "VWMA"
Output Structure
pub struct KairiRelativeIndexOutput {
    pub values: Vec<f64>,
}

// Formula:
// ((source - moving_average) * 100.0) / moving_average
Builders, Batch Range, and Stream
  • KairiRelativeIndexBuilder::new() exposes length(), ma_type(), kernel(), apply(), apply_candles(), apply_slices(), and into_stream().
  • KairiRelativeIndexStream::update(source, volume) returns Option<f64>; invalid source values, and invalid volume values in VWMA mode, reset the stream and return None.
  • KairiRelativeIndexStream::reset() reconstructs the internal moving-average state from the current params.
  • KairiRelativeIndexStream::get_warmup_period() returns required_samples(length) - 1.
  • KairiRelativeIndexBatchRange contains length: (start, end, step) and fixed ma_type: String; defaults are (50, 258, 1) and "SMA".
  • KairiRelativeIndexBatchBuilder::new() exposes length_range(), length_static(), ma_type(), kernel(), apply_slices(), and apply_candles().
  • Batch output is KairiRelativeIndexBatchOutput { values, combos, rows, cols } with flattened row-major values.
Validation, Warmup & NaNs
  • source and volume must be non-empty and have matching lengths.
  • length must satisfy 2 <= length <= source.len().
  • The indicator rejects unknown ma_type values with InvalidMaType.
  • The longest contiguous valid run must be long enough for the chosen moving average: most types need length samples, VIDYA and WWMA need 1, and HMA needs length + floor(sqrt(length)) - 1.
  • Output values remain NaN until the selected MA stream produces a usable moving average. If the MA becomes zero, the indicator returns 0.0 only when source == 0.0; otherwise that step yields no value.
  • Only VWMA requires finite volume values for validity checks and streaming updates.
Error Handling
use vector_ta::indicators::kairi_relative_index::KairiRelativeIndexError;

match kairi_relative_index(&input) {
    Ok(out) => println!("{:?}", out.values),
    Err(KairiRelativeIndexError::EmptyInputData) =>
        eprintln!("source and volume cannot be empty"),
    Err(KairiRelativeIndexError::InputLengthMismatch { source_len, volume_len }) =>
        eprintln!("length mismatch: source={}, volume={}", source_len, volume_len),
    Err(KairiRelativeIndexError::InvalidLength { length, data_len }) =>
        eprintln!("invalid length {} for data len {}", length, data_len),
    Err(KairiRelativeIndexError::InvalidMaType { ma_type }) =>
        eprintln!("invalid ma_type: {}", ma_type),
    Err(KairiRelativeIndexError::NotEnoughValidData { needed, valid }) =>
        eprintln!("need {} contiguous valid samples, got {}", needed, valid),
    Err(KairiRelativeIndexError::InvalidKernelForBatch(kernel)) =>
        eprintln!("invalid batch kernel: {:?}", kernel),
    Err(e) => eprintln!("KRI error: {}", e),
}

Python Bindings

Basic Usage

Python exposes kairi_relative_index(source, volume, length=50, ma_type="SMA", kernel=None) and returns a NumPy array.

import numpy as np
from vector_ta import kairi_relative_index

source = np.array([100.0, 101.0, 102.0, 101.5, 103.0, 104.0], dtype=np.float64)
volume = np.array([1200.0, 1100.0, 1300.0, 1250.0, 1400.0, 1500.0], dtype=np.float64)

values = kairi_relative_index(source, volume, length=14, ma_type="EMA")
print(values)
Streaming Real-time Updates

The Python stream class is KairiRelativeIndexStream. It exposes update(source, volume); there is no Python reset() method in this binding.

from vector_ta import KairiRelativeIndexStream

stream = KairiRelativeIndexStream(length=20, ma_type="VWMA")

for src, vol in feed:
    value = stream.update(src, vol)
    if value is not None:
        print(value)
Batch Processing

kairi_relative_index_batch returns a dict with a 2D values matrix and grid metadata.

import numpy as np
from vector_ta import kairi_relative_index_batch

result = kairi_relative_index_batch(
    source,
    volume,
    length_range=(10, 30, 10),
    ma_type="SMA",
)

values = result["values"]
lengths = result["lengths"]
rows = result["rows"]
cols = result["cols"]
ma_type = result["ma_type"]

JavaScript/WASM Bindings

Basic Usage

WASM exports kairi_relative_index_js(source, volume, length, ma_type) and returns the values array.

import { kairi_relative_index_js } from 'vectorta-wasm';

const source = new Float64Array([100.0, 101.0, 102.0, 101.5, 103.0, 104.0]);
const volume = new Float64Array([1200.0, 1100.0, 1300.0, 1250.0, 1400.0, 1500.0]);

const values = kairi_relative_index_js(source, volume, 14, 'EMA');
console.log(values);
Memory-Efficient Operations

Use kairi_relative_index_alloc, kairi_relative_index_into, and kairi_relative_index_free to write directly into a caller-managed buffer.

import {
  kairi_relative_index_alloc,
  kairi_relative_index_free,
  kairi_relative_index_into,
  memory,
} from 'vectorta-wasm';

const len = source.length;
const sourcePtr = kairi_relative_index_alloc(len);
const volumePtr = kairi_relative_index_alloc(len);
const outPtr = kairi_relative_index_alloc(len);

new Float64Array(memory.buffer, sourcePtr, len).set(source);
new Float64Array(memory.buffer, volumePtr, len).set(volume);

kairi_relative_index_into(sourcePtr, volumePtr, outPtr, len, 14, 'VWMA');

const values = new Float64Array(memory.buffer, outPtr, len).slice();

kairi_relative_index_free(sourcePtr, len);
kairi_relative_index_free(volumePtr, len);
kairi_relative_index_free(outPtr, len);
Batch Processing

WASM batch uses kairi_relative_index_batch_js with { length_range, ma_type } and returns { values, rows, cols, combos }.

import { kairi_relative_index_batch_js } from 'vectorta-wasm';

const batch = kairi_relative_index_batch_js(source, volume, {
  length_range: [10, 30, 10],
  ma_type: 'SMA',
});

console.log(batch.values);
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