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

    Function vortex

    • The Vortex Indicator (Etienne Botes & Douglas Siepman, Technical Analysis of Stocks & Commodities, January 2010) — the trend-direction companion to Wilder's DI pair, measured across consecutive bars instead of along them:

      +VM = |high − prevLow|VM = |low − prevHigh|
      +VI = Σ +VM / Σ TR ${prefix}Plus
      VI = ΣVM / Σ TR ${prefix}Minus (sums over `period` bars)

      Where directionalMovement asks how far a bar moved beyond the previous bar's own high or low — so at most one of its legs is non-zero — the vortex crosses them, and both legs are always positive. What carries the signal is their ratio: a rising market puts today's high a long way above yesterday's low (+VM large) while today's low stays close under yesterday's high (−VM small), so +VI climbs above −VI and the crossings mark the turns. Normalising both by the same true-range total is what makes the pair comparable across instruments.

      Reads high, low and close, each named by an option defaulting to its DEFAULT_OHLCV column — the atr shape. The close is there for the true range only.

      The authors' original, replicated in pandas in the oracle — TA-Lib has no vortex function, so there is nothing to be bar-for-bar with. The two choices worth naming, both the published ones: the absolute values on the movement legs (they matter only on a bar that gaps clear of its predecessor, where the crossing distance would come out negative), and TR as Wilder's true range rather than the plain bar range — the same trueRangeValues the ATR family uses, which the oracle asserts is talib.TRANGE bit-for-bit.

      Both columns emit from bar period: +VM, −VM and TR all read the previous bar, so a period-bar sum of them needs period + 1 bars.

      The ratio is taken between two rolling means rather than two sums — they share the divisor period, so it cancels exactly, and going through rollingMeanValues is what buys the strict window rule (every one of the period cells must be finite) instead of a hand-rolled sum that would have to restate it.

      • Σ TR = 0undefined. Unlike directionalMovement's DX, the numerator is not forced to zero with it: a window of perfectly flat bars can still be preceded by a bar at a different level, leaving +VM positive over a zero total range. That is a genuine x/0, so the guard is real (and, unlike the guard commodityChannelIndex deleted, it changes an answer — the alternative is ±Infinity reaching withColumn).
      • Both columns are non-negative — every term is an absolute value over a non-negative range — and scale-invariant: a ratio of price differences. Both pinned by property tests.
      • Not bounded by 1. +VI and −VI typically live around 0.8–1.2 and sum to roughly 2, but neither is a fraction of anything: a bar can gap far enough that |high − prevLow| exceeds its own true range. Nothing is clamped.
      • A gap costs at most period + 1 bars and then recovers, unlike the Wilder family's carry-to-the-end: these are windows, not recursions. The two legs lose different rows, which is worth knowing when reading them as a pair. Measured on an 80-bar series with one missing cell at bar 40 and period 14: a missing high blanks +VI over bars 40–53 (it costs +VM on bar 40 and the true range with it) and −VI over 40–54 (−VM on bar 41 reads that high as prevHigh); a missing low is the mirror image; a missing close costs only the true range on bar 41, so both legs blank over 41–54.

      Type Parameters

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

      Parameters

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