Deviation Stop
period = 20 | mult = 0 (0–5) | devtype = 0 (0–2) | direction = long | ma_type = sma Overview
Deviation Stop creates an adaptive trailing stop that adjusts to market volatility by combining range measurements with statistical deviation calculations. The indicator first measures the two bar price range, capturing the distance between consecutive highs and lows. This range is then smoothed using your chosen moving average type to filter out erratic spikes. A deviation measure of this smoothed range is calculated and multiplied by your specified factor, then added to create a volatility adjusted offset. The result undergoes a final transformation using rolling extremes that ensures the stop only moves favorably, never retreating against your position.
DevStop offers extensive customization through multiple parameters that control its behavior. The deviation type selection allows choosing between standard deviation for sensitivity, mean absolute deviation for stability, or median absolute deviation for outlier resistance. The multiplier parameter determines how far the stop trails from price, with higher values providing more breathing room but potentially giving back larger profits. Direction settings accommodate both long and short positions, while the moving average type selection lets you fine tune the smoothing characteristics. This flexibility makes DevStop adaptable to various trading styles and market conditions.
Traders employ DevStop as a sophisticated position management tool that automatically adapts to changing volatility. During calm markets, the stop tightens to protect profits, while volatile periods see it widen to avoid premature exits. The ratcheting mechanism ensures the stop locks in gains as trends extend, providing systematic profit protection without manual adjustment. Many traders prefer DevStop over fixed percentage or ATR based stops because it combines multiple volatility measures for more nuanced market adaptation. The indicator works particularly well in trending markets where its adaptive nature helps capture extended moves while protecting against reversals.
Implementation Examples
Compute DevStop from high/low arrays or from a Candles struct:
use vectorta::indicators::devstop::{devstop, DevStopInput, DevStopParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// Using with high/low slices
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 = DevStopParams {
period: Some(20),
mult: Some(0.0),
devtype: Some(0),
direction: Some("long".to_string()),
ma_type: Some("sma".to_string()),
};
let input = DevStopInput::from_slices(&high, &low, params);
let result = devstop(&input)?;
// Using Candles (defaults: high/low sources, period=20, mult=0.0, devtype=0, direction="long", ma_type="sma")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = DevStopInput::with_default_candles(&candles);
let result = devstop(&input)?;
// Access the trailing stop values
for v in result.values { println!("DevStop: {}", v); } API Reference
Input Methods ▼
// From high/low slices
DevStopInput::from_slices(&[f64], &[f64], DevStopParams) -> DevStopInput
// From candles with custom sources
DevStopInput::from_candles(&Candles, &str /* high */, &str /* low */, DevStopParams) -> DevStopInput
// From candles with defaults (sources: "high"/"low"; params: period=20, mult=0.0, devtype=0, direction="long", ma_type="sma")
DevStopInput::with_default_candles(&Candles) -> DevStopInput Parameters Structure ▼
#[derive(Debug, Clone)]
pub struct DevStopParams {
pub period: Option<usize>, // Default: 20
pub mult: Option<f64>, // Default: 0.0
pub devtype: Option<usize>, // Default: 0 (0=std, 1=mean abs, 2=median abs)
pub direction: Option<String>, // Default: "long"
pub ma_type: Option<String>, // Default: "sma"
} Output Structure ▼
#[derive(Debug, Clone)]
pub struct DevStopOutput {
pub values: Vec<f64>, // Final trailing stop line (ratcheted)
} Validation, Warmup & NaNs ▼
period > 0and not greater than data length; otherwiseDevStopError::InvalidPeriod.- Requires at least
periodvalid points after the first finite high/low; otherwiseDevStopError::NotEnoughValidData. devtype ∈ {0,1,2}; other values error viaDevStopError::DevStopCalculation("invalid devtype").- Warmup: indices before
first + 2·period − 1areNaN(two stages: base and trailing extremum). directionis case‑insensitive; non‑"long" values are treated as short path.
Error Handling ▼
use vectorta::indicators::devstop::{devstop, DevStopError};
match devstop(&input) {
Ok(out) => use_values(out.values),
Err(DevStopError::AllValuesNaN) => eprintln!("All values are NaN for high/low"),
Err(DevStopError::InvalidPeriod { period, data_len }) =>
eprintln!("Invalid period {} for data_len {}", period, data_len),
Err(DevStopError::NotEnoughValidData { needed, valid }) =>
eprintln!("Need {} valid points after first finite; only {}", needed, valid),
Err(DevStopError::DevStopCalculation(msg)) => eprintln!("Calculation error: {}", msg),
} Python Bindings
Basic Usage ▼
Compute DevStop using NumPy arrays (all parameters explicit):
import numpy as np
from vectorta import devstop
high = np.array([101.0, 102.5, 103.0, 102.0, 101.5], dtype=float)
low = np.array([ 99.5, 100.8, 101.2, 100.0, 99.9], dtype=float)
# period, mult, devtype, direction, ma_type, kernel (optional)
stops = devstop(high, low, 20, 0.0, 0, 'long', 'sma', kernel='auto')
print(stops) Batch Parameter Sweep ▼
Test multiple parameter combinations:
import numpy as np
from vectorta import devstop_batch
high = np.array([...], dtype=float)
low = np.array([...], dtype=float)
res = devstop_batch(
high,
low,
period_range=(10, 30, 10), # 10, 20, 30
mult_range=(0.0, 3.0, 1.0), # 0.0, 1.0, 2.0, 3.0
devtype_range=(0, 2, 1), # 0, 1, 2
kernel='auto'
)
print(res['values'].shape) # (num_combos, len(series))
print(res['periods'])
print(res['mults'])
print(res['devtypes']) JavaScript / WASM
Basic Usage ▼
Compute DevStop with typed arrays:
import { devstop } 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, devtype, direction, ma_type
const stops = devstop(high, low, 20, 0.0, 0, 'long', 'sma');
console.log(stops); Memory-Efficient Operations ▼
Use zero‑copy with explicit alloc/free:
import { devstop_alloc, devstop_free, devstop_into, memory } from 'vectorta-wasm';
const len = high.length;
const highPtr = devstop_alloc(len);
const lowPtr = devstop_alloc(len);
const outPtr = devstop_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, devtype, direction, ma_type
devstop_into(highPtr, lowPtr, outPtr, len, 20, 0.0, 0, 'long', 'sma');
const out = new Float64Array(memory.buffer, outPtr, len).slice();
devstop_free(highPtr, len);
devstop_free(lowPtr, len);
devstop_free(outPtr, len); Batch Processing ▼
Sweep parameter combinations in one call:
import { devstop_batch } from 'vectorta-wasm';
const config = {
period_range: [10, 30, 10],
mult_range: [0.0, 2.0, 1.0],
devtype_range: [0, 2, 1]
};
const out = devstop_batch(high, low, config);
console.log(out.rows, out.cols);
console.log(out.combos); // DevStopParams per row
// out.values is flat: rows * cols CUDA
CUDA support for DevStop is coming soon.
Performance Analysis
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05