Ehlers Distance Coefficient Filter (EDCF)

Parameters: period = 15

Overview

The Ehlers Distance Coefficient Filter (EDCF), developed by John Ehlers, creates an adaptive smoothing filter that automatically adjusts its behavior based on market volatility using a unique distance weighting approach. Rather than using fixed weights like traditional moving averages, EDCF calculates weights dynamically by measuring the squared distances between consecutive price samples within the lookback window. Larger price movements generate higher weights, causing the filter to respond more quickly to significant changes. This non linear weighting scheme allows EDCF to reduce noise during sideways markets while maintaining responsiveness during trending periods. The filter essentially becomes more reactive when price movements are decisive and more stable when movements are minor.

EDCF excels at adapting to changing market conditions without manual parameter adjustments. During low volatility consolidation phases, the distance weights become more uniform, causing the filter to smooth price action similar to a traditional moving average. When volatility increases and price makes larger moves, the squared distance calculation heavily weights these significant changes, allowing the filter to track price more closely. This adaptive behavior makes EDCF particularly effective in markets that alternate between trending and ranging states. The period parameter determines the lookback window for distance calculations, with typical values ranging from 10 to 20 periods depending on the desired balance between smoothness and responsiveness.

Traders use EDCF as a superior alternative to traditional moving averages for trend identification and signal generation. The filter provides cleaner signals during choppy markets by automatically reducing sensitivity when price movements lack conviction. Crossovers between price and EDCF generate trading signals with fewer whipsaws than fixed weight averages, as the adaptive weighting helps distinguish genuine breakouts from noise. Many traders employ EDCF as a baseline for other calculations, using its adaptive smoothing to improve oscillators or band indicators. The filter also works well for dynamic support and resistance levels, as its adaptive nature keeps it relevant to current market volatility rather than lagging behind like traditional smoothing methods.

Implementation Examples

Get started with EDCF in a few lines:

use vectorta::indicators::moving_averages::edcf::{edcf, EdcfInput, EdcfParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};

// Using with a price slice
let prices = vec![100.0, 102.0, 101.5, 103.0, 105.0, 104.5];
let params = EdcfParams { period: Some(15) };
let input = EdcfInput::from_slice(&prices, params);
let result = edcf(&input)?;

// Using with Candles (defaults: period=15, source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = EdcfInput::with_default_candles(&candles);
let result = edcf(&input)?;

// Access the filtered values
for value in result.values {
    println!("EDCF: {}", value);
}

API Reference

Input Methods
// From price slice
EdcfInput::from_slice(&[f64], EdcfParams) -> EdcfInput

// From candles with custom source
EdcfInput::from_candles(&Candles, &str, EdcfParams) -> EdcfInput

// From candles with default params (close, period=15)
EdcfInput::with_default_candles(&Candles) -> EdcfInput
Parameters Structure
pub struct EdcfParams {
    pub period: Option<usize>, // Default: 15
}
Output Structure
pub struct EdcfOutput {
    pub values: Vec<f64>, // Weighted filter values matching input length
}
Validation, Warmup & NaNs
  • period > 0 and period ≤ len(data), otherwise EdcfError::InvalidPeriod.
  • Must have at least 2×period valid points after the first finite value; otherwise EdcfError::NotEnoughValidData.
  • Warmup: indices [.. first_finite + 2×period) are NaN by design.
  • Constant windows can yield NaN when the weights’ sum is zero.
  • edcf_into_slice: destination length must equal input length, else EdcfError::OutputLenMismatch.
  • Streaming: returns None until filled with period samples; non‑finite inputs return None.
Error Handling
use vectorta::indicators::moving_averages::edcf::{edcf, EdcfInput, EdcfParams, EdcfError};

