Average Directional Index Rating (ADXR)

Parameters: period = 14 (2–100)

Overview

ADXR smooths trend strength measurements by averaging today's ADX with the ADX value from N periods ago, creating a less reactive indicator that confirms sustained directional movement. Where standard ADX might spike on short lived volatility bursts, ADXR requires persistent trend strength across multiple timeframes to generate high readings. The calculation simply takes the arithmetic mean of current ADX and historical ADX, effectively creating a moving average that spans twice the base period. Traders use ADXR when markets exhibit erratic behavior that causes ADX to fluctuate rapidly between trending and ranging signals. Values above 25 confirm established trends worth following, while readings below 20 suggest choppy conditions where trend following strategies underperform. The smoother nature of ADXR makes it particularly valuable for position traders who need confirmation of long term trend persistence before committing capital.

Implementation Examples

Get started with ADXR in just a few lines:

use vectorta::indicators::adxr::{adxr, AdxrInput, AdxrParams};
use vectorta::utilities::data_loader::Candles;

// Using with HLC data slices
let high = vec![100.5, 102.0, 101.8, 103.5, 105.2, 104.8];
let low = vec![99.5, 100.2, 100.5, 101.0, 103.0, 103.2];
let close = vec![100.0, 101.5, 101.0, 102.5, 104.5, 104.0];
let params = AdxrParams {
    period: Some(14),
};
let input = AdxrInput::from_slices(&high, &low, &close, params);
let result = adxr(&input)?;

// Using with Candles data structure
// Quick and simple with default parameters
let input = AdxrInput::with_default_candles(&candles);
let result = adxr(&input)?;

// Access the ADXR values
for value in result.values {
    if !value.is_nan() {
        println!("ADXR: {:.2}", value);
    }
}

API Reference

Input Methods
// From HLC slices
AdxrInput::from_slices(&[f64], &[f64], &[f64], AdxrParams) -> AdxrInput

// From candles structure
AdxrInput::from_candles(&Candles, AdxrParams) -> AdxrInput

// From candles with default params (period=14)
AdxrInput::with_default_candles(&Candles) -> AdxrInput
Parameters Structure
pub struct AdxrParams {
    pub period: Option<usize>, // Default: 14
}
Output Structure
pub struct AdxrOutput {
    pub values: Vec<f64>, // ADXR values (average of current and N-period-ago ADX)
}
Error Handling
use vectorta::indicators::adxr::AdxrError;

match adxr(&input) {
    Ok(output) => process_results(output.values),
    Err(AdxrError::CandleFieldError(msg)) =>
        println!("Failed to retrieve HLC data: {}", msg),
    Err(AdxrError::HlcLengthMismatch { high_len, low_len, close_len }) =>
        println!("Data length mismatch: H={}, L={}, C={}", high_len, low_len, close_len),
    Err(AdxrError::AllValuesNaN) =>
        println!("All input values are NaN"),
    Err(AdxrError::InvalidPeriod { period, data_len }) =>
        println!("Invalid period {} for data length {}", period, data_len),
    Err(AdxrError::NotEnoughData { needed, valid }) =>
        println!("Need {} data points, only {} valid", needed, valid),
    Err(e) => println!("ADXR error: {}", e)
}

Python Bindings

Basic Usage

Calculate ADXR using NumPy arrays:

import numpy as np
from vectorta import adxr

# Prepare HLC data as NumPy arrays
high = np.array([100.5, 102.0, 101.8, 103.5, 105.2, 104.8])
low = np.array([99.5, 100.2, 100.5, 101.0, 103.0, 103.2])
close = np.array([100.0, 101.5, 101.0, 102.5, 104.5, 104.0])

# Calculate ADXR with default parameters (period=14)
result = adxr(high, low, close)

# Or specify custom parameters
result = adxr(high, low, close, period=20)

# Specify kernel for performance optimization
result = adxr(high, low, close, period=14, kernel="avx2")

