🚧 SportsPerp is currently live on devnet. Mainnet target: before Jun 12, 2026 (World Cup kickoff).
TradingMarkets

Markets

SportsPerp launches with 68 markets — 20 EPL teams and 48 rostered players. Every market is a perpetual future priced against the composite OBV Index, collateralized in USDC, and settled on Solana.

Market types

TypeID rangeCountNotes
Team0–1920Contiguous — one market per EPL club, alphabetically assigned
Player20–9948Sparse — IDs are permanent even as players transfer, get injured, or drop out of roster

The market_type field on MarketConfig is 0 for teams, 1 for players. Market IDs are stored as u16 and used as PDA seeds.

Why stable, sparse IDs

A traditional listing system would re-index markets whenever the player roster changes — new signings get the next available slot, dropped players free their ID, existing markets shift. That’s a disaster for a perp protocol:

  • Open positions reference market IDs. Reassigning an ID would either silently reassign positions (destructive) or force-close them (user-hostile).
  • Historical candles are keyed by market ID. A reassignment severs the price history.

SportsPerp instead uses stable, sparse IDs in the 20–99 range for players. A player’s ID is never reused, and the market stays open — unaffected — through injuries, absences, and rotations; the market is priced and tradable the entire time, so open positions carry through those events with their price history intact.

A market is only put on the path to sunset when the player actually leaves the roster (roster.json regeneration drops them, e.g. a transfer out of the EPL) — the oracle stops receiving pushes, and once staleness passes 72 hours the market is permissionlessly sunset (see Market Lifecycle). Sunset is a one-way door: it settles and closes every remaining open position at the frozen oracle price. Positions open at the moment of sunset are not preserved through it — they are paid out at that price, not carried forward.

The roster as single source of truth

roster.json at the repo root defines every market: ID, name, team affiliation, canonical source ID, position group, and metadata. The file is:

  • File-watched. The engine hot-reloads when roster.json changes — no service restart required.
  • Consumed by every service. Crank, oracle pusher, keeper, liquidator, frontend, and init scripts all read from the same file. No drift.
  • Versioned. Currently v4 (every player entry carries an sb_player_id for stable identity across roster rotations). Changes are backed up automatically before being applied.

Roster updates are generated by a script that pulls the current EPL player pool from the data partner’s REST feed, applies the selection algorithm described in the next section, and fuzzy-matches against the existing roster to preserve market IDs.

Player selection algorithm

To keep player markets tradable, the roster algorithm enforces quality and diversity constraints:

  1. Fetch all EPL players (~535) from the data partner’s REST feed.
  2. Filter by minimum playing time: minutes ≥ 900 (~319 eligible).
  3. Rank each player by their composite z-score within position group (OBV 55% + Form 30% + Minutes 15%).
  4. Select the top 48 subject to:
    • Position floors: ≥ 8 FW, ≥ 15 MF, ≥ 10 DF, ≥ 3 GK
    • Team cap: ≤ 5 players per club (prevents stacking on the best teams)
  5. Fuzzy-match against existing roster names to preserve stable IDs.
  6. Back up the previous roster before writing.

The cap on players-per-team is deliberate: a trader wanting leveraged exposure to the top club gets the team market (ID 0–19); player markets are for speculating on individual performance, not dodging the team-market liquidity.

Market volatility characteristics

Teams and players have different risk profiles:

DimensionTeam marketsPlayer markets
Signal windowWhole club across 38 matchesIndividual across 24–38 appearances
Volatility driversResults, manager changes, European fixturesInjuries, transfers, rotations, suspensions
Default max leverage5x5x (same base; confidence scaling narrows in practice)

Production oracle confidence is uniform across every market by liveness, not by market type: 300 bps between matches (1.0× leverage) and 600 bps during a live match (0.6× on new opens only — closes are never confidence-gated). There is no player-vs-team confidence differential today. The design direction is a per-market dynamic confidence override: automated, source-attributed availability signals (e.g. a confirmed in-match exit, a pre-kickoff lineup absence) can widen a specific player’s market confidence within a bounded [300, 1000] bps range, on a mandatory TTL, throttling new-open leverage without touching existing positions or their exits. This channel is not yet built — today, a transfer rumor, a minor injury, or a rotation decision has no effect on confidence or leverage; the index itself is what moves (slowly, and only at the bounded Minutes weight — see Composite Index Design).

Current state

  • Program ID: 6d4fSCD7mNy7aDNS2mXUxYpZjFFQKBKwAsM5kojKQA6h (devnet)
  • Markets deployed: 20 teams + 48 players = 68 active
  • Next update: weekly roster regeneration as the EPL season progresses

Further reading