Adjustable MA Alternating Extremities
length = 50 | mult = 2 | alpha = 1 | beta = 0.5 Overview
Adjustable MA Alternating Extremities smooths high, low, and close with a custom weighted moving average, then builds symmetric bands around the smoothed close from the rolling average absolute distance between price and that moving average. Rather than treating the band pair as a passive envelope, the indicator tracks whether price is currently operating off the upper side or the lower side and promotes that active boundary into a dedicated extremity output.
The result is useful when you want both a smoothed structure and a simple regime marker. The ma series is the centerline, upper and lower define the adaptive envelope, state shows which side is active, changed flags boundary flips, and extremity publishes the currently selected live edge. The smoothed open, high, low, and close outputs make it possible to plot the transformed structure directly instead of reconstructing it from the internal weights.
Defaults: Adjustable MA Alternating Extremities uses `length = 50`, `mult = 2.0`, `alpha = 1.0`, and `beta = 0.5`.
Implementation Examples
Compute the indicator from high, low, and close slices or from a candle container.
use vector_ta::indicators::adjustable_ma_alternating_extremities::{
adjustable_ma_alternating_extremities,
AdjustableMaAlternatingExtremitiesInput,
AdjustableMaAlternatingExtremitiesParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
let high = vec![101.0, 102.4, 103.1, 102.7, 104.9, 105.5];
let low = vec![99.8, 100.7, 101.6, 101.2, 103.0, 104.0];
let close = vec![100.6, 101.9, 102.7, 101.8, 104.1, 104.8];
let params = AdjustableMaAlternatingExtremitiesParams {
length: Some(50),
mult: Some(2.0),
alpha: Some(1.0),
beta: Some(0.5),
};
let output = adjustable_ma_alternating_extremities(
&AdjustableMaAlternatingExtremitiesInput::from_slices(&high, &low, &close, params)
)?;
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_output = adjustable_ma_alternating_extremities(
&AdjustableMaAlternatingExtremitiesInput::with_default_candles(&candles)
)?;
println!("Latest MA: {:?}", output.ma.last());
println!("Latest extremity: {:?}", output.extremity.last());
println!("Latest state: {:?}", output.state.last());
println!("Smoothed close length: {}", candle_output.smoothed_close.len()); API Reference
Input Methods ▼
// From candles
AdjustableMaAlternatingExtremitiesInput::from_candles(&Candles, AdjustableMaAlternatingExtremitiesParams)
-> AdjustableMaAlternatingExtremitiesInput
// From high/low/close slices
AdjustableMaAlternatingExtremitiesInput::from_slices(
&[f64],
&[f64],
&[f64],
AdjustableMaAlternatingExtremitiesParams,
) -> AdjustableMaAlternatingExtremitiesInput
// From candles with default parameters
AdjustableMaAlternatingExtremitiesInput::with_default_candles(&Candles)
-> AdjustableMaAlternatingExtremitiesInput Parameters Structure ▼
pub struct AdjustableMaAlternatingExtremitiesParams {
pub length: Option<usize>, // default 50
pub mult: Option<f64>, // default 2.0
pub alpha: Option<f64>, // default 1.0
pub beta: Option<f64>, // default 0.5
} Output Structure ▼
pub struct AdjustableMaAlternatingExtremitiesOutput {
pub ma: Vec<f64>,
pub upper: Vec<f64>,
pub lower: Vec<f64>,
pub extremity: Vec<f64>,
pub state: Vec<f64>,
pub changed: Vec<f64>,
pub smoothed_open: Vec<f64>,
pub smoothed_high: Vec<f64>,
pub smoothed_low: Vec<f64>,
pub smoothed_close: Vec<f64>,
} Validation, Warmup & NaNs ▼
high.len() == low.len() == close.len(); otherwise the function returnsDataLengthMismatch.- The first finite bar across all three inputs is used as the warmup anchor. If no finite bar exists, the function returns
AllValuesNaN. lengthmust be at least2and no larger than the data length.multmust be finite and at least1.0.alphaandbetamust be finite and non-negative.- The custom weight builder can fail with
DegenerateKernelif the chosenalpha/betapair collapses the weighting curve. - At least
(length * 2) - 1valid bars are required after the first finite index. The moving-average outputs warm up atfirst + length - 1, the bands and regime outputs warm up atfirst + (length * 2) - 2, andsmoothed_openstarts two bars after the moving average because it depends on prior smoothed closes. - Batch mode accepts only batch-capable kernels; otherwise
InvalidKernelForBatchis returned.
Builder, Streaming & Batch APIs ▼
// Builder
AdjustableMaAlternatingExtremitiesBuilder::new()
.length(usize)
.mult(f64)
.alpha(f64)
.beta(f64)
.kernel(Kernel)
.apply_slices(&[f64], &[f64], &[f64])
AdjustableMaAlternatingExtremitiesBuilder::new()
.apply(&Candles)
AdjustableMaAlternatingExtremitiesBuilder::new()
.into_stream()
// Stream
AdjustableMaAlternatingExtremitiesStream::try_new(AdjustableMaAlternatingExtremitiesParams)
AdjustableMaAlternatingExtremitiesStream::update(high, low, close)
-> Option<AdjustableMaAlternatingExtremitiesStreamOutput>
// Batch
AdjustableMaAlternatingExtremitiesBatchBuilder::new()
.range(AdjustableMaAlternatingExtremitiesBatchRange)
.kernel(Kernel)
.apply_slices(&[f64], &[f64], &[f64])
AdjustableMaAlternatingExtremitiesBatchBuilder::new()
.apply(&Candles) Error Handling ▼
pub enum AdjustableMaAlternatingExtremitiesError {
EmptyInputData,
DataLengthMismatch { high: usize, low: usize, close: usize },
AllValuesNaN,
InvalidLength { length: usize, data_len: usize },
NotEnoughValidData { needed: usize, valid: usize },
InvalidMult { mult: f64 },
InvalidAlpha { alpha: f64 },
InvalidBeta { beta: f64 },
DegenerateKernel { alpha: f64, beta: f64 },
OutputLengthMismatch { expected: usize, got: usize },
InvalidRange { start: String, end: String, step: String },
InvalidKernelForBatch(Kernel),
} Python Bindings
Python exposes slice-based single-run and batch functions plus a streaming class. The single-run binding returns a dictionary of NumPy arrays for every output family. Batch returns 2D arrays for each output together with the parameter axes and matrix dimensions. The stream returns a ten-value tuple once the full warmup has completed.
import numpy as np
from vector_ta import (
adjustable_ma_alternating_extremities,
adjustable_ma_alternating_extremities_batch,
AdjustableMaAlternatingExtremitiesStream,
)
high = np.asarray(high_values, dtype=np.float64)
low = np.asarray(low_values, dtype=np.float64)
close = np.asarray(close_values, dtype=np.float64)
result = adjustable_ma_alternating_extremities(
high,
low,
close,
length=50,
mult=2.0,
alpha=1.0,
beta=0.5,
kernel="auto",
)
print(result["ma"][-1], result["extremity"][-1], result["state"][-1])
batch = adjustable_ma_alternating_extremities_batch(
high,
low,
close,
length_range=(30, 50, 10),
mult_range=(1.5, 2.5, 0.5),
alpha_range=(0.8, 1.2, 0.2),
beta_range=(0.3, 0.7, 0.2),
kernel="auto",
)
stream = AdjustableMaAlternatingExtremitiesStream(50, 2.0, 1.0, 0.5)
bar = stream.update(high[-1], low[-1], close[-1]) JavaScript/WASM Bindings
The WASM surface exposes one function for a normal run and one for batch sweeps. Both accept JavaScript typed
arrays and return plain objects. The single-run call returns the ten output arrays. The batch call returns the
flattened matrices plus the parameter lists and the final rows / cols
shape metadata needed to reshape them on the host side.
import init, {
adjustable_ma_alternating_extremities_js,
adjustable_ma_alternating_extremities_batch,
} from "/pkg/vector_ta.js";
await init();
const high = new Float64Array(highValues);
const low = new Float64Array(lowValues);
const close = new Float64Array(closeValues);
const result = adjustable_ma_alternating_extremities_js(
high,
low,
close,
50,
2.0,
1.0,
0.5
);
console.log(result.ma.at(-1), result.upper.at(-1), result.extremity.at(-1));
const batch = adjustable_ma_alternating_extremities_batch(high, low, close, {
length_range: [30, 50, 10],
mult_range: [1.5, 2.5, 0.5],
alpha_range: [0.8, 1.2, 0.2],
beta_range: [0.3, 0.7, 0.2],
});
console.log(batch.rows, batch.cols, batch.lengths, batch.ma.slice(0, 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)
Related Indicators
Accumulation/Distribution
Technical analysis indicator
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
Dma
Technical analysis indicator