SGF

Parameters: period = 21 | poly_order = 2

Overview

SGF is an endpoint Savitzky-Golay smoother. It builds coefficients for the requested window and polynomial order, applies those weights to each rolling slice, and emits the fitted value at the current bar rather than a centered value that would require future samples.

That makes the indicator useful as a smooth moving-average-style trend line with less lag than a plain average, while still preserving local curvature. The stream path uses the same endpoint weights and starts returning values once the effective window is filled.

Defaults: `period = 21` and `poly_order = 2`.

Implementation Examples

Run SGF on candle closes or any direct numeric slice.

use vector_ta::indicators::moving_averages::sgf::{sgf, SgfInput, SgfParams};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

let out = sgf(&SgfInput::from_slice(
    &close,
    SgfParams {
        period: Some(21),
        poly_order: Some(2),
    },
))?;

let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_out = sgf(&SgfInput::with_default_candles(&candles))?;

println!("last sgf = {:?}", out.values.last());
println!("candle sgf = {:?}", candle_out.values.last());

API Reference

Input Methods
SgfInput::from_candles(&Candles, "close", SgfParams) -> SgfInput
SgfInput::from_slice(&[f64], SgfParams) -> SgfInput
SgfInput::with_default_candles(&Candles) -> SgfInput
Parameters Structure
pub struct SgfParams {
    pub period: Option<usize>,      // default 21
    pub poly_order: Option<usize>,  // default 2
}
Output Structure
pub struct SgfOutput {
    pub values: Vec<f64>,
}
Validation, Warmup & NaNs
  • The input slice must not be empty and must contain at least one finite value.
  • period must resolve to an odd effective period of at least 3 and no larger than the available data length.
  • poly_order must stay strictly below the effective period.
  • The direct and batch paths require at least effective_period valid bars after the first finite value.
  • The stream path returns None until the effective period has filled its ring buffer.
  • Batch mode rejects non-batch kernels and validates both period and poly_order sweep ranges.
Builder, Streaming & Batch APIs
SgfBuilder::new()
    .period(usize)
    .poly_order(usize)
    .kernel(Kernel)
    .apply(&Candles)
    .apply_slice(&[f64])
    .into_stream()

SgfStream::try_new(params)
stream.update(f64) -> Option<f64>

SgfBatchBuilder::new()
    .kernel(Kernel)
    .period_range(start, end, step)
    .period_static(value)
    .poly_order_range(start, end, step)
    .poly_order_static(value)
    .apply_slice(&[f64])
    .apply_candles(&Candles, "close")

Python Bindings

Python exposes one scalar function, one stream class, and one batch helper. The scalar path returns one NumPy array, the stream returns either one floating-point value or None, and the batch helper returns a dictionary containing the value matrix plus the expanded period and polynomial-order axes.

from vector_ta import sgf, sgf_batch, SgfStream

values = sgf(close, period=21, poly_order=2)

stream = SgfStream(period=21, poly_order=2)
point = stream.update(close[-1])

batch = sgf_batch(
    close,
    period_range=(15, 31, 2),
    poly_order_range=(1, 3, 1),
)

print(batch["values"].shape)
print(batch["periods"])
print(batch["poly_orders"])

JavaScript/WASM Bindings

The WASM layer exposes a scalar helper, a config-driven batch helper, and low-level allocation and into-buffer APIs. The high-level batch call returns rows, cols, values, and parameter combos, while the low-level batch path writes one flattened matrix and returns the number of parameter rows.

import init, {
  sgf_js,
  sgf_batch,
  sgf_alloc,
  sgf_free,
  sgf_into,
  sgf_batch_into,
} from "vector-ta-wasm";

await init();

const values = sgf_js(close, 21, 2);

const batch = sgf_batch(close, {
  period_range: [15, 31, 2],
  poly_order_range: [1, 3, 1],
});

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