Reflex

Parameters: period = 20

Overview

Reflex detects turning points in price cycles by measuring the difference between smoothed prices and a linear projection, then normalizing this deviation to produce a dimensionless oscillator. The indicator applies a two pole SuperSmoother filter to reduce noise, computes the expected slope over the period window, and divides the difference by an exponentially smoothed variance measure. Values oscillate around zero with spikes appearing at market inflection points while staying flat during steady trends. The normalization ensures readings remain bounded regardless of price scale, making Reflex especially useful for identifying cycle reversals in advance. Traders watch for crossovers through zero as potential entry signals, with positive values suggesting upward momentum and negative values indicating downward pressure. The default 20 period setting balances responsiveness with stability across most timeframes.

Implementation Examples

Get started with Reflex using price slices or candles:

use vector_ta::indicators::reflex::{reflex, ReflexInput, ReflexParams};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

// Using with price data slice
let prices = vec![100.0, 101.2, 100.7, 102.1, 103.0, 102.4];
let params = ReflexParams { period: Some(20) }; // Default is 20 if None
let input = ReflexInput::from_slice(&prices, params);
let out = reflex(&input)?; // ReflexOutput { values: Vec<f64> }

// Using with Candles (defaults: source="close", period=20)
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = ReflexInput::with_default_candles(&candles);
let out = reflex(&input)?;

// Access values
for v in out.values { println!("Reflex: {}", v); }

API Reference

Input Methods
// From price slice
ReflexInput::from_slice(&[f64], ReflexParams) -> ReflexInput

// From candles with custom source
ReflexInput::from_candles(&Candles, &str, ReflexParams) -> ReflexInput

// From candles with default params (close, period=20)
ReflexInput::with_default_candles(&Candles) -> ReflexInput
Parameters Structure
pub struct ReflexParams {
    pub period: Option<usize>, // Default: 20
}
Output Structure
pub struct ReflexOutput {
    pub values: Vec<f64>, // Reflex values
}
Validation, Warmup & NaNs
  • period >= 2; NoData on empty input; AllValuesNaN if no finite values.
  • Requires at least period valid points after the first finite value; else NotEnoughData { needed, found }.
  • Warmup: the first period outputs are 0.0 by contract (batch); streaming yields None until warmed.
  • Normalization uses mst = 0.04·my_sumt2 + 0.96·mst-1; typical values remain within about ±5.
Error Handling
#[derive(Debug, Error)]
pub enum ReflexError {
    NoData,
    InvalidPeriod { period: usize },
    NotEnoughData { needed: usize, found: usize },
    AllValuesNaN,
}

// Example handling
match reflex(&input) {
    Ok(out) => {/* use out.values */},
    Err(ReflexError::InvalidPeriod { period }) => {/* fix params */},
    Err(e) => {/* log or bail */},
}

Python Bindings

Basic Usage

Operate on NumPy arrays; optionally pin the kernel.

import numpy as np
from vector_ta import reflex

prices = np.asarray([100.0, 101.2, 100.7, 102.1, 103.0], dtype=np.float64)

values = reflex(prices, period=20)
values_scalar = reflex(prices, period=20, kernel="scalar")
Batch Sweeps

Test multiple period values and analyze results:

from vector_ta import reflex_batch

result = reflex_batch(prices, periods=(5, 50, 5), kernel="auto")

values = result["values"]   # shape: (rows, len(prices))
periods = result["periods"] # vector of tested periods
CUDA Acceleration

CUDA helpers are available when the Python package is built with CUDA support. Inputs must be float32; outputs are device arrays (DLPack / __cuda_array_interface__ compatible).

import numpy as np
from vector_ta import reflex_cuda_batch_dev, reflex_cuda_many_series_one_param_dev

# One series (float32)
data_f32 = np.asarray(load_data(), dtype=np.float32)

dev = reflex_cuda_batch_dev(
    data_f32=data_f32,
    period_range=(5, 30, 5),
    device_id=0,
)

# Many series (time-major)
data_tm_f32 = np.asarray(load_data_time_major_matrix(), dtype=np.float32)

dev_tm = reflex_cuda_many_series_one_param_dev(
    data_tm_f32=data_tm_f32,
    period=14,
    device_id=0,
)

JavaScript/WASM Bindings

Basic Usage

Calculate Reflex in JavaScript/TypeScript:

import { reflex_js } from 'vectorta-wasm';

const prices = new Float64Array([100.0, 101.2, 100.7, 102.1, 103.0]);
const result = reflex_js(prices, 20);  // period=20
console.log('Reflex values:', result);
Memory-Efficient Operations

Use zero-copy operations for better performance with large datasets:

import { reflex_alloc, reflex_free, reflex_into, memory } from 'vectorta-wasm';

const length = prices.length;
const inPtr = reflex_alloc(length);
const outPtr = reflex_alloc(length);

new Float64Array(memory.buffer, inPtr, length).set(prices);
reflex_into(inPtr, outPtr, length, 20);
const values = new Float64Array(memory.buffer, outPtr, length).slice();

reflex_free(inPtr, length);
reflex_free(outPtr, length);
Batch Processing

Test multiple period values efficiently:

import { reflex_batch_js, reflex_batch_metadata_js } from 'vectorta-wasm';

const prices = new Float64Array([/* historical prices */]);
const start = 5, end = 50, step = 5;

const meta = reflex_batch_metadata_js(start, end, step); // [p1, p2, ...]
const flat = reflex_batch_js(prices, start, end, step);

const block = prices.length;
const rows = meta.length;
const matrix = [];
for (let i = 0; i < rows; i++) {
  matrix.push(flat.slice(i * block, (i + 1) * block));
}

CUDA Bindings (Rust)

use vector_ta::cuda::CudaReflex;
use vector_ta::indicators::moving_averages::reflex::ReflexBatchRange;

let cuda = CudaReflex::new(0)?;

let prices: [f32] = /* ... */;
let sweep = ReflexBatchRange::default();

let out = cuda.reflex_batch_dev(&prices, &sweep)?;
let _ = out;

Performance Analysis

Comparison:
View:
Loading chart...

AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-02-28

CUDA note

In our benchmark workload, the Rust CPU implementation is faster than CUDA for this indicator. Prefer the Rust/CPU path unless your workload differs.

Related Indicators