Moving Average Cross Probability

Parameters: 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_window must be at least 2.
  • slow_length must be at least 2, and fast_length must be at least 1.
  • slow_length must remain strictly greater than fast_length.
  • resolution must be at least 2.
  • The fast and slow average warmups are fast_length - 1 and slow_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

Comparison:
View:
Placeholder data (no recorded benchmarks for this indicator)

Across sizes, Rust CPU runs about 1.14× faster than Tulip C in this benchmark.

Loading chart...

AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU)

Related Indicators