# Result is a NumPy array matching input length
print(f"ADXR values: {result}")
print(f"Current ADXR: {result[-1]:.2f}")
Streaming Real-time Updates

Process real-time price updates efficiently:

from vectorta import AdxrStream

# Initialize streaming ADXR calculator
stream = AdxrStream(period=14)

# Process real-time price updates
for candle in price_feed:
    adxr_value = stream.update(candle.high, candle.low, candle.close)

    if adxr_value is not None:
        # ADXR value is ready (None during warmup period)
        print(f"Current ADXR: {adxr_value:.2f}")

        # Make trading decisions based on ADXR
        if adxr_value > 25:
            print("Strong trend - suitable for trend following")
        elif adxr_value < 20:
            print("Weak trend - consider range trading strategies")

        # Combine with ADX for confirmation
        if adxr_value > previous_adxr:
            print("Trend strength increasing")
Batch Parameter Optimization

Test multiple parameter combinations for optimization:

import numpy as np
from vectorta import adxr_batch

# Your HLC data
high = np.array([...])  # Your historical high prices
low = np.array([...])   # Your historical low prices
close = np.array([...]) # Your historical close prices

# Define parameter range to test
# (start, end, step) for period parameter
period_range = (5, 50, 5)  # Test: 5, 10, 15, ..., 50

# Run batch calculation
results = adxr_batch(
    high, low, close,
    period_range=period_range,
    kernel="auto"  # Auto-select best kernel
)

# Access results
print(f"Values shape: {results['values'].shape}")  # (num_periods, len(prices))
print(f"Periods tested: {results['periods']}")

# Find best performing period
# Example: Find period with highest average ADXR value
avg_adxr = np.nanmean(results['values'], axis=1)
best_idx = np.argmax(avg_adxr)
best_period = results['periods'][best_idx]
print(f"Optimal period: {best_period}")
CUDA Acceleration

CUDA support for ADXR is currently under development. The API will follow the same pattern as other CUDA-enabled indicators.

# Coming soon: CUDA-accelerated ADXR calculations
#
# from vectorta import adxr_cuda_batch, adxr_cuda_many_series_one_param
# import numpy as np
#
# # Option 1: One Series, Many Parameters (parameter optimization)
# # Test multiple period values on a single price series
# results = adxr_cuda_batch(
#     high=high_data,
#     low=low_data,
#     close=close_data,
#     period_range=(5, 50, 1),  # Test all periods from 5 to 50
#     device_id=0
# )
# # Returns:
# # - results['values']: 2D array [num_periods x len(prices)]
# # - results['periods']: array of periods tested
#
# # Option 2: Many Series, One Parameter Set (portfolio processing)
# # Process multiple stocks/assets with the same ADXR parameters
# portfolio_high = np.array([...])  # Shape: [time_steps, num_assets]
# portfolio_low = np.array([...])   # Shape: [time_steps, num_assets]
# portfolio_close = np.array([...]) # Shape: [time_steps, num_assets]
#
# results = adxr_cuda_many_series_one_param(
#     high_tm=portfolio_high,   # Time-major format [T, N]
#     low_tm=portfolio_low,
#     close_tm=portfolio_close,
#     period=14,
#     device_id=0
# )
# # Returns: 2D array [time_steps, num_assets] with ADXR for each asset
#
# # Zero-copy variant with pre-allocated output (F32 for GPU efficiency)
# out = np.empty((time_steps, num_assets), dtype=np.float32)
# adxr_cuda_many_series_one_param_into(
#     high_tm_f32=portfolio_high.astype(np.float32),
#     low_tm_f32=portfolio_low.astype(np.float32),
#     close_tm_f32=portfolio_close.astype(np.float32),
#     period=14,
#     out=out,
#     device_id=0
# )

JavaScript/WASM Bindings

Basic Usage

Calculate ADXR in JavaScript/TypeScript:

import { adxr_js } from 'vectorta-wasm';

