▾ Documentation

Hyperliquid query examples

Practical SQL patterns for Hyperliquid perpetual trading analysis — traders, markets, liquidations, funding, TWAP, and cross-analysis.

// updated 2026-06-04

Practical SQL patterns for perpetual trading analysis on the Hyperliquid Indexer. See /hyperliquid/tables for the full schema reference.

NOTE

The patterns below use table and field aliases (fills, fundings, twaps, user_fundings; user, px, sz, closedPnl, time) to express common analytics shapes. Map them onto the physical schema in the Table Reference when adapting a query to your own pipeline.

Trader analysis

Most profitable traders (30 days)

SELECT
    user,
    count(*)             AS trades,
    sum(closedPnl) / 1e6 AS realized_pnl,
    avg(closedPnl) / 1e6 AS avg_pnl_per_trade,
    countIf(closedPnl > 0) AS wins,
    countIf(closedPnl < 0) AS losses
FROM fills
WHERE time > now() - INTERVAL 30 DAY
  AND closedPnl != 0
GROUP BY user
HAVING trades > 50
ORDER BY realized_pnl DESC
LIMIT 100

Trading volume by wallet

SELECT
    user,
    count(*)              AS trades,
    sum(sz * px)          AS notional_volume,
    count(DISTINCT coin)  AS markets_traded,
    count(DISTINCT toDate(time)) AS active_days
FROM fills
WHERE time > now() - INTERVAL 7 DAY
GROUP BY user
ORDER BY notional_volume DESC
LIMIT 50

Win rate analysis

SELECT
    user,
    count(*)               AS closing_trades,
    countIf(closedPnl > 0) AS profitable,
    countIf(closedPnl < 0) AS unprofitable,
    round(countIf(closedPnl > 0) / count(*) * 100, 2) AS win_rate_pct,
    sum(closedPnl) / 1e6   AS total_pnl
FROM fills
WHERE time > now() - INTERVAL 30 DAY
  AND closedPnl != 0
GROUP BY user
HAVING closing_trades > 100
ORDER BY win_rate_pct DESC
LIMIT 50

Market analysis

Volume by market

SELECT
    coin,
    count(*)     AS trades,
    sum(sz * px) AS notional_volume,
    uniq(user)   AS unique_traders,
    avg(sz * px) AS avg_trade_size
FROM fills
WHERE time > now() - INTERVAL 24 HOUR
GROUP BY coin
ORDER BY notional_volume DESC

Hourly volume trend

SELECT
    toStartOfHour(time) AS hour,
    coin,
    count(*)            AS trades,
    sum(sz * px)        AS volume
FROM fills
WHERE time > now() - INTERVAL 7 DAY
  AND coin = 'BTC'
GROUP BY hour, coin
ORDER BY hour

Long vs short bias

SELECT
    toStartOfHour(time) AS hour,
    coin,
    sumIf(sz, side = 'B') AS buy_volume,
    sumIf(sz, side = 'A') AS sell_volume,
    sumIf(sz, side = 'B') - sumIf(sz, side = 'A') AS net_bias
FROM fills
WHERE time > now() - INTERVAL 24 HOUR
  AND coin = 'ETH'
GROUP BY hour, coin
ORDER BY hour

Liquidation analysis

Recent liquidations

SELECT
    time,
    user,
    coin,
    side,
    px AS liquidation_price,
    sz AS size,
    closedPnl / 1e6 AS pnl
FROM fills
WHERE liquidation = 1
  AND time > now() - INTERVAL 24 HOUR
ORDER BY time DESC
LIMIT 100

Liquidation volume by market

SELECT
    coin,
    count(*)             AS liquidations,
    sum(sz * px)         AS liquidated_notional,
    sum(closedPnl) / 1e6 AS total_pnl_lost
FROM fills
WHERE liquidation = 1
  AND time > now() - INTERVAL 7 DAY
GROUP BY coin
ORDER BY liquidated_notional DESC

Wallets with multiple liquidations

