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

    Function historicalVolatility

    • Historical volatility — the standard deviation of log returns over period bars, annualised:

      r[i] = ln(value[i] / value[i − 1])
      hv[i] = σ(r[i − period + 1 .. i]) × √annualize

      Appends one column; undefined for the first period rows. Note that is period, not period − 1: HV is a σ of returns, and period returns need period + 1 prices — the same off-by-one rsi and atr have, for the same reason.

      There is no TA-Lib function to arbitrate these (it has none for HV), so they are pinned here and in the pandas oracle instead:

      • Population σ (ddof = 0). The package convention — bollinger, rollingStdev and zScore all use it, and TA-Lib's own STDDEV does too. A sample σ (ddof = 1) is √(period/(period − 1)) larger: 2.6% at period 20, 5.4% at 10. If you need it, scale by that factor rather than looking for an option.
      • Log returns, not simple returns. ln(p[i]/p[i−1]) is symmetric (a move up and back down sums to zero) and additive across bars, which is what makes the √time annualisation below legitimate. On ordinary daily data the two differ in the third significant figure; on a large move they diverge materially.
      • Annualised by √annualize, default 252. Volatility scales with the square root of time, so a per-bar σ becomes annual by multiplying by the root of the bars per year. 252 is the US trading-day count and the right default for daily bars only — it is an option, not a hidden constant, precisely because intraday and 7-day markets need a different number. annualize: 1 gives the raw per-bar σ.
      • A decimal, not a percent. 0.18 means 18% annualised. That is the form volatility is consumed in (option pricing, position sizing, a σ · √t band), and the one every other study here uses — only percentChange multiplies by 100, because "percent" is its name.
      • A non-positive price has no log. The two returns that touch it (its own and the next bar's) are missing, and the guard is explicit rather than left to Math.log: ln(−4 / −5) is a perfectly finite number that is not a return. Those missing returns then behave like any gap under the rolling kernel's contract — the window still spans period rows, σ is over the finite returns in it, and a window with no finite return is undefined.

        Read the consequence before relying on it. A window with exactly ONE finite return has a σ of 0, so an interior bad price emits hv = 0 on the bars around it — and 0 reads as "no volatility", the opposite of what a corrupt price means. This is the package's rolling contract (rollingStdev, bollinger and zScore do the same over a gap), kept here for consistency with them; it is a deliberate divergence from pandas, whose rolling(n).std() reports NaN unless all n are present. Pinned by a test so the behaviour is chosen rather than incidental. Fill or drop bad prices upstream if a gap must not read as calm.

      • A leading gap shifts the start rather than shrinking the first window: over another study's output (whose warm-up leaves missing rows at the head) the first σ still covers period real returns. That is the Wilder-kernel convention rsi and atr follow, and it is also what pandas' rolling(n).std() does — so the oracle pins it.

      • Scale-invariant: log returns are ratios, so multiplying every price by a constant leaves HV unchanged (pinned by a property test). Contrast momentum and atr, which are in the price's units.

      The σ is rollingMeanSdInto — the same range-exact, shifted-frame kernel rollingStdev and bollinger sit on — but over the derived returns array rather than a scratch column. A scratch column would go through rollingValues, whose window is a count of rows: with the first return undefined (bar 0 has no predecessor) it would emit at bar period − 1 over period − 1 returns, one bar early with one return short. Calling the kernel directly on the returns, starting from the first real one, is what makes the warm-up period without an index hack.

      Type Parameters

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

      Parameters

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