Time Series Forecast (TSF)
period = 14 Overview
Time Series Forecast applies least squares linear regression over a rolling window to project the expected price one bar into the future, providing a forward looking trend estimate rather than a lagging average. TSF fits a straight line through the most recent period bars using regression analysis, then extends that line one step ahead to forecast where price should move next if the current trend continues. This projection makes TSF inherently more responsive than traditional moving averages, as it anticipates the next value based on recent trajectory rather than simply averaging past data. The indicator updates with each new bar by recalculating the regression and generating a new forecast, creating a smooth line that adjusts quickly to trend changes while filtering out random noise. Traders value TSF for its ability to stay ahead of price action during trends, positioning the forecast line where support or resistance should appear rather than where it has been, making it particularly useful for setting trailing stops or identifying early trend reversals.
Implementation Examples
Compute TSF over a price slice or candles:
use vectorta::indicators::tsf::{tsf, TsfInput, TsfParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// Using with price data slice
let prices = vec![100.0, 101.0, 102.5, 101.0, 103.0, 105.0];
let params = TsfParams { period: Some(14) };
let input = TsfInput::from_slice(&prices, params);
let result = tsf(&input)?;
// Using with Candles (defaults: period=14, source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = TsfInput::with_default_candles(&candles);
let result = tsf(&input)?;
// Access the TSF values
for value in result.values {
println!("TSF: {}", value);
} API Reference
Input Methods ▼
// From price slice
TsfInput::from_slice(&[f64], TsfParams) -> TsfInput
// From candles with custom source
TsfInput::from_candles(&Candles, &str, TsfParams) -> TsfInput
// From candles with default params (close prices, period=14)
TsfInput::with_default_candles(&Candles) -> TsfInput Parameters Structure ▼
#[derive(Debug, Clone)]
pub struct TsfParams {
pub period: Option<usize>, // Default: 14
} Output Structure ▼
#[derive(Debug, Clone)]
pub struct TsfOutput {
pub values: Vec<f64>, // one-step-ahead forecast for each index
} Validation, Warmup & NaNs ▼
period ≥ 2; otherwiseTsfError::PeriodTooSmall.period ≤ len(data); elseTsfError::InvalidPeriod { period, data_len }.- After the first finite input at index
first, there must be at leastperiodvalid points; elseTsfError::NotEnoughValidData { needed, valid }. - Slice paths: indices
[0 .. first + period − 1)are filled withNaN(warmup prefix). - Windows containing any
NaNyieldNaNoutputs for those indices. - Streaming: returns
Noneuntil the buffer fills toperiodpoints, then returnsSome(f64)each update (may beNaNif the current ring includes aNaN).
Error Handling ▼
use vectorta::indicators::tsf::{tsf, TsfError, TsfInput, TsfParams};
match tsf(&input) {
Ok(output) => process(output.values),
Err(TsfError::EmptyInputData) => eprintln!("no data provided"),
Err(TsfError::AllValuesNaN) => eprintln!("all values are NaN"),
Err(TsfError::InvalidPeriod { period, data_len }) => {
eprintln!("invalid period: {} (data_len={})", period, data_len)
}
Err(TsfError::NotEnoughValidData { needed, valid }) => {
eprintln!("need {} valid points, only {} available after first finite", needed, valid)
}
Err(TsfError::MismatchedOutputLen { expected, actual }) => {
eprintln!("output len {} does not match input len {}", actual, expected)
}
Err(TsfError::PeriodTooSmall { period }) => eprintln!("period must be ≥ 2 (got {})", period),
} Python Bindings
Basic Usage ▼
Calculate TSF using NumPy arrays (required argument: period):
import numpy as np
from vectorta import tsf
prices = np.array([100.0, 101.0, 102.5, 101.0, 103.0, 105.0])
# period is required for TSF Python API
result = tsf(prices, period=14)
# Select SIMD kernel if desired: "auto" | "scalar" | "avx2" | "avx512"
result = tsf(prices, period=14, kernel="auto")
print("TSF values:", result) Streaming Real-time Updates ▼
Use the streaming class to process tick-by-tick data:
from vectorta import TsfStream
stream = TsfStream(period=14)
for price in price_feed:
value = stream.update(price)
if value is not None:
# value may be NaN if the window contains NaN
handle(value) Batch Parameter Sweep ▼
Test many period values efficiently:
import numpy as np
from vectorta import tsf_batch
prices = np.array([...], dtype=np.float64)
# (start, end, step)
results = tsf_batch(prices, period_range=(5, 30, 5), kernel="auto")
# results['values'] shape: (num_periods, len(prices))
print(results['values'].shape)
# List of tested periods
print(results['periods']) CUDA Acceleration ▼
CUDA support for TSF is currently under development. The API will follow the same pattern as other CUDA-enabled indicators.
# Coming soon: CUDA-accelerated TSF calculations
# The planned APIs will mirror other indicators' CUDA functions. JavaScript/WASM Bindings
Basic Usage ▼
Calculate TSF in JavaScript/TypeScript:
import { tsf_js } from 'vectorta-wasm';
const prices = new Float64Array([100.0, 101.0, 102.5, 101.0, 103.0, 105.0]);
// Calculate TSF with specified period
const result = tsf_js(prices, 14);
console.log('TSF values:', result); Memory-Efficient Operations ▼
Use zero-copy operations for large datasets:
import { tsf_alloc, tsf_free, tsf_into, memory } from 'vectorta-wasm';
const prices = new Float64Array([/* your data */]);
const length = prices.length;
const inPtr = tsf_alloc(length);
const outPtr = tsf_alloc(length);
new Float64Array(memory.buffer, inPtr, length).set(prices);
// Args: in_ptr, out_ptr, len, period
tsf_into(inPtr, outPtr, length, 14);
const tsfValues = new Float64Array(memory.buffer, outPtr, length).slice();
tsf_free(inPtr, length);
tsf_free(outPtr, length);
console.log('TSF values:', tsfValues); Batch Processing ▼
Test multiple period values:
import { tsf_batch } from 'vectorta-wasm';
const prices = new Float64Array([/* historical prices */]);
// Provide configuration as an object; tuple is deserialized from the array
const res = tsf_batch(prices, { period_range: [5, 30, 5] });
// res = { values: Float64Array, combos: [{ period: 5 }, ...], rows, cols }
const periods = res.combos.map(c => c.period);
// Extract first combo's row
const valuesFirst = res.values.slice(0, res.cols);
console.log('Periods tested:', periods);
console.log('First row length:', valuesFirst.length); Performance Analysis
Across sizes, Rust CPU runs about 1.04× faster than Tulip C in this benchmark.
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
Average Directional Index
Technical analysis indicator
Average Directional Movement Index Rating
Technical analysis indicator
Alligator
Technical analysis indicator
Aroon
Technical analysis indicator
Aroon Oscillator
Technical analysis indicator
Chande Momentum Oscillator
Technical analysis indicator