Files
QuanTAlib/lib/oscillators/dpo/Dpo.md
T
Miha Kralj 92709ef2ed Add Stochastic Oscillator implementation and validation tests
- Implemented Stochastic Oscillator (%K and %D) in Stoch.cs with streaming and batch processing capabilities.
- Added validation tests for the Stochastic Oscillator in Stoch.Validation.Tests.cs, ensuring consistency with Skender.Stock.Indicators.
- Created documentation for the Stochastic Oscillator in Stoch.md, detailing its mathematical formula, architecture, parameters, and common pitfalls.
- Updated project file to include necessary numeric libraries for highest and lowest calculations.
2026-02-12 14:29:54 -08:00

3.2 KiB
Raw Blame History

Detrended Price Oscillator (DPO)

Overview

The Detrended Price Oscillator (DPO) removes the trend component from price data by displacing a Simple Moving Average (SMA), isolating short-term price cycles. Unlike most oscillators, DPO is not aligned to the latest price—it references a past SMA value to filter out long-term trends.

Formula

displacement = floor(period / 2) + 1
DPO = price  SMA(period)[displacement bars ago]

Where:

  • period — SMA lookback window (default: 20)
  • displacement — number of bars the SMA is shifted backward
  • SMA — Simple Moving Average of the source series

Architecture

Source ──→ RingBuffer(period) ──→ SMA ──→ RingBuffer(displacement+1) ──→ DPO
           [running sum]         [O(1)]    [stores SMA history]

Streaming (O(1) per bar)

Component Role
_smaBuffer RingBuffer(period) — maintains running sum for O(1) SMA via Sum / period
_smaHistory RingBuffer(displacement + 1) — stores past SMA values; .Oldest gives the displaced SMA

Bar Correction

Uses Snapshot() / Restore() on both RingBuffers for intra-bar updates (isNew = false).

Warmup

WarmupPeriod = period + displacement — need period bars to compute the first SMA, then displacement more bars before the displaced SMA is available.

Performance Profile

Metric Value
Time complexity O(1) per bar (streaming)
Space complexity O(period + displacement)
Allocations Zero per update
NaN handling Last valid value substitution
SIMD Not applicable (displacement dependency)

Usage

// Streaming
var dpo = new Dpo(period: 20);
TValue result = dpo.Update(new TValue(time, price));

// Event-based
var source = new TSeries();
var dpo = new Dpo(source, period: 20);

// Batch
TSeries results = Dpo.Batch(source, period: 20);

// Span
Dpo.Batch(sourceSpan, outputSpan, period: 20);

Interpretation

  • Zero Line Crossovers:

    • DPO crosses above zero: Price is above the displaced moving average (short-term bullish)
    • DPO crosses below zero: Price is below the displaced moving average (short-term bearish)
  • Cycle Identification:

    • DPO peaks and troughs correspond to short-term price cycles
    • Distance between peaks estimates the dominant cycle period
    • Works best when the dominant cycle length approximates the DPO period
  • Overbought/Oversold:

    • Extreme DPO values suggest price has deviated significantly from its trend
    • No fixed bounds; context-dependent interpretation
  • Divergence:

    • Bullish: Price makes lower lows while DPO makes higher lows
    • Bearish: Price makes higher highs while DPO makes lower highs

Validation

Cross-validated against:

  • Tulip Indicators (dpo) — exact match within 1e-9 tolerance
  • Manual SMA computation — independent verification of displaced SMA algorithm

Parameters

Parameter Type Default Range Description
period int 20 > 0 SMA lookback period

References

  • William Blau, Momentum, Direction, and Divergence, 1995
  • Thomas Dorsey, Point and Figure Charting, 2007
  • PineScript reference: dpo.pine