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

    Function gopalakrishnanRangeIndex

    • Gopalakrishnan Range Index (GAPO, Jayanthi Gopalakrishnan) — the logarithm of the window's own high-to-low range, normalised by the logarithm of the look-back:

      ${output} = ln( highest(high, period) − lowest(low, period) ) / ln(period)
      

      Appends one column. Reads high and low, each named by an option defaulting to its DEFAULT_OHLCV name (the atr precedent).

      It is the simplest study in the volatility group and the least normalised: a compressed range reads low, an expanded one reads high, and the ln flattens the scale so that a range ten times wider adds a fixed amount rather than multiplying the reading. Gopalakrishnan's use of it is comparative — the shape against its own recent history, a squeeze followed by an expansion — not the absolute level.

      TA-Lib has no GAPO, so the oracle is a pandas replication with the analytic first-valid bar asserted and a measured separation from the plausible wrong turns.

      ln is ChartIQ's, and it is what ships — but the base cancels, exactly as it does in choppinessIndex: log_b(x)/log_b(n) is log_n(x) for every b, so GAPO is simply the logarithm of the window's range in base period and the log10 form is the same number. The generator asserts that (2.2e-16) rather than leaving it to be rederived, because the first question the formula raises is "which log?" and the honest answer is "either — but not one of each". Mixing the bases (log10 on top, ln underneath) is a real bug and is what the separation assert pins, alongside dropping the ln(period) normalisation altogether.

      period must be at least 2: ln(1) = 0, and one bar's range over nothing is not a reading. The study throws rather than dividing by zero (the same rule choppinessIndex takes for the same reason).

      One window, so the column first lands on bar period − 1 — bar 9 at the default. Length-preserving.

      • Shift-invariant, and not scale-invariant — it is scale-additive. Adding a constant to every price leaves the range alone, so the reading does not move. Multiplying every price by k multiplies the range by k, and the logarithm turns that into an exact constant offset: gapo(k · price) = gapo(price) + ln(k)/ln(period). That identity is pinned by a property test rather than an invariance, because it is the whole character of the study — GAPO is the one reading in this group that carries the units of the price, and comparing it across instruments priced differently is comparing their price levels. (Every other study in the batch — choppinessIndex, verticalHorizontalFilter, ulcerIndex, chaikinVolatility, massIndex, relativeVolatilityIndexis scale-invariant.)
      • Negative readings are normal, not an error: any range below 1 in the price's units has a negative logarithm. On an instrument quoted in fractions of a unit the whole series sits below zero.
      • A flat window → undefined. ln(0) is −Infinity, which withColumn rejects, and there is no reading for "no range" on a logarithmic scale — the honest answer is that the study is not defined there, not that volatility was minimal. The same guard also catches a negative span, which high and low redirected at crossing columns produce and whose logarithm is NaN anyway.
      • A leading gap shifts the start; an interior gap is skipped rather than blanking the window — this study reads only core's rolling max/min, which take the extreme over the cells the window does hold (highestLowestValues' documented policy). So GAPO keeps reporting across a hole, over one bar fewer, where the studies in this batch built on rollingMeanValues blank. It is the one study here with no averaging half to set a stricter mask, and the difference is pinned by a missing-cell test rather than left to be discovered.

      Type Parameters

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

      Parameters

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