Trend Flex Filter (TrendFlex)
period = 20 Overview
TrendFlex measures the cyclical deviation of price from its underlying trend using sophisticated digital filtering techniques developed by John Ehlers. The indicator isolates transient price movements by first applying a low pass filter to establish the dominant trend, then calculating how current prices oscillate around this smoothed baseline. This approach effectively separates trending behavior from mean reverting fluctuations, helping traders identify when markets are likely to continue their current direction versus when they might snap back toward equilibrium. The oscillator highlights short to medium term cycles that traditional trend following indicators miss, making it valuable for timing entries and exits within established trends. Positive values indicate price is flexing above the filtered trend, while negative readings suggest downward deviation, with extreme readings often preceding reversals back toward the trend line. Default period is 20, calibrated to capture meaningful cyclical behavior while filtering noise in most market timeframes.
Implementation Examples
Get started with TrendFlex in a few lines:
use vectorta::indicators::moving_averages::trendflex::{trendflex, TrendFlexInput, TrendFlexParams};
use vectorta::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 = TrendFlexParams { period: Some(20) }; // default is 20
let input = TrendFlexInput::from_slice(&prices, params);
let result = trendflex(&input)?; // TrendFlexOutput
// Using with Candles (defaults: period=20, source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = TrendFlexInput::with_default_candles(&candles);
let result = trendflex(&input)?;
// Access values
for value in result.values {
println!("TrendFlex: {}", value);
} API Reference
Input Methods ▼
// From price slice
TrendFlexInput::from_slice(&[f64], TrendFlexParams) -> TrendFlexInput
// From candles with custom source
TrendFlexInput::from_candles(&Candles, &str, TrendFlexParams) -> TrendFlexInput
// From candles with default params (close prices, period=20)
TrendFlexInput::with_default_candles(&Candles) -> TrendFlexInput Parameters Structure ▼
pub struct TrendFlexParams {
pub period: Option<usize>, // Default: 20
} Output Structure ▼
pub struct TrendFlexOutput {
pub values: Vec<f64>, // Normalized momentum values; NaN until warmup
} Validation, Warmup & NaNs ▼
- Input must be non-empty; otherwise
TrendFlexError::NoDataProvided. period > 0andperiod < len; otherwiseTrendFlexError::ZeroTrendFlexPeriodorTrendFlexError::TrendFlexPeriodExceedsData.- Uses the first finite value index; if all
NaN, returnsTrendFlexError::AllValuesNaN. - Super smoother period
ss = round(period/2); ifssexceeds available data,TrendFlexError::SmootherPeriodExceedsData. - Warmup: indices before
first_valid + periodareNaN. After warmup, outputs are finite.
Error Handling ▼
use vectorta::indicators::moving_averages::trendflex::{trendflex, TrendFlexError};
match trendflex(&input) {
Ok(output) => process(output.values),
Err(TrendFlexError::NoDataProvided) =>
eprintln!("No data provided"),
Err(TrendFlexError::AllValuesNaN) =>
eprintln!("All values are NaN"),
Err(TrendFlexError::ZeroTrendFlexPeriod { period }) =>
eprintln!("Period must be > 0 (got {})", period),
Err(TrendFlexError::TrendFlexPeriodExceedsData { period, data_len }) =>
eprintln!("Period {} exceeds available data after first valid ({}).", period, data_len),
Err(TrendFlexError::SmootherPeriodExceedsData { ss_period, data_len }) =>
eprintln!("Smoother period {} exceeds data length {}.", ss_period, data_len),
} Python Bindings
Basic Usage ▼
Calculate TrendFlex using NumPy arrays (default period=20):
import numpy as np
from vectorta import trendflex
# Prepare price data as NumPy array
prices = np.array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5])
# Calculate TrendFlex with defaults (period=20)
result = trendflex(prices)
# Or specify a custom period and kernel
result = trendflex(prices, period=20, kernel="avx2")
# Result is a NumPy array matching input length
print(f"TrendFlex values: {result}") Streaming Real-time Updates ▼
Process real-time price updates efficiently:
from vectorta import TrendFlexStream
# Initialize streaming TrendFlex calculator
stream = TrendFlexStream(period=20)
# Process real-time price updates
for price in price_feed:
tf_value = stream.update(price)
if tf_value is not None:
print(f"Current TrendFlex: {tf_value}") Batch Parameter Sweep ▼
Test multiple period values in a single pass:
import numpy as np
from vectorta import trendflex_batch
prices = np.array([...])
results = trendflex_batch(
prices,
period_range=(5, 50, 5),
kernel="auto"
)
print(f"Values shape: {results['values'].shape}") # (rows, len(prices))
print(f"Periods tested: {results['periods']}") CUDA Acceleration ▼
Developer APIs available when built with CUDA and Python features.
# Requires vectorta built with CUDA support
from vectorta import trendflex_cuda_batch_dev, trendflex_cuda_many_series_one_param_dev
import numpy as np
# One series, many periods (GPU)
prices_f32 = np.asarray(prices, dtype=np.float32)
out_dev, meta = trendflex_cuda_batch_dev(
data_f32=prices_f32,
period_range=(5, 50, 1),
device_id=0
)
print(meta["periods"]) # Tested periods
# Many series (time-major), one period (GPU)
tm_f32 = np.asarray(time_major_matrix, dtype=np.float32) # shape [T, N]
dev_arr = trendflex_cuda_many_series_one_param_dev(
data_tm_f32=tm_f32,
period=20,
device_id=0
) JavaScript/WASM Bindings
Basic Usage ▼
Calculate TrendFlex in JavaScript/TypeScript:
import { trendflex_js } from 'vectorta-wasm';
// Price data as Float64Array or regular array
const prices = new Float64Array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5]);
// Calculate TrendFlex with specified period
const result = trendflex_js(prices, 20);
// Result is a Float64Array
console.log('TrendFlex values:', result); Memory-Efficient Operations ▼
Use zero-copy operations for large datasets:
import { trendflex_alloc, trendflex_free, trendflex_into, memory } from 'vectorta-wasm';
const prices = new Float64Array([/* your data */]);
const length = prices.length;
// Allocate WASM memory
const inPtr = trendflex_alloc(length);
const outPtr = trendflex_alloc(length);
// Copy input data into WASM memory
new Float64Array(memory.buffer, inPtr, length).set(prices);
// Compute TrendFlex directly into allocated memory
trendflex_into(inPtr, outPtr, length, 20);
// Read results (slice to copy out)
const tfValues = new Float64Array(memory.buffer, outPtr, length).slice();
// Free allocated memory
trendflex_free(inPtr, length);
trendflex_free(outPtr, length);
console.log('TrendFlex values:', tfValues); Batch Processing ▼
Test multiple period values efficiently:
import { trendflex_batch_js, trendflex_batch_metadata_js } from 'vectorta-wasm';
const prices = new Float64Array([/* historical prices */]);
// Define parameter sweep
const pStart = 5, pEnd = 50, pStep = 5; // 5, 10, 15, ...
// Get metadata about combinations (periods)
const metadata = trendflex_batch_metadata_js(pStart, pEnd, pStep);
const numCombos = metadata.length;
// Calculate all combinations
const flat = trendflex_batch_js(prices, pStart, pEnd, pStep);
// Reshape to matrix [rows x len]
const rows = numCombos;
const cols = prices.length;
const matrix = [] as Float64Array[];
for (let i = 0; i < rows; i++) {
const start = i * cols;
const end = start + cols;
matrix.push(flat.slice(start, end));
}
console.log('Periods:', metadata);
console.log('Matrix rows:', matrix.length); Performance Analysis
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
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