Decycler Oscillator

Parameters: high_pass_period = 125 | scale = 1

Overview

The Decycler Oscillator, developed by John Ehlers, isolates long term trend components by removing short term cyclical movements from price data using advanced digital filtering techniques. The indicator employs cascaded two pole high pass filters that systematically strip out high frequency oscillations and noise, leaving only the underlying trend component. By applying these filters sequentially, the decycler achieves superior noise reduction compared to single stage filtering. The filtered result is then expressed as a percentage of current price, creating a normalized oscillator that reveals pure trend strength without the distortion of short term fluctuations.

DEC_OSC oscillates around zero, with positive values indicating upward trending conditions and negative values showing downward trends. The magnitude reflects trend strength, with larger absolute values suggesting stronger directional movement. Because the indicator filters out cyclical components, it remains remarkably stable during choppy market conditions that would cause traditional oscillators to whipsaw. The high pass period parameter, typically set to 125, determines which frequency components are removed. Longer periods filter out more cycles, producing an even smoother trend indication at the cost of increased lag.

Traders use DEC_OSC to identify and confirm major trend changes without being misled by short term noise or market cycles. The indicator excels at staying with long term trends through minor corrections that might trigger false signals in other systems. Zero line crossovers provide clear trend change signals, while divergences between price and the oscillator often precede significant reversals. Many systematic traders combine DEC_OSC with shorter term indicators, using it as a trend filter to determine overall market direction. The indicator proves particularly valuable for position traders and investors who need to separate genuine trend changes from temporary market noise.

Implementation Examples

Get started with DEC_OSC in a few lines:

use vectorta::indicators::dec_osc::{dec_osc, DecOscInput, DecOscParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};

// Using with price data slice
let prices = vec![100.0, 102.0, 101.5, 103.0, 105.0, 104.5];
let params = DecOscParams { hp_period: Some(125), k: Some(1.0) };
let input = DecOscInput::from_slice(&prices, params);
let result = dec_osc(&input)?;

// Using with Candles data structure (defaults: hp_period=125, k=1.0; source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = DecOscInput::with_default_candles(&candles);
let result = dec_osc(&input)?;

// Access the oscillator values
for value in result.values {
    println!("DEC_OSC: {}", value);
}

API Reference

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

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

// From candles with defaults (close, hp_period=125, k=1.0)
DecOscInput::with_default_candles(&Candles) -> DecOscInput
Parameters Structure
pub struct DecOscParams {
    pub hp_period: Option<usize>, // Default: 125
    pub k: Option<f64>,           // Default: 1.0 (must be > 0)
}
Output Structure
pub struct DecOscOutput {
    pub values: Vec<f64>, // DEC_OSC values (percent of price)
}
Validation, Warmup & NaNs
  • hp_period ≥ 2 and hp_period ≤ data.len(); otherwise DecOscError::InvalidPeriod.
  • Requires at least 2 valid points after the first finite value; otherwise DecOscError::NotEnoughValidData.
  • k > 0 and finite; otherwise DecOscError::InvalidK.
  • Warmup: indices [first, first+1] are NaN (two values after first finite input).
  • Subsequent NaN inputs propagate through arithmetic.
Error Handling
use vectorta::indicators::dec_osc::{dec_osc, DecOscError};

match dec_osc(&input) {
    Ok(output) => process_results(output.values),
    Err(DecOscError::EmptyInputData) => eprintln!("no data"),
    Err(DecOscError::AllValuesNaN) => eprintln!("all values NaN"),
    Err(DecOscError::InvalidPeriod { period, data_len }) => {
        eprintln!("invalid period: {} (len={})", period, data_len)
    }
    Err(DecOscError::NotEnoughValidData { needed, valid }) => {
        eprintln!("need {} valid points, got {}", needed, valid)
    }
    Err(DecOscError::InvalidK { k }) => eprintln!("invalid k: {}", k),
}

Python Bindings

Basic Usage

Calculate DEC_OSC using NumPy arrays (defaults: hp_period=125, k=1.0):

import numpy as np
from vectorta import dec_osc

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

# Defaults
result = dec_osc(prices)

# Custom parameters and kernel
result = dec_osc(prices, hp_period=125, k=1.0, kernel="auto")

print(result)
Streaming Real-time Updates

Use the streaming API to process ticks incrementally:

from vectorta import DecOscStream

stream = DecOscStream(hp_period=125, k=1.0)
for price in price_feed:
    value = stream.update(price)
    if value is not None:
        handle(value)
Batch Parameter Optimization

Test multiple combinations with dec_osc_batch:

import numpy as np
from vectorta import dec_osc_batch

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

results = dec_osc_batch(
    prices,
    hp_period_range=(50, 150, 25),
    k_range=(0.5, 2.0, 0.5),
    kernel="auto"
)

print(results['values'].shape)  # (num_combos, len(prices))
print(results['hp_periods'])
print(results['ks'])
CUDA Acceleration

CUDA support for DEC_OSC is currently under development.

# Coming soon: CUDA-accelerated DEC_OSC calculations
# API will follow the pattern used by other CUDA-enabled indicators.

JavaScript/WASM Bindings

Basic Usage

Calculate DEC_OSC in JavaScript/TypeScript:

import { dec_osc_js } from 'vectorta-wasm';

const prices = new Float64Array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5]);

// Args: data, hp_period, k
const values = dec_osc_js(prices, 125, 1.0);
console.log('DEC_OSC values:', values);
Memory-Efficient Operations

Use zero-copy operations for large datasets:

import { dec_osc_alloc, dec_osc_free, dec_osc_into, memory } from 'vectorta-wasm';

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

const inPtr = dec_osc_alloc(len);
const outPtr = dec_osc_alloc(len);

new Float64Array(memory.buffer, inPtr, len).set(prices);

// Args: in_ptr, out_ptr, len, hp_period, k
dec_osc_into(inPtr, outPtr, len, 125, 1.0);

const osc = new Float64Array(memory.buffer, outPtr, len).slice();

dec_osc_free(inPtr, len);
dec_osc_free(outPtr, len);
console.log('DEC_OSC:', osc);
Batch Processing

Test parameter ranges in one call:

import { dec_osc_batch } from 'vectorta-wasm';

const prices = new Float64Array([/* historical prices */]);

const result = dec_osc_batch(prices, {
  hp_period_range: [50, 150, 25],
  k_range: [0.5, 2.0, 0.5]
});

// result: { values: Float64Array, combos: {hp_period,k}[], rows, cols }
console.log(result);

Performance Analysis

Comparison:
View:
Loading chart...

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

Related Indicators