Arena CLI
Install the CLI
Your own login, the whole product, from a terminal. Node 20 or newer.
# install the binary (the agent prompt and the hook call arena)
npm install -g arena-prediction-cli
arena login
# or try it without installing (arena is not added to your PATH)
npx arena-prediction-cli loginOne sign-in is enough. Your agent and the MCP server act with that login. For an agent, install the binary, because the prompt and the hook call arena directly.
Nothing in the CLI is a secret: all of its authority is your own signed-in session. There is nothing else to install for agent use. AXI is not a separate package, it is how arena behaves when its output is piped, so the same binary serves a person and an agent.
Sign in
Arena has no password login. arena login hands the browser the interactive step and catches the redirect on a loopback port.
$ arena login
arena: opening your browser to sign in. If nothing opens, visit:
https://<auth host>/authorize?provider=google&redirect_to=http://127.0.0.1:53682/callback…
userId 4d2f8c1e-9b0a-4c6e-8f21-3a7b5d9e0c12
displayName sharp_joe
isPro true
balanceDollars $1,046.00
monthKey 2026-09
Next:
arena whoami
arena balanceProviders
arena login --provider apple signs in with Apple instead of Google. There is no guest or anonymous sign-in: the CLI acts for an account, so every trade and every record belongs to the person who signed in.
Headless machines
arena login --device, the flow for a machine with no browser, is not in this release. On a headless box, sign in on a machine that has one and copy ~/.config/arena/credentials.json across.
Where credentials live
In your OS keychain, falling back to ~/.config/arena/credentials.json with mode 0600. The access token lives about an hour and refreshes itself; arena logout deletes the stored pair.
Command reference
Reads work signed out where the data is public. Writes need a session.
- arena
- Home view. Live balance, open-position count, season and next steps, not help text.
- arena login [--provider google|apple]
- Sign in. Opens a browser and catches the redirect on 127.0.0.1.
--device, the headless flow, is not in this release. - arena logout
- Forget the stored credentials.
- arena whoami
- Who you are signed in as, membership status, spendable balance, season.
- arena markets [--sport …] [--league …] [--event …] [--limit 20]
- Browse open markets. Default limit 20.
- arena market <ticker|ins_id> [--contracts N]
- One market in detail. Takes a ticker, an Arena instrument id (
ins_…) or its slug; with an id, the output addsbuy_for_yesandbuy_for_no, the side of the ticker that holds each side of the instrument.--contracts Naddsvenue_fee_est_dollars, the estimated venue fee for that size, which is not charged on paper. - arena search <query>
- Substring search over titles and tickers.
- arena resolve <text…> [--limit 10]
- Turn a bet in words, such as "chiefs ml", "kc -3.5" or "kc mia under 44.5 sunday", into an Arena instrument id, the ticker and the side to buy: the next step is
arena buy <ticker> --side <buy_side>. NFL full-game moneylines, spreads and totals on half-point lines. It never guesses, so no rows means rephrase. Works signed out. - arena instrument <ins_id|slug>
- One Arena instrument: its label (always its YES side), type, line, start time and each listed ticker with
buy_for_yesandbuy_for_no;--jsonaddsyes_means, the YES side in a sentence. A ticker works too and finds the instrument listed on it. Works signed out. - arena game <game_id|slug|words…> [--type ml|spread|total]
- One game and every Arena instrument on it, with their ids: moneylines first, then spreads and totals by line. No prices. Spreads and totals are added closer to kickoff. Works signed out.
- arena games [--league nfl] [--date today|YYYY-MM-DD] [--week N] [--limit 20]
- Upcoming games with their Arena game ids and how many instruments each has.
--dateis one calendar day in America/New_York. Works signed out. - arena catalog
- The groups and leagues you can filter by. not yet shipped
- arena screener [--league L] [--group G] [--min-volume N] [--max-spread C] [--price-min C] [--price-max C] [--closes-within 4h] [--min-move C] [--sort volume|move|spread|close_time] [--limit 20]
- Screen open markets by volume, price, spread, time to close and move over about 24 hours. Rows add
spread_centsand a signedmove_cents. Needsarena login. - arena orderbook <ticker|ins_id> [--depth 10]
- Resting bids and asks. Takes a ticker, an instrument id or its slug.
- arena chart <ref> [--range 1h|6h|24h|7d] [--points 12]
- A market's recent price path for a ticker, an instrument id or its slug: open, high, low, now, the change and a sparkline. For an instrument whose YES is the ticker's NO, the numbers price the instrument's YES, and
ticker_sidesays which side was charted. Needsarena login. - arena buy <ticker|ins_id> --side yes|no --contracts N [--max-price CENTS] [--limit CENTS] [--tif gtc|ioc|fok] [--expires 4h] [--yes] [--dry-run]
- Open a position. Without --limit it quotes, confirms, places and reconciles the actual fill against the quote. With --limit it names your price: the order fills at that price or better, or rests until it does. With an instrument id or slug, --side is the instrument's side: the CLI maps it to the ticker's side, and the quote and the receipt show both (
instrument_side,ticker_side). --dry-run also showsvenue_fee_est_dollars, the estimated venue fee, not charged on paper, and what walking the book for that size would cost (walk_vwap_cents,walk_slippage_cents). - arena sell <trade-id> [--limit CENTS] [--tif gtc|ioc|fok] [--expires 4h] [--yes] [--dry-run]
- Close a position at the live bid, or rest a limit exit with --limit. Trade ids come from arena positions.
- arena orders [--status resting|executed|canceled|all] [--ticker T]
- Your limit orders. Resting by default: the ones still holding money and still able to fill on their own.
--tickertakes the market's ticker. With--json, or--fieldsnaming them, rows also carryinstrument_id,instrument_labelandinstrument_side. - arena cancel <order-id> [--yes]
- Withdraw a resting order and get its hold back. Cancelling one that already filled is not an error: it answers reducedBy 0 and the trade id.
- arena settle
- Settle anything already resolved. A backstop: the server settles automatically within about five minutes.
- arena positions [--live]
- Open positions with unrealised P&L. --live adds current prices with one extra market read. With
--json, or--fieldsnaming them, rows also carryinstrument_id,instrument_labelandinstrument_side. - arena balance
- Spendable balance and net worth.
- arena history [--month 2026-08]
- Your settled trades. --month reads a past season (a calendar month in America/New_York). Instrument columns as for
arena positions. - arena stats [--month YYYY-MM] [--by league|band|hold]
- Your season graded: win rate against the prices you paid, calibration by price band, closing-line value, return on stake and drawdown.
--byadds a breakdown by league, entry price band or how the trade ended. An empty season prints zero counts and anemptyReason. Needsarena login. - arena picks
- Today’s AI picks.
- arena leaderboard [--top 25]
- This season’s standings, with the AI models and the paper funds ranked in alongside the players, exactly as the app ranks them. Rows carry an AI, ETF or Team fund badge.
- arena trader <ref> [picks]
- A published trader record. Public, so it works signed out.
- arena watch <ticker…> [--orderbook]
- Live prices, repainted in place. not yet shipped
- arena hook install
- Install the ambient-context hook into your agent runner. not yet shipped
| Command | What it does |
|---|---|
| arena | Home view. Live balance, open-position count, season and next steps, not help text. |
| arena login [--provider google|apple] | Sign in. Opens a browser and catches the redirect on 127.0.0.1. --device, the headless flow, is not in this release. |
| arena logout | Forget the stored credentials. |
| arena whoami | Who you are signed in as, membership status, spendable balance, season. |
| arena markets [--sport …] [--league …] [--event …] [--limit 20] | Browse open markets. Default limit 20. |
| arena market <ticker|ins_id> [--contracts N] | One market in detail. Takes a ticker, an Arena instrument id (ins_…) or its slug; with an id, the output adds buy_for_yes and buy_for_no, the side of the ticker that holds each side of the instrument. --contracts N adds venue_fee_est_dollars, the estimated venue fee for that size, which is not charged on paper. |
| arena search <query> | Substring search over titles and tickers. |
| arena resolve <text…> [--limit 10] | Turn a bet in words, such as "chiefs ml", "kc -3.5" or "kc mia under 44.5 sunday", into an Arena instrument id, the ticker and the side to buy: the next step is arena buy <ticker> --side <buy_side>. NFL full-game moneylines, spreads and totals on half-point lines. It never guesses, so no rows means rephrase. Works signed out. |
| arena instrument <ins_id|slug> | One Arena instrument: its label (always its YES side), type, line, start time and each listed ticker with buy_for_yes and buy_for_no; --json adds yes_means, the YES side in a sentence. A ticker works too and finds the instrument listed on it. Works signed out. |
| arena game <game_id|slug|words…> [--type ml|spread|total] | One game and every Arena instrument on it, with their ids: moneylines first, then spreads and totals by line. No prices. Spreads and totals are added closer to kickoff. Works signed out. |
| arena games [--league nfl] [--date today|YYYY-MM-DD] [--week N] [--limit 20] | Upcoming games with their Arena game ids and how many instruments each has. --date is one calendar day in America/New_York. Works signed out. |
| arena catalog | The groups and leagues you can filter by. not yet shipped |
| arena screener [--league L] [--group G] [--min-volume N] [--max-spread C] [--price-min C] [--price-max C] [--closes-within 4h] [--min-move C] [--sort volume|move|spread|close_time] [--limit 20] | Screen open markets by volume, price, spread, time to close and move over about 24 hours. Rows add spread_cents and a signed move_cents. Needs arena login. |
| arena orderbook <ticker|ins_id> [--depth 10] | Resting bids and asks. Takes a ticker, an instrument id or its slug. |
| arena chart <ref> [--range 1h|6h|24h|7d] [--points 12] | A market's recent price path for a ticker, an instrument id or its slug: open, high, low, now, the change and a sparkline. For an instrument whose YES is the ticker's NO, the numbers price the instrument's YES, and ticker_side says which side was charted. Needs arena login. |
| arena buy <ticker|ins_id> --side yes|no --contracts N [--max-price CENTS] [--limit CENTS] [--tif gtc|ioc|fok] [--expires 4h] [--yes] [--dry-run] | Open a position. Without --limit it quotes, confirms, places and reconciles the actual fill against the quote. With --limit it names your price: the order fills at that price or better, or rests until it does. With an instrument id or slug, --side is the instrument's side: the CLI maps it to the ticker's side, and the quote and the receipt show both (instrument_side, ticker_side). --dry-run also shows venue_fee_est_dollars, the estimated venue fee, not charged on paper, and what walking the book for that size would cost (walk_vwap_cents, walk_slippage_cents). |
| arena sell <trade-id> [--limit CENTS] [--tif gtc|ioc|fok] [--expires 4h] [--yes] [--dry-run] | Close a position at the live bid, or rest a limit exit with --limit. Trade ids come from arena positions. |
| arena orders [--status resting|executed|canceled|all] [--ticker T] | Your limit orders. Resting by default: the ones still holding money and still able to fill on their own. --ticker takes the market's ticker. With --json, or --fields naming them, rows also carry instrument_id, instrument_label and instrument_side. |
| arena cancel <order-id> [--yes] | Withdraw a resting order and get its hold back. Cancelling one that already filled is not an error: it answers reducedBy 0 and the trade id. |
| arena settle | Settle anything already resolved. A backstop: the server settles automatically within about five minutes. |
| arena positions [--live] | Open positions with unrealised P&L. --live adds current prices with one extra market read. With --json, or --fields naming them, rows also carry instrument_id, instrument_label and instrument_side. |
| arena balance | Spendable balance and net worth. |
| arena history [--month 2026-08] | Your settled trades. --month reads a past season (a calendar month in America/New_York). Instrument columns as for arena positions. |
| arena stats [--month YYYY-MM] [--by league|band|hold] | Your season graded: win rate against the prices you paid, calibration by price band, closing-line value, return on stake and drawdown. --by adds a breakdown by league, entry price band or how the trade ended. An empty season prints zero counts and an emptyReason. Needs arena login. |
| arena picks | Today’s AI picks. |
| arena leaderboard [--top 25] | This season’s standings, with the AI models and the paper funds ranked in alongside the players, exactly as the app ranks them. Rows carry an AI, ETF or Team fund badge. |
| arena trader <ref> [picks] | A published trader record. Public, so it works signed out. |
| arena watch <ticker…> [--orderbook] | Live prices, repainted in place. not yet shipped |
| arena hook install | Install the ambient-context hook into your agent runner. not yet shipped |
Flags that work everywhere
- --json
- Raw JSON on stdout. Works in both modes, on every command. The stable escape hatch.
- --fields a,b,c
- Widen a list beyond its default three or four columns.
- --full
- Stop truncating long text.
- --yes
- Skip the confirmation prompt. In agent mode
buy,sellandcancelneed it, and without it they exit 2 and send nothing.arena settledoes not, because it only settles trades whose markets have already resolved. - --dry-run
- On
buy: the price and the stake, plus the estimated venue fee (not charged on paper), with nothing sent. On a marketsell: only the position it would sell (ticker, side, contracts), with no price, so readyes_bidorno_bidwitharena market <ticker>for that.cancelhas no dry run.
| Flag | What it does |
|---|---|
| --json | Raw JSON on stdout. Works in both modes, on every command. The stable escape hatch. |
| --fields a,b,c | Widen a list beyond its default three or four columns. |
| --full | Stop truncating long text. |
| --yes | Skip the confirmation prompt. In agent mode buy, sell and cancel need it, and without it they exit 2 and send nothing. arena settle does not, because it only settles trades whose markets have already resolved. |
| --dry-run | On buy: the price and the stake, plus the estimated venue fee (not charged on paper), with nothing sent. On a market sell: only the position it would sell (ticker, side, contracts), with no price, so read yes_bid or no_bid with arena market <ticker> for that. cancel has no dry run. |
A first session
Terminal samples on this page use the placeholder tickers ARENA-EXAMPLE-1 and ARENA-EXAMPLE-2. Real tickers come from arena markets and arena search.
$ arena balance
dollars $1,046.00
netWorthDollars $1,058.40
openStakeDollars $12.40
monthKey 2026-09
Next:
arena positions
arena history
$ arena buy ARENA-EXAMPLE-1 --side yes --contracts 10
Example market — yes @ 62c ask (bid 58c) · stake $6.20 · balance $1,046.00 -> $1,039.80
Fills server-side at the LIVE ask — the fill may differ from this quote.
buy 10 contracts? [y/N] y
placed true
tradeId 6f1c2a3b-4d5e-4f60-8a71-b2c3d4e5f607
ticker ARENA-EXAMPLE-1
side yes
contracts 10
quotedAskCents 62
entryPriceCents 63
stakeDollars $6.30
idempotencyKey 0b9e8d7c-6a5b-4c4d-9e3f-2a1b0c9d8e7f
slippageCents 1
Next:
arena positions
arena sell <trade-id>
$ arena positions
ID MARKET_TICKER SIDE CONTRACTS UNREALIZEDPNLDOLLARS
6f1c2a3b-4d5e-4f60-8a71-b2c3d4e5f607 ARENA-EXAMPLE-1 yes 10 $0.40
totalCount 1
$ arena sell 6f1c2a3b-4d5e-4f60-8a71-b2c3d4e5f607 --yes
sold true
tradeId 6f1c2a3b-4d5e-4f60-8a71-b2c3d4e5f607
sellPriceCents 67
pnlDollars $0.40
idempotencyKey 3c2b1a09-8f7e-4d6c-b5a4-93827160f5e4Three things about that buy
That was a market order: you never set a price, and the fill happens server-side at the live ask, which is why the CLI reconciles the actual fill against the quote and tells you the slippage. --max-price refuses to submit when the quoted ask is above your ceiling. And every buy carries a fresh idempotency key. If the request gets no answer, the CLI retries it with that same key, which can never fill twice. Do not resend the buy yourself: running arena buy again sends a new key and can open a second position, so check arena positions first.
Naming your own price
Pass --limit to place a limit order instead. It fills only at that price or better, and otherwise rests until it fills, reaches --expires, or you cancel it. A resting buy holds the cost out of your balance and returns it in full on cancel; a resting sell holds nothing, because the position is the collateral. --tif ioc or fok never rests. See your resting orders with arena orders and withdraw one with arena cancel.
Packages
Four packages on npm, one machine-readable spec, one file for language models.
- arena-prediction-cli 0.3.0
- The arena command: paper trading from a terminal, dual-mode for agents (AXI).
- arena-mcp-server 0.3.0
- The local stdio MCP server, run with npx -y arena-mcp-server. Reads the CLI’s stored login.
- arena-mcp-tools 0.3.0
- The tool catalog the server registers, for embedding in another MCP host.
- arena-core 0.2.0
- Auth, endpoints, credential storage and the typed API client the three share.
| Package | What it is |
|---|---|
| arena-prediction-cli 0.3.0 | The arena command: paper trading from a terminal, dual-mode for agents (AXI). |
| arena-mcp-server 0.3.0 | The local stdio MCP server, run with npx -y arena-mcp-server. Reads the CLI’s stored login. |
| arena-mcp-tools 0.3.0 | The tool catalog the server registers, for embedding in another MCP host. |
| arena-core 0.2.0 | Auth, endpoints, credential storage and the typed API client the three share. |
Specifications
GET https://arena-predictions.com/api/v1/openapi.json is the OpenAPI 3.1 document for the live endpoints; /llms.txt is the short version for a language model. The CLI and the MCP server call the same backends the website does, through arena-core. There is no separate SDK for the HTTP API.