Source: https://tesseralytics.dev/blog/funding-forecast

[← Blog](https://tesseralytics.dev/blog)

Tutorial 2 July 2026

# Forecasting Hyperliquid funding: a 10-minute tutorial

Pull hourly Hyperliquid funding with the Python SDK, measure how sticky it is, and build the innovation series that actually carries the forecast. Requires a Pro API key.

Perpetual funding on Hyperliquid *looks* easy to forecast. It's sticky: today's hourly rate is a good guess for tomorrow's. But "tomorrow ≈ today" is a **base rate**, not a forecast — anyone can read it off the last price. The real question is what's left *after* you subtract that stickiness.

This is a follow-along tutorial. You'll need the Python SDK and a **Pro** API key (funding is a Pro dataset). By the end you'll have pulled real hourly funding, measured exactly how sticky it is, and built the **innovation** series — funding minus its own trailing average — which is where any genuine forecast has to live.

## Set up

Install the SDK and export your key:

```
pip install "tessera-api[polars]"
export TESSERA_API_KEY="..."   # from https://tesseralytics.dev
```

Funding is a **Pro** dataset — a free key raises `tessera.ForbiddenError` on the read below. Get a Pro key from [pricing](https://tesseralytics.dev/pricing).

## Pull hourly funding

`gold_funding_1h` is hourly funding, partitioned per (coin, month). Read BTC, ETH and SOL for six months, projecting just the columns we need:

```
import polars as pl
import tessera

client = tessera.TesseraClient()  # reads $TESSERA_API_KEY

funding = client.read(
    "gold_funding_1h",
    coin=["BTC", "ETH", "SOL"],
    month=tessera.MonthSpan("2026-01", "2026-06"),
    columns=["time", "coin", "funding_rate"],
)

# Autocorrelation of hourly funding at increasing lags, per coin.
lags = [1, 6, 12, 24, 72, 168]   # hours

def autocorr(s: pl.Series, h: int) -> float:
    # Pearson correlation of the series against itself, lagged by h rows.
    df = pl.DataFrame({"x": s.slice(0, s.len() - h), "y": s.slice(h)})
    return df.select(pl.corr("x", "y")).item()

rows = []
for coin in funding["coin"].unique().to_list():
    s = funding.filter(pl.col("coin") == coin).sort("time")["funding_rate"]
    rows.append({"coin": coin, **{f"{h}h": round(autocorr(s, h), 3) for h in lags}})

pl.DataFrame(rows)
```

Funding is sticky — autocorrelation of hourly funding against itself, averaged over BTC, ETH and SOL.

Close to 0.9 at a one-hour lag, fading to almost nothing within a week. That slow decay is the base rate: "tomorrow ≈ today".

## Subtract the stickiness

Define the **innovation** as funding minus its own 7-day trailing mean (168 hourly bars). Persistence lives in the level; strip it off and see how much survives:

```
d = (
    funding.sort("coin", "time")
    .with_columns(
        pl.col("funding_rate")
        .rolling_mean(window_size=168, min_samples=1)
        .over("coin")
        .alias("trailing_7d")
    )
    .with_columns(
        (pl.col("funding_rate") - pl.col("trailing_7d")).alias("innovation")
    )
    .drop_nulls()
)

for name in ("funding_rate", "innovation"):
    s = d.filter(pl.col("coin") == "BTC").sort("time")[name]
    print(f"{name:>13}  24h: {autocorr(s, 24):.3f}   72h: {autocorr(s, 72):.3f}")
```

At the one-day lag the subtraction barely moves the number — `0.285 → 0.234`: the innovation still carries a little momentum of its own. At three days the picture flips — the raw level still autocorrelates at `0.122`, while the innovation is `0.001`. Past a day or so, essentially all of the level's stickiness was the trailing average; strip it and nothing multi-day survives.

## What that means

"Tomorrow ≈ today" is doing almost all of the work. Persistence is a free base rate anyone can compute; subtract it and the forecastable leftover is small — and short-lived, with the innovation's autocorrelation dead inside about three days. That near-zero number is the honest size of the surprise: a feature to stack on a model you already have, not a buy/sell button. Everything above runs on one dataset — [the funding tile](https://tesseralytics.dev/datasets/gold_funding_1h) — pulled through [the SDK](https://tesseralytics.dev/sdks).

[← Back to blog](https://tesseralytics.dev/blog)
