Gopalakrishnan Range Index

Parameters: length = 5

Overview

Gopalakrishnan Range Index, often abbreviated GAPO or GRI, tracks how large the rolling high-low envelope has become relative to the selected window length. It takes the logarithm of the current rolling range and divides it by the logarithm of the lookback period, which creates a normalized scale that rises when price swings widen quickly and falls when the market compresses.

This implementation works directly from high and low inputs, so it is a pure range indicator rather than a close-based volatility estimate. In streaming mode it maintains rolling high and low deques, while the batch path sweeps alternative window lengths and returns one flattened output row per tested length.

Defaults: Gopalakrishnan Range Index uses `length = 5`.

Implementation Examples

Compute the normalized range series from raw high/low inputs or candle data.

use vector_ta::indicators::gopalakrishnan_range_index::{
    gopalakrishnan_range_index,
    GopalakrishnanRangeIndexInput,
    GopalakrishnanRangeIndexParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

let high = vec![101.0, 102.4, 101.8, 103.1, 104.0, 103.6];
let low = vec![99.8, 100.7, 100.2, 101.4, 102.8, 102.1];

let output = gopalakrishnan_range_index(&GopalakrishnanRangeIndexInput::from_slices(
    &high,
    &low,
    GopalakrishnanRangeIndexParams { length: Some(5) },
))?;

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

println!("latest gri = {:?}", output.values.last());
println!("series length = {}", candle_output.values.len());

API Reference

Input Methods
// From candles
GopalakrishnanRangeIndexInput::from_candles(&Candles, GopalakrishnanRangeIndexParams)
    -> GopalakrishnanRangeIndexInput

// From high/low slices
GopalakrishnanRangeIndexInput::from_slices(&[f64], &[f64], GopalakrishnanRangeIndexParams)
    -> GopalakrishnanRangeIndexInput

// From candles with default parameters
GopalakrishnanRangeIndexInput::with_default_candles(&Candles)
    -> GopalakrishnanRangeIndexInput
Parameters Structure
pub struct GopalakrishnanRangeIndexParams {
    pub length: Option<usize>, // default 5
}
Output Structure
pub struct GopalakrishnanRangeIndexOutput {
    pub values: Vec<f64>,
}
Validation, Warmup & NaNs
  • High and low inputs must be non-empty and have matching lengths.
  • length must be greater than 1.
  • The indicator requires at least length valid high/low bars.
  • The one-shot output is NaN-prefixed until the first full rolling window is available.
  • Streaming returns None during warmup, and if a completed window contains invalid bars it returns NaN for that step.
  • If the rolling high-low range is non-positive, the normalized value is NaN.
  • Batch mode validates the length sweep and rejects non-batch kernels through InvalidKernelForBatch.
Builder, Streaming & Batch APIs
// Builder
GopalakrishnanRangeIndexBuilder::new()
    .length(usize)
    .kernel(Kernel)
    .apply(&Candles)

GopalakrishnanRangeIndexBuilder::new()
    .apply_slices(&[f64], &[f64])

GopalakrishnanRangeIndexBuilder::new()
    .into_stream()

// Stream
GopalakrishnanRangeIndexStream::try_new(GopalakrishnanRangeIndexParams)
GopalakrishnanRangeIndexStream::update(f64, f64) -> Option<f64>
GopalakrishnanRangeIndexStream::get_warmup_period() -> usize

// Batch
GopalakrishnanRangeIndexBatchBuilder::new()
    .kernel(Kernel)
    .length_range(start, end, step)
    .length_static(value)
    .apply_slices(&[f64], &[f64])

GopalakrishnanRangeIndexBatchBuilder::new()
    .apply_candles(&Candles)

GopalakrishnanRangeIndexBatchBuilder::with_default_candles(&Candles)
Error Handling
pub enum GopalakrishnanRangeIndexError {
    EmptyInputData,
    AllValuesNaN,
    InvalidLength { length: usize, data_len: usize },
    NotEnoughValidData { needed: usize, valid: usize },
    InconsistentSliceLengths { high_len: usize, low_len: usize },
    OutputLengthMismatch { expected: usize, got: usize },
    InvalidRange { start: String, end: String, step: String },
    InvalidKernelForBatch(Kernel),
}

Python Bindings

Python exposes a scalar high/low function, a streaming class, and a batch sweep. The scalar path returns one NumPy range-index array. Streaming returns one floating-point value or `None`, while batch returns the flattened values matrix together with the tested lengths and output dimensions.

import numpy as np
from vector_ta import (
    gopalakrishnan_range_index,
    gopalakrishnan_range_index_batch,
    GopalakrishnanRangeIndexStream,
)

high = np.asarray(high_values, dtype=np.float64)
low = np.asarray(low_values, dtype=np.float64)

values = gopalakrishnan_range_index(high, low, length=5, kernel="auto")

stream = GopalakrishnanRangeIndexStream(length=5)
print(stream.update(high[-1], low[-1]))

batch = gopalakrishnan_range_index_batch(
    high,
    low,
    length_range=(5, 15, 5),
    kernel="auto",
)

print(batch["values"].shape)
print(batch["lengths"])
print(batch["rows"], batch["cols"])

JavaScript/WASM Bindings

The WASM layer exposes a scalar function, a batch function, and raw allocation and into-buffer helpers. The scalar binding returns a single array of GRI values. The batch binding returns the flattened matrix together with the tested lengths, parameter combinations, and matrix dimensions.

import init, {
  gopalakrishnan_range_index_js,
  gopalakrishnan_range_index_batch_js,
} from "@vectoralpha/vector_ta";

await init();

const values = gopalakrishnan_range_index_js(high, low, 5);
console.log(values);

const batch = gopalakrishnan_range_index_batch_js(high, low, {
  length_range: [5, 15, 5],
});

console.log(batch.values);
console.log(batch.lengths);
console.log(batch.rows, batch.cols);

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