API + MCP live · talk to us

// AI AGENTS THAT TRADE

Building a prediction-market bot with Claude Code (walkthrough)

2026-07-16 · Mithril

There are two ways to put AI in your trading loop. The first is letting a model trade directly, via tools — covered in the MCP tutorial. The second, this post, is older-fashioned and often better: use an AI coding agent to write a deterministic bot, so the LLM's judgment is applied at development time and what runs in production is ordinary, testable code. Claude Code — Anthropic's terminal coding agent — is very good at this, and a prediction-market bot is a nicely bounded project: one strategy, one API, binary contracts.

This walkthrough builds a simple mean-reversion bot against a trading API in Python. The specific commands assume Claude Code, but the workflow — scope, scaffold, iterate, sandbox, guardrail — transfers to any coding agent.

Step 0: pick your API surface

Decide before you scaffold: integrate the venues directly (Kalshi's REST API and Polymarket's CLOB each have Python clients — see the Python bot guide for that route), or build against a unified API that fronts both venues with one auth model and one ID scheme. For a first bot the unified route removes the two biggest time sinks — dual authentication and market matching across venues — so that's what this walkthrough assumes. The strategy code is identical either way.

Step 1: write a CLAUDE.md before writing code

Claude Code reads a CLAUDE.md at the project root on every session. For a trading bot, this file is where your engineering discipline lives — write it first:

markdown
# CLAUDE.md — mean-reversion bot

## Non-negotiable rules
- ALL order placement goes through `execution.py` — never call the
  API's order endpoint from anywhere else.
- `SANDBOX=true` is the default. Live trading requires an explicit
  env change; never flip it in code.
- Never commit credentials. API token comes from the environment.
- Every order must pass `risk.check()` first. Do not add bypasses,
  even for tests.
- Prices are decimals 0.01–0.99 everywhere internally; convert at
  the API boundary only.

## Commands
- `make test` — unit tests (mocked API, no network)
- `make paper` — run against sandbox

This matters more with an AI pair than a human one: the agent will touch every file, so invariants must be written down, not tribal. The single choke-point for orders (execution.py) is the load-bearing rule — it's what makes every later guardrail enforceable.

Step 2: scaffold

A prompt that works well:

Scaffold a Python project for a prediction-market trading bot. Modules: markets.py (search/quotes), strategy.py (signal generation, pure functions, no I/O), risk.py (pre-trade checks), execution.py (the only module that places or cancels orders), main.py (the loop). Include pytest setup with the API fully mocked, a Makefile, and typed dataclasses for Market, Signal, and Order. Follow CLAUDE.md.

Two structural choices to insist on, because they pay off immediately:

  • Pure strategy functions. strategy.py takes market snapshots and returns Signal objects; it never talks to the network. This makes the interesting code trivially testable and backtestable.
  • Typed boundaries. Dataclasses between modules mean that when you later ask Claude to "add a momentum filter," it can't quietly change what a signal is without the type checker complaining.

Step 3: iterate on the strategy — with tests as the contract

The core loop of AI-assisted development: describe behavior, let the agent implement and test it, review the tests harder than the code. For a toy mean-reversion signal:

In strategy.py, implement: if a market's mid has moved more than 5 cents in 15 minutes with no change in its linked news feed flag, emit a fade signal sized by half-Kelly, capped at 100 contracts. Write property-based tests: signals are never emitted within 2 cents of 0 or 1, size is always ≤ cap, and no signal fires twice for the same move.

Reviewing tests rather than implementations is the honest division of labor: you're the one who knows what "correct" means. Watch for the classic AI-generated-strategy failure smells:

  • Look-ahead bias — the backtest indexing tomorrow's price today. Ask Claude directly: "audit this backtest for look-ahead bias" — coding agents are genuinely good at catching it when asked, and reliably bad at avoiding it unprompted.
  • Fee blindness — a strategy that's profitable at mid and dead after the taker fee and spread. Make fees a required parameter of the backtest, not an afterthought.
  • Silent exception handling — agents love try/except: pass around network calls. In a trading loop, a swallowed error is a position you don't know you have. Ban it in CLAUDE.md if you see it twice.

Step 4: sandbox is a phase, not a smoke test

Run make paper and leave it running for days, not minutes. Sandbox trading is where you find the failure modes unit tests can't reach: what happens when a quote goes stale mid-decision, when an order rests unfilled for an hour, when the process restarts with open positions it must re-discover rather than re-derive. Have Claude Code build the observability while the bot runs:

Add structured JSON logging for every signal, risk check result, order, and fill. Then write a small script that reconciles our local order log against get_portfolio and screams if they diverge.

That reconciliation script is the deterministic-bot version of the "verify, don't narrate" rule from the MCP tutorial: your bot's opinion of its positions is not ground truth; the venue's is.

Step 5: guardrails before going live

Before flipping SANDBOX=false, two layers of protection, in order of trust:

  1. In-process checks in risk.py: per-order notional cap, max open positions, daily loss stop, a cooldown after consecutive rejections. Cheap, fast — and insufficient alone, because your own code (or a future Claude edit) can bypass them.
  2. Server-side limits at the API layer: notional caps, per-market position limits, slippage bounds, and a kill switch enforced outside your process, so no bug you deploy can exceed them. The full argument for why the outer layer is the one that counts is in Risk limits for AI trading agents — it applies to buggy code exactly as it applies to confused models.

The same logic covers credentials: your bot's box holds a scoped API token, not venue keys — see agent custody for why that distinction survives a compromised machine.

Go live with limits set to lunch-money levels, run the reconciliation script on a schedule, and widen limits only as the live track record earns it.

The takeaway

Claude Code compresses the boring 80% of a trading bot — scaffolding, plumbing, tests, logging — from weeks to hours, which frees you to spend your attention where the AI can't be trusted alone: strategy validity and risk. Structure the project so the agent can't violate your invariants (one execution path, typed boundaries, server-side caps) and you get the speed without the horror stories.

If you'd rather skip venue plumbing entirely, Mithril's REST API is the unified surface this walkthrough assumes — one API over Kalshi and Polymarket with sandbox mode, server-side limits, and an execution receipt on every fill; free during the beta. And for the broader architecture of letting models near markets at all, start at the hub: How to let an AI agent trade prediction markets safely.

Tools and venue details change. Everything above reflects public documentation as of July 2026 — confirm against current docs before trading real money.

One API + MCP for Kalshi and Polymarket

Fee-aware routing, unified market IDs, and hard server-side risk limits — live today, free during beta.