Gaussian Filter
period = 14 | poles = 4 (1–4) Overview
The Gaussian Filter creates an exceptionally smooth price curve by cascading multiple stages of exponential smoothing to approximate the bell shaped Gaussian distribution, producing minimal lag while eliminating market noise more effectively than traditional moving averages. Each pole represents a filtering stage that recursively smooths the output of the previous stage, with more poles creating a response closer to the ideal Gaussian curve that balances responsiveness with stability. When using four poles, the filter achieves near perfect Gaussian characteristics, removing high frequency noise while preserving the underlying trend structure with less delay than comparable smooth averages. Traders employ Gaussian filters to identify clean trend direction without the jagged movements of faster averages or the excessive lag of slower ones, making it ideal for automated systems that require stable signals. The adjustable pole count allows fine tuning between aggressive filtering for noisy markets (4 poles) and responsive tracking for cleaner price action (1 or 2 poles). Additionally, the Gaussian filter excels as a baseline for oscillators and divergence analysis because its mathematical properties create predictable lag characteristics that remain consistent across different market conditions.
Implementation Examples
Create inputs from a slice or candles and compute Gaussian:
use vectorta::indicators::gaussian::{gaussian, GaussianInput, GaussianParams};
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 = GaussianParams { period: Some(14), poles: Some(4) };
let input = GaussianInput::from_slice(&prices, params);
let result = gaussian(&input)?;
// Using with Candles data structure (defaults: period=14, poles=4; source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = GaussianInput::with_default_candles(&candles);
let result = gaussian(&input)?;
// Access values
for v in result.values { println!("Gaussian: {}", v); } API Reference
Input Methods ▼
// From price slice
GaussianInput::from_slice(&[f64], GaussianParams) -> GaussianInput
// From candles with custom source
GaussianInput::from_candles(&Candles, &str, GaussianParams) -> GaussianInput
// From candles with default params (close prices, period=14, poles=4)
GaussianInput::with_default_candles(&Candles) -> GaussianInput Parameters Structure ▼
pub struct GaussianParams {
pub period: Option<usize>, // Default: 14
pub poles: Option<usize>, // Default: 4 (allowed: 1..=4)
} Output Structure ▼
pub struct GaussianOutput {
pub values: Vec<f64>, // Filtered values
} Validation, Warmup & NaNs ▼
period ≥ 2.period == 1is rejected:GaussianError::PeriodOneDegenerate;period < 2yieldsGaussianError::DegeneratePeriod.poles ∈ [1, 4]; otherwiseGaussianError::InvalidPoles.period ≤ data.len(); otherwiseGaussianError::PeriodLongerThanData.- Must have at least
periodvalid points after first finite input; otherwiseGaussianError::NotEnoughValidData. - Leading indices up to
first_valid + periodare set toNaN(warmup); subsequent NaNs propagate.
Error Handling ▼
use vectorta::indicators::gaussian::GaussianError;
match gaussian(&input) {
Ok(output) => process_results(output.values),
Err(GaussianError::NoData) => println!("No input data"),
Err(GaussianError::PeriodOneDegenerate) => println!("period=1 is not allowed"),
Err(GaussianError::DegeneratePeriod { period }) => println!("period {} must be ≥ 2", period),
Err(GaussianError::InvalidPoles { poles }) => println!("poles must be 1..4; got {}", poles),
Err(GaussianError::PeriodLongerThanData { period, data_len }) =>
println!("period {} exceeds data length {}", period, data_len),
Err(GaussianError::AllValuesNaN) => println!("All inputs are NaN"),
Err(GaussianError::NotEnoughValidData { needed, valid }) =>
println!("Need {} valid points after first finite; got {}", needed, valid),
} Python Bindings
Basic Usage ▼
Calculate Gaussian using NumPy arrays (explicit parameters required):
import numpy as np
from vectorta import gaussian
prices = np.array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5], dtype=np.float64)
# Specify parameters explicitly (no implicit defaults in Python wrapper)
values = gaussian(prices, period=14, poles=4, kernel="auto") Streaming ▼
import numpy as np
from vectorta import GaussianStream
stream = GaussianStream(period=14, poles=4)
for x in [100.0, 101.0, 100.5, 102.0]:
y = stream.update(float(x))
print(y) Batch Processing ▼
Test multiple parameter combinations efficiently:
import numpy as np
from vectorta import gaussian_batch
prices = np.array([/* your data */], dtype=np.float64)
out = gaussian_batch(
prices,
period_range=(10, 30, 10),
poles_range=(1, 4, 1),
kernel="auto"
)
print(out["values"].shape) # (num_combos, len(prices))
print(out["periods"]) # list of periods for each row
print(out["poles"]) # list of pole counts for each row CUDA Acceleration ▼
Available when built with Python + CUDA features.
import numpy as np
from vectorta import gaussian_cuda_batch_dev, gaussian_cuda_many_series_one_param_dev
# Option 1: One series, many parameters (parameter sweep)
prices_f32 = np.array([/* your data */], dtype=np.float32)
res = gaussian_cuda_batch_dev(
data_f32=prices_f32,
period_range=(10, 30, 1),
poles_range=(1, 4, 1),
device_id=0
)
# res is a device-resident array wrapper (DeviceArrayF32Py)
# Option 2: Many series, one parameter set (time-major: [T, N])
tm = np.array([/* T x N */], dtype=np.float32)
out = gaussian_cuda_many_series_one_param_dev(
prices_tm_f32=tm,
period=14,
poles=4,
device_id=0
) JavaScript/WASM Bindings
Basic Usage ▼
Calculate Gaussian in JavaScript/TypeScript:
import { gaussian_js } from 'vectorta-wasm';
const prices = new Float64Array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5]);
const values = gaussian_js(prices, 14, 4);
console.log('Gaussian values:', values); Memory-Efficient Operations ▼
Use zero-copy operations for large datasets:
import { gaussian_alloc, gaussian_free, gaussian_into, memory } from 'vectorta-wasm';
const prices = new Float64Array([/* your data */]);
const len = prices.length;
const inPtr = gaussian_alloc(len);
const outPtr = gaussian_alloc(len);
new Float64Array(memory.buffer, inPtr, len).set(prices);
// Args: in_ptr, out_ptr, len, period, poles
gaussian_into(inPtr, outPtr, len, 14, 4);
const out = new Float64Array(memory.buffer, outPtr, len).slice();
gaussian_free(inPtr, len);
gaussian_free(outPtr, len); Batch Processing ▼
Test parameter combinations in one call:
import { gaussian_batch_js, gaussian_batch_metadata_js } from 'vectorta-wasm';
const prices = new Float64Array([/* historical prices */]);
const pStart = 10, pEnd = 30, pStep = 10; // 10, 20, 30
const kStart = 1, kEnd = 4, kStep = 1; // 1..4
const metadata = gaussian_batch_metadata_js(pStart, pEnd, pStep, kStart, kEnd, kStep);
const numCombos = metadata.length / 2; // [period, poles] pairs
const flat = gaussian_batch_js(prices, pStart, pEnd, pStep, kStart, kEnd, kStep);
// Reshape flat results into matrix
const matrix = [];
for (let i = 0; i < numCombos; i++) {
const start = i * prices.length;
const end = start + prices.length;
matrix.push(flat.slice(start, end));
} Performance Analysis
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05
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
Arnaud Legoux Moving Average
Moving average indicator
Compound Ratio Moving Average (CoRa Wave)
Moving average indicator
Centered Weighted Moving Average
Moving average indicator
Double Exponential Moving Average
Moving average indicator
Ehlers Distance Coefficient Filter
Moving average indicator
Ehlers Error-Correcting EMA (ECEMA)
Moving average indicator