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

    Function klinger

    • Klinger Volume Oscillator (Stephen Klinger, 1997) — the difference of two EMAs of a volume force that carries its own trend state. Kernel K6 feeding the K2 engine.

      trend[i] = (high+low+close)[i] > (high+low+close)[i−1] ? +1 :1
      dm[i] = high[i] − low[i]
      cm[i] = trend[i] === trend[i−1] ? cm[i−1] + dm[i] : dm[i−1] + dm[i]
      vf[i] = volume[i] × |2 × (dm[i]/cm[i] − 1)| × trend[i] × 100

      ${prefix} = EMA(vf, fastPeriod) − EMA(vf, slowPeriod)
      ${prefix}Signal = EMA(${prefix}, signalPeriod)

      Appends two columns (kvo / kvoSignal at the default prefix). Reads four — high, low, close and volume — each named by an option defaulting to its DEFAULT_OHLCV name.

      The corpus assessment flags this study F-AMBIG and it earns it: two different formulas ship under the name.

      • This study is the original, as Klinger published it and as StockCharts documents it: the volume force above, with the trend state and the cumulative measurement. The |2 × (dm/cm − 1)| factor is the part every restatement garbles; the reading taken here is 2 × ((dm/cm) − 1) under the absolute value, not 2 × (dm/cm) − 1. The two differ by a constant inside the modulus and therefore by a different amount on every bar; the oracle carries a case that separates them.
      • The named alternative is TradingView's ta.kvo, which drops the dm/cm factor entirely: its volume force is just ±volume × 100 on the sign of the HLC change, so it is an EMA-pair oscillator of signed volume and no state machine at all. It is not implemented here, and it is not an option on this study — the two are different indicators that share a name, and a variant knob would hide that. Measured on the oracle's 80 bars, the two disagree by more than the oscillator's own range: the simplified form's kvo spans a different order of magnitude entirely (the generator prints both).

      The EMAs are pond's — first-sample seed, α = 2/(span+1), the movingAverageValues array door — matching macd and for the same reason (making them TA-Lib-seeded here would make this study's EMAs disagree with ema() inside the package). TA-Lib has no Klinger, so nothing arbitrates it.

      The volume force starts at bar 1 (it needs a predecessor for the trend comparison and for dm[i−1]), so on gap-free input the oscillator starts at bar slowPeriod and the signal at slowPeriod + signalPeriod − 1. Each column is emitted where it is genuinely defined rather than both waiting for the slower — the same per-column warm-up macd uses.

      • Scale behaviour is mixed, and the mixture is the point. The volume force is volume × (a ratio of ranges) × ±1 × 100, so the study is linear in volume (double every volume and both columns double) but invariant to a price scale and a price shift: dm/cm is a ratio of ranges, so a scale cancels and a shift never reaches it, and the trend flag compares two high + low + close sums, which a positive scale and a +3c on both sides both preserve. Adding a constant to every volume is not a no-op, unlike negativeVolumeIndex, which only compares volumes — the force multiplies by one. All four are asserted as property tests.
      • A zero-range leg (cm = 0, which needs every bar in the leg to have high === low) is a genuine 0/0 and reads undefined for that bar; the EMAs then propagate it, since a recursion has no state to carry across a hole. There is no guard for it: cm is a sum of non-negative ranges, so a zero cm forces a zero dm with it and the ratio is NaN on its own — a guard would be dead code.
      • A missing cell in any of the four inputs resets the K6 machine ([PND-SFOLD]): the volume force is undefined for that bar and the trend/cm state re-seeds from the next complete pair. The EMAs downstream nonetheless carry the undefined forward — pond's EMA skips a missing bar in its recursion, so the oscillator resumes, but the two spans resume at different points, which is why an interior gap is best filled before running this.

      Type Parameters

      • S extends SeriesSchema
      • const Prefix extends string = "kvo"

      Parameters

      Returns TimeSeries<
          readonly [
              S[0],
              ValueColumnsForSchema<
                  readonly [
                      S[0],
                      ValueColumnsForSchema<S>,
                      OptionalNumberColumn<Prefix>,
                  ],
              >,
              OptionalNumberColumn<`${Prefix}Signal`>,
          ],
      >