Moving Average Adaptive Q (MAAQ)
period = 11 | fast_period = 2 | slow_period = 30 Overview
The Moving Average Adaptive Q, developed by Perry Kaufman in 1995, adjusts its smoothing factor dynamically based on the ratio of directional price movement to total volatility over a specified window. MAAQ calculates signal strength as the absolute change from the current price to the price n periods ago, then divides this by the sum of all individual price changes within that window to derive an efficiency ratio. This ratio scales between fast and slow smoothing constants (0.667 and 0.0645 by default), with the unique characteristic that the resulting adaptive factor is squared before application, creating a quadratic response that amplifies the difference between trending and ranging markets. When markets trend efficiently with minimal noise, MAAQ accelerates dramatically to track price closely, while in choppy sideways markets it slows down substantially to filter out whipsaws. Unlike its sibling KAMA which uses a linear smoothing constant, MAAQ's squared adaptive factor provides more aggressive filtering during consolidation and faster response during breakouts, making it particularly effective for trend following strategies that require clear distinction between signal and noise.
Defaults: period = 11, fast = 2, slow = 30.
Implementation Examples
Get started with MAAQ in just a few lines:
use vectorta::indicators::moving_averages::maaq::{maaq, MaaqInput, MaaqParams};
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 = MaaqParams { period: Some(11), fast_period: Some(2), slow_period: Some(30) };
let input = MaaqInput::from_slice(&prices, params);
let result = maaq(&input)?;
// Using with Candles data structure (defaults: period=11, fast=2, slow=30; source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = MaaqInput::with_default_candles(&candles);
let result = maaq(&input)?;
// Access the MAAQ values
for value in result.values {
println!("MAAQ: {}", value);
} API Reference
Input Methods ▼
// From price slice
MaaqInput::from_slice(&[f64], MaaqParams) -> MaaqInput
// From candles with custom source
MaaqInput::from_candles(&Candles, &str, MaaqParams) -> MaaqInput
// From candles with default params (close, period=11, fast=2, slow=30)
MaaqInput::with_default_candles(&Candles) -> MaaqInput Parameters Structure ▼
pub struct MaaqParams {
pub period: Option<usize>, // Default: 11
pub fast_period: Option<usize>, // Default: 2
pub slow_period: Option<usize>, // Default: 30
} Output Structure ▼
pub struct MaaqOutput {
pub values: Vec<f64>, // Adaptive moving average values
} Validation, Warmup & NaNs ▼
period > 0,fast_period > 0,slow_period > 0; otherwiseMaaqError::ZeroPeriods.- If
period ≥ data.len()thenMaaqError::InvalidPeriod. - After the first finite input at index
first, there must be at leastperiodvalid points: elseMaaqError::NotEnoughValidData. - All inputs NaN yields
MaaqError::AllValuesNaN. - Batch: indices
[0 .. first + period − 2]areNaN(ALMA parity). Streaming: returns raw inputs during warmup, then MAAQ values.
Error Handling ▼
use vectorta::indicators::moving_averages::maaq::{maaq, MaaqError};
match maaq(&input) {
Ok(output) => process(output.values),
Err(MaaqError::ZeroPeriods { period, fast_p, slow_p }) => eprintln!("Zero periods: p={}, f={}, s={}", period, fast_p, slow_p),
Err(MaaqError::InvalidPeriod { period, data_len }) => eprintln!("Invalid period: {} for len {}", period, data_len),
Err(MaaqError::NotEnoughValidData { needed, valid }) => eprintln!("Need {} valid points, have {}", needed, valid),
Err(MaaqError::AllValuesNaN) => eprintln!("All input values are NaN"),
} Python Bindings
Basic Usage ▼
import numpy as np
from vectorta import maaq
prices = np.array([...], dtype=float)
# Defaults: period=11, fast=2, slow=30
result = maaq(prices, period=11, fast_period=2, slow_period=30)
print(result) # 1D array of MAAQ values Batch Processing ▼
Test multiple parameter combinations for optimization:
import numpy as np
from vectorta import maaq_batch
prices = np.array([...], dtype=float)
# Define parameter ranges (start, end, step)
period_range = (9, 20, 1)
fast_range = (1, 5, 1)
slow_range = (20, 50, 5)
results = maaq_batch(
prices,
period_range=period_range,
fast_period_range=fast_range,
slow_period_range=slow_range,
kernel="auto"
)
print(results['values'].shape) # (num_combos, len(prices))
print(results['periods'])
print(results['fast_periods'])
print(results['slow_periods']) CUDA Acceleration ▼
CUDA bindings are available for batch and multi-series operations when built with CUDA support.
from vectorta import (
maaq_cuda_batch_dev,
maaq_cuda_many_series_one_param_dev,
)
import numpy as np
# 1) One series, many parameters (parameter sweep)
prices = np.array([...], dtype=float)
period_range = (9, 20, 1)
fast_range = (1, 5, 1)
slow_range = (20, 50, 5)
dev_buf = maaq_cuda_batch_dev(prices, period_range, fast_range, slow_range, device_id=0)
# dev_buf is a device array wrapper (float32) with grid results
# 2) Many series, one parameter set (portfolio/time-major)
data_tm_f32 = np.array([...], dtype=np.float32) # shape [T, N]
dev_buf2 = maaq_cuda_many_series_one_param_dev(
data_tm_f32,
period=11,
fast_period=2,
slow_period=30,
device_id=0,
) JavaScript/WASM Bindings
Basic Usage ▼
Calculate MAAQ in JavaScript/TypeScript:
import { maaq_js } from 'vectorta-wasm';
// Price data as Float64Array or regular array
const prices = new Float64Array([100, 102, 101.5, 103, 105, 104.5]);
// Calculate MAAQ with specified parameters
const result = maaq_js(prices, 11, 2, 30); // period=11, fast=2, slow=30
console.log('MAAQ values:', result); Memory-Efficient Operations ▼
Use zero-copy operations for better performance with large datasets:
import { maaq_alloc, maaq_free, maaq_into, memory } from 'vectorta-wasm';
const prices = new Float64Array([/* your data */]);
const length = prices.length;
// Allocate WASM memory for input and output
const inPtr = maaq_alloc(length);
const outPtr = maaq_alloc(length);
// Copy input data into WASM memory
new Float64Array(memory.buffer, inPtr, length).set(prices);
// Args: in_ptr, out_ptr, len, period, fast_period, slow_period
maaq_into(inPtr, outPtr, length, 11, 2, 30);
// Read results (slice() to copy out)
const maaqValues = new Float64Array(memory.buffer, outPtr, length).slice();
maaq_free(inPtr, length);
maaq_free(outPtr, length);
console.log('MAAQ values:', maaqValues); Batch Processing ▼
Test parameter grids efficiently with unified batch output:
import { maaq_batch, maaq_batch_metadata_js } from 'vectorta-wasm';
const prices = new Float64Array([/* historical prices */]);
// Define parameter sweep ranges (three axes)
const p = [9, 20, 1];
const f = [1, 5, 1];
const s = [20, 50, 5];
// Get metadata about parameter combinations: [p1,f1,s1, p2,f2,s2, ...]
const metadata = maaq_batch_metadata_js(p[0], p[1], p[2], f[0], f[1], f[2], s[0], s[1], s[2]);
const numCombos = metadata.length / 3;
// Calculate all combinations using unified batch API
const result = maaq_batch(prices, {
period_range: p,
fast_period_range: f,
slow_period_range: s,
});
// result has { values, combos, rows, cols }
console.log(result.rows, result.cols);
// Access first combo row
const firstRow = result.values.slice(0, prices.length); 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