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

    Function priceOscillator

    • Price Oscillator — the spread between a fast and a slow moving average of one column, either as a percent of the slow average (mode: 'percent', the default) or in the source's own units (mode: 'absolute'):

      percent    100 · (MA(fastPeriod) − MA(slowPeriod)) / MA(slowPeriod)
      absolute MA(fastPeriod) − MA(slowPeriod)

      Both averages come from the shared K2 engine, so maType is the whole MaType menu rather than a private pair of smoothers.

      TA-Lib ships the two forms as two functionsAPO (absolute) and PPO (percent) — over identical inputs, so the name alone does not settle a default. Two things do:

      • The absolute form at the default parameters is already shipped. priceOscillator({ mode: 'absolute', maType: 'ema', fastPeriod: 12, slowPeriod: 26 }) is macd's macdLine, bar for bar — a test pins that identity. Defaulting to it would make the headline call of a new study a rename of an existing column, which is what the studies README's step 0 exists to catch. Defaulting to 'percent' makes the default call the thing MACD cannot give you.
      • The percent form is the comparable one. It is scale-invariant (a property test pins it), so a reading of 1.8 means the same thing on a $4 stock and a $4,000 one; the absolute form is in price units and is linear in them (pinned too).

      The knob is a mode string rather than a percent: boolean so the two settings read as what they are at the call site, and rather than two exported functions (apo / ppo) because one study with one knob is the shape stochastic already set with slowing: 1 for the fast stochastic.

      TA-Lib's APO/PPO(matype) are exactly MA(fast) − MA(slow) and 100·(MA(fast) − MA(slow))/MA(slow) over the same MA(matype) — verified in the oracle generator, which rebuilds both from talib.MA and asserts they agree to 8.9e-16 before using them as the reference.

      On the types TA-Lib ships that are not in the EMA family, we match it outright: { maType: 'sma', fastPeriod: 5, slowPeriod: 13, mode: 'absolute' } agrees with APO(matype=0) to 7.1e-14 with an identical warm-up mask (oracle case).

      On 'ema' (and dema/tema) the macd seed precedent applies: pond's EMA is seeded on the first sample, TA-Lib's on the SMA of the first n, so the values differ by a decaying transient. Reseeding here would make priceOscillator({ maType: 'ema' }) disagree with ema() and with macd() inside this package — a worse surprise than a sub-percent divergence from a vendor whose bar-for-bar parity is an explicit non-goal. The generator therefore splits the check the way the K2 engine's does: the formula is rebuilt on TA-Lib's own SMA seed and required to match PPO/APO exactly (matched to 2.8e-14), and the seed transient is bounded separately over the last 20 shared bars. Measured on the oracle input at {12, 26, ema, percent}: 6.61% of scale at the first shared bar, 0.41% at its worst over the last 20 (0.089% at the last bar), masks identical. The bound discriminates: the same replication run on a wrong rate is 5.09% (2/(n+2)), 5.99% (2/n) or 44.4% (1/n) over those same 20 bars.

      • Warm-up is the slower average's, per the K2 engine's table — bar slowPeriod − 1 for the window types and ema, later for dema / tema / hull / kama / zlema. Length-preserving; earlier rows are undefined.
      • A leading gap shifts the start for every maType except 'sma', which keeps sma()'s row-counting window (the column door's documented asymmetry). Running over another study's output therefore starts late rather than coming back empty.
      • An interior gap costs whatever the chosen maType costs — window types recover once it leaves the window, the ema family skips the bar, smma and kama propagate to the end. Stated per type on movingAverageValues, not averaged into a slogan.
      • A zero slow average (only reachable on a column that can be zero or negative — a return series, another oscillator) makes the percent form a 0/0 or a division by zero. It reports no value, not Infinity and not 0: the ratio is genuinely undefined there, and a ±Infinity reaching a chart's y-domain is worse than a gap. The absolute form has no such case and keeps reporting the spread.
      • fastPeriod must be shorter than slowPeriod — a caller who swaps them wants the negated series, and silently obliging would make the sign of every reading meaningless. Throws, like macd.

      Type Parameters

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

      Parameters

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