Intraday Momentum Index

Parameters: length = 14 | length_ma = 6 | mult = 2 | length_bb = 20 | apply_smoothing = | low_band = 10

Overview

Intraday Momentum Index is an intraday-style oscillator that compares up-close and down-close pressure over a rolling window. Instead of using full high and low range structure, it works from open and close values, making it useful when you want a compact measure of whether recent sessions have tended to finish strong or weak relative to where they started.

This implementation returns the core IMI line together with upper-hit and lower-hit markers and an EMA signal line. Optional smoothing can be enabled before the Bollinger-style band test, so the indicator can be run either as a raw momentum oscillator or as a more filtered mean-reversion overlay.

Defaults: length = 14, length_ma = 6, mult = 2.0, length_bb = 20, apply_smoothing = false, and low_band = 10.

Implementation Examples

Compute IMI, upper-hit markers, lower-hit markers, and the signal line from slices or candles.

use vector_ta::indicators::intraday_momentum_index::{
    intraday_momentum_index,
    IntradayMomentumIndexInput,
    IntradayMomentumIndexParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

let output = intraday_momentum_index(
    &IntradayMomentumIndexInput::from_slices(
        &open,
        &close,
        IntradayMomentumIndexParams::default(),
    ),
)?;

let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_output = intraday_momentum_index(
    &IntradayMomentumIndexInput::with_default_candles(&candles),
)?;

println!("{:?}", output.imi.last());
println!("{:?}", candle_output.signal.last());

API Reference

Input Methods
// From candles
IntradayMomentumIndexInput::from_candles(&Candles, IntradayMomentumIndexParams) -> IntradayMomentumIndexInput

// From slices
IntradayMomentumIndexInput::from_slices(&[f64], &[f64], IntradayMomentumIndexParams) -> IntradayMomentumIndexInput

// From candles with default parameters
IntradayMomentumIndexInput::with_default_candles(&Candles) -> IntradayMomentumIndexInput
Parameters Structure
pub struct IntradayMomentumIndexParams {
    pub length: Option<usize>,
    pub length_ma: Option<usize>,
    pub mult: Option<f64>,
    pub length_bb: Option<usize>,
    pub apply_smoothing: Option<bool>,
    pub low_band: Option<usize>,
}
Output Structure
pub struct IntradayMomentumIndexOutput {
    pub imi: Vec<f64>,
    pub upper_hit: Vec<f64>,
    pub lower_hit: Vec<f64>,
    pub signal: Vec<f64>,
}
Validation, Warmup & NaNs
  • Open and close arrays must be non-empty and equal in length.
  • The core length, signal length_ma, and band length_bb must be positive, and mult must be finite and non-negative.
  • If smoothing is enabled, low_band must be at least 1.
  • Not enough valid open/close pairs yields NotEnoughValidData.
  • The stream warmup is length - 1 bars before IMI can emit a finite value.
Builder, Streaming & Batch APIs
// Builder
IntradayMomentumIndexBuilder::new()
    .length(usize)
    .length_ma(usize)
    .mult(f64)
    .length_bb(usize)
    .apply_smoothing(bool)
    .low_band(usize)
    .kernel(Kernel)
    .apply(&Candles)

IntradayMomentumIndexBuilder::new()
    .apply_slices(&[f64], &[f64])
    .into_stream()

// Stream
IntradayMomentumIndexStream::try_new(IntradayMomentumIndexParams)
IntradayMomentumIndexStream::update(f64, f64) -> Option<(f64, f64, f64, f64)>
IntradayMomentumIndexStream::get_warmup_period() -> usize

// Batch
IntradayMomentumIndexBatchBuilder::new()
    .length_range(usize, usize, usize)
    .length_ma_range(usize, usize, usize)
    .mult_range(f64, f64, f64)
    .length_bb_range(usize, usize, usize)
    .apply_smoothing(bool)
    .low_band_range(usize, usize, usize)
    .apply_slices(&[f64], &[f64])
Error Handling
pub enum IntradayMomentumIndexError {
    EmptyInputData,
    AllValuesNaN,
    InconsistentSliceLengths { open_len: usize, close_len: usize },
    InvalidLength { length: usize, data_len: usize },
    InvalidLengthMa { length_ma: usize, data_len: usize },
    InvalidLengthBb { length_bb: usize, data_len: usize },
    InvalidMult { mult: f64 },
    InvalidLowBand { low_band: usize },
    NotEnoughValidData { needed: usize, valid: usize },
    OutputLengthMismatch { expected: usize, imi_got: usize, upper_hit_got: usize, lower_hit_got: usize, signal_got: usize },
    InvalidRange { start: String, end: String, step: String },
    InvalidKernelForBatch(Kernel),
}

Python Bindings

Python exposes a scalar function, a stream class, and a batch sweep. The scalar function returns four arrays in order: IMI, upper_hit, lower_hit, and signal. The stream returns the same four-field tuple per update. Batch returns those matrices plus the tested parameter arrays and grid dimensions.

import numpy as np
from vector_ta import (
    intraday_momentum_index,
    intraday_momentum_index_batch,
    IntradayMomentumIndexStream,
)

open_ = np.asarray(open_values, dtype=np.float64)
close = np.asarray(close_values, dtype=np.float64)

imi, upper_hit, lower_hit, signal = intraday_momentum_index(
    open_,
    close,
    length=14,
    length_ma=6,
    mult=2.0,
    length_bb=20,
    apply_smoothing=False,
    low_band=10,
    kernel="auto",
)

stream = IntradayMomentumIndexStream()
print(stream.update(float(open_[-1]), float(close[-1])))
print(stream.warmup_period)

batch = intraday_momentum_index_batch(
    open_,
    close,
    length_range=(10, 14, 2),
    length_ma_range=(4, 6, 1),
    mult_range=(2.0, 3.0, 0.5),
    length_bb_range=(18, 20, 2),
    apply_smoothing=True,
    low_band_range=(10, 12, 2),
    kernel="auto",
)

print(batch["imi"].shape)
print(batch["lengths"])

JavaScript/WASM Bindings

The WASM layer exposes scalar, batch, and into-buffer helpers. The scalar binding returns an object containing `imi`, `upper_hit`, `lower_hit`, and `signal`. The batch binding returns those flattened arrays plus `combos`, per-axis parameter arrays, and the `rows` and `cols` needed to reshape the results.

import init, {
  intraday_momentum_index_js,
  intraday_momentum_index_batch_js,
} from "@vectoralpha/vector_ta";

await init();

const single = intraday_momentum_index_js(
  open_,
  close,
  14,
  6,
  2.0,
  20,
  false,
  10,
);

const batch = intraday_momentum_index_batch_js(open_, close, {
  length_range: [10, 14, 2],
  length_ma_range: [4, 6, 1],
  mult_range: [2.0, 3.0, 0.5],
  length_bb_range: [18, 20, 2],
  apply_smoothing: true,
  low_band_range: [10, 12, 2],
});

console.log(single.imi);
console.log(batch.rows, batch.cols);
console.log(batch.lengths);

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