Exponential Moving Average (EMA)
period = 9 Overview
The Exponential Moving Average tracks price trends by applying exponentially decreasing weights to older data points, with the most recent prices receiving the highest influence. Unlike simple averages that weight all values equally, EMA uses a smoothing factor (typically 2/(period+1)) that creates a recursive calculation where each new value depends on the previous EMA and current price. When prices rise above the EMA, it signals potential upward momentum, while prices below suggest bearish pressure. Traders use EMA crossovers as entry and exit signals: faster EMAs crossing above slower ones indicate buying opportunities, while the reverse suggests selling points. The exponential weighting makes EMA particularly effective for tracking trending markets, as it responds quickly to directional moves while maintaining enough smoothing to filter out minor fluctuations.
Implementation Examples
Get started with EMA in just a few lines:
use vector_ta::indicators::ema::{ema, EmaInput, EmaParams};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
// Using with price data slice
let prices = vec![100.0, 102.0, 101.5, 103.0, 105.0, 104.5];
let params = EmaParams { period: Some(9) };
let input = EmaInput::from_slice(&prices, params);
let result = ema(&input)?;
// Using with Candles (default: source="close", period=9)
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = EmaInput::with_default_candles(&candles);
let result = ema(&input)?;
// Access EMA values
for value in result.values {
println!("EMA: {}", value);
} API Reference
Input Methods ▼
// From price slice
EmaInput::from_slice(&[f64], EmaParams) -> EmaInput
// From candles with custom source
EmaInput::from_candles(&Candles, &str, EmaParams) -> EmaInput
// From candles with default params (source="close", period=9)
EmaInput::with_default_candles(&Candles) -> EmaInput Parameters Structure ▼
pub struct EmaParams {
pub period: Option<usize>, // Default: 9
} Output Structure ▼
pub struct EmaOutput {
pub values: Vec<f64>, // EMA values
} Validation, Warmup & NaNs ▼
period > 0andperiod ≤ data.len(); elseEmaError::InvalidPeriod.- There must be at least
periodvalid points after the first finite value; otherwiseEmaError::NotEnoughValidData. - Indices before the first finite input are
NaN. - Warmup: from first finite value until
first + period - 1, output is a running mean; then standard EMA withα = 2/(n+1). - Non‑finite inputs during warmup carry forward the current mean; during EMA phase they carry forward the previous EMA value.
- Streaming: returns
Noneuntilperiodvalid values have been processed; then returns the current EMA. NaNs do not update state.
Error Handling ▼
use vector_ta::indicators::ema::{ema, EmaError};
match ema(&input) {
Ok(output) => process_results(output.values),
Err(EmaError::EmptyInputData) =>
println!("Input data is empty"),
Err(EmaError::AllValuesNaN) =>
println!("All input values are NaN"),
Err(EmaError::InvalidPeriod { period, data_len }) =>
println!("Invalid period {} for data length {}", period, data_len),
Err(EmaError::NotEnoughValidData { needed, valid }) =>
println!("Need {} valid points, have {}", needed, valid),
} Python Bindings
Basic EMA Calculation ▼
import numpy as np
from vector_ta import ema
# Price data
prices = np.array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5], dtype=float)
# Compute EMA (default kernel = auto)
values = ema(prices, period=9)
print(values) Kernel Selection ▼
# Choose execution kernel (optional)
from vector_ta import ema
values = ema(prices, period=14, kernel="avx2") # or "neon" on ARM
print(values) CUDA Acceleration ▼
CUDA helpers are available when the Python package is built with CUDA support. Inputs must be float32; outputs are device arrays (DLPack / __cuda_array_interface__ compatible).
import numpy as np
from vector_ta import ema_cuda_batch_dev, ema_cuda_many_series_one_param_dev
# One series (float32)
data_f32 = np.asarray(load_data(), dtype=np.float32)
dev = ema_cuda_batch_dev(
data_f32=data_f32,
period_range=(5, 30, 5),
device_id=0,
)
# Many series (time-major)
data_tm_f32 = np.asarray(load_data_time_major_matrix(), dtype=np.float32)
dev_tm = ema_cuda_many_series_one_param_dev(
data_tm_f32=data_tm_f32,
period=14,
device_id=0,
) JavaScript / WASM Bindings
Basic Usage ▼
import { ema_js } from 'vectorta-wasm';
const prices = new Float64Array([100, 102, 101.5, 103, 105, 104.5]);
const period = 9;
const values = ema_js(prices, period);
console.log(values); Memory-Efficient Operations ▼
Use zero-copy operations for large datasets:
import { ema_alloc, ema_free, ema_into, memory } from 'vectorta-wasm';
const prices = new Float64Array([/* your data */]);
const length = prices.length;
// Allocate WASM memory for input and output
const inPtr = ema_alloc(length);
const outPtr = ema_alloc(length);
// Copy input data into WASM memory
new Float64Array(memory.buffer, inPtr, length).set(prices);
// Calculate EMA directly into allocated memory
// Args: in_ptr, out_ptr, len, period
ema_into(inPtr, outPtr, length, 9);
// Read results from WASM memory (slice() to copy out)
const emaValues = new Float64Array(memory.buffer, outPtr, length).slice();
// Free allocated memory when done
ema_free(inPtr, length);
ema_free(outPtr, length);
console.log('EMA values:', emaValues); Batch Processing ▼
Test multiple period values efficiently:
import { ema_batch, ema_batch_metadata_js } from 'vectorta-wasm';
const prices = new Float64Array([/* historical prices */]);
// Define parameter sweep range
const start = 5, end = 50, step = 5; // 5, 10, 15, ... 50
// Get metadata about period combinations (single axis)
const metadata = ema_batch_metadata_js(start, end, step);
const numCombos = metadata.length;
// Calculate all combinations using unified batch API
const config = { period_range: [start, end, step] };
const result = ema_batch(prices, config);
// result is an object with values/combos/rows/cols
console.log(result.rows, result.cols);
// Access a specific row (e.g., first period)
const firstRow = result.values.slice(0, prices.length); CUDA Bindings (Rust)
use vector_ta::cuda::CudaEma;
use vector_ta::indicators::moving_averages::ema::EmaBatchRange;
let cuda = CudaEma::new(0)?;
let data_f32: [f32] = /* ... */;
let sweep = EmaBatchRange::default();
let out = cuda.ema_batch_dev(&data_f32, &sweep)?;
let _ = out; Performance Analysis
Across sizes, Rust CPU runs about 1.23× faster than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-02-28
Related Indicators
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
Ehlers Distance Coefficient Filter
Moving average indicator
Ehlers Error-Correcting EMA (ECEMA)
Moving average indicator