MAGISTERY

Subgraph - The Data Layer

Query markets, order books, trades, positions, and price history via The Graph. Endpoint, entities, and copy-paste GraphQL examples.

The subgraph indexes every protocol event on Polygon into a queryable GraphQL API. It is the data layer for every frontend, bot, and keeper in the ecosystem: the contracts are the source of truth, the subgraph is how you read them at scale.

Endpoint

https://api.studio.thegraph.com/query/1744387/magistery/v3.0.0

Hosted on The Graph's Subgraph Studio. Free, but rate-limited - fine for development and light production use. Migration to The Graph's decentralized network (independent indexers, no rate limits, per-query GRT payments) is planned; all consumers read the endpoint from a single config value, so the swap is one line.

curl -s https://api.studio.thegraph.com/query/1744387/magistery/v3.0.0 \
  -H 'content-type: application/json' \
  -d '{"query": "{ protocol(id: \"1\") { totalMarkets totalVolumeUsd totalFeesUsd } }"}'

Entities

EntityWhat it holds
ProtocolSingleton (id: "1"). Lifetime totals: markets, orders, matches, volume, fees, users.
MarketOne binary market per conditionId. Question, creator, resolver, deadline, status (Active / Pending / Resolved / Voided), volume, linked flag for Kalshi/Polymarket resolvers.
MarketOutcomePer-outcome state: positionId (ERC-1155 token ID), lastPrice, bestBid / bestAsk (1e6 scale), liquidity totals, active price levels.
OrderBookLevelPre-aggregated depth: total unfilled shares and order count per price level, per side.
OrderIndividual limit order: side, price (1e6), amount, filled, cancelled.
MatchOne matched fill: fillType (BuyVsBuy / BuyVsSell), execution price, volume, fee.
TradeExecutionPer-side detail within a match: user, side, price, amount, cost.
UserOutcomePositionUser's net position per outcome, with cost basis and realized PnL.
UserMarketSummaryPer-market PnL rollup: invested, returned (sells + redemptions), realized PnL.
AssertionUMA/Kalshi resolution assertions: status (Pending / Settled / Disputed / Rejected).
NegRiskMarket / NegRiskLegMulti-outcome markets and their binary legs.
MarketHourData / MarketDayDataOHLCV candles per outcome: open, high, low, close, volume, trade count.
Resolver, UserResolver registry (with isTrusted for known deployments) and per-user aggregates.

Full-text search on market questions is built in: marketSearch(text: "election").

Balances are not canonical

UserOutcomePosition.balance tracks net protocol activity (OrderBook buys minus sells). It does not see ERC-1155 transfers made outside the protocol. For true wallet balances, read CTF.balanceOf(user, positionId) on-chain. Also note: MarketOutcome.totalBidLiquidity and totalAskLiquidity are denominated in shares, not USDC.

Examples

Active markets by volume, with current prices:

{
  markets(
    first: 10
    orderBy: volumeUsd
    orderDirection: desc
    where: { status: "Active" }
  ) {
    id
    question
    deadline
    volumeUsd
    uniqueTraders
    outcomes {
      outcomeIndex
      lastPrice
      bestBid
      bestAsk
    }
  }
}

Order book depth

Full depth for one market, pre-aggregated by price level (prices are 1e6 scale, totalAmount is shares):

{
  orderBookLevels(
    where: { outcome_: { market: "0xYOUR_CONDITION_ID" } }
    orderBy: price
    orderDirection: desc
  ) {
    outcome { outcomeIndex }
    side
    price
    totalAmount
    orderCount
  }
}

User positions and PnL

{
  user(id: "0xyour_address_lowercase") {
    totalVolumeUsd
    positions(where: { balance_gt: 0 }) {
      market { question status }
      outcome { outcomeIndex lastPrice }
      balance
      totalCostBasis
      realizedPnl
    }
    marketSummaries {
      market { question }
      totalInvested
      totalReturned
      realizedPnl
      redeemed
    }
  }
}

Remember: balance here is the protocol-level net position. Confirm on-chain before letting a user redeem.

Price candles

Hourly OHLCV for one outcome (use marketDayDatas for daily):

{
  marketHourDatas(
    where: { outcome: "0xYOUR_CONDITION_ID-0" }
    orderBy: periodStart
    orderDirection: desc
    first: 168
  ) {
    periodStart
    open
    high
    low
    close
    volumeUsd
    tradeCount
  }
}
{
  marketSearch(text: "bitcoin") {
    id
    question
    status
  }
}

Conventions

  • IDs are lowercase hex. Markets are keyed by conditionId, users by address, outcomes by conditionId-outcomeIndex.
  • Prices come in two scales. bestBid / bestAsk / Order.price / OrderBookLevel.price are raw 1e6 integers (500000 = $0.50). lastPrice, candle OHLC, and execution prices are decimals (0.5 = $0.50).
  • Amounts are 1e6 shares. Same scale as USDC.
  • Trading survives the deadline. status: "Pending" markets (past deadline, not yet resolved) still accept and match orders. Filter accordingly.

On this page