Qstick
period = 5 Overview
Qstick measures the average size and direction of candlestick bodies over a rolling window by calculating the simple moving average of the close minus open difference for each bar, revealing whether buyers or sellers have controlled the session closes. Positive Qstick values indicate that closing prices have consistently exceeded opening prices, suggesting bullish pressure as buyers pushed price higher throughout the measured periods. Negative values show the opposite, with sellers dominating to close prices below opens and signaling bearish control. The magnitude of Qstick reflects the strength of directional bias, with larger absolute values indicating more decisive control by one side and readings near zero suggesting balanced or choppy conditions where neither buyers nor sellers establish dominance. Traders interpret Qstick crossovers above zero as bullish signals showing buyers taking control, while drops below zero warn of seller dominance and potential downtrends. Divergences between Qstick and price can reveal weakening momentum, such as when price makes new highs but Qstick fails to confirm by showing smaller positive readings, indicating that although price rose the intrabar strength has diminished. The default five period setting captures short term shifts in body direction for tactical entries and exits, though longer periods smooth the signal for strategic trend assessment at the cost of responsiveness.
Defaults: period=5.
Implementation Examples
Compute Qstick from slices or candles:
use vectorta::indicators::qstick::{qstick, QstickInput, QstickParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// Using slices: open and close
let open = vec![/* ... */];
let close = vec![/* ... */];
let params = QstickParams { period: Some(5) }; // default
let input = QstickInput::from_slices(&open, &close, params);
let result = qstick(&input)?;
// Using Candles with defaults: sources ("open", "close"), period=5
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = QstickInput::with_default_candles(&candles);
let result = qstick(&input)?;
// Access values
for v in result.values { println!("Qstick: {}", v); } API Reference
Input Methods ▼
// From open/close slices
QstickInput::from_slices(&[f64], &[f64], QstickParams) -> QstickInput
// From candles with custom sources
QstickInput::from_candles(&Candles, &str, &str, QstickParams) -> QstickInput
// From candles with defaults (sources: "open", "close"; period=5)
QstickInput::with_default_candles(&Candles) -> QstickInput Parameters Structure ▼
pub struct QstickParams {
pub period: Option<usize>, // Default: 5
} Output Structure ▼
pub struct QstickOutput {
pub values: Vec<f64>, // Average (Close - Open)
} Validation, Warmup & NaNs ▼
period > 0andperiod ≤ min(len(open), len(close)); otherwiseQstickError::InvalidPeriod.- First valid index is the first bar where both Open and Close are finite; if none,
QstickError::AllValuesNaN. - There must be at least
periodvalid bars from that index; elseQstickError::NotEnoughValidData. - Outputs before
first_valid + period − 1areNaN; streaming returnsNoneuntil filled.
Error Handling ▼
use vectorta::indicators::qstick::{qstick, QstickError};
match qstick(&input) {
Ok(output) => process(output.values),
Err(QstickError::AllValuesNaN) => eprintln!("No finite Open/Close pairs found"),
Err(QstickError::InvalidPeriod { period, data_len }) => {
eprintln!("Invalid period: {} (data_len={})", period, data_len)
}
Err(QstickError::NotEnoughValidData { needed, valid }) => {
eprintln!("Need {} data points, only {} valid", needed, valid)
}
} Python Bindings
Basic Usage ▼
Calculate Qstick using NumPy arrays (default period=5):
import numpy as np
from vectorta import qstick
# Prepare open/close arrays
open_arr = np.array([...], dtype=np.float64)
close_arr = np.array([...], dtype=np.float64)
# Calculate with defaults
values = qstick(open_arr, close_arr, period=5)
# Or specify kernel ("auto", "avx2", "avx512", "scalar")
values = qstick(open_arr, close_arr, period=10, kernel="auto")
print(values) Streaming Real-time Updates ▼
Process pairs of Open/Close values per bar:
from vectorta import QstickStream
stream = QstickStream(period=5)
for o, c in zip(live_open, live_close):
q = stream.update(float(o), float(c))
if q is not None:
handle(q) Batch Parameter Optimization ▼
Test multiple periods efficiently:
import numpy as np
from vectorta import qstick_batch
open_arr = np.array([...], dtype=np.float64)
close_arr = np.array([...], dtype=np.float64)
res = qstick_batch(open_arr, close_arr, period_range=(5, 20, 5), kernel="auto")
# res: { 'values': ndarray[rows, cols], 'periods': ndarray[rows] }
print(res['values'].shape, res['periods']) CUDA Acceleration
Status ▼
CUDA support for Qstick is coming soon. The API will follow the same pattern as other CUDA-enabled indicators.
JavaScript/WASM Bindings
Basic Usage ▼
Calculate Qstick in JavaScript/TypeScript:
import { qstick_js } from 'vectorta-wasm';
const open = new Float64Array([/* ... */]);
const close = new Float64Array([/* ... */]);
const values = qstick_js(open, close, 5);
console.log('Qstick values:', values); Memory-Efficient Operations ▼
Use zero-copy buffers for large arrays:
import { qstick_alloc, qstick_free, qstick_into, memory } from 'vectorta-wasm';
const len = open.length;
const openPtr = qstick_alloc(len);
const closePtr = qstick_alloc(len);
const outPtr = qstick_alloc(len);
// Copy inputs into WASM memory
new Float64Array(memory.buffer, openPtr, len).set(open);
new Float64Array(memory.buffer, closePtr, len).set(close);
// Compute into pre-allocated buffer
qstick_into(openPtr, closePtr, outPtr, len, 5);
// Read results (copy out)
const qvals = new Float64Array(memory.buffer, outPtr, len).slice();
qstick_free(openPtr, len);
qstick_free(closePtr, len);
qstick_free(outPtr, len); Batch Processing ▼
Sweep periods using the unified JS API:
import { qstick_batch } from 'vectorta-wasm';
const cfg = { period_range: [5, 20, 5] };
const res = qstick_batch(open, close, cfg);
// res: { values: Float64Array, combos: Array<{ period?: number }>, rows: number, cols: number }
console.log(res.rows, res.cols);
// Extract first combo's series
const firstRow = res.values.slice(0, res.cols); Performance Analysis
Across sizes, Rust CPU runs about 1.01× slower than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05