HELIX// subgraph home docs sdk trade stats api
MOCK api
SUBGRAPH

HELIX subgraph. — entity schema, endpoint, sample queries.

v0.1 · published on launch · The Graph decentralized network

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

networkThe Graph decentralized network chainBase · id 8453 query urlhttps://api.studio.thegraph.com/query/helix/perps/v0.1 studiothegraph.com/studio/subgraph/helix-perps manifestgithub.com/helixperps/subgraph publishedon launch · this URL flips live when the GraphQL endpoint resolves
why a subgraph The HELIX REST endpoints give you the current state. The subgraph gives you the full history — every position ever opened, every liquidation, every fee accrued — indexed and queryable in GraphQL. Build leaderboards, PnL charts, and any backtest tool off the same source the canonical contract emits.

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:

eventindexed into
Deposit · Withdrawupdates Trader.totalVolume + free margin tracking
Opencreates Fill · upserts Position · increments Market OI
Closecreates Fill · marks Position.closedAt · realizes PnL
Liquidationcreates Liquidation · increments counts · marks position
FundingSettledupdates Market.cumulativeFundingWad + lastFundingRateWad
MarkRecordedupdates Market.lastMarkWad
HLPDeposit · HLPWithdraw · Donateupserts HLPSnapshot · routes through ProtocolDaily
Buybackincrements ProtocolDaily.burned
MarketAdded · MarketsLocked · BindingsLockedcreates / 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.

canonicality The subgraph is a derived view. The deployed contract is the source of truth — if the subgraph and contract disagree, the contract wins. Always reconcile critical state (margin, position size, liquidation eligibility) against the on-chain read functions before acting on it.