match edcf(&EdcfInput::from_slice(&prices, EdcfParams { period: Some(15) })) {
    Ok(output) => process_results(output.values),
    Err(EdcfError::NoData) => println!("No data provided"),
    Err(EdcfError::AllValuesNaN) => println!("All input values are NaN"),
    Err(EdcfError::InvalidPeriod { period, data_len }) =>
        println!("Invalid period {} for data length {}", period, data_len),
    Err(EdcfError::NotEnoughValidData { needed, valid }) =>
        println!("Need {} valid points, only {}", needed, valid),
    Err(EdcfError::OutputLenMismatch { expected, got }) =>
        println!("Output buffer len mismatch: expected {}, got {}", expected, got),
    Err(EdcfError::InvalidKernel) => println!("Invalid kernel specified for batch computation"),
}

Python Bindings

Basic Usage
import numpy as np
from vectorta import edcf, EdcfStream

prices = np.array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5], dtype=np.float64)

# One-shot calculation
values = edcf(prices, period=15)

# Streaming
stream = EdcfStream(period=15)
out = []
for p in prices:
    v = stream.update(float(p))
    out.append(np.nan if v is None else v)
Batch Processing

Test parameter ranges efficiently:

import numpy as np
from vectorta import edcf_batch

prices = np.array([...], dtype=np.float64)
period_range = (5, 30, 5)  # 5, 10, 15, 20, 25, 30

res = edcf_batch(prices, period_range, kernel="auto")
print(res.keys())  # values, periods
print(res['values'].shape)  # (num_periods, len(prices))
print(res['periods'])
CUDA Acceleration

CUDA interfaces are available for EDCF when built with CUDA support.

import numpy as np
from vectorta import edcf_cuda_batch_dev, edcf_cuda_many_series_one_param_dev

# Option 1: Single series, many parameters
prices_f32 = np.array([...], dtype=np.float32)
period_range = (5, 30, 1)
dev_id = 0
gpu_out = edcf_cuda_batch_dev(prices_f32, period_range, device_id=dev_id)

# Option 2: Many series (time-major [T, N]), one parameter
tm = np.array([[...], [...]], dtype=np.float32)  # shape [T, N]
gpu_out2 = edcf_cuda_many_series_one_param_dev(tm, period=15, device_id=dev_id)

JavaScript/WASM Bindings

Basic Usage

Calculate EDCF in JavaScript/TypeScript:

import { edcf_js } from 'vectorta-wasm';

const prices = new Float64Array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5]);
const values = edcf_js(prices, 15);
console.log('EDCF values:', values);

Note: EDCF allocates and reads a full distance buffer; in WASM this is significantly slower than native (20–60×). Consider ALMA/EMA/HMA for browser workloads.

Memory-Efficient Operations

Use zero-copy operations for large datasets:

import { edcf_alloc, edcf_free, edcf_into, memory } from 'vectorta-wasm';

const prices = new Float64Array([/* your data */]);
const len = prices.length;

const inPtr = edcf_alloc(len);
const outPtr = edcf_alloc(len);

new Float64Array(memory.buffer, inPtr, len).set(prices);

// Args: in_ptr, out_ptr, len, period
edcf_into(inPtr, outPtr, len, 15);

const values = new Float64Array(memory.buffer, outPtr, len).slice();

edcf_free(inPtr, len);
edcf_free(outPtr, len);
Batch Processing

Test multiple period values efficiently:

import { edcf_batch_js, edcf_batch_metadata_js } from 'vectorta-wasm';

const prices = new Float64Array([/* historical prices */]);

const periodStart = 5, periodEnd = 30, periodStep = 5;
const metadata = edcf_batch_metadata_js(periodStart, periodEnd, periodStep);
const numCombos = metadata.length; // one value per period

const results = edcf_batch_js(prices, periodStart, periodEnd, periodStep);

// results is flat: [combo1..., combo2..., ...]
const matrix: number[][] = [];
for (let i = 0; i < numCombos; i++) {
  const start = i * prices.length;
  const end = start + prices.length;
  matrix.push(Array.from(results.slice(start, end)));
}

Performance Analysis

Comparison:
View:
Loading chart...

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

Related Indicators