GMMA Oscillator
gmma_type = guppy | smooth_length = 1 | signal_length = 13 | anchor_minutes = 0 | interval_minutes = Overview
GMMA Oscillator condenses Guppy Multiple Moving Average structure into a single spread measure. It maintains a family of fast EMAs and a family of slow EMAs, averages each side independently, then expresses the difference as a percentage of the slow-group average. Positive readings mean the fast group is leading the slow group, while negative readings show downside compression. A separate signal line tracks that spread with an EMA.
VectorTA supports the classic six-fast and six-slow Guppy set as well as a denser Super Guppy set. It also supports anchored-timeframe scaling, where the underlying EMA periods are multiplied to approximate a higher timeframe. The main output is the oscillator itself, optionally smoothed with an SMA, alongside the signal line.
Defaults: GMMA Oscillator uses `gmma_type = "guppy"`, `smooth_length = 1`, `signal_length = 13`, `anchor_minutes = 0`, and `interval_minutes = null`.
Implementation Examples
Compute the oscillator and signal line from a price slice or from candle closes.
use vector_ta::indicators::gmma_oscillator::{
gmma_oscillator,
GmmaOscillatorInput,
GmmaOscillatorParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
let close = vec![100.0, 100.8, 101.4, 101.1, 102.2, 103.0, 102.7];
let output = gmma_oscillator(&GmmaOscillatorInput::from_slice(
&close,
GmmaOscillatorParams {
gmma_type: Some("guppy".to_string()),
smooth_length: Some(1),
signal_length: Some(13),
anchor_minutes: Some(0),
interval_minutes: None,
},
))?;
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_output = gmma_oscillator(&GmmaOscillatorInput::with_default_candles(&candles))?;
println!("oscillator = {:?}", output.oscillator.last());
println!("signal = {:?}", candle_output.signal.last()); API Reference
Input Methods ▼
// From candles with an explicit source
GmmaOscillatorInput::from_candles(&Candles, &str, GmmaOscillatorParams)
-> GmmaOscillatorInput
// From a raw price slice
GmmaOscillatorInput::from_slice(&[f64], GmmaOscillatorParams)
-> GmmaOscillatorInput
// From candles with default source and parameters
GmmaOscillatorInput::with_default_candles(&Candles)
-> GmmaOscillatorInput Parameters Structure ▼
pub struct GmmaOscillatorParams {
pub gmma_type: Option<String>, // "guppy" or "super_guppy"
pub smooth_length: Option<usize>, // default 1
pub signal_length: Option<usize>, // default 13
pub anchor_minutes: Option<usize>, // default 0
pub interval_minutes: Option<usize>,
} Output Structure ▼
pub struct GmmaOscillatorOutput {
pub oscillator: Vec<f64>,
pub signal: Vec<f64>,
} Validation, Warmup & NaNs ▼
- The input series must be non-empty and contain at least one finite value.
gmma_typemust resolve to eitherguppyorsuper_guppy.smooth_lengthandsignal_lengthmust both be greater than0.anchor_minutesmust stay within a valid daily range, and anchored operation requires eitherinterval_minutesor candle timestamps so the multiplier can be resolved.- When
smooth_length > 1, the oscillator output is NaN-prefixed until that SMA warmup has filled. - Streaming resets when it sees a non-finite value.
- Batch mode validates the parameter axes and rejects unsupported kernels through
InvalidKernelForBatch.
Builder, Streaming & Batch APIs ▼
// Builder
GmmaOscillatorBuilder::new()
.gmma_type(&'static str)
.smooth_length(usize)
.signal_length(usize)
.anchor_minutes(usize)
.interval_minutes(usize)
.kernel(Kernel)
.apply(&Candles)
GmmaOscillatorBuilder::new()
.apply_candles(&Candles, &str)
GmmaOscillatorBuilder::new()
.apply_slice(&[f64])
GmmaOscillatorBuilder::new()
.into_stream()
// Stream
GmmaOscillatorStream::try_new(GmmaOscillatorParams)
GmmaOscillatorStream::update(f64) -> Option<(f64, f64)>
GmmaOscillatorStream::reset()
GmmaOscillatorStream::get_warmup_period() -> usize
// Batch
GmmaOscillatorBatchBuilder::new()
.gmma_type(&'static str)
.anchor_minutes(usize)
.interval_minutes(usize)
.smooth_length_range((usize, usize, usize))
.signal_length_range((usize, usize, usize))
.kernel(Kernel)
.apply_slice(&[f64])
GmmaOscillatorBatchBuilder::new()
.apply_candles(&Candles, &str) Error Handling ▼
pub enum GmmaOscillatorError {
EmptyInputData,
AllValuesNaN,
InvalidGmmaType { gmma_type: String },
InvalidSmoothLength { smooth_length: usize },
InvalidSignalLength { signal_length: usize },
InvalidAnchorMinutes { anchor_minutes: usize },
InvalidIntervalMinutes { interval_minutes: usize },
OutputLengthMismatch { expected: usize, got: usize },
InvalidRange { start: usize, end: usize, step: usize },
InvalidKernelForBatch(Kernel),
MismatchedOutputLen { dst_len: usize, expected_len: usize },
InvalidInput { msg: String },
} Python Bindings
Python exposes a scalar price-series function, a streaming class, and a batch sweep. The scalar path returns two NumPy arrays: oscillator and signal. The stream returns one `(oscillator, signal)` tuple or `None`, while batch returns both flattened matrices plus the tested smoothing lengths, signal lengths, GMMA mode labels, and output dimensions.
import numpy as np
from vector_ta import (
gmma_oscillator,
gmma_oscillator_batch,
GmmaOscillatorStream,
)
data = np.asarray(close_values, dtype=np.float64)
oscillator, signal = gmma_oscillator(
data,
gmma_type="guppy",
smooth_length=1,
signal_length=13,
anchor_minutes=0,
interval_minutes=None,
kernel="auto",
)
stream = GmmaOscillatorStream(
gmma_type="super_guppy",
smooth_length=3,
signal_length=21,
anchor_minutes=60,
interval_minutes=5,
)
print(stream.update(data[-1]))
batch = gmma_oscillator_batch(
data,
gmma_type="guppy",
smooth_length_range=(1, 3, 1),
signal_length_range=(9, 21, 6),
anchor_minutes=0,
interval_minutes=None,
kernel="auto",
)
print(batch["oscillator"].shape)
print(batch["signal_lengths"])
print(batch["gmma_types"]) JavaScript/WASM Bindings
The WASM surface exposes scalar, batch, and into-buffer entry points. The scalar function returns an object with `oscillator` and `signal` arrays. The batch function returns flattened oscillator and signal matrices plus the tested parameter combinations and output dimensions.
import init, {
gmma_oscillator_js,
gmma_oscillator_batch_js,
} from "@vectoralpha/vector_ta";
await init();
const single = gmma_oscillator_js(
close,
"guppy",
1,
13,
0,
null,
);
console.log(single.oscillator);
console.log(single.signal);
const batch = gmma_oscillator_batch_js(close, {
gmma_type: "super_guppy",
smooth_length_range: [1, 3, 1],
signal_length_range: [9, 21, 6],
anchor_minutes: 60,
interval_minutes: 5,
});
console.log(batch.oscillator);
console.log(batch.signal);
console.log(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)