Range Filter
range_size = 2.618 (0.1–10) | range_period = 14 | smooth_range = true | smooth_period = 27 Overview
The Range Filter creates a smooth price line that follows significant movements while filtering out minor fluctuations by restricting price changes to a volatility based channel around the previous filtered value. This indicator measures market volatility through the exponential moving average of absolute price changes, then uses this dynamic range to determine whether new price movements are significant enough to update the filter or should be ignored as noise. When price moves beyond the established range boundaries, the filter updates to follow the trend, but smaller movements within the range get absorbed, creating a step like pattern that clearly shows genuine trend changes. The optional range smoothing adds another layer of filtering that prevents the bands from reacting too quickly to volatility spikes. Traders apply the Range Filter for trend identification and as a trailing stop mechanism, since it naturally follows price at a distance determined by market volatility rather than fixed parameters.
Implementation Examples
Get started with the Range Filter in a few lines:
use vectorta::indicators::range_filter::{range_filter, RangeFilterInput, RangeFilterParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// Using with price data slice
let prices = vec![100.0, 102.0, 101.5, 103.0, 105.0, 104.5];
let params = RangeFilterParams {
range_size: Some(2.618),
range_period: Some(14),
smooth_range: Some(true),
smooth_period: Some(27),
};
let input = RangeFilterInput::from_slice(&prices, params);
let out = range_filter(&input)?;
// Using with Candles (defaults: source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = RangeFilterInput::with_default_candles(&candles);
let out = range_filter(&input)?;
// Access the outputs
for (f, h, l) in itertools::izip!(out.filter, out.high_band, out.low_band) {
println!("filter={}, high={}, low={}", f, h, l);
} API Reference
Input Methods ▼
// From price slice
RangeFilterInput::from_slice(&[f64], RangeFilterParams) -> RangeFilterInput
// From candles with explicit source
RangeFilterInput::from_candles(&Candles, &str, RangeFilterParams) -> RangeFilterInput
// With defaults (source = "close"; params = defaults)
RangeFilterInput::with_default_candles(&Candles) -> RangeFilterInput Parameters Structure ▼
#[derive(Debug, Clone)]
pub struct RangeFilterParams {
pub range_size: Option<f64>, // Default: 2.618 (must be > 0)
pub range_period: Option<usize>, // Default: 14 (>= 1)
pub smooth_range: Option<bool>, // Default: true
pub smooth_period: Option<usize>,// Default: 27 (>= 1 when smooth_range)
} Output Structure ▼
#[derive(Debug, Clone)]
pub struct RangeFilterOutput {
pub filter: Vec<f64>,
pub high_band: Vec<f64>,
pub low_band: Vec<f64>,
} Validation, Warmup & NaNs ▼
range_sizemust be finite and> 0; otherwiseRangeFilterError::InvalidRangeSize.range_period≥ 1 and ≤len; ifsmooth_range=true, thensmooth_period≥ 1 and ≤len; elseRangeFilterError::InvalidPeriod.- Leading
NaNs are skipped; if all values areNaN, returnsRangeFilterError::AllValuesNaN. - Warmup: indices
[0 .. first + max(range_period, smooth_period if smooth_range)]are set toNaNin all three outputs. - If there aren’t enough valid points after the first finite value, returns
RangeFilterError::NotEnoughValidDatawith required vs valid counts.
Error Handling ▼
use vectorta::indicators::range_filter::{range_filter, RangeFilterError};
match range_filter(&input) {
Ok(out) => handle(out),
Err(RangeFilterError::EmptyInputData) => eprintln!("empty input"),
Err(RangeFilterError::AllValuesNaN) => eprintln!("all values are NaN"),
Err(RangeFilterError::InvalidRangeSize { range_size }) =>
eprintln!("invalid range_size: {}", range_size),
Err(RangeFilterError::InvalidPeriod { period, data_len }) =>
eprintln!("invalid period={} for len={}", period, data_len),
Err(RangeFilterError::NotEnoughValidData { needed, valid }) =>
eprintln!("need {} valid points, only {}", needed, valid),
} Python Bindings
Basic Usage ▼
Calculate the Range Filter on NumPy arrays (defaults: 2.618 / 14 / smooth=true / 27):
import numpy as np
from vectorta import range_filter
prices = np.array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5])
# Defaults
f, h, l = range_filter(prices)
# Custom parameters and kernel selection
f, h, l = range_filter(
prices,
range_size=2.618,
range_period=14,
smooth_range=True,
smooth_period=27,
kernel="avx2" # or "auto"
)
print(f"Filter: {f}
High: {h}
Low: {l}") Streaming Real-time Updates ▼
Use the Python stream class to process price ticks:
from vectorta import RangeFilterStream
# Constructor requires explicit parameters
stream = RangeFilterStream(
range_size=2.618,
range_period=14,
smooth_range=True,
smooth_period=27,
)
for price in price_feed:
value = stream.update(price) # (filter, high, low) or None during warmup
if value is not None:
f, h, l = value
# ... use f/h/l ... Batch Parameter Optimization ▼
Sweep multiple combinations and get columnar metadata:
import numpy as np
from vectorta import range_filter_batch
prices = np.array([...])
res = range_filter_batch(
prices,
range_size_start=1.5, range_size_end=3.0, range_size_step=0.5,
range_period_start=10, range_period_end=20, range_period_step=5,
smooth_range=True, smooth_period=27, kernel="auto"
)
print(res['filter'].shape, res['rows'], res['cols'])
print(res['range_sizes'], res['range_periods']) JavaScript / WASM
Quick Start ▼
Compute filter and bands from a Float64Array:
import { range_filter_js } from 'vectorta-wasm';
const prices = new Float64Array([/* prices */]);
// Optional params (use null for defaults)
const result = range_filter_js(prices, 2.618, 14, true, 27);
// result is a JSON-like object with { filter, high, low, rows, cols?, combos? } in this build
console.log(result); Memory-Efficient Operations ▼
Use flat output buffers to avoid extra allocations:
import { range_filter_alloc, range_filter_free, range_filter_into_flat, memory } from 'vectorta-wasm';
const prices = new Float64Array([/* your data */]);
const n = prices.length;
// Allocate WASM memory for input and a single flat output buffer (3 * n)
const inPtr = range_filter_alloc(n);
const outPtr = range_filter_alloc(3 * n);
// Copy input into WASM memory
new Float64Array(memory.buffer, inPtr, n).set(prices);
// Compute directly into flat buffer: [filter..., high..., low...]
range_filter_into_flat(inPtr, outPtr, n, 2.618, 14, true, 27);
// Read back slices
const outFlat = new Float64Array(memory.buffer, outPtr, 3 * n).slice();
const filter = outFlat.slice(0, n);
const high = outFlat.slice(n, 2 * n);
const low = outFlat.slice(2 * n, 3 * n);
// Free memory
range_filter_free(inPtr, n);
range_filter_free(outPtr, 3 * n); Batch Processing ▼
Evaluate multiple parameter sets in one call:
import { range_filter_batch } from 'vectorta-wasm';
const prices = new Float64Array([/* prices */]);
const res = range_filter_batch(
prices,
1.5, 3.0, 0.5, // range_size: start, end, step
10, 20, 5, // range_period: start, end, step
true, 27 // smoothing controls
);
// res contains flat arrays and metadata fields in this build
console.log(res); CUDA
CUDA Acceleration ▼
CUDA support for Range Filter is coming soon.
# Coming soon: CUDA-accelerated Range Filter calculations
# The API will mirror other CUDA-enabled indicators in this project. Performance Analysis
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05