Z-Score
period = 14 | ma_type = sma | nbdev = 1 | devtype = 0 Overview
The Z-Score normalizes price data by measuring how many standard deviations the current value sits from a rolling mean, creating a standardized oscillator useful for mean reversion strategies and outlier detection. The indicator calculates a moving average baseline using the specified method (SMA, EMA, or others), then measures dispersion through standard deviation, mean absolute deviation, or median absolute deviation. Dividing the difference between current price and the mean by the chosen deviation metric yields the Z-Score, typically ranging between -3 and +3 for normal market behavior. Values beyond ±2 suggest price has moved to statistical extremes relative to recent history, often signaling potential reversion opportunities. The nbdev parameter scales the deviation divisor, allowing traders to adjust sensitivity without changing the underlying period. This normalization makes Z-Score particularly valuable for comparing overbought and oversold conditions across different instruments or timeframes, as the standardized scale remains consistent regardless of absolute price levels. Mean reversion traders watch for extreme Z-Score readings to identify entry points, while trend followers may use sustained elevated readings to confirm strength. The flexible deviation type selection accommodates different market assumptions about return distributions and outlier handling.
Formula: zt = (xt − MAt) / Dt, where MA is the chosen moving average
and D is the chosen deviation type (stddev/MAD/MedAD). Defaults (VectorTA):
period=14, ma_type="sma", nbdev=1.0, devtype=0.
See also
- Deviation — rolling deviation (stddev/MAD/MedAD).
- Standard Deviation — volatility measure used in z-score.
- MAC‑Z (ZVWAP + MACD) — uses Z‑score of VWAP.
Interpretation & Use
- Zero-line: Above 0 = price above mean; below 0 = price below mean.
- Extremes: |Z| ≥ 2 often marks statistically unusual moves; mean-reversion traders watch for fades.
- Normalization: Compare standardized moves across symbols or regimes.
- Choice of MA/Deviation:
ma_typetunes the mean;devtypeselects stddev/MAD/MedAD robustness.
Implementation Examples
Compute Z‑Score from a slice or candles:
use vector_ta::indicators::zscore::{zscore, ZscoreInput, ZscoreParams};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
// From price slice
let prices = vec![100.0, 102.0, 101.5, 103.0, 105.0];
let params = ZscoreParams {
period: Some(14),
ma_type: Some("sma".to_string()),
nbdev: Some(1.0),
devtype: Some(0),
};
let input = ZscoreInput::from_slice(&prices, params);
let result = zscore(&input)?;
// From candles with defaults (period=14, ma_type="sma", nbdev=1.0, devtype=0; source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = ZscoreInput::with_default_candles(&candles);
let result = zscore(&input)?;
// Access Z-Score values
for v in result.values {
println!("zscore: {}", v);
} API Reference
Input Methods ▼
// From price slice
ZscoreInput::from_slice(&[f64], ZscoreParams) -> ZscoreInput
// From candles with custom source
ZscoreInput::from_candles(&Candles, &str, ZscoreParams) -> ZscoreInput
// From candles with default params (close, period=14, ma_type="sma", nbdev=1.0, devtype=0)
ZscoreInput::with_default_candles(&Candles) -> ZscoreInput Parameters Structure ▼
pub struct ZscoreParams {
pub period: Option<usize>, // Default: 14
pub ma_type: Option<String>, // Default: "sma"
pub nbdev: Option<f64>, // Default: 1.0
pub devtype: Option<usize>, // Default: 0 (stddev)
} Output Structure ▼
pub struct ZscoreOutput {
pub values: Vec<f64>, // Z-Score values
} Validation, Warmup & NaNs ▼
period > 0andperiod ≤ len; otherwiseZscoreError::InvalidPeriod.- Requires at least
periodvalid points after the first finite value; otherwiseZscoreError::NotEnoughValidData. - Warmup: indices before
first + period − 1areNaN; first finite output at that index. - If the deviation at an index is
0.0orNaN, the output isNaNfor that index.
Error Handling ▼
use vector_ta::indicators::zscore::{zscore, ZscoreError};
match zscore(&input) {
Ok(output) => process(output.values),
Err(ZscoreError::AllValuesNaN) => eprintln!("All input values are NaN"),
Err(ZscoreError::InvalidPeriod { period, data_len }) =>
eprintln!("Invalid period {} for data length {}", period, data_len),
Err(ZscoreError::NotEnoughValidData { needed, valid }) =>
eprintln!("Need {} valid points, only {}", needed, valid),
Err(ZscoreError::DevError(e)) => eprintln!("Deviation error: {}", e),
Err(ZscoreError::MaError(e)) => eprintln!("MA error: {}", e),
} Python Bindings
Basic Usage ▼
Function zscore(data, period=14, ma_type="sma", nbdev=1.0, devtype=0, kernel=None) -> np.ndarray
import numpy as np
# from vector_ta import zscore # Depending on package exposure
prices = np.array([100.0, 102.0, 101.5, 103.0, 105.0], dtype=float)
zs = zscore(prices, period=14, ma_type='sma', nbdev=1.0, devtype=0)
print(zs) Streaming ▼
# from vector_ta import ZscoreStream
stream = ZscoreStream(period=14, ma_type='sma', nbdev=1.0, devtype=0)
for price in [100.0, 101.0, 102.0, 101.5, 103.0]:
val = stream.update(price)
if val is not None:
print('zscore:', val) Batch Sweep ▼
# from vector_ta import zscore_batch
import numpy as np
prices = np.array([/* your data */], dtype=float)
out = zscore_batch(
prices,
period_range=(10, 20, 5),
ma_type='sma',
nbdev_range=(0.5, 2.0, 0.5),
devtype_range=(0, 0, 0)
)
# out is a dict with 'values' shaped (rows, cols) and combo metadata
values = out['values']
periods = out['periods']
ma_types = out['ma_types']
nbdevs = out['nbdevs']
devtypes = out['devtypes'] CUDA ▼
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 zscore_cuda_batch_dev, zscore_cuda_many_series_one_param_dev
data_f32 = np.asarray(load_data(), dtype=np.float32)
dev, meta = zscore_cuda_batch_dev(
data_f32,
period_range=(10, 20, 5),
nbdev_range=(0.5, 2.0, 0.5),
device_id=0,
)
# Many series (time-major), flattened for this API
data_tm = np.asarray(load_data_time_major_matrix(), dtype=np.float32)
rows, cols = data_tm.shape
data_tm = data_tm.ravel()
dev_tm = zscore_cuda_many_series_one_param_dev(
data_tm_f32=data_tm,
cols=cols,
rows=rows,
period=14,
nbdev=1.0,
device_id=0,
) JavaScript / WASM
Basic ▼
import { zscore_js } from 'vectorta-wasm';
const prices = new Float64Array([/* data */]);
// Args: data, period, ma_type, nbdev, devtype
const zs = zscore_js(prices, 14, 'sma', 1.0, 0); Memory-Efficient Operations ▼
import { zscore_alloc, zscore_free, zscore_into, memory } from 'vectorta-wasm';
const prices = new Float64Array([/* your data */]);
const n = prices.length;
const inPtr = zscore_alloc(n);
const outPtr = zscore_alloc(n);
new Float64Array(memory.buffer, inPtr, n).set(prices);
// in_ptr, out_ptr, len, period, ma_type, nbdev, devtype
zscore_into(inPtr, outPtr, n, 14, 'sma', 1.0, 0);
const out = new Float64Array(memory.buffer, outPtr, n).slice();
zscore_free(inPtr, n);
zscore_free(outPtr, n); Batch Processing ▼
import { zscore_batch as zscore_batch_js } from 'vectorta-wasm';
const prices = new Float64Array([/* historical prices */]);
const config = {
period_range: [10, 20, 5],
ma_type: 'sma',
nbdev_range: [0.5, 2.0, 0.5],
devtype_range: [0, 0, 0],
};
// Returns { values: f64[], combos: ZscoreParams[], rows, cols }
const res = zscore_batch_js(prices, config);
// Flattened row-major values: reshape using rows/cols as needed CUDA Bindings (Rust)
use vector_ta::cuda::CudaZscore;
use vector_ta::indicators::zscore::ZscoreBatchRange;
let cuda = CudaZscore::new(0)?;
let data_f32: [f32] = /* ... */;
let sweep = ZscoreBatchRange::default();
let out = cuda.zscore_batch_dev(&data_f32, &sweep)?;
let _ = out; Export Code
use vector_ta::indicators::zscore;
// Calculate ZSCORE with custom parameters
let result = zscore(&data, 14, sma, 1, 0);
// Or using the builder pattern
let result = indicators::zscore::new()
.period(14)
.ma_type(sma)
.nbdev(1)
.devtype(0)
.calculate(&data);This code snippet shows how to use the ZSCORE indicator with your current parameter settings.
Performance Analysis
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-02-28