@pond-ts/financial API Reference
    Preparing search index...

    Function detrendedPriceOscillator

    • Detrended Price Oscillator (DPO) — the price less a moving average displaced shift = ⌊period/2⌋ + 1 bars back:

      DPO[i] = price[i] − MA(period)[i − shift]        shift = ⌊period/2+ 1
      

      The displacement is the whole point: subtracting the current average leaves a series that still lags the trend, while subtracting an average from half a window ago removes the trend the average was measuring and leaves the cycle. DPO is used to read cycle length, not direction, and it deliberately does not extend to the last bar of a trend the way a plain price − MA does.

      period/2 + 1 is not an integer for odd period, and the published sources write it without saying which way it goes. We floor: shift = ⌊period/2⌋ + 1, so period 20 → 11 and period 15 → 8. That is StockCharts' {X/2 + 1} read as the number of whole bars back, and it is the only rule that keeps the study a pure re-indexing of the average (the alternative is interpolating between two bars of it, which no implementation does). The kernel makes the same call for zlema's lag, for the same reason.

      There are two published DPOs and they are different series, not one series plotted two ways:

      • Ours (TradingView's default, isCentered = false): price[i] − MA[i − shift] — the current bar's price against a displaced average.
      • The centered form (StockCharts, TradingView's isCentered = true): price[i − shift] − MA[i] — a past price against the current average.

      Both are causal at bar i; they differ in which bar the value describes. We ship the first because a study here appends a column aligned to the source's own time axis: the value on bar i has to be about bar i's price, or it silently misaligns with everything else on that row (the bar's close, another study's output, a chart's crosshair). The centered form's value on bar i is about a price shift bars earlier, which is a plotting convention, not a column. A caller who wants it can shift ours — the numbers are not the same series, so we do not claim they are.

      maType is offered because the average is the only free choice in the definition and the K2 engine already names the menu; the classic DPO is the SMA one, which is the default.

      TA-Lib has no DPO, so the oracle is a pandas replication with the analytic first-valid bar asserted (below), not a vendor mask copied.

      • Warm-up is the average's, plus the displacement: first value on bar period − 1 + shift for the window types and ema (bar 30 at the default period 20), later for dema / tema / hull / kama / zlema, whose own first valid bar is later. Length-preserving; earlier rows undefined.
      • Linear in the input, and shift-invariant — a difference of prices, so scaling every price by k scales the reading by k (the macd side of the scale pair, not the disparityIndex side), while adding a constant adds it to both the price and the displaced average and cancels. Both pinned by a property test, over every maType, since every type in the menu satisfies MA(a·x + b) = a·MA(x) + b.
      • An interior gap costs the bar itself (the price is missing) and the bar shift later (the displaced average is missing there), plus whatever the maType's own gap rule costs — window types recover, the ema family skips, smma and kama propagate to the end.
      • A series shorter than period − 1 + shift reads entirely undefined, with the row count kept.

      Type Parameters

      • S extends SeriesSchema
      • const Output extends string = "dpo"

      Parameters

      Returns TimeSeries<
          readonly [S[0], ValueColumnsForSchema<S>, OptionalNumberColumn<Output>],
      >