// HLC data as Float64Array or regular arrays
const high = new Float64Array([100.5, 102.0, 101.8, 103.5, 105.2, 104.8]);
const low = new Float64Array([99.5, 100.2, 100.5, 101.0, 103.0, 103.2]);
const close = new Float64Array([100.0, 101.5, 101.0, 102.5, 104.5, 104.0]);

// Calculate ADXR with specified period
const result = adxr_js(high, low, close, 14);  // period=14

// Result is a Float64Array
console.log('ADXR values:', result);

// TypeScript type definitions
interface AdxrResult {
  values: Float64Array;
}

// Use with async/await for better error handling
async function calculateADXR(
  high: Float64Array,
  low: Float64Array,
  close: Float64Array
): Promise<Float64Array> {
  try {
    return adxr_js(high, low, close, 14);
  } catch (error) {
    console.error('ADXR calculation failed:', error);
    throw error;
  }
}
Memory-Efficient Operations

Use zero-copy operations for better performance with large datasets:

import { adxr_alloc, adxr_free, adxr_into, memory } from 'vectorta-wasm';

// Prepare your HLC data
const high = new Float64Array([/* your high data */]);
const low = new Float64Array([/* your low data */]);
const close = new Float64Array([/* your close data */]);
const length = close.length;

// Allocate WASM memory for output
const outputPtr = adxr_alloc(length);

// Get input data pointers in WASM memory
const highArray = new Float64Array(memory.buffer, /* offset */, length);
const lowArray = new Float64Array(memory.buffer, /* offset */, length);
const closeArray = new Float64Array(memory.buffer, /* offset */, length);
highArray.set(high);
lowArray.set(low);
closeArray.set(close);

// Calculate ADXR directly into allocated memory (zero-copy)
adxr_into(
  highArray.byteOffset,   // High pointer
  lowArray.byteOffset,    // Low pointer
  closeArray.byteOffset,  // Close pointer
  outputPtr,               // Output pointer
  length,                  // Data length
  14                       // Period
);

// Read results from WASM memory
const result = new Float64Array(memory.buffer, outputPtr, length);
const adxrValues = Array.from(result); // Convert to regular array if needed

// Important: Free allocated memory when done
adxr_free(outputPtr, length);

console.log('ADXR values:', adxrValues);
Batch Processing

Test multiple parameter combinations efficiently:

import { adxr_batch_js, adxr_batch_metadata_js } from 'vectorta-wasm';

// Your HLC data
const high = new Float64Array([/* historical high prices */]);
const low = new Float64Array([/* historical low prices */]);
const close = new Float64Array([/* historical close prices */]);

// Define parameter sweep range
const periodStart = 5, periodEnd = 50, periodStep = 5;  // 5, 10, 15...50

// Get metadata about parameter combinations
const metadata = adxr_batch_metadata_js(
  periodStart, periodEnd, periodStep
);

// metadata contains period values
const numCombos = metadata.length;

// Calculate all combinations
const results = adxr_batch_js(
  high, low, close,
  periodStart, periodEnd, periodStep
);

// Results is a flat array: [combo1_values..., combo2_values..., ...]
// Reshape based on your needs
const resultMatrix = [];
for (let i = 0; i < numCombos; i++) {
  const start = i * close.length;
  const end = start + close.length;
  resultMatrix.push(results.slice(start, end));
}

// Access specific parameter combination results
const period = metadata[0];        // First combo's period
const adxrValues = resultMatrix[0]; // First combo's ADXR values

// Find optimal period
let bestPeriod = metadata[0];
let bestScore = -Infinity;

for (let i = 0; i < numCombos; i++) {
  const score = calculatePerformanceScore(resultMatrix[i]);
  if (score > bestScore) {
    bestScore = score;
    bestPeriod = metadata[i];
  }
}

console.log('Optimal ADXR period:', bestPeriod);

Performance Analysis

Comparison:
View:

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

Loading chart...

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

Related Indicators