Kairi Relative Index
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()exposeslength(),ma_type(),kernel(),apply(),apply_candles(),apply_slices(), andinto_stream().KairiRelativeIndexStream::update(source, volume)returnsOption<f64>; invalid source values, and invalid volume values inVWMAmode, reset the stream and returnNone.KairiRelativeIndexStream::reset()reconstructs the internal moving-average state from the current params.KairiRelativeIndexStream::get_warmup_period()returnsrequired_samples(length) - 1.KairiRelativeIndexBatchRangecontainslength: (start, end, step)and fixedma_type: String; defaults are(50, 258, 1)and"SMA".KairiRelativeIndexBatchBuilder::new()exposeslength_range(),length_static(),ma_type(),kernel(),apply_slices(), andapply_candles().- Batch output is
KairiRelativeIndexBatchOutput { values, combos, rows, cols }with flattened row-majorvalues.
Validation, Warmup & NaNs ▼
sourceandvolumemust be non-empty and have matching lengths.lengthmust satisfy2 <= length <= source.len().- The indicator rejects unknown
ma_typevalues withInvalidMaType. - The longest contiguous valid run must be long enough for the chosen moving average: most types need
lengthsamples,VIDYAandWWMAneed1, andHMAneedslength + floor(sqrt(length)) - 1. - Output values remain
NaNuntil the selected MA stream produces a usable moving average. If the MA becomes zero, the indicator returns0.0only whensource == 0.0; otherwise that step yields no value. - Only
VWMArequires 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
Across sizes, Rust CPU runs about 1.14× faster than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU)