Parabolic SAR (SAR)
acceleration = 0.02 (0.005–0.2) | maximum = 0.2 (0.1–1) Overview
The Parabolic SAR tracks trends by plotting accelerating stop points that trail price action and flip sides when penetrated. Developed by J. Welles Wilder, the indicator begins with an initial acceleration factor that increases each period the trend continues, causing the SAR points to accelerate toward price until reaching a maximum value. During an uptrend, SAR points appear below price and rise progressively faster with each new high, while downtrends place SAR points above price that fall increasingly rapidly with each new low. When price crosses the SAR level, the indicator immediately reverses direction and starts tracking the new trend from the opposite side. The parabolic nature creates tightening stops as trends mature, helping traders exit positions before major reversals while staying in strong moves. The acceleration parameter controls initial sensitivity, while the maximum parameter caps how aggressive the stop becomes, balancing between early exits and adequate profit protection.
Defaults: acceleration = 0.02, maximum = 0.2.
Implementation Examples
Get started with SAR using highs and lows:
use vector_ta::indicators::sar::{sar, SarInput, SarParams};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
// Using high/low slices
let high = vec![101.0, 103.0, 102.5, 104.0, 105.5];
let low = vec![ 99.0, 100.5, 100.0, 101.0, 102.0];
let params = SarParams { acceleration: Some(0.02), maximum: Some(0.2) };
let input = SarInput::from_slices(&high, &low, params);
let result = sar(&input)?;
// Using Candles with defaults (acceleration=0.02, maximum=0.2)
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = SarInput::with_default_candles(&candles);
let result = sar(&input)?;
// Access SAR values
for v in result.values { println!("SAR: {}", v); } API Reference
Input Methods ▼
// From candles (uses high/low)
SarInput::from_candles(&Candles, SarParams) -> SarInput
// From high/low slices
SarInput::from_slices(&[f64], &[f64], SarParams) -> SarInput
// From candles with default parameters (acc=0.02, max=0.2)
SarInput::with_default_candles(&Candles) -> SarInput Parameters Structure ▼
pub struct SarParams {
pub acceleration: Option<f64>, // Default: 0.02
pub maximum: Option<f64>, // Default: 0.2
} Output Structure ▼
pub struct SarOutput {
pub values: Vec<f64>, // SAR values
} Validation, Warmup & NaNs ▼
- Inputs require highs and lows. Candles path uses
candles.highandcandles.low. - At least
2valid points after the first finite pair are required; otherwiseSarError::NotEnoughValidData. acceleration > 0.0andmaximum > 0.0; invalid values returnInvalidAcceleration/InvalidMaximum.- Before the first computed SAR, outputs are
NaN. First value is written at indexfirst_valid + 1. - Slice-based APIs trim to the minimum of
high.len()andlow.len(). sar_into_slicerequires output length to match inputs; otherwiseSarError::LengthMismatch.- Streaming returns
Noneon the first update; firstSomevalue appears on the second update.
Error Handling ▼
use vector_ta::indicators::sar::{sar, SarError};
match sar(&input) {
Ok(output) => process(output.values),
Err(SarError::EmptyData) => eprintln!("empty input"),
Err(SarError::AllValuesNaN) => eprintln!("all values are NaN"),
Err(SarError::NotEnoughValidData { needed, valid }) => {
eprintln!("need {needed} valid points, got {valid}");
}
Err(SarError::InvalidAcceleration { acceleration }) => {
eprintln!("invalid acceleration: {acceleration}");
}
Err(SarError::InvalidMaximum { maximum }) => {
eprintln!("invalid maximum: {maximum}");
}
Err(SarError::LengthMismatch { got, expected }) => {
eprintln!("output length {got} != {expected}");
}
} Python Bindings
Basic Usage ▼
Calculate SAR from NumPy arrays of highs and lows:
import numpy as np
from vector_ta import sar
high = np.array([101.0, 103.0, 102.5, 104.0, 105.5])
low = np.array([ 99.0, 100.5, 100.0, 101.0, 102.0])
# Defaults: acceleration=0.02, maximum=0.2
values = sar(high, low)
# Or specify parameters and kernel
values = sar(high, low, acceleration=0.02, maximum=0.2, kernel="auto")
print(values) # NumPy array Streaming Real-time Updates ▼
Update from high/low ticks:
from vector_ta import SarStream
stream = SarStream(acceleration=0.02, maximum=0.2)
for high_tick, low_tick in tick_stream:
value = stream.update(high_tick, low_tick)
if value is not None:
print("SAR:", value) Batch Parameter Optimization ▼
Test multiple acceleration/maximum combinations:
import numpy as np
from vector_ta import sar_batch
high = np.array([...], dtype=float)
low = np.array([...], dtype=float)
results = sar_batch(
high,
low,
acceleration_range=(0.01, 0.05, 0.01),
maximum_range=(0.2, 0.5, 0.1),
kernel="auto"
)
# results is a dict with:
# - values: 2D array [rows x cols]
# - accelerations: tested acceleration values
# - maximums: tested maximum values
print(results["values"].shape, results["accelerations"], results["maximums"]) CUDA Acceleration ▼
CUDA helpers are available when the Python package is built with CUDA support. Inputs must be float32; outputs are device arrays (DLPack / __cuda_array_interface__ compatible).
import numpy as np
from vector_ta import sar_cuda_batch_dev, sar_cuda_many_series_one_param_dev
# One series (float32)
high_f32 = np.asarray(load_high(), dtype=np.float32)
low_f32 = np.asarray(load_low(), dtype=np.float32)
dev = sar_cuda_batch_dev(
high_f32=high_f32,
low_f32=low_f32,
acceleration_range=(0.5, 2.0, 0.5),
maximum_range=(0.5, 2.0, 0.5),
device_id=0,
)
# Many series (time-major)
high_tm_f32 = np.asarray(load_high_time_major_matrix(), dtype=np.float32)
rows, cols = high_tm_f32.shape
high_tm_f32 = high_tm_f32.ravel()
low_tm_f32 = np.asarray(load_low_time_major_matrix(), dtype=np.float32)
low_tm_f32 = low_tm_f32.ravel()
dev_tm = sar_cuda_many_series_one_param_dev(
high_tm_f32=high_tm_f32,
low_tm_f32=low_tm_f32,
cols=cols,
rows=rows,
acceleration=1.0,
maximum=1.0,
device_id=0,
) JavaScript/WASM Bindings
Basic Usage ▼
Calculate SAR in JavaScript/TypeScript:
import { sar_js } from 'vectorta-wasm';
const high = new Float64Array([101.0, 103.0, 102.5, 104.0, 105.5]);
const low = new Float64Array([ 99.0, 100.5, 100.0, 101.0, 102.0]);
// Args: high, low, acceleration, maximum
const sarValues = sar_js(high, low, 0.02, 0.2);
console.log('SAR values:', sarValues); Memory-Efficient Operations ▼
Use zero-copy operations for large datasets:
import { sar_alloc, sar_free, sar_into, memory } from 'vectorta-wasm';
const len = 1024;
const high = new Float64Array(len);
const low = new Float64Array(len);
// ... fill high/low ...
const highPtr = sar_alloc(len);
const lowPtr = sar_alloc(len);
const outPtr = sar_alloc(len);
new Float64Array(memory.buffer, highPtr, len).set(high);
new Float64Array(memory.buffer, lowPtr, len).set(low);
// Calculate into pre-allocated memory
sar_into(highPtr, lowPtr, outPtr, len, 0.02, 0.2);
const out = new Float64Array(memory.buffer, outPtr, len).slice();
sar_free(highPtr, len);
sar_free(lowPtr, len);
sar_free(outPtr, len); Batch Processing ▼
Run a sweep and get combinations with outputs:
import { sar_batch as sar_batch_js } from 'vectorta-wasm';
const high = new Float64Array([...]);
const low = new Float64Array([...]);
// Unified batch API returns an object: { values, combos, rows, cols }
const cfg = {
acceleration_range: [0.01, 0.05, 0.01],
maximum_range: [0.2, 0.5, 0.1],
};
const { values, combos, rows, cols } = sar_batch_js(high, low, cfg);
// values is flat: rows*cols; reshape per row if needed
const rowsArr = [] as number[][];
for (let r = 0; r < rows; r++) {
const start = r * cols;
rowsArr.push(Array.from(values.slice(start, start + cols)));
}
// combos is an array of { acceleration: number | null, maximum: number | null }
console.log(combos); CUDA Bindings (Rust)
use vector_ta::cuda::CudaSar;
use vector_ta::indicators::sar::SarBatchRange;
let cuda = CudaSar::new(0)?;
let high: [f32] = /* ... */;
let low: [f32] = /* ... */;
let sweep = SarBatchRange::default();
let out = cuda.sar_batch_dev(&high, &low, &sweep)?;
let _ = out; Performance Analysis
Across sizes, Rust CPU runs about 1.24× slower than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-08
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