SELECT
    user,
    count(*)     AS liquidation_count,
    sum(sz * px) AS total_liquidated,
    arrayDistinct(groupArray(coin)) AS markets
FROM fills
WHERE liquidation = 1
  AND time > now() - INTERVAL 30 DAY
GROUP BY user
HAVING liquidation_count > 3
ORDER BY liquidation_count DESC
LIMIT 50

Funding analysis

Current funding rates

SELECT
    coin,
    argMax(fundingRate, time)              AS latest_funding,
    argMax(fundingRate, time) * 24 * 365   AS annualized
FROM fundings
WHERE time > now() - INTERVAL 1 HOUR
GROUP BY coin
ORDER BY abs(latest_funding) DESC

Funding rate history

SELECT
    toStartOfHour(time) AS hour,
    coin,
    avg(fundingRate)             AS avg_funding,
    avg(fundingRate) * 24 * 365  AS annualized
FROM fundings
WHERE time > now() - INTERVAL 7 DAY
  AND coin IN ('BTC', 'ETH', 'SOL')
GROUP BY hour, coin
ORDER BY hour, coin

Top funding earners

SELECT
    user,
    sum(usdc) AS total_funding_pnl,
    count(*)  AS funding_events,
    avg(usdc) AS avg_funding_payment
FROM user_fundings
WHERE time > now() - INTERVAL 30 DAY
GROUP BY user
ORDER BY total_funding_pnl DESC
LIMIT 50

TWAP analysis

Active TWAP orders

SELECT
    twapId,
    user,
    coin,
    side,
    min(time) AS started,
    max(time) AS last_fill,
    count(*)  AS fills,
    sum(sz)   AS total_filled,
    sum(sz * px) / sum(sz) AS avg_price
FROM twaps
WHERE time > now() - INTERVAL 24 HOUR
GROUP BY twapId, user, coin, side
ORDER BY started DESC
LIMIT 50

TWAP execution quality

WITH twap_summary AS (
    SELECT
        twapId,
        user,
        coin,
        sum(sz * px) / sum(sz) AS twap_avg_price,
        sum(sz)                AS total_size,
        dateDiff('minute', min(time), max(time)) AS duration_minutes
    FROM twaps
    WHERE time > now() - INTERVAL 7 DAY
    GROUP BY twapId, user, coin
    HAVING count(*) > 5
)
SELECT
    coin,
    count(*)              AS twap_orders,
    avg(total_size)       AS avg_order_size,
    avg(duration_minutes) AS avg_duration_min
FROM twap_summary
GROUP BY coin
ORDER BY twap_orders DESC

Cross-analysis

Correlation: large fills and liquidations

SELECT
    toStartOfMinute(time) AS minute,
    coin,
    sumIf(sz * px, liquidation = 0) AS regular_volume,
    sumIf(sz * px, liquidation = 1) AS liquidation_volume,
    countIf(liquidation = 1)        AS liquidation_count
FROM fills
WHERE time > now() - INTERVAL 1 HOUR
  AND coin = 'BTC'
GROUP BY minute, coin
HAVING liquidation_count > 0
ORDER BY minute

Smart wallet tracker

Track wallets with high win rates and significant volume.

WITH wallet_stats AS (
    SELECT
        user,
        count(*)     AS trades,
        sum(sz * px) AS volume,
        sum(closedPnl) / 1e6 AS pnl,
        countIf(closedPnl > 0) / countIf(closedPnl != 0) AS win_rate
    FROM fills
    WHERE time > now() - INTERVAL 30 DAY
    GROUP BY user
    HAVING trades > 100
       AND countIf(closedPnl != 0) > 50
)
SELECT *
FROM wallet_stats
WHERE win_rate > 0.55
  AND pnl > 10000
ORDER BY pnl DESC
LIMIT 50

Performance tips

  • Always filter by time — tables are partitioned by date.
  • Use a coin filter — narrows the scan significantly.
  • Aggregate first — reduce data before complex operations.

Check a query plan before running heavy scans:

EXPLAIN SELECT count(*) FROM fills WHERE time > today()

Get started

Provision access or start a trial: @supanode_tgs.