Directional Imbalance Index
length = 10 | period = 70 Overview
Directional Imbalance Index measures how often recent highs keep pressing the rolling upper boundary versus how often recent lows keep pressing the rolling lower boundary. For each bar, the indicator checks whether the current high matches the highest high in the rolling length window and whether the current low matches the lowest low in the same window. Those events are recorded as simple directional hits.
The hit counts are then accumulated over the longer period window. The raw up and down counts show how many recent breakout-style touches occurred on each side, while the bull and bear outputs normalize those counts into percentages of the total directional activity. The result is less about price distance and more about persistent directional pressure at the edges of a rolling range. Upper and lower channel levels are returned too, so the imbalance read can be inspected alongside the exact range boundaries that generated it.
Defaults: Directional Imbalance Index uses `length = 10` and `period = 70`.
Implementation Examples
Compute the raw directional hit counts, their normalized bull-bear split, and the active channel bounds.
use vector_ta::indicators::directional_imbalance_index::{
directional_imbalance_index,
DirectionalImbalanceIndexInput,
DirectionalImbalanceIndexParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
let output = directional_imbalance_index(&DirectionalImbalanceIndexInput::from_slices(
&high,
&low,
DirectionalImbalanceIndexParams::default(),
))?;
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_output = directional_imbalance_index(
&DirectionalImbalanceIndexInput::with_default_candles(&candles)
)?;
println!("bulls = {:?}", output.bulls.last());
println!("bears = {:?}", output.bears.last());
println!("upper = {:?}", candle_output.upper.last()); API Reference
Input Methods ▼
// From candles
DirectionalImbalanceIndexInput::from_candles(&Candles, DirectionalImbalanceIndexParams)
-> DirectionalImbalanceIndexInput
// From high and low slices
DirectionalImbalanceIndexInput::from_slices(&[f64], &[f64], DirectionalImbalanceIndexParams)
-> DirectionalImbalanceIndexInput
// From candles with default parameters
DirectionalImbalanceIndexInput::with_default_candles(&Candles)
-> DirectionalImbalanceIndexInput Parameters Structure ▼
pub struct DirectionalImbalanceIndexParams {
pub length: Option<usize>, // default 10
pub period: Option<usize>, // default 70
} Output Structure ▼
pub struct DirectionalImbalanceIndexOutput {
pub up: Vec<f64>,
pub down: Vec<f64>,
pub bulls: Vec<f64>,
pub bears: Vec<f64>,
pub upper: Vec<f64>,
pub lower: Vec<f64>,
} Validation, Warmup & NaNs ▼
- High and low must be non-empty slices with identical lengths.
lengthandperiodmust both be greater than zero.- The indicator accepts the first valid high-low pair immediately, so its warmup period is reported as
0. - Invalid high-low pairs reset the stream state and return
None. - If no valid pair exists in the whole input, the indicator returns
AllValuesNaN. - Batch range expansion rejects invalid integer ranges and shape overflows before execution.
- All six output buffers for in-place APIs must match the expected single-run or flattened batch lengths exactly.
Builder, Streaming & Batch APIs ▼
// Builder
DirectionalImbalanceIndexBuilder::new()
.length(usize)
.period(usize)
.kernel(Kernel)
.apply_slices(&[f64], &[f64])
DirectionalImbalanceIndexBuilder::new()
.apply(&Candles)
DirectionalImbalanceIndexBuilder::new()
.into_stream()
// Stream
DirectionalImbalanceIndexStream::try_new(DirectionalImbalanceIndexParams)
DirectionalImbalanceIndexStream::update(high, low) -> Option<DirectionalImbalanceIndexPoint>
DirectionalImbalanceIndexStream::reset()
DirectionalImbalanceIndexStream::get_warmup_period() -> usize
// Batch
DirectionalImbalanceIndexBatchBuilder::new()
.length_range((start, end, step))
.period_range((start, end, step))
.kernel(Kernel)
.apply_slices(&[f64], &[f64]) Error Handling ▼
pub enum DirectionalImbalanceIndexError {
EmptyInputData,
InputLengthMismatch { high_len: usize, low_len: usize },
AllValuesNaN,
InvalidLength { length: usize },
InvalidPeriod { period: usize },
OutputLengthMismatch { expected: usize, got: usize },
InvalidRange { field: &'static str, start: usize, end: usize, step: usize },
InvalidKernelForBatch(Kernel),
MismatchedOutputLen { dst_len: usize, expected_len: usize },
InvalidInput { msg: String },
} Python Bindings
Python exposes a tuple-returning single-run function, a streaming class, and a batch function. The single-run binding returns six NumPy arrays in order: up, down, bulls, bears, upper, and lower. Batch returns those same matrices plus the tested length and period axes together with rows and cols.
import numpy as np
from vector_ta import (
directional_imbalance_index,
directional_imbalance_index_batch,
DirectionalImbalanceIndexStream,
)
high = np.asarray(high_values, dtype=np.float64)
low = np.asarray(low_values, dtype=np.float64)
up, down, bulls, bears, upper, lower = directional_imbalance_index(
high,
low,
length=10,
period=70,
kernel="auto",
)
stream = DirectionalImbalanceIndexStream(length=10, period=70)
print(stream.update(high[-1], low[-1]))
batch = directional_imbalance_index_batch(
high,
low,
length_range=(10, 14, 2),
period_range=(50, 70, 20),
kernel="auto",
)
print(batch["lengths"], batch["periods"], batch["rows"], batch["cols"]) JavaScript/WASM Bindings
The WASM layer exposes object-returning single-run and batch wrappers plus low-level allocation and in-place exports. The standard JavaScript path returns all six output arrays directly. The batch wrapper adds rows, cols, and the combo objects that describe each tested length-period pair.
import init, {
directional_imbalance_index_js,
directional_imbalance_index_batch_js,
} from "/pkg/vector_ta.js";
await init();
const high = new Float64Array(highValues);
const low = new Float64Array(lowValues);
const result = directional_imbalance_index_js(high, low, 10, 70);
console.log(result.bulls, result.upper);
const batch = directional_imbalance_index_batch_js(high, low, {
length_range: [10, 14, 2],
period_range: [50, 70, 20],
});
console.log(batch.combos, batch.rows, batch.cols); 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)