Moving Average Cross Probability
ma_type = ema | smoothing_window = 7 | slow_length = 30 | fast_length = 14 | resolution = 50 Overview
Moving Average Cross Probability models whether a fast moving average is likely to cross a slow moving average inside a near-term forecast band. It first computes the chosen slow and fast averages, then builds a projected centerline from a Hull moving average plus its one-step slope. A four-sigma standard deviation envelope around that forecast defines the range of future prices tested for possible cross events.
The main output is a percentage probability. VectorTA also returns the slow and fast averages, the forecasted centerline, the upper and lower test bounds, and a directional state that reflects whether the fast average is currently above or below the slow average. The direction series determines which side of the crossing condition is counted as a hit inside the simulated band.
Defaults: `ma_type = "ema"`, `smoothing_window = 7`, `slow_length = 30`, `fast_length = 14`, and `resolution = 50`.
Implementation Examples
Run the probability model on a raw close slice or directly from candle closes.
use vector_ta::indicators::moving_average_cross_probability::{
moving_average_cross_probability,
MovingAverageCrossProbabilityInput,
MovingAverageCrossProbabilityMaType,
MovingAverageCrossProbabilityParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
let output = moving_average_cross_probability(&MovingAverageCrossProbabilityInput::from_slice(
&close,
MovingAverageCrossProbabilityParams {
ma_type: Some(MovingAverageCrossProbabilityMaType::Ema),
smoothing_window: Some(7),
slow_length: Some(30),
fast_length: Some(14),
resolution: Some(50),
},
))?;
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_output = moving_average_cross_probability(
&MovingAverageCrossProbabilityInput::with_default_candles(&candles),
)?;
println!("probability = {:?}", output.value.last());
println!("slow_ma = {:?}", candle_output.slow_ma.last());
println!("fast_ma = {:?}", candle_output.fast_ma.last());
println!("direction = {:?}", candle_output.direction.last()); API Reference
Input Methods ▼
// From candles
MovingAverageCrossProbabilityInput::from_candles(&Candles, MovingAverageCrossProbabilityParams)
-> MovingAverageCrossProbabilityInput
// From a raw close slice
MovingAverageCrossProbabilityInput::from_slice(&[f64], MovingAverageCrossProbabilityParams)
-> MovingAverageCrossProbabilityInput
// From candles with default parameters
MovingAverageCrossProbabilityInput::with_default_candles(&Candles)
-> MovingAverageCrossProbabilityInput Parameters Structure ▼
pub struct MovingAverageCrossProbabilityParams {
pub ma_type: Option<MovingAverageCrossProbabilityMaType>, // default Ema
pub smoothing_window: Option<usize>, // default 7
pub slow_length: Option<usize>, // default 30
pub fast_length: Option<usize>, // default 14
pub resolution: Option<usize>, // default 50
} Output Structure ▼
pub struct MovingAverageCrossProbabilityOutput {
pub value: Vec<f64>,
pub slow_ma: Vec<f64>,
pub fast_ma: Vec<f64>,
pub forecast: Vec<f64>,
pub upper: Vec<f64>,
pub lower: Vec<f64>,
pub direction: Vec<f64>,
} Validation, Warmup & NaNs ▼
- The input series must be non-empty and contain at least one finite value.
smoothing_windowmust be at least2.slow_lengthmust be at least2, andfast_lengthmust be at least1.slow_lengthmust remain strictly greater thanfast_length.resolutionmust be at least2.- The fast and slow average warmups are
fast_length - 1andslow_length - 1. - The forecast band warmup is
smoothing_window + floor(sqrt(smoothing_window)) - 1. - The probability warmup is the maximum of the forecast warmup, the direction warmup, and
2 * slow_length. - Any non-finite value inside the rolling history window suppresses the probability output until the full history becomes finite again.
Builder, Streaming & Batch APIs ▼
// Builder
MovingAverageCrossProbabilityBuilder::new()
.ma_type(MovingAverageCrossProbabilityMaType)
.smoothing_window(usize)
.slow_length(usize)
.fast_length(usize)
.resolution(usize)
.kernel(Kernel)
.apply(&Candles)
MovingAverageCrossProbabilityBuilder::new()
.apply_slice(&[f64])
MovingAverageCrossProbabilityBuilder::new()
.into_stream()
// Stream
MovingAverageCrossProbabilityStream::try_new(MovingAverageCrossProbabilityParams)
MovingAverageCrossProbabilityStream::update(f64)
-> (f64, f64, f64, f64, f64, f64, f64)
// Batch
MovingAverageCrossProbabilityBatchBuilder::new()
.ma_type(MovingAverageCrossProbabilityMaType)
.smoothing_window_range(usize, usize, usize)
.slow_length_range(usize, usize, usize)
.fast_length_range(usize, usize, usize)
.resolution_range(usize, usize, usize)
.kernel(Kernel)
.apply_slice(&[f64])
MovingAverageCrossProbabilityBatchBuilder::new()
.apply(&Candles) Error Handling ▼
pub enum MovingAverageCrossProbabilityError {
EmptyInputData,
AllValuesNaN,
InvalidSmoothingWindow { smoothing_window: usize },
InvalidSlowLength { slow_length: usize },
InvalidFastLength { fast_length: usize },
InvalidResolution { resolution: usize },
InvalidLengthOrder { fast_length: usize, slow_length: usize },
OutputLengthMismatch { expected: usize, got: usize },
InvalidRange { start: String, end: String, step: String },
InvalidKernelForBatch(Kernel),
} Python Bindings
Python exposes a scalar function, a streaming class, and a batch sweep. The scalar path returns a dict with the seven output series. The stream returns a seven-value tuple on every update, and batch returns the flattened matrices plus the tested smoothing windows, slow lengths, fast lengths, resolutions, and output dimensions.
from vector_ta import (
moving_average_cross_probability,
moving_average_cross_probability_batch,
MovingAverageCrossProbabilityStream,
)
result = moving_average_cross_probability(
close_values,
ma_type="ema",
smoothing_window=7,
slow_length=30,
fast_length=14,
resolution=50,
kernel="auto",
)
print(result["value"])
print(result["forecast"])
stream = MovingAverageCrossProbabilityStream(
ma_type="sma",
smoothing_window=9,
slow_length=40,
fast_length=18,
resolution=64,
)
print(stream.update(close_values[-1]))
batch = moving_average_cross_probability_batch(
close_values,
smoothing_window_range=(7, 11, 2),
slow_length_range=(30, 40, 5),
fast_length_range=(10, 18, 4),
resolution_range=(50, 90, 20),
ma_type="ema",
kernel="auto",
)
print(batch["value"].shape)
print(batch["slow_lengths"])
print(batch["resolutions"]) JavaScript/WASM Bindings
The WASM surface exposes scalar, batch, allocation, free, and into-buffer entry points. Scalar output returns the seven series directly. Batch output returns the same flattened row-major matrices plus the tested parameter axes and the row and column counts.
import init, {
moving_average_cross_probability_js,
moving_average_cross_probability_batch_js,
} from "@vectoralpha/vector_ta";
await init();
const single = moving_average_cross_probability_js(
close,
"ema",
7,
30,
14,
50,
);
console.log(single.value);
console.log(single.forecast);
console.log(single.direction);
const batch = moving_average_cross_probability_batch_js(close, {
smoothing_window_range: [7, 11, 2],
slow_length_range: [30, 40, 5],
fast_length_range: [10, 18, 4],
resolution_range: [50, 90, 20],
ma_type: "ema",
});
console.log(batch.value);
console.log(batch.slow_lengths);
console.log(batch.fast_lengths);
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)
Related Indicators
Arnaud Legoux Moving Average
Moving average indicator
Buff Averages
Technical analysis 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