True Range Adjusted EMA (TRADJEMA)

Parameters: length = 40 | mult = 10 (1–25)

Overview

True Range Adjusted Exponential Moving Average dynamically adapts its smoothing characteristics based on current market volatility conditions. The indicator measures True Range for each bar and normalizes it within a rolling lookback window, then scales the EMA smoothing factor proportionally to create a volatility responsive average. When markets become more volatile, the smoothing factor increases to make the average more reactive to price changes, allowing it to track rapid moves more closely. Conversely, during quiet periods with low volatility, the factor contracts to filter out noise and provide a steadier trend signal. This adaptive behavior makes TRADJEMA particularly valuable for traders who need a single indicator that automatically adjusts to changing market conditions without manual parameter optimization. Default settings use a 40 period lookback window with a volatility multiplier of 10.0, calibrated to provide balanced adaptation across diverse market environments.

Implementation Examples

Calculate TRADJEMA from OHLC candles or explicit high/low/close slices:

use vectorta::indicators::moving_averages::tradjema::{
    TradjemaParams, TradjemaInput, tradjema,
};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};

// Using with OHLC slices
let high = vec![..];
let low = vec![..];
let close = vec![..];
let params = TradjemaParams { length: Some(40), mult: Some(10.0) };
let input = TradjemaInput::from_slices(&high, &low, &close, params);
let out = tradjema(&input)?;

// Using with Candles (defaults: length=40, mult=10.0)
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = TradjemaInput::with_default_candles(&candles);
let out = tradjema(&input)?;

// Access values
for v in out.values { println!("{}", v); }

API Reference

Input Methods
// From candles (uses high/low/close internally)
TradjemaInput::from_candles(&Candles, TradjemaParams) -> TradjemaInput

// From explicit OHLC slices
TradjemaInput::from_slices(&[f64], &[f64], &[f64], TradjemaParams) -> TradjemaInput

// With defaults (length=40, mult=10.0)
TradjemaInput::with_default_candles(&Candles) -> TradjemaInput
Parameters Structure
pub struct TradjemaParams {
    pub length: Option<usize>, // Default: 40
    pub mult: Option<f64>,     // Default: 10.0
}
Output Structure
pub struct TradjemaOutput {
    pub values: Vec<f64>, // TR-adjusted EMA values
}
Validation, Warmup & NaNs
  • length ≥ 2 and length ≤ data_len; otherwise TradjemaError::InvalidLength.
  • OHLC arrays must have equal length; otherwise TradjemaError::MissingData.
  • There must be at least length valid points after the first finite close; otherwise TradjemaError::NotEnoughValidData.
  • mult must be finite and > 0.0; otherwise TradjemaError::InvalidMult.
  • Leading invalid inputs: indices before first + length - 1 are NaN; first finite output occurs at warmup.
Error Handling
use vectorta::indicators::moving_averages::tradjema::{tradjema, TradjemaError};

match tradjema(&input) {
    Ok(output) => process(output.values),
    Err(TradjemaError::EmptyInputData) => eprintln!("Input data is empty"),
    Err(TradjemaError::AllValuesNaN) => eprintln!("All values are NaN"),
    Err(TradjemaError::MissingData) => eprintln!("OHLC length mismatch"),
    Err(TradjemaError::InvalidLength { length, data_len }) =>
        eprintln!("Invalid length {} for data_len {}", length, data_len),
    Err(TradjemaError::NotEnoughValidData { needed, valid }) =>
        eprintln!("Need {} valid points, only {}", needed, valid),
    Err(TradjemaError::InvalidMult { mult }) =>
        eprintln!("Invalid mult: {} (must be > 0 and finite)", mult),
}

Python Bindings

Basic Usage

Compute TRADJEMA from NumPy arrays (OHLC):

import numpy as np
from vectorta import tradjema

high = np.array([...], dtype=float)
low = np.array([...], dtype=float)
close = np.array([...], dtype=float)

# Defaults: length=40, mult=10.0
values = tradjema(high, low, close, 40, 10.0)

# Custom kernel
values = tradjema(high, low, close, 30, 8.0, kernel="auto")
Batch Processing

Sweep parameter grids and analyze combinations:

import numpy as np
from vectorta import tradjema_batch

high = np.array([...], dtype=float)
low = np.array([...], dtype=float)
close = np.array([...], dtype=float)

res = tradjema_batch(
    high, low, close,
    length_range=(20, 60, 10),
    mult_range=(5.0, 15.0, 2.5),
    kernel="auto"
)

# Results
vals = res["values"]        # shape: (rows, len(close))
lengths = res["lengths"]    # list of tested lengths (per row)
mults = res["mults"]        # list of tested mults (per row)
print(vals.shape, len(lengths), len(mults))
CUDA Acceleration

Available when built with python + cuda features:

from vectorta import (
    tradjema_cuda_batch_dev,
    tradjema_cuda_many_series_one_param_dev,
)
import numpy as np

# One series, many parameter combinations (device arrays returned)
rows = tradjema_cuda_batch_dev(
    high.astype('float32'),
    low.astype('float32'),
    close.astype('float32'),
    length_range=(20, 60, 10),
    mult_range=(5.0, 15.0, 2.5),
    device_id=0
)

# Many series, one parameter set (time-major [T, N] f32)
high_tm, low_tm, close_tm = ...  # np.ndarray[T, N] float32
dev_arr = tradjema_cuda_many_series_one_param_dev(
    high_tm, low_tm, close_tm,
    length=40, mult=10.0,
    device_id=0
)

JavaScript/WASM Bindings

Basic Usage

Compute TRADJEMA from OHLC arrays:

import { tradjema_js } from 'vectorta-wasm';

const high = new Float64Array([/* ... */]);
const low = new Float64Array([/* ... */]);
const close = new Float64Array([/* ... */]);

// length=40, mult=10.0
const values = tradjema_js(high, low, close, 40, 10.0);
Memory-Efficient Operations

Use zero-copy compute into preallocated WASM memory:

import { tradjema_alloc, tradjema_free, tradjema_into, memory } from 'vectorta-wasm';

const n = close.length;
const hPtr = tradjema_alloc(n);
const lPtr = tradjema_alloc(n);
const cPtr = tradjema_alloc(n);
const outPtr = tradjema_alloc(n);

new Float64Array(memory.buffer, hPtr, n).set(high);
new Float64Array(memory.buffer, lPtr, n).set(low);
new Float64Array(memory.buffer, cPtr, n).set(close);

// Compute directly into WASM buffer
tradjema_into(hPtr, lPtr, cPtr, outPtr, n, 40, 10.0);
const out = new Float64Array(memory.buffer, outPtr, n).slice();

// Free
tradjema_free(hPtr, n); tradjema_free(lPtr, n);
tradjema_free(cPtr, n); tradjema_free(outPtr, n);

Performance Analysis

Comparison:
View:
Loading chart...

AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05

CUDA note

In our benchmark workload, the Rust CPU implementation is faster than CUDA for this indicator. Prefer the Rust/CPU path unless your workload differs.

Related Indicators