> ## 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.

# Kalman pairs spread

> The chart's market hedged against another by a ratio a Kalman filter re-estimates every bar.

![Kalman pairs spread on a BTC chart](https://mintcdn.com/0xarchive-e895b8e7/iWF6OFnAgDYSS9hp/images/terminal/examples/kalman-pairs.webp?fit=max\&auto=format\&n=iWF6OFnAgDYSS9hp\&q=85\&s=9e6f98580679ae18d08e22de2b0f8ea7)

BTC on 1-hour bars in the 0xArchive Terminal, 2026-10-25.

> **[Open on a chart](https://terminal.0xarchive.io/?symbol=BTC\&interval=1h\&scripts=example%3Akalman-pairs)**
>
> Load it on BTC 1h in the terminal, then change its settings or open it in the script editor.

The spread of a pair trade, in standard deviations: the chart's market (in logs) less the hedge ratio times the other's, less a drifting intercept. Past ±2, the spread has stretched further from the hedge than usual, and the background says so.

## How it works

`ml.kalmanBeta` treats the pair as `y = α + βx` with α and β drifting slowly, and updates both on every bar. Its `spread` is the bar's surprise against the estimates from before the bar, so it never uses the bar to explain itself; `stats.zscore` puts it in standard deviations of its last 200 bars. (`spreadZ` scales it by the filter's own noise setting instead, which suits daily bars at the default `noiseVar` and reads small on hourly ones.) **Drift** (`delta`) sets how fast the hedge ratio may move: larger follows the pair faster and leaves a flatter spread. The ratio itself is a hidden line, in the legend.

## The script

```ts kalman-pairs.ts theme={"theme":"github-dark"}
// A pairs trade's spread: the chart's market against another, hedged by a ratio a Kalman filter
// re-estimates on every bar. Both are logs of price, so the ratio is how many percent the chart's
// market moves for one percent of the other. The spread is a z-score over its last 200 bars:
// past ±2 it has stretched further than usual from the hedge.
indicator('Kalman pairs spread', { shortName: 'Pairs z', precision: 2 });

const against = input.market('Hedge with', 'ETH');
const delta = input.float('Drift', 0.0001, { min: 0.0000001, max: 0.1, step: 0.0001, legend: false, tooltip: 'How fast the hedge ratio may move. Larger follows the pair faster and flattens the spread.' });

const chart = bars();
const other = bars(against === null ? {} : { market: against });
const hedge = ml.kalmanBeta({ delta });
const usual = stats.zscore(200);

const z = plot.line('Spread z', { width: 2 });
const ratio = plot.line('Hedge ratio', { hidden: true, precision: 3 });
plot.level('Stretched up', 2, { style: 'dashed' });
plot.level('Stretched down', -2, { style: 'dashed' });
const stretched = plot.background('Stretched');

chart.onBar(() => {
  const r = hedge.update(Math.log(chart.close), Math.log(other.close));
  const spread = usual.update(r.spread);
  z.set(spread, spread >= 0 ? color.up : color.down);
  ratio.set(r.beta);
  stretched.set(Math.abs(spread) > 2 ? color.withAlpha(spread > 0 ? color.up : color.down, 0.12) : null);
});
```

## Next step

See the next example, [Basket residual](https://docs.0xarchive.io/terminal/examples/basket-residual.md).


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