Market Facilitation Index (marketefi)
Overview
The Market Facilitation Index, developed by Bill Williams, measures the market's willingness to move price by calculating the ratio of price range (High minus Low) to trading volume, revealing how efficiently the market generates price movement per unit of volume traded. Williams designed MFI to answer the critical question of how much price responds to a given amount of trading activity, with higher values indicating that price moved significantly on relatively low volume, suggesting efficient directional movement, while lower values show that high volume produced minimal price change, indicating inefficiency or consolidation. In Williams' trading system, MFI values are typically displayed as a four-color histogram where green bars (MFI up, volume up) signal strong trend continuation as new participants enter the market, brown bars (MFI down, volume down) indicate trend exhaustion as market interest wanes, blue bars (MFI up, volume down) warn of potential manipulation or unsustainable moves on thin volume, and pink bars (MFI down, volume up) represent battles between bulls and bears that often precede breakouts. Williams emphasized that MFI should never be used in isolation but rather combined with his Fractal indicator for entry points and the Alligator indicator for trend direction, as MFI itself does not generate buy or sell signals but instead assesses whether current market conditions favor trend trading or range strategies.
Implementation Examples
Compute Market Facilitation Index from slices or candles:
use vectorta::indicators::marketefi::{marketefi, MarketefiInput, MarketefiParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// Using with slices (high, low, volume)
let high = vec![10.0, 11.5, 12.0, 12.3];
let low = vec![9.5, 10.9, 11.8, 12.0];
let volume = vec![1500.0, 2200.0, 2000.0, 1800.0];
let input = MarketefiInput::from_slices(&high, &low, &volume, MarketefiParams::default());
let result = marketefi(&input)?;
// Using with Candles (defaults: sources "high", "low", "volume")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = MarketefiInput::with_default_candles(&candles);
let result = marketefi(&input)?;
// Access values
for v in result.values { println!("MarketEFI: {}", v); }
API Reference
Input Methods ▼
// From slices (high, low, volume)
MarketefiInput::from_slices(&[f64], &[f64], &[f64], MarketefiParams) -> MarketefiInput
// From candles with explicit sources
MarketefiInput::from_candles(&Candles, &str, &str, &str, MarketefiParams) -> MarketefiInput
// From candles with defaults: sources "high", "low", "volume"
MarketefiInput::with_default_candles(&Candles) -> MarketefiInput Parameters Structure ▼
pub struct MarketefiParams; // No adjustable parameters (Default: MarketefiParams::default()) Output Structure ▼
pub struct MarketefiOutput {
pub values: Vec<f64>, // (high - low) / volume
} Validation, Warmup & NaNs ▼
- Errors:
MarketefiError::EmptyData,MismatchedDataLength,AllValuesNaN,NotEnoughValidData,ZeroOrNaNVolume. - Leading indices before the first bar where
high,low, andvolumeare all finite are set toNaN. - For any index where
volume == 0or any input isNaN, the output at that index isNaN. - No warmup window; the first finite output appears at the first fully valid index.
- Streaming:
MarketefiStream::updatereturnsNonewhen inputs are invalid orvolume == 0, elseSome((high - low) / volume).
Error Handling ▼
use vectorta::indicators::marketefi::{marketefi, MarketefiError, MarketefiInput, MarketefiParams};
let input = MarketefiInput::from_slices(&high, &low, &volume, MarketefiParams::default());
match marketefi(&input) {
Ok(output) => process(output.values),
Err(MarketefiError::EmptyData) => eprintln!("Empty data provided"),
Err(MarketefiError::MismatchedDataLength) => eprintln!("Length mismatch among inputs"),
Err(MarketefiError::AllValuesNaN) => eprintln!("All values are NaN"),
Err(MarketefiError::NotEnoughValidData) => eprintln!("Not enough valid data"),
Err(MarketefiError::ZeroOrNaNVolume) => eprintln!("Zero or NaN volume at a valid index"),
} Python Bindings
Basic Usage ▼
Calculate Market Facilitation Index using NumPy arrays:
import numpy as np
from vectorta import marketefi
# Prepare inputs
high = np.array([10.0, 11.5, 12.0, 12.3])
low = np.array([9.5, 10.9, 11.8, 12.0])
volume = np.array([1500.0, 2200.0, 2000.0, 1800.0])
# Calculate (optional: kernel="auto" | "scalar" | "avx2" | "avx512")
values = marketefi(high, low, volume)
print(values) Streaming Real-time Updates ▼
Compute values tick-by-tick:
from vectorta import MarketefiStream
stream = MarketefiStream()
for h, l, v in stream_source:
val = stream.update(h, l, v)
if val is not None:
use(val) Batch (single configuration) ▼
Batch returns one row since there are no parameters to sweep:
import numpy as np
from vectorta import marketefi_batch
high = np.array([...])
low = np.array([...])
volume = np.array([...])
result = marketefi_batch(high, low, volume, kernel="auto")
values = result['values'] # shape: (1, len(data))
print(values.shape) CUDA Acceleration ▼
CUDA support for Market Facilitation Index is currently under development. The API will follow the same pattern as other CUDA-enabled indicators.
# Coming soon: CUDA-accelerated marketefi calculations JavaScript/WASM Bindings
Basic Usage ▼
Compute Market Facilitation Index with arrays of high, low, and volume:
import { marketefi_js } from 'vectorta-wasm';
const high = new Float64Array([10.0, 11.5, 12.0, 12.3]);
const low = new Float64Array([9.5, 10.9, 11.8, 12.0]);
const volume = new Float64Array([1500.0, 2200.0, 2000.0, 1800.0]);
const values = marketefi_js(high, low, volume);
console.log('MarketEFI values:', values); Memory-Efficient Operations ▼
Use zero-copy operations for large datasets:
import { marketefi_alloc, marketefi_free, marketefi_into, memory } from 'vectorta-wasm';
const len = high.length;
const highPtr = marketefi_alloc(len);
const lowPtr = marketefi_alloc(len);
const volumePtr = marketefi_alloc(len);
const outPtr = marketefi_alloc(len);
new Float64Array(memory.buffer, highPtr, len).set(high);
new Float64Array(memory.buffer, lowPtr, len).set(low);
new Float64Array(memory.buffer, volumePtr, len).set(volume);
// Args: high_ptr, low_ptr, volume_ptr, out_ptr, len
marketefi_into(highPtr, lowPtr, volumePtr, outPtr, len);
const values = new Float64Array(memory.buffer, outPtr, len).slice();
marketefi_free(highPtr, len);
marketefi_free(lowPtr, len);
marketefi_free(volumePtr, len);
marketefi_free(outPtr, len);
Batch Processing ▼
Batch returns a single row (no parameter sweep):
import { marketefi_batch } from 'vectorta-wasm';
const out = marketefi_batch(high, low, volume, {});
console.log('rows:', out.rows, 'cols:', out.cols);
console.log('values length:', out.values.length); Performance Analysis
Across sizes, Rust CPU runs about 2.41× slower than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05
Benchmark note
VectorTA’s Market Facilitation Index implementation includes additional edge-case handling (e.g., guarding against zero-volume inputs) compared to Tulip C. Because of this, Tulip C vs VectorTA timings may not be a strict apples-to-apples comparison.
Related Indicators
Accumulation/Distribution
Technical analysis indicator
Accumulation/Distribution Oscillator
Technical analysis indicator
Balance of Power
Technical analysis indicator
Chaikin Flow Oscillator
Technical analysis indicator
Elder Force Index
Technical analysis indicator
Ease of Movement
Technical analysis indicator