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

# State and indicators

> Keep values between bars with declared state, sum events with tallies, and use the ta library's indicators.

Keep a value from one bar to the next. A local variable in a handler starts fresh on every run, so anything that must persist is declared at the top, with a lifetime that says what happens to it while the newest bar is still forming.

## State

| Declared with | Kept |
| - | - |
| A local in a handler | Never: fresh on every run |
| `state.bar(x)`, `state.list(n)`, `state.map(n)`, `series(n)`, every `ta.*` instance | Across bars; rolled back before each update of the forming bar, like Pine's `var` |
| `state.live(x)`, `state.list(n, 'live')`, `state.map(n, 'live')` | Across bars and across updates of the forming bar, like Pine's `varip` |
| `tally()`, `tallyBy(n)` | Within one bar: empty on each new chart bar, and each event is applied once |

A cell holds one value, read and written through `.value`:

```ts theme={"theme":"github-dark"}
const highest = state.bar(na);

chart.onBar(() => {
  if (isNa(highest.value) || chart.high > highest.value) highest.value = chart.high;
});
```

Because `state.bar` is rolled back before every update of the forming bar, the update always starts from the last closed bar and nothing is counted twice. Use `state.live` only for something that should count every update, such as how many updates a bar received.

## Lists and maps

`state.list<T>(capacity)` and `state.map<T>(capacity)` hold numbers, booleans, strings or `null`, up to 100,000 entries. A map is keyed by strings. Size them for what they will hold: adding past the capacity stops the script with `OX2004`, so `shift` a list's oldest entry before it fills.

```ts theme={"theme":"github-dark"}
const seen = state.map<number>(10_000, 'live');

liq.onLiquidation((l) => {
  if (l.user !== null) seen.set(l.user, (seen.get(l.user) ?? 0) + l.notional);
});
```

An event handler may change only live state and tallies, which is why this map is `'live'`.

## Series

`series(lookback)` is a number with history: `set` the current bar's value, then read `value`, or `ago(n)` for `n` bars back, up to the declared lookback (at most 5,000).

```ts theme={"theme":"github-dark"}
const range = series(20);

chart.onBar(() => {
  range.set(chart.high - chart.low);
  const widest = Math.max(range.value, range.ago(1), range.ago(2));
});
```

The bars themselves have history too: `chart.ago(n)` is the bar `n` bars ago.

## Tallies

A tally sums what event handlers add during one bar: `add` in `onTrade` or `onLiquidation`, read `value` (and `count`) in the chart's handlers. It empties on each new bar and never rolls back, so each trade counts once even while the bar is forming.

```ts theme={"theme":"github-dark"}
const tape = trades();
const delta = tally();
const deltaBars = plot.histogram('Delta $');

tape.onTrade((t) => delta.add(t.side === 'buy' ? t.notional : -t.notional));

chart.onBar(() => {
  deltaBars.set(delta.value);
});
```

`tallyBy(capacity)` keeps a sum per key, such as per taker order or per wallet, up to 10,000 keys; read it with `get(key)` or `entries()`. Keys past its capacity are dropped for the rest of the bar.

## Indicators

`ta.*` creates an indicator instance at the top; `update` feeds it a value and returns the result. Values match TradingView's built-ins, including their seeds and how they treat `na`.

```ts theme={"theme":"github-dark"}
const rsi = ta.rsi(14);
const atr = ta.atr(14);

chart.onBar(() => {
  const r = rsi.update(chart.close);
  const a = atr.update(chart);
});
```

* **Update on every bar.** An instance advances only when `update` runs, so updating it inside an `if` gives a different result. This is Pine's rule that every call keeps its own history, made visible.
* **One instance per use.** Two RSIs of different sources are two instances.
* **`value`** is the result of the latest update in this run; **`confirmed`** is the value as of the stream's last closed bar, for reading from another stream's handler.

Updated twice in one run, an instance starts the second update again from the bar's start: the last update of the bar wins.

## Next step

Read other markets, intervals and 0xArchive's data in [data and timeframes](/terminal/guides/data).


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