SafeZone Stop
period = 22 | mult = 2.5 | max_lookback = 3 Overview
SafeZone Stop creates volatility adjusted trailing stops that adapt to changing market conditions by measuring directional penetration strength. The indicator calculates Wilder smoothed directional movement separately for upward and downward price action, then applies a multiplier to this smoothed value to establish a buffer zone around the position. For long positions, it tracks downside penetrations from previous highs and places stops below the recent low, while short positions use upside penetrations to position stops above recent highs. The calculation applies a rolling maximum or minimum over a lookback window to produce a ratcheting stop that only moves in one direction, preventing whipsaws from minor retracements. This approach ensures stops widen during volatile periods when directional movement increases and tighten during calm markets when movements shrink. Traders value SafeZone stops for automatically adjusting to market conditions without manual intervention, providing protection while allowing profitable trends to develop fully.
Implementation Examples
Compute SafeZone Stop from high/low slices or a Candles struct:
use vectorta::indicators::safezonestop::{safezonestop, SafeZoneStopInput, SafeZoneStopParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// High/Low arrays
let high = vec![101.0, 102.5, 103.0, 102.0, 101.5];
let low = vec![ 99.5, 100.8, 101.2, 100.0, 99.9];
let params = SafeZoneStopParams { period: Some(22), mult: Some(2.5), max_lookback: Some(3) };
let input = SafeZoneStopInput::from_slices(&high, &low, "long", params);
let out = safezonestop(&input)?;
// Candles input (defaults: period=22, mult=2.5, max_lookback=3, direction="long")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = SafeZoneStopInput::with_default_candles(&candles);
let out = safezonestop(&input)?;
// Access stop values
for v in out.values { println!("SafeZone: {}", v); } API Reference
Input Methods ▼
// From candles (uses 'high'/'low' sources)
SafeZoneStopInput::from_candles(&Candles, &str /* direction: "long"|"short" */, SafeZoneStopParams) -> SafeZoneStopInput
// From high/low slices
SafeZoneStopInput::from_slices(&[f64], &[f64], &str /* direction */, SafeZoneStopParams) -> SafeZoneStopInput
// Candles with defaults (period=22, mult=2.5, max_lookback=3, direction="long")
SafeZoneStopInput::with_default_candles(&Candles) -> SafeZoneStopInput Parameters Structure ▼
#[derive(Debug, Clone)]
pub struct SafeZoneStopParams {
pub period: Option<usize>, // Default: 22
pub mult: Option<f64>, // Default: 2.5
pub max_lookback: Option<usize> // Default: 3
} Output Structure ▼
#[derive(Debug, Clone)]
pub struct SafeZoneStopOutput {
pub values: Vec<f64>, // Stop levels (long or short depending on direction)
} Validation, Warmup & NaNs ▼
- High/low lengths must match; otherwise
MismatchedLengths. period > 0andperiod ≤ len; elseInvalidPeriod.directionmust be"long"or"short"; elseInvalidDirection.- First valid index is the earliest bar where both high/low are finite; all-leading-NaN inputs yield
AllValuesNaN. - Require at least
max(period+1, max_lookback)valid values after the first valid pair; elseNotEnoughValidData. - Warmup: outputs are
NaNuntil DM bootstrap and lookback are satisfied (prefix length ≈first + max(period, max_lookback−1)).
Error Handling ▼
use vectorta::indicators::safezonestop::SafeZoneStopError;
match safezonestop(&input) {
Ok(output) => process(output.values),
Err(SafeZoneStopError::AllValuesNaN) => eprintln!("All inputs are NaN"),
Err(SafeZoneStopError::InvalidPeriod { period, data_len }) =>
eprintln!("Invalid period {} for length {}", period, data_len),
Err(SafeZoneStopError::NotEnoughValidData { needed, valid }) =>
eprintln!("Need {} valid points, found {}", needed, valid),
Err(SafeZoneStopError::MismatchedLengths) => eprintln!("High/low length mismatch"),
Err(SafeZoneStopError::InvalidDirection) => eprintln!("Direction must be 'long' or 'short'"),
} Python Bindings
Basic Usage ▼
Calculate SafeZone Stop from NumPy arrays:
import numpy as np
from vectorta import safezonestop
high = np.array([101.0, 102.5, 103.0, 102.0, 101.5])
low = np.array([ 99.5, 100.8, 101.2, 100.0, 99.9])
# Args: high, low, period, mult, max_lookback, direction, kernel(optional)
stops = safezonestop(high, low, 22, 2.5, 3, 'long', kernel='auto')
print(stops) Streaming Real-time Updates ▼
from vectorta import SafeZoneStopStream
stream = SafeZoneStopStream(22, 2.5, 3, 'long')
for (h, l) in feed:
val = stream.update(h, l)
if val is not None:
handle_stop(val) Batch Parameter Optimization ▼
import numpy as np
from vectorta import safezonestop_batch
high = np.array([...], dtype=float)
low = np.array([...], dtype=float)
res = safezonestop_batch(
high, low,
period_range=(14, 28, 7),
mult_range=(1.5, 3.0, 0.5),
max_lookback_range=(2, 6, 2),
direction='long',
kernel='auto'
)
values = res['values'] # shape: (rows, len)
periods = res['periods']
mults = res['mults']
max_lookbacks = res['max_lookbacks'] JavaScript/WASM
Basic Usage ▼
Compute SafeZone Stop using WASM bindings:
import { safezonestop_js } from 'vectorta-wasm';
const high = new Float64Array([101, 102.5, 103, 102, 101.5]);
const low = new Float64Array([ 99.5, 100.8, 101.2, 100, 99.9]);
// Args: high, low, period, mult, max_lookback, direction
const stops = safezonestop_js(high, low, 22, 2.5, 3, 'long');
console.log(stops); Memory-Efficient Operations ▼
Zero-copy compute into preallocated buffers:
import { safezonestop_alloc, safezonestop_free, safezonestop_into, memory } from 'vectorta-wasm';
const len = high.length;
const highPtr = safezonestop_alloc(len);
const lowPtr = safezonestop_alloc(len);
const outPtr = safezonestop_alloc(len);
new Float64Array(memory.buffer, highPtr, len).set(high);
new Float64Array(memory.buffer, lowPtr, len).set(low);
// Args: high_ptr, low_ptr, out_ptr, len, period, mult, max_lookback, direction
safezonestop_into(highPtr, lowPtr, outPtr, len, 22, 2.5, 3, 'long');
const out = new Float64Array(memory.buffer, outPtr, len).slice();
safezonestop_free(highPtr, len);
safezonestop_free(lowPtr, len);
safezonestop_free(outPtr, len); Batch Processing ▼
Test many parameter combos in one call:
import { safezonestop_batch } from 'vectorta-wasm';
const config = {
period_range: [14, 28, 7],
mult_range: [1.5, 3.0, 0.5],
max_lookback_range: [2, 6, 2],
direction: 'long',
};
const out = safezonestop_batch(high, low, config);
console.log(out.rows, out.cols);
console.log(out.combos); // SafeZoneStopParams per row
// out.values is flat: rows*cols CUDA
CUDA support for SafeZone Stop is coming soon.
Performance Analysis
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05