HELIX subgraph. — entity schema, endpoint, sample queries.
The HELIX subgraph indexes every event from HelixPerps.sol + HelixHook.sol into queryable GraphQL entities. Use it to build trader dashboards, position-tracking bots, leaderboards, copytrade rigs, or any historical analytics that the read endpoints don't surface directly.
01endpoint
02schema
Entity-per-event with derived rollups. The schema is frozen at v0.1 — additive changes only post-launch.
# ─── Trader · per-wallet aggregates ─────────────────────────── type Trader @entity { id: ID! # wallet address totalVolume: BigInt! # lifetime notional (USDC, 6dp) totalFees: BigInt! # lifetime fees paid realizedPnl: BigInt! # lifetime closed PnL liquidationCount: Int! openPositionCount: Int! firstSeenAt: BigInt! lastActiveAt: BigInt! positions: [Position!]! @derivedFrom(field: "trader") fills: [Fill!]! @derivedFrom(field: "trader") } # ─── Market · per-market live state + rollups ───────────────── type Market @entity { id: ID! # marketId as string symbol: String! class: String! # majors | alts | base | memes poolKey: Bytes! fundingRefSym: String # Hyperliquid mirror symbol, null if self-ref openInterestLong: BigInt! openInterestShort: BigInt! cumulativeVolume: BigInt! cumulativeFundingWad: BigInt! cumulativeFees: BigInt! liquidationCount: Int! lastMarkWad: BigInt! lastFundingRateWad: BigInt! positions: [Position!]! @derivedFrom(field: "market") } # ─── Position · one entity per (trader, market) ─────────────── type Position @entity { id: ID! # trader-marketId composite trader: Trader! market: Market! isLong: Boolean! notional: BigInt! margin: BigInt! entryPriceWad: BigInt! realizedPnl: BigInt! fundingPaid: BigInt! openedAt: BigInt! closedAt: BigInt isOpen: Boolean! fills: [Fill!]! @derivedFrom(field: "position") liquidation: Liquidation } # ─── Fill · every Open / Close event ────────────────────────── type Fill @entity { id: ID! # txHash-logIndex position: Position! trader: Trader! market: Market! kind: String! # open | close notional: BigInt! marginAdd: BigInt! priceWad: BigInt! fee: BigInt! realizedPnl: BigInt blockNumber: BigInt! blockTime: BigInt! txHash: Bytes! } # ─── Liquidation · every Liquidation event ──────────────────── type Liquidation @entity { id: ID! trader: Trader! market: Market! liquidator: Bytes! bounty: BigInt! traderResidual: BigInt! # negative = absorbed by insurance/HLP hlpAbsorbed: BigInt! blockNumber: BigInt! blockTime: BigInt! txHash: Bytes! } # ─── HLPSnapshot · 1 per block on any HLP-touching event ────── type HLPSnapshot @entity { id: ID! # blockNumber totalShares: BigInt! vaultUsdc: BigInt! sharePriceWad: BigInt! peakSharePriceWad: BigInt! isInDrawdown: Boolean! blockNumber: BigInt! blockTime: BigInt! } # ─── ProtocolDaily · 1 per UTC day, gas-cheap rollup ────────── type ProtocolDaily @entity { id: ID! # YYYY-MM-DD date: BigInt! volume: BigInt! fees: BigInt! newTraders: Int! activeTraders: Int! liquidationCount: Int! hlpStartUsdc: BigInt! hlpEndUsdc: BigInt! insuranceUsdc: BigInt! burned: BigInt! # $HELIX burned via buyback }
03sample queries
top 10 traders by realized PnL (7d)
{
traders(
first: 10,
orderBy: realizedPnl,
orderDirection: desc,
where: { lastActiveAt_gt: 1779379200 }
) {
id
realizedPnl
totalVolume
liquidationCount
}
}
open positions for a wallet
{
positions(where: {
trader: "0x...",
isOpen: true
}) {
market { symbol class }
isLong
notional
margin
entryPriceWad
fundingPaid
openedAt
}
}
HLP NAV curve (last 30 days)
{
hlpsnapshots(
first: 1000,
orderBy: blockTime,
orderDirection: desc,
where: { blockTime_gt: 1776796800 }
) {
blockTime
sharePriceWad
vaultUsdc
isInDrawdown
}
}
per-market 24h activity
{
protocoldailies(
first: 1,
orderBy: date,
orderDirection: desc
) {
date volume fees newTraders activeTraders liquidationCount burned
}
markets(orderBy: cumulativeVolume, orderDirection: desc, first: 10) {
symbol class openInterestLong openInterestShort lastMarkWad
}
}
all liquidations in a block range
{
liquidations(
where: {
blockNumber_gte: 19840000,
blockNumber_lte: 19841000
},
orderBy: blockNumber
) {
market { symbol }
trader { id }
liquidator
bounty
hlpAbsorbed
txHash
}
}
04indexed events
The subgraph indexes every event emitted by HelixPerps.sol and HelixHook.sol. Full list:
| event | indexed into |
|---|---|
Deposit · Withdraw | updates Trader.totalVolume + free margin tracking |
Open | creates Fill · upserts Position · increments Market OI |
Close | creates Fill · marks Position.closedAt · realizes PnL |
Liquidation | creates Liquidation · increments counts · marks position |
FundingSettled | updates Market.cumulativeFundingWad + lastFundingRateWad |
MarkRecorded | updates Market.lastMarkWad |
HLPDeposit · HLPWithdraw · Donate | upserts HLPSnapshot · routes through ProtocolDaily |
Buyback | increments ProtocolDaily.burned |
MarketAdded · MarketsLocked · BindingsLocked | creates / freezes Market entities |
05rate limits & caching
The Graph's hosted query endpoint enforces standard query-complexity limits. For high-throughput indexers, run a self-hosted node from the public manifest. The subgraph is open-source and deterministic — anyone can mirror it.
- Free tier: 1000 queries/min, 10 second timeout per query.
- Paid tier: via The Graph billing — pay per query in GRT.
- Self-hosted: run graph-node against any Base RPC; the manifest at github.com/helixperps/subgraph is the canonical config.
06quick start
Two lines of code to read the live HELIX subgraph from any JS environment:
// node 20+ or browser · zero deps const r = await fetch('https://api.studio.thegraph.com/query/helix/perps/v0.1', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ query: `{ markets(first:5) { symbol cumulativeVolume } }` }), }); const { data } = await r.json(); console.log(data.markets);
For TypeScript with type-safe codegen, see the /sdk — it bundles @helix/subgraph-types generated from this schema.