The universal ticker
The universal ticker
One permanent Arena id for each bet, so a person or a bot can store what it traded without depending on a venue’s ticker.
Ids
- game_ + 10 characters
- One real game. A postponement moves its start time, never its id.
- ins_ + 12 characters
- One instrument: one bet on one game, such as the Chiefs to win by more than 3.5 points. This is the id to store.
- ent_ + 8 characters
- One team. Outputs name teams by code and name, so you will rarely need it.
| Prefix | Names |
|---|---|
| game_ + 10 characters | One real game. A postponement moves its start time, never its id. |
| ins_ + 12 characters | One instrument: one bet on one game, such as the Chiefs to win by more than 3.5 points. This is the id to store. |
| ent_ + 8 characters | One team. Outputs name teams by code and name, so you will rarely need it. |
The characters after the prefix are Crockford base32: digits and capital letters, without I, L, O or U. Ids are permanent: store them, and never build or parse one. The CLI and the MCP server accept an id in any case.
Slugs are readable aliases, such as nfl-2026-w03-kc-at-mia-spread-kc-3.5. Anything that takes an id takes its slug too, but a slug may change and the id does not. Ids on this page are made-up examples of the format.
What an instrument means
Every instrument has a YES side, and its label always names it: KC ML (the Chiefs win), KC -3.5 (the Chiefs win by more than 3.5 points), Over 44.5 (the two teams score more than 44.5 points combined). yes_means says the same in a sentence.
A spread is always stored as “subject wins by more than L”, with L above zero. So KC -3.5 and MIA +3.5 are one instrument seen from opposite sides: MIA +3.5 is its NO side. MIA -3.5 is a different instrument.
Spreads and totals count what the sport counts: points in football and basketball, runs in baseball (the run line) and goals in hockey (the puck line) and soccer. canes over 5.5 is the two teams scoring more than 5.5 goals combined.
Soccer moneylines have three outcomes, and each is its own instrument: a club to win, the other club to win, and the draw (arsenal leeds draw). So the NO side of a club’s win is the other club winning or a draw. Soccer settles on 90 minutes plus stoppage time.
push_possible is true when the result can settle at neither 0 nor 100, such as a moneyline on a game that ends tied, and tie_rule says how the venue settles a tie (half means at 50). How Arena grades a result that is neither yes nor no is on /docs/execution.
Listings and polarity
A listing is one side of one venue market that pays on the instrument. venue names the venue, and ticker is its market. The lookups list Kalshi listings only. Kalshi is Arena’s reference venue: every game and instrument starts from a Kalshi market, and a paper trade fills at Kalshi’s price unless a best-price fill takes another venue’s.
polarity 1 means holding the listing’s side pays when the instrument is YES; -1 means it pays when the instrument is NO. Do not work it out yourself, and do not assume 1: each listing gives buy_for_yes and buy_for_no, the side of its ticker to buy to hold the instrument’s YES or NO.
Query side and instrument side
arena resolve and resolve_market answer with the instrument and query_side, the side of it your words asked for. "mia +3.5" resolves to the KC -3.5 instrument with query_side no. In the CLI, the default columns show the words’ own label, buy_side, the id and query_side.
There are two ways to trade exactly what the words asked: buy buy_side on the listed ticker (arena buy <ticker> --side <buy_side>), or pass the id with the query side (arena buy <ins_id> --side <query_side>; on the MCP server, instrument_id with instrument_side set to query_side).
With an id or slug, --side in the CLI and instrument_side on the MCP server always mean the instrument’s side. Arena maps it to the ticker’s side, and quotes and receipts show both, as instrument_side and ticker_side.
Prices on other venues
arena quotes and the MCP tool get_cross_venue_quotes show one instrument’s price on Kalshi and, while Arena shows them, on Novig, Polymarket and ProphetX, where Arena has matched a market on those venues to the same instrument. ProphetX prices come from its sandbox exchange until Arena’s production access is approved, and its rows arrive in the CLI and the npm MCP server with their next release. Every price is the chance of the instrument’s YES, whichever side of the venue’s market was read.
Each price names its venue and the time it was current. A last trade has its own time (last_trade_at), and on Polymarket each outcome’s own last trade is listed (outcome_last_trades); last_trade is always the YES outcome’s own; each outcome’s print is its price and time only. Novig’s prices arrive over Novig’s live feed when Arena’s proxy is connected to it, and by polling otherwise, so a quiet market can sit unchanged for minutes; Arena shows a Novig price up to 5 minutes old, with its time, when it could not read it again sooner: in the CLI and the MCP server a row more than a minute older than the answer has stale: true and a note, so compare as_of before you compare prices. During a game Novig shows only when Novig updated its price in the last minute, and ProphetX not at all; before a game, a Novig price Novig has not updated for 5 minutes is left out as out of date, with a note. Venues are always listed Kalshi, Novig, Polymarket, ProphetX, and are not ranked by price. When a venue’s contract differs from Kalshi’s, the note says how. For example, a tied or unfinished NFL game voids a Novig moneyline, which Novig then settles at a fair price it sets, while Kalshi settles a tie at 50%. Every Novig and Polymarket match so far was made by rule, and the note says when no person has reviewed it yet.
arena gaps and the MCP tool find_price_gaps compare the same prices after each venue’s fees. A paper trade can also take Novig’s, Polymarket’s or ProphetX’s price when it passes Arena’s checks (/docs/execution). How matching, freshness, fees, gaps and best-price fills work is on /docs/methodology. Paper trades fill in Arena’s sandbox and are not sent to Kalshi, Novig or Polymarket. Arena can stop showing other venues at any time; the answer then says cross_venue: false and lists Kalshi only.
Coverage
Full-game moneylines, spreads and game totals on half-point lines, in the NFL, college football (FBS), MLB, the NHL, the NBA and the Premier League. The Champions League is set up and gets instruments once Kalshi lists its games. Team totals, halves, player props and other leagues have no instruments yet, so the resolver answers no rows for them. Spreads and totals are added closer to the game, so a game far out may list only its moneylines, and a league out of season lists none.
The resolver reads a bet as teams plus the bet: yankees run line -1.5, canes over 5.5, arsenal -1.5, arsenal leeds draw. A name two leagues share, such as rangers, spurs or hurricanes, may need the league word. A club in two competitions resolves to its next game. In soccer, an over or under with one club or a bare number needs both clubs or the word game.
Looking ids up
- arena resolve "chiefs ml"
- A bet in words to the instrument id, the ticker and the side to buy. MCP:
resolve_market. Works signed out. - arena instrument <ins_id|slug>
- One instrument with its listings. MCP:
get_instrument. Works signed out. - arena game <game_id|slug|words…> [--type spread]
- Every instrument on one game. MCP:
get_game. Works signed out. - arena games [--date today]
- Upcoming games with their ids; from CLI 0.6.0 today's games in every league with each team's chance to win. MCP:
list_games. Works signed out. - arena quotes <ins_id|words…>
- The instrument’s price on Kalshi and, while Arena shows them, on Novig, Polymarket and ProphetX. MCP:
get_cross_venue_quotes. Works signed out. - arena gaps <ins_id|words…>
- The same prices as YES plus NO pairs across venues, with each pair’s cost after both venues’ fees. MCP:
find_price_gaps. Works signed out.
| CLI | What it does, and the MCP tool |
|---|---|
| arena resolve "chiefs ml" | A bet in words to the instrument id, the ticker and the side to buy. MCP: resolve_market. Works signed out. |
| arena instrument <ins_id|slug> | One instrument with its listings. MCP: get_instrument. Works signed out. |
| arena game <game_id|slug|words…> [--type spread] | Every instrument on one game. MCP: get_game. Works signed out. |
| arena games [--date today] | Upcoming games with their ids; from CLI 0.6.0 today's games in every league with each team's chance to win. MCP: list_games. Works signed out. |
| arena quotes <ins_id|words…> | The instrument’s price on Kalshi and, while Arena shows them, on Novig, Polymarket and ProphetX. MCP: get_cross_venue_quotes. Works signed out. |
| arena gaps <ins_id|words…> | The same prices as YES plus NO pairs across venues, with each pair’s cost after both venues’ fees. MCP: find_price_gaps. Works signed out. |
Ids and slugs are accepted wherever a quote or a trade takes a ticker: arena market, orderbook, chart and buy in the CLI; get_market, get_orderbook, get_price_history, place_trade (instrument_id with instrument_side) and the get_orders filter on the MCP server. Those quotes, prices and trades need arena login; arena quotes and get_cross_venue_quotes do not.
Account rows carry instrument_id, instrument_label (the instrument’s YES side) and instrument_side (which side of it the row holds) when the ticker maps to an instrument: always on the MCP server, and with --json or --fields in the CLI. Picks from the HTTP API carry instrumentId and Arena’s own marketLabel, and positions and trades from GET /portfolio carry instrumentId, instrumentLabel and instrumentSide.
With an API key that has markets:read, the HTTP API answers the same instruments: GET /api/v1/instruments (a page, filtered by league, game, type and time), /instruments/search?q= (a bet in words), /instruments/{ref} (one, with every venue listing and a merged id followed), /games and /games/{ref}. The reference is at https://docs.arena-predictions.com.
$ arena instrument ins_0123456789AB | cat
instrument:
instrument_id: ins_0123456789AB
label: KC -3.5
market_type: spread
line: 3.5
starts_at: 2026-09-20T17:00:00+00:00
game_status: scheduled
push_possible: false
tie_rule: null
listings[1]{venue,ticker,listing_side,polarity,buy_for_yes,buy_for_no}:
kalshi,ARENA-EXAMPLE-1,yes,1,yes,no
help[3]:
- arena login
- arena market ins_0123456789AB
- arena buy ins_0123456789AB --side yes --contracts 10 --dry-runErrors and empty results
- No rows from resolve
- Exit 0 with an empty list,
count: 0and anemptyReason(empty_reasonon the MCP server). The resolver never guesses, so rephrase. - Unknown id or slug
- CLI exit 6; MCP
not_found. Resolve the bet in words again to get the current id. - A game where a bet goes
- A
game_id passed tomarket,orderbook,chartorbuyexits 2 before any request, with the hintarena game <ref>. MCP:invalid_request. - No single live listing
- The instrument has no listing to trade right now, or more than one. CLI exit 6; MCP
market_not_open. Trade a listed ticker instead. - A game with no instruments yet
- Exit 0 with an empty list and an
emptyReason: spreads and totals are added closer to kickoff. - Merged or retired ids
- When two ids turn out to name the same bet, Arena records the merge on its server, but those redirects are not readable publicly yet. A merged or retired id answers not found: resolve the bet in words again to get the current id.
| Case | What you get |
|---|---|
| No rows from resolve | Exit 0 with an empty list, count: 0 and an emptyReason (empty_reason on the MCP server). The resolver never guesses, so rephrase. |
| Unknown id or slug | CLI exit 6; MCP not_found. Resolve the bet in words again to get the current id. |
| A game where a bet goes | A game_ id passed to market, orderbook, chart or buy exits 2 before any request, with the hint arena game <ref>. MCP: invalid_request. |
| No single live listing | The instrument has no listing to trade right now, or more than one. CLI exit 6; MCP market_not_open. Trade a listed ticker instead. |
| A game with no instruments yet | Exit 0 with an empty list and an emptyReason: spreads and totals are added closer to kickoff. |
| Merged or retired ids | When two ids turn out to name the same bet, Arena records the merge on its server, but those redirects are not readable publicly yet. A merged or retired id answers not found: resolve the bet in words again to get the current id. |