2-Pole High‑Pass Filter
period = 48 | k = 0.707 (0.1–1) Overview
The 2-Pole High Pass Filter isolates short term price oscillations by systematically removing trend components, revealing the cyclical patterns and noise that remain after the dominant directional bias gets filtered out. Using second order recursive filtering with two feedback loops, the indicator achieves sharper frequency separation than single pole filters, creating a cleaner distinction between trend and cycle components in price data. The resulting output oscillates around zero, with positive values indicating price sits above its trend component and negative values showing price below trend, effectively detrending the series to expose pure momentum dynamics. Traders employ this filter to identify overbought and oversold conditions within trending markets, as extreme readings suggest price has deviated too far from its underlying trend and may revert. The cutoff factor k controls the filter's selectivity, with the default 0.707 providing critical damping that balances response sharpness against stability, preventing the ringing artifacts that plague more aggressive filter designs. Advanced traders combine the high pass output with other indicators to separate signal from noise, using the filtered values to confirm whether price movements represent genuine momentum shifts or merely temporary fluctuations around the prevailing trend.
Implementation Examples
Compute the 2‑pole high‑pass filter from a slice or candles:
use vectorta::indicators::highpass_2_pole::{highpass_2_pole, HighPass2Input, HighPass2Params};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// From a price slice
let prices = vec![100.0, 102.0, 101.5, 103.0, 105.0, 104.5];
let params = HighPass2Params { period: Some(48), k: Some(0.707) }; // defaults
let input = HighPass2Input::from_slice(&prices, params);
let out = highpass_2_pole(&input)?;
// From candles (default params; source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = HighPass2Input::with_default_candles(&candles);
let out = highpass_2_pole(&input)?;
// Values
for v in out.values { println!("hp2: {}", v); } API Reference
Input Methods ▼
// From price slice
HighPass2Input::from_slice(&[f64], HighPass2Params) -> HighPass2Input
// From candles with custom source
HighPass2Input::from_candles(&Candles, &str, HighPass2Params) -> HighPass2Input
// From candles with default params (close, period=48, k=0.707)
HighPass2Input::with_default_candles(&Candles) -> HighPass2Input Parameters Structure ▼
pub struct HighPass2Params {
pub period: Option<usize>, // Default: 48
pub k: Option<f64>, // Default: 0.707
} Output Structure ▼
pub struct HighPass2Output {
pub values: Vec<f64>, // High‑pass values
} Validation, Warmup & NaNs ▼
period ≥ 2andperiod ≤ data.len(); otherwiseHighPass2Error::InvalidPeriod.k > 0and finite; otherwiseHighPass2Error::InvalidK.- After the first finite input, need at least
periodvalid points; elseHighPass2Error::NotEnoughValidData. - Indices before the first finite value are
NaN. First two finite outputs seed from input; full values accrue after warmup. - Streaming:
HighPass2Stream::updatereturnsNoneuntilperiodsamples are processed.
Error Handling ▼
use vectorta::indicators::highpass_2_pole::{highpass_2_pole, HighPass2Error};
match highpass_2_pole(&input) {
Ok(output) => consume(output.values),
Err(HighPass2Error::EmptyInputData) => eprintln!("empty input"),
Err(HighPass2Error::AllValuesNaN) => eprintln!("all values are NaN"),
Err(HighPass2Error::InvalidPeriod { period, data_len }) =>
eprintln!("invalid period {} for len {}", period, data_len),
Err(HighPass2Error::InvalidK { k }) => eprintln!("invalid k {}", k),
Err(HighPass2Error::NotEnoughValidData { needed, valid }) =>
eprintln!("need {} valid points, have {}", needed, valid),
Err(HighPass2Error::OutputLengthMismatch { .. }) => eprintln!("buffer length mismatch"),
} Python Bindings
Basic Usage ▼
import numpy as np
from vectorta import highpass_2_pole
prices = np.array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5])
# Defaults period=48, k=0.707
hp = highpass_2_pole(prices, period=48, k=0.707)
# Specify kernel ('auto', 'scalar', 'avx2', 'avx512') if desired
hp = highpass_2_pole(prices, period=48, k=0.707, kernel="auto")
print(hp) Streaming Real‑time Updates ▼
from vectorta import HighPass2Stream
stream = HighPass2Stream(period=48, k=0.707)
for price in price_feed:
val = stream.update(price)
if val is not None:
handle(val) Batch Parameter Optimization ▼
import numpy as np
from vectorta import highpass_2_pole_batch
prices = np.array([...], dtype=float)
results = highpass_2_pole_batch(
prices,
period_range=(24, 64, 8),
k_range=(0.5, 1.0, 0.1),
kernel="auto",
)
vals = results["values"] # shape: (num_combos, len(prices))
periods = results["periods"] # tested period values
ks = results["k"] # tested k values CUDA Acceleration ▼
CUDA device APIs for HP2 (development names):
import numpy as np
from vectorta import (
highpass_2_pole_cuda_batch_dev,
highpass_2_pole_cuda_many_series_one_param_dev,
)
# One series, many params (Float32 input on device)
data_f32 = np.asarray([...], dtype=np.float32)
dev_arr = highpass_2_pole_cuda_batch_dev(
data_f32,
period_range=(48, 48, 0),
k_range=(0.707, 0.707, 0.0),
device_id=0,
)
# Many series (time‑major), one parameter set
tm = np.asarray([[...]], dtype=np.float32) # shape [T, N]
dev_arr = highpass_2_pole_cuda_many_series_one_param_dev(
tm, period=48, k=0.707, device_id=0
) JavaScript/WASM Bindings
Basic Usage ▼
import { highpass_2_pole_js } from 'vectorta-wasm';
const prices = new Float64Array([100, 102, 101.5, 103, 105, 104.5]);
const hp = highpass_2_pole_js(prices, 48, 0.707);
console.log('HP2:', hp); Memory‑Efficient Operations ▼
import { highpass_2_pole_alloc, highpass_2_pole_free, highpass_2_pole_into, memory } from 'vectorta-wasm';
const prices = new Float64Array([/* data */]);
const n = prices.length;
const inPtr = highpass_2_pole_alloc(n);
const outPtr = highpass_2_pole_alloc(n);
new Float64Array(memory.buffer, inPtr, n).set(prices);
highpass_2_pole_into(inPtr, outPtr, n, 48, 0.707);
const hp = new Float64Array(memory.buffer, outPtr, n).slice();
highpass_2_pole_free(inPtr, n);
highpass_2_pole_free(outPtr, n); Batch Processing ▼
import { highpass_2_pole_batch } from 'vectorta-wasm';
const prices = new Float64Array([/* historical prices */]);
const config = { period_range: [24, 64, 8], k_range: [0.5, 1.0, 0.1] };
const res = highpass_2_pole_batch(prices, config);
// res = { values: Float64Array, combos: Array<{ period?: number, k?: number }>, rows: number, cols: number }
// Example: reshape into matrix of rows x cols
const rows = res.rows, cols = res.cols;
const mat: number[][] = [];
for (let r = 0; r < rows; r++) {
const start = r * cols;
mat.push(Array.from(res.values.slice(start, start + cols)));
} Performance Analysis
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05
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