Market Meanness Index
length = 300 | source_mode = Price Overview
Market Meanness Index counts how often a rolling source keeps moving away from the median of its current window.
In Price mode the source is close. In Change mode the source is
close - open. After ordering the rolling window, the implementation computes its median and counts
bars where the current value is above the median and above the prior value, or below the median and below the
prior value. Raw MMI is then scaled to a percentage with
count * 100 / (length - 1), and
mmi_smoothed is a simple moving average of mmi over the same length.
Defaults: length = 300 and source_mode = "Price". Candle input uses
open and close.
Implementation Examples
Use candle helpers or explicit open/close slices:
use vector_ta::indicators::market_meanness_index::{
market_meanness_index,
MarketMeannessIndexInput,
MarketMeannessIndexParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
let open = vec![100.0, 100.4, 100.8, 100.6, 101.2, 101.9];
let close = vec![100.3, 100.7, 100.5, 101.0, 101.8, 102.2];
let input = MarketMeannessIndexInput::from_slices(
&open,
&close,
MarketMeannessIndexParams::default(),
);
let out = market_meanness_index(&input)?;
// Candles path uses candles.open and candles.close
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_out = market_meanness_index(&MarketMeannessIndexInput::with_default_candles(&candles))?;
println!("{:?}", out.mmi.last());
println!("{:?}", out.mmi_smoothed.last()); API Reference
Input Methods ▼
// From candles
MarketMeannessIndexInput::from_candles(
&Candles,
MarketMeannessIndexParams,
) -> MarketMeannessIndexInput
// From open/close slices
MarketMeannessIndexInput::from_slices(
&[f64],
&[f64],
MarketMeannessIndexParams,
) -> MarketMeannessIndexInput
// Default candles params
MarketMeannessIndexInput::with_default_candles(&Candles)
-> MarketMeannessIndexInput Parameters and Outputs ▼
pub struct MarketMeannessIndexParams {
pub length: Option<usize>, // default 300
pub source_mode: Option<String>, // "Price" or "Change"
}
pub struct MarketMeannessIndexOutput {
pub mmi: Vec<f64>,
pub mmi_smoothed: Vec<f64>,
} Builder, Stream, and Batch Surface ▼
MarketMeannessIndexBuilder::new()
.length(usize)
.source_mode(&str) -> Result<Self, MarketMeannessIndexError>
.kernel(Kernel)
.apply(&Candles) -> Result<MarketMeannessIndexOutput, _>
MarketMeannessIndexBuilder::new()
.apply_slices(&[f64], &[f64]) -> Result<MarketMeannessIndexOutput, _>
MarketMeannessIndexBuilder::new()
.into_stream() -> Result<MarketMeannessIndexStream, _>
MarketMeannessIndexStream::update(open, close) -> Option<(f64, f64)>
MarketMeannessIndexStream::update_reset_on_nan(open, close) -> Option<(f64, f64)>
MarketMeannessIndexBatchBuilder::new()
.kernel(Kernel)
.length_range(start, end, step)
.length_static(length)
.source_mode(&str) -> Result<Self, MarketMeannessIndexError>
.apply_slices(&[f64], &[f64]) -> Result<MarketMeannessIndexBatchOutput, _>
MarketMeannessIndexBatchBuilder::new()
.apply_candles(&Candles) -> Result<MarketMeannessIndexBatchOutput, _> Validation, Warmup, and NaNs ▼
openandclosemust be non-empty and equal-length.lengthmust be at least6and at most the data length.source_modemust be"Price"or"Change"(case-insensitive on input, normalized to canonical spelling).- The first valid bar depends on mode:
Priceonly needs a finite close;Changeneeds finite open and close. - The scalar validator requires at least
lengthvalid bars from the first valid bar. mmiwarmup prefix isfirst_valid + length - 1.mmi_smoothedwarmup prefix isfirst_valid + 2 * length - 2.- The compute path uses
update_reset_on_nan, so invalid bars reset stream state and leave NaNs in the outputs for that index.
Calculation and Batch Output ▼
Pricemode usesclose.Changemode usesclose - open.- For each full window, the implementation orders the ring buffer into a contiguous window, computes the median, and counts directional moves that continue away from the median.
- Raw MMI is
count * 100 / (length - 1). mmi_smoothedis a rolling SMA of raw MMI over the samelength.- Batch defaults are
length = (300, 300, 0)andsource_mode = "Price". - Rust batch output is
MarketMeannessIndexBatchOutputwith flattenedmmiandmmi_smoothedrows, pluscombos,rows, andcols. row_for_params()matches bothlengthand normalizedsource_mode.
Error Handling ▼
use vector_ta::indicators::market_meanness_index::MarketMeannessIndexError;
// Common errors:
// - EmptyInputData
// - DataLengthMismatch
// - AllValuesNaN
// - InvalidLength
// - InvalidSourceMode
// - NotEnoughValidData
// - OutputLengthMismatch
// - InvalidRange
// - InvalidKernelForBatch Python Bindings
Basic Usage ▼
The Python scalar function returns raw and smoothed MMI arrays:
from vector_ta import market_meanness_index
mmi, mmi_smoothed = market_meanness_index(
open,
close,
length=300,
source_mode="Price",
kernel="auto",
) Streaming Real-time Updates ▼
The Python stream wrapper uses reset-on-invalid semantics:
from vector_ta import MarketMeannessIndexStream
stream = MarketMeannessIndexStream(length=300, source_mode="Change")
for open_i, close_i in live_bars:
result = stream.update(open_i, close_i)
if result is not None:
mmi, mmi_smoothed = result Batch Processing ▼
Python batch returns both output matrices and parameter columns:
from vector_ta import market_meanness_index_batch
result = market_meanness_index_batch(
open,
close,
length_range=(100, 300, 100),
source_mode="Price",
kernel="auto",
)
mmi = result["mmi"]
mmi_smoothed = result["mmi_smoothed"]
lengths = result["lengths"]
source_modes = result["source_modes"]
rows = result["rows"]
cols = result["cols"] JavaScript/WASM Bindings
Basic Usage ▼
The scalar JS/WASM call returns an object with raw and smoothed series:
import { market_meanness_index_js } from 'vectorta-wasm';
const result = market_meanness_index_js(open, close, 300, "Price") as {
mmi: number[];
mmi_smoothed: number[];
};
console.log(result.mmi);
console.log(result.mmi_smoothed); Host Buffer API ▼
Low-level WASM allocates one packed buffer of length len * 2, split into mmi then mmi_smoothed:
import {
market_meanness_index_alloc,
market_meanness_index_free,
market_meanness_index_into_host,
} from 'vectorta-wasm';
const len = close.length;
const outPtr = market_meanness_index_alloc(len);
try {
market_meanness_index_into_host(open, close, outPtr, 300, "Price");
} finally {
market_meanness_index_free(outPtr, len);
} Batch Processing ▼
The JS batch config takes a 3-element length_range and optional source_mode:
import { market_meanness_index_batch_js } from 'vectorta-wasm';
const batch = market_meanness_index_batch_js(open, close, {
length_range: [100, 300, 100],
source_mode: "Price",
}) as {
mmi: number[];
mmi_smoothed: number[];
rows: number;
cols: number;
combos: Array<{ length?: number; source_mode?: string }>;
};
console.log(batch.rows, batch.cols);
console.log(batch.combos); 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)