Trend Follower

Parameters: matype = ema | trend_period = 20 | ma_period = 20 | channel_rate_percent = 1 | use_linear_regression = true | linear_regression_period = 5

Overview

Trend Follower is a single-output trend line designed to stay readable while still exposing several important choices: the moving-average family, the trend and smoothing periods, a channel-rate control, and an optional linear-regression pass. The result is a directional study that can be tuned to act more like a classic moving average, a channel-guided trend filter, or a smoother regime line with reduced noise.

In VectorTA the indicator works on HLCV input, accepts either raw slices or candle data, supports several moving average types, streams one update at a time, and exposes batch sweeps across the numeric controls while keeping the moving-average family and linear-regression toggle explicit. It fits best when you want one stable trend line rather than a stacked indicator with many separate outputs.

Defaults: `matype = "ema"`, `trend_period = 20`, `ma_period = 20`, `channel_rate_percent = 1.0`, `use_linear_regression = true`, and `linear_regression_period = 5`.

Implementation Examples

Run Trend Follower from raw HLCV slices or from a candle set using the default EMA configuration.

use vector_ta::indicators::trend_follower::{
    trend_follower,
    TrendFollowerInput,
    TrendFollowerParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

let direct = trend_follower(&TrendFollowerInput::from_slices(
    &high,
    &low,
    &close,
    &volume,
    TrendFollowerParams {
        matype: Some("ema".to_string()),
        trend_period: Some(20),
        ma_period: Some(20),
        channel_rate_percent: Some(1.0),
        use_linear_regression: Some(true),
        linear_regression_period: Some(5),
    },
))?;

let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let from_candles = trend_follower(&TrendFollowerInput::with_default_candles(&candles))?;

println!("latest trend = {:?}", direct.values.last());
println!("candle trend = {:?}", from_candles.values.last());

API Reference

Input Methods
TrendFollowerInput::from_candles(&Candles, TrendFollowerParams)
    -> TrendFollowerInput

TrendFollowerInput::from_slices(&[f64], &[f64], &[f64], &[f64], TrendFollowerParams)
    -> TrendFollowerInput

TrendFollowerInput::with_default_candles(&Candles)
    -> TrendFollowerInput
Parameters Structure
pub struct TrendFollowerParams {
    pub matype: Option<String>,                 // default "ema"
    pub trend_period: Option<usize>,            // default 20
    pub ma_period: Option<usize>,               // default 20
    pub channel_rate_percent: Option<f64>,      // default 1.0
    pub use_linear_regression: Option<bool>,    // default true
    pub linear_regression_period: Option<usize> // default 5
}
Output Structure
pub struct TrendFollowerOutput {
    pub values: Vec<f64>,
}
Validation, Warmup & NaNs
  • High, low, close, and volume slices must all have the same non-zero length and contain valid numeric data.
  • The moving-average family must be one of ema, sma, rma, wma, or vwma.
  • The resolved trend_period, ma_period, linear_regression_period, and channel_rate_percent must pass the module validation rules.
  • Batch mode validates the integer and float range axes before expanding the grid.
Builder, Streaming & Batch APIs
TrendFollowerBuilder::new()
    .trend_period(usize)
    .ma_period(usize)
    .channel_rate_percent(f64)
    .use_linear_regression(bool)
    .linear_regression_period(usize)
    .kernel(Kernel)
    .apply(&Candles)
    .apply_with_matype(&Candles, "ema")
    .apply_slices(&[f64], &[f64], &[f64], &[f64], "ema")
    .into_stream("ema")

TrendFollowerStream::try_new(params)
stream.update(high, low, close, volume) -> Option<f64>

TrendFollowerBatchBuilder::new()
    .trend_period_range(start, end, step)
    .ma_period_range(start, end, step)
    .channel_rate_percent_range(start, end, step)
    .linear_regression_period_range(start, end, step)
    .matype_static("ema")
    .use_linear_regression(bool)
    .apply_slices(&[f64], &[f64], &[f64], &[f64])

Python Bindings

Python exposes a direct function returning the trend line, a stream class for HLCV updates, and a batch helper that returns the flattened value grid alongside the resolved parameter axes for each row.

from vector_ta import (
    trend_follower,
    trend_follower_batch,
    TrendFollowerStream,
)

values = trend_follower(
    high,
    low,
    close,
    volume,
    matype="ema",
    trend_period=20,
    ma_period=20,
    channel_rate_percent=1.0,
    use_linear_regression=True,
    linear_regression_period=5,
)

stream = TrendFollowerStream(
    matype="ema",
    trend_period=20,
    ma_period=20,
    channel_rate_percent=1.0,
    use_linear_regression=True,
    linear_regression_period=5,
)
point = stream.update(high[-1], low[-1], close[-1], volume[-1])

batch = trend_follower_batch(
    high,
    low,
    close,
    volume,
    trend_period_range=(10, 40, 5),
    ma_period_range=(10, 30, 5),
    channel_rate_percent_range=(0.5, 2.0, 0.5),
    linear_regression_period_range=(3, 9, 2),
    matype="ema",
    use_linear_regression=True,
)

JavaScript/WASM Bindings

The WASM surface includes direct, batch, and into-buffer helpers. The main JS entry points return the trend line as a plain array or a batch object, while the manual memory APIs support higher-throughput integrations.

import init, {
  trend_follower_js,
  trend_follower_batch_js,
  trend_follower_alloc,
  trend_follower_free,
  trend_follower_into,
  trend_follower_into_host,
  trend_follower_batch_into,
} from "vector-ta-wasm";

await init();

const single = trend_follower_js(
  high,
  low,
  close,
  volume,
  "ema",
  20,
  20,
  1.0,
  true,
  5,
);

const batch = trend_follower_batch_js(high, low, close, volume, {
  trend_period_range: [10, 40, 5],
  ma_period_range: [10, 30, 5],
  channel_rate_percent_range: [0.5, 2.0, 0.5],
  linear_regression_period_range: [3, 9, 2],
  matype: "ema",
  use_linear_regression: true,
});

console.log(single.at(-1), batch.rows, batch.cols);

CUDA Bindings (Rust)

Additional details for the CUDA bindings can be found inside the VectorTA repository.

Performance Analysis

Comparison:
View:
Placeholder data (no recorded benchmarks for this indicator)

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

Loading chart...

AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU)

Related Indicators