> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hyperprop.com/llms.txt
> Use this file to discover all available pages before exploring further.

# TA helpers

> Moving averages, ATR, RSI, regression, VWAP, anchored VWAP, pivots and crossovers in the hp helper bundle.

`compute`'s third argument, `hp`, bundles common technical analysis functions.
Series helpers take and return `Array<number | null>` aligned to the input.
`null` means "no value yet", so check for it before doing arithmetic.

| Helper | Notes |
| - | - |
| `hp.sma(values, length)` | Simple moving average |
| `hp.ema(values, length)` | Exponential moving average |
| `hp.rma(values, length)` | Wilder's moving average |
| `hp.stdev(values, length)` | Rolling standard deviation |
| `hp.highest(values, length)` / `hp.lowest(values, length)` | Rolling extremes |
| `hp.change(values, length = 1)` | Difference from `length` bars back |
| `hp.atr(bars, length)` | Average true range. Takes **bars**, not values. Matches Pine's `ta.atr`. |
| `hp.rsi(values, length)` | Relative strength index, 0 to 100 |
| `hp.linreg(values, length)` | Least-squares regression value (Pine `ta.linreg` with offset 0) |
| `hp.cum(values)` | Running sum |
| `hp.vwap(bars)` | Volume-weighted average price, reset at each UTC date change |
| `hp.avwap(bars, anchor, options?)` | Anchored VWAP from a bar index, or from an array of bar indices. See [below](#anchored-vwap-from-swings). |
| `hp.pivothigh(values, left, right = left)` / `hp.pivotlow(...)` | Pivot value at the pivot bar itself, `null` elsewhere |
| `hp.crossover(a, b)` / `hp.crossunder(a, b)` | Returns `boolean[]`. `b` may be a series or a constant. |
| `hp.chart` | The [chart context](https://docs.hyperprop.com/indicators/chart-context.md) |

Anything else is ordinary JavaScript. Write your own loops and math freely.

## Pivots are reported at the pivot bar

Pine reports a pivot `right` bars after it happens. `hp.pivothigh` and
`hp.pivotlow` put the value **at the pivot bar**. A pivot at index `p` is only
known from bar `p + right` onward, so account for that in signal logic.

## Recursive averages need warm-up

`hp.atr`, `hp.rma` and `hp.ema` match TradingView once they have about 10×
their length in bars. With long lengths, compare values away from the first
bars on the chart.

## Anchored VWAP from swings

`hp.avwap` computes anchored VWAPs in a single pass over the bars, however
many anchors you pass. Use it instead of nested loops, which can run over the
[execution budget](https://docs.hyperprop.com/indicators/limits.md#execution-budget) on long charts.

| Call | Returns |
| - | - |
| `hp.avwap(bars, index)` | One series, `null` before the anchor bar |
| `hp.avwap(bars, [i1, i2, ...])` | One series per anchor, in the same order |
| `hp.avwap(bars, [i1, i2, ...], { reset: true })` | One series that restarts at each anchor |

Options:

* `source`: `'open'`, `'high'`, `'low'`, `'close'`, `'hl2'`, `'hlc3'` (default)
  or `'ohlc4'`.
* `reset`: as in the table above.

Bars without volume count as zero volume. Until the first bar with volume
after an anchor, the value is `null`.

```js theme={null}
const left = input.int('Swing length', 10, { min: 1 });
const shown = input.int('Swings shown', 4, { min: 1, max: 20 });

function compute(bars, inputs, hp) {
  const highs = hp.pivothigh(bars.map(b => b.h), left);
  const lows = hp.pivotlow(bars.map(b => b.l), left);
  const swingHighs = [], swingLows = [];
  bars.forEach((b, i) => {
    if (highs[i] !== null) swingHighs.push(i);
    if (lows[i] !== null) swingLows.push(i);
  });
  const fromHighs = hp.avwap(bars, swingHighs.slice(-shown));
  const fromLows = hp.avwap(bars, swingLows.slice(-shown));
  return {
    plots: [
      ...fromHighs.map(values => ({ values, color: '#ef5350' })),
      ...fromLows.map(values => ({ values, color: '#26a69a' })),
    ],
  };
}
```

## Using helpers on another timeframe

Run helpers on `h.bars` from [`request.bars`](https://docs.hyperprop.com/indicators/other-timeframes),
then map the result to chart bars with `h.align`:

```js theme={null}
const daily = request.bars('1D');

function compute(bars, inputs, hp) {
  if (daily.status !== 'ready') return { plots: [] };
  const sma20 = daily.align(hp.sma(daily.bars.map(b => b.c), 20));
  return { plots: [{ title: 'Daily SMA 20', values: sma20, color: '#42a5f5' }] };
}
```

## Example: crossover markers

```js theme={null}
const fastLen = input.int('Fast', 9, { min: 1 });
const slowLen = input.int('Slow', 21, { min: 1 });

function compute(bars, inputs, hp) {
  const closes = bars.map(b => b.c);
  const fast = hp.ema(closes, fastLen), slow = hp.ema(closes, slowLen);
  const up = hp.crossover(fast, slow), down = hp.crossunder(fast, slow);
  const markers = [];
  bars.forEach((b, i) => {
    if (up[i]) markers.push({ x: i, y: 'below', shape: 'arrow-up', color: '#26a69a' });
    if (down[i]) markers.push({ x: i, y: 'above', shape: 'arrow-down', color: '#ef5350' });
  });
  return {
    plots: [
      { title: 'Fast', values: fast, color: '#26a69a' },
      { title: 'Slow', values: slow, color: '#ef5350' },
    ],
    markers: markers.slice(-500),
  };
}
```


## Related topics

- [Custom indicators](https://docs.hyperprop.com/indicators/overview.md)
- [Porting from Pine Script](https://docs.hyperprop.com/indicators/pine-porting.md)
- [Changelog](https://docs.hyperprop.com/changelog.md)
- [Other timeframes](https://docs.hyperprop.com/indicators/other-timeframes.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.