QQE Weighted Oscillator
length = 14 | factor = 4.236 | smooth = 5 | weight = 2 Overview
QQE Weighted Oscillator starts from price-to-price changes, smooths those gains and losses in an RSI-like fashion, then emphasizes changes that continue moving in the same direction as the active trailing stop. The resulting oscillator stays in RSI-style space, while the companion trailing stop expands or contracts based on the recent absolute change in that oscillator.
In VectorTA the indicator returns both the weighted RSI line and the adaptive trailing stop, supports close-based candle input or raw slices, and exposes builder, streaming, and batch APIs. Non-finite values break the live stream path cleanly by clearing the previous source point before the next update resumes.
Defaults: `length = 14`, `factor = 4.236`, `smooth = 5`, and `weight = 2.0`.
Implementation Examples
Run the oscillator from a close slice or from candles with an explicit close source.
use vector_ta::indicators::qqe_weighted_oscillator::{
qqe_weighted_oscillator,
QqeWeightedOscillatorInput,
QqeWeightedOscillatorParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
let direct = qqe_weighted_oscillator(&QqeWeightedOscillatorInput::from_slice(
&close,
QqeWeightedOscillatorParams {
length: Some(14),
factor: Some(4.236),
smooth: Some(5),
weight: Some(2.0),
},
))?;
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let from_candles = qqe_weighted_oscillator(&QqeWeightedOscillatorInput::from_candles(
&candles,
"close",
QqeWeightedOscillatorParams::default(),
))?;
println!("rsi = {:?}", direct.rsi.last());
println!("stop = {:?}", from_candles.trailing_stop.last());API Reference
Input Methods▼
QqeWeightedOscillatorInput::from_candles(&Candles, "close", QqeWeightedOscillatorParams)
-> QqeWeightedOscillatorInput
QqeWeightedOscillatorInput::from_slice(&[f64], QqeWeightedOscillatorParams)
-> QqeWeightedOscillatorInput
QqeWeightedOscillatorInput::with_default_candles(&Candles)
-> QqeWeightedOscillatorInputParameters Structure▼
pub struct QqeWeightedOscillatorParams {
pub length: Option<usize>, // default 14
pub factor: Option<f64>, // default 4.236
pub smooth: Option<usize>, // default 5
pub weight: Option<f64>, // default 2.0
}Output Structure▼
pub struct QqeWeightedOscillatorOutput {
pub rsi: Vec<f64>,
pub trailing_stop: Vec<f64>,
}
pub struct QqeWeightedOscillatorStreamOutput {
pub rsi: f64,
pub trailing_stop: f64,
}Validation & Warmup▼
- The input slice must not be empty and must contain at least one finite value.
lengthandsmoothmust both be greater than0.factormust be finite and non-negative, andweightmust be finite.- The direct path requires at least
length + 1finite values after the first valid source point. - Warmup on the vector path starts at
first_valid + length, so earlier indices remainNaN. - Non-finite streaming input clears the previous source point and returns
None. - Batch mode validates each sweep axis and rejects non-batch kernels.
Builder, Streaming & Batch APIs▼
QqeWeightedOscillatorBuilder::new()
.length(usize)
.factor(f64)
.smooth(usize)
.weight(f64)
.kernel(Kernel)
.apply(&Candles)
.apply_slice(&[f64])
.into_stream()
QqeWeightedOscillatorStream::try_new(params)
stream.update(f64) -> Option<QqeWeightedOscillatorStreamOutput>
QqeWeightedOscillatorBatchBuilder::new()
.range(QqeWeightedOscillatorBatchRange)
.kernel(Kernel)
.apply_slice(&[f64])
.apply(&Candles)Python Bindings
Python exposes a scalar function returning a dictionary with the RSI and trailing-stop arrays, a stream class returning a two-value tuple once warmup has completed, and a batch helper that returns reshaped matrices plus the resolved parameter axes.
from vector_ta import (
qqe_weighted_oscillator,
qqe_weighted_oscillator_batch,
QqeWeightedOscillatorStream,
)
single = qqe_weighted_oscillator(
close,
length=14,
factor=4.236,
smooth=5,
weight=2.0,
)
stream = QqeWeightedOscillatorStream(length=14, factor=4.236, smooth=5, weight=2.0)
point = stream.update(close[-1])
batch = qqe_weighted_oscillator_batch(
close,
length_range=(14, 18, 2),
factor_range=(3.5, 4.5, 0.5),
smooth_range=(5, 7, 2),
weight_range=(1.5, 2.0, 0.5),
)
print(single["rsi"][-1], single["trailing_stop"][-1])
print(batch["rows"], batch["cols"])JavaScript/WASM Bindings
The WASM layer exposes object-returning scalar and batch helpers along with lower-level allocation and into-buffer APIs for caller-managed memory.
import init, {
qqe_weighted_oscillator_js,
qqe_weighted_oscillator_batch,
qqe_weighted_oscillator_alloc,
qqe_weighted_oscillator_free,
qqe_weighted_oscillator_into,
} from "vector-ta-wasm";
await init();
const single = qqe_weighted_oscillator_js(close, 14, 4.236, 5, 2.0);
const batch = qqe_weighted_oscillator_batch(close, {
length_range: [14, 18, 2],
factor_range: [3.5, 4.5, 0.5],
smooth_range: [5, 7, 2],
weight_range: [1.5, 2.0, 0.5],
});
const ptrIn = qqe_weighted_oscillator_alloc(close.length);
const ptrRsi = qqe_weighted_oscillator_alloc(close.length);
const ptrStop = qqe_weighted_oscillator_alloc(close.length);
qqe_weighted_oscillator_into(ptrIn, ptrRsi, ptrStop, close.length, 14, 4.236, 5, 2.0);
qqe_weighted_oscillator_free(ptrIn, close.length);
qqe_weighted_oscillator_free(ptrRsi, close.length);
qqe_weighted_oscillator_free(ptrStop, close.length);
console.log(single.rsi, single.trailing_stop, batch.rows, batch.cols);CUDA Bindings (Rust)
Additional details for the CUDA bindings can be found inside the VectorTA repository.
Performance Analysis
Across sizes, Rust CPU runs about 1.14× faster than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU)