Slope Adaptive Moving Average (SAMA)

Parameters: length = 200 | maj_length = 14 | min_length = 6

Overview

The Slope Adaptive Moving Average dynamically adjusts its responsiveness by measuring where current price falls within a recent high to low range. SAMA computes the highest and lowest prices over an extended lookback period, then determines price position as a ratio within that range to derive an adaptive smoothing factor. When price trades near range extremes, the indicator blends toward a faster minor exponential moving average to capture trend acceleration, while prices in the middle of the range shift toward a slower major EMA for stability. This position based adaptation allows SAMA to respond quickly during breakouts and trending moves while remaining smooth during consolidation phases. The calculation normalizes the position ratio and interpolates between two EMA alpha values, producing a single adaptive moving average that naturally adjusts to market structure. Traders use SAMA for dynamic support and resistance that adapts to volatility, with the indicator staying close to price during trends and widening distance during ranges.

Implementation Examples

Get started with SAMA using slices or candles:

use vectorta::indicators::moving_averages::sama::{sama, SamaInput, SamaParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};

// From a price slice
let prices = vec![100.0, 102.0, 101.5, 103.0, 105.0, 104.5];
let params = SamaParams { length: Some(200), maj_length: Some(14), min_length: Some(6) };
let input = SamaInput::from_slice(&prices, params);
let out = sama(&input)?;

// From candles with defaults (source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = SamaInput::with_default_candles(&candles);
let out = sama(&input)?;

for v in out.values { println!("SAMA: {}", v); }

API Reference

Input Methods
// From price slice
SamaInput::from_slice(&[f64], SamaParams) -> SamaInput

// From candles with custom source
SamaInput::from_candles(&Candles, &str, SamaParams) -> SamaInput

// From candles with default params (close prices; 200/14/6)
SamaInput::with_default_candles(&Candles) -> SamaInput
Parameters Structure
pub struct SamaParams {
    pub length: Option<usize>,     // Default: 200
    pub maj_length: Option<usize>, // Default: 14
    pub min_length: Option<usize>, // Default: 6
}
Output Structure
pub struct SamaOutput {
    pub values: Vec<f64>, // Adaptive MA values
}
Validation, Warmup & NaNs
  • length > 0, maj_length > 0, min_length > 0. Also length + 1 ≤ data.len() or SamaError::InvalidPeriod.
  • Requires at least one valid sample after the first finite value; otherwise SamaError::NotEnoughValidData.
  • Indices before the first finite input are NaN. First finite output is seeded to the first finite price (Pine‑compatible warmup).
  • Batch mode: NaN inputs at index i produce NaN at i. Streaming: update(NaN) leaves state unchanged and returns the current value if initialized.
Error Handling
use vectorta::indicators::moving_averages::sama::{sama, SamaError};

match sama(&input) {
    Ok(output) => process(output.values),
    Err(SamaError::EmptyInputData) => eprintln!("empty input"),
    Err(SamaError::AllValuesNaN) => eprintln!("all values are NaN"),
    Err(SamaError::InvalidPeriod { period, data_len }) => {
        eprintln!("invalid period: {} for data_len {}", period, data_len)
    }
    Err(SamaError::NotEnoughValidData { needed, valid }) => {
        eprintln!("need {} data points, only {} valid", needed, valid)
    }
}

Python Bindings

Basic Usage

Calculate SAMA using NumPy arrays (length, maj_length, min_length are required):

import numpy as np
from vectorta import sama

prices = np.array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5])

# Specify parameters explicitly; choose kernel optionally ("auto", "avx2", ...)
values = sama(prices, length=200, maj_length=14, min_length=6, kernel="auto")
print(values)
Streaming Real-time Updates
from vectorta import SamaStream

stream = SamaStream(length=200, maj_length=14, min_length=6)
for price in feed:
    value = stream.update(price)
    if value is not None:
        print("SAMA:", value)
Batch Parameter Optimization
import numpy as np
from vectorta import sama_batch

prices = np.array([...])

results = sama_batch(
    prices,
    length_range=(100, 300, 50),
    maj_length_range=(10, 20, 2),
    min_length_range=(4, 12, 2),
    kernel="auto",
)

# Results is a dict-like object with 'values', 'combos', 'rows', 'cols'
print(results["rows"], results["cols"])
CUDA Acceleration

CUDA support for SAMA is currently under development. The API will follow the same pattern as other CUDA-enabled indicators.

# Coming soon: CUDA-accelerated SAMA calculations
# from vectorta import sama_cuda_batch, sama_cuda_many_series_one_param
# import numpy as np
#
# # One series, many parameter combinations
# results = sama_cuda_batch(
#     data=prices,
#     length_range=(100, 300, 1),
#     maj_length_range=(10, 20, 1),
#     min_length_range=(4, 12, 1),
#     device_id=0,
# )
#
# # Many series, one parameter set
# out = sama_cuda_many_series_one_param(
#     data_tm=portfolio_data,  # [T, N]
#     length=200, maj_length=14, min_length=6,
#     device_id=0,
# )

JavaScript/WASM Bindings

Basic Usage

Calculate SAMA in JavaScript/TypeScript:

import { sama_js } from 'vectorta-wasm';

const prices = new Float64Array([100, 102, 101.5, 103, 105, 104.5]);
const values = sama_js(prices, 200, 14, 6);
console.log('SAMA:', values);
Memory-Efficient Operations

Use zero-copy operations for large datasets:

import { sama_alloc, sama_free, sama_into, memory } from 'vectorta-wasm';

const prices = new Float64Array([/* your data */]);
const len = prices.length;
const inPtr = sama_alloc(len);
const outPtr = sama_alloc(len);

new Float64Array(memory.buffer, inPtr, len).set(prices);
sama_into(inPtr, outPtr, len, 200, 14, 6);

const out = new Float64Array(memory.buffer, outPtr, len).slice();
sama_free(inPtr, len);
sama_free(outPtr, len);
Batch Processing

Test multiple combinations using unified batch API:

import { sama_batch } from 'vectorta-wasm';

const prices = new Float64Array([/* historical prices */]);
const config = {
  length_range: [100, 300, 50],
  maj_length_range: [10, 20, 2],
  min_length_range: [4, 12, 2],
};

const result = sama_batch(prices, config);
// result = { values: Float64Array(flat), combos: SamaParams[], rows, cols }
console.log(result.rows, result.cols);

Performance Analysis

Comparison:
View:
Loading chart...

AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05

Related Indicators