Skip to main content

Prediction market strategy research, backtesting, and paper trading toolkit

Project description

agenttrader

A toolkit for AI agents to research, backtest, and paper trade prediction market strategies on Polymarket and Kalshi — autonomously, from a single prompt.

Works as an MCP server (for Claude Code, Cursor, Codex) or directly from the CLI.

Live data and paper trading is available via pmxt , an open source unified API for prediction markets. Backtesting is available via an open source dataset, courtesy of Jon Becker.


Install

pip install agenttrader
npm install -g pmxtjs

Then initialize:

agenttrader init

That's it. init sets up your local database and walks you through the optional dataset download.

Downloading the historical dataset (recommended)

Backtesting works best with the full dataset — thousands of resolved Polymarket and Kalshi markets going back to 2021.

# Optional but highly recommended:

# aria2 → faster + more reliable large downloads
# zstd  → required to validate/extract .tar.zst archives using system tools

# macOS
brew install aria2 zstd

# Windows (Chocolatey)
choco install aria2 zstandard

# Linux (Debian/Ubuntu)
sudo apt install aria2 zstd

agenttrader dataset download      # ~36GB, one-time
agenttrader dataset build-index   # ~5-10 min, one-time

Don't want to download 36GB? Backtesting still works using live-synced data. Run agenttrader sync before backtesting and it'll use whatever is cached locally.


Quickstart

1. Set up the MCP server

Add to your MCP config (e.g. .claude/mcp.json):

{
  "mcpServers": {
    "agenttrader": {
      "command": "agenttrader",
      "args": ["mcp"]
    }
  }
}

MCP Setup (Reference Links)

Here are official docs for configuring MCP servers with popular clients:

2. Give your agent a prompt

Use agenttrader to find the top 10 highest volume markets on polymarket right now

The agent will utilize the agenttrader MCP in order to make the correct API calls, and return the top 10 highest volume polymarket markets currently.


Core Workflow

This is the loop an agent (or human) follows when using agenttrader. Every step maps to an MCP tool call.

 research_markets          Find markets with price analytics and capabilities
        │
        ▼
 Write strategy.py         Python class extending BaseStrategy
        │
        ▼
 validate_and_backtest     Validate syntax + run backtest in one call
        │
        ▼
 Evaluate metrics          Sharpe, return %, max drawdown, win rate
        │
   ┌────┴────┐
   │ Good?   │
   │  No ────┼──▶ Edit strategy, re-run backtest
   │  Yes    │
   └────┬────┘
        ▼
 start_paper_trade         Deploy to live paper trading
        │
        ▼
 get_portfolio             Monitor positions and P&L

The agent handles research, strategy writing, validation, backtesting, iteration, and deployment.

Example: full autonomous session

Here's a single prompt that exercises the complete workflow:

I want to trade Polymarket politics markets using a contrarian strategy.

1. Use research_markets to find 10 active politics markets with 30 days
   of history. Check their capabilities to confirm they're backtestable.

2. Write a strategy that buys YES when the price drops more than 10%
   below its 7-day average, and sells when it recovers to the average.
   Use position sizing of 5% of portfolio per trade.

3. Backtest from 2024-01-01 to 2024-12-31 with $10,000.

4. If Sharpe < 0.5, adjust the entry threshold and retest. Iterate
   up to 3 times.

5. Once satisfied, start paper trading with the best-performing version
   and report the portfolio ID and initial positions.

This prompt will trigger ~10-15 tool calls across research, validation, backtesting (with iteration), and paper trading deployment.

Quick Disclaimer

You most likely aren't going to find an actual good strategy by saying "Claude, use the agenttrader MCP to develop a strategy to make me a billion dollars". Agenttrader exists to help making the process of testing strategies easier, not necessarily developing them from complete scratch. I would highly recommend to do research on quantitative trading strategies, and how they can be applied to prediction markets. Then, work with your agent to implement this strategy.

As of now, the BaseStrategy class does not support external APIs (e.g. chainlink for 5min crypto markets). You can override this by creating a new script to ingest API data, then import it to your strategy.py file.


Data Architecture


                  ┌──────────────┐
                  │   PMXT API   │  live prices, candles, orderbooks
                  └──────┬───────┘
                         │ agenttrader sync / live fetch
                         ▼
                  ┌──────────────┐
                  │ SQLite Cache │  ~/.agenttrader/db.sqlite
                  │ (live cache) │  paper trading state + recent history
                  └──────┬───────┘
                         │ used by
        ┌────────────────┼───────────────────────────────┐
        │                │                               │
        ▼                ▼                               ▼
 research_markets   start_paper_trade                 get_portfolio
 (live analytics)   (orders/positions)                (P&L/positions)

   ┌─────────────────────┐       build-index        ┌──────────────────────┐
   │ Parquet Dataset      │ ───────────────────────▶ │ DuckDB Backtest Index │
   │ ~36GB raw (poly+kalshi)                        │ ~13GB normalized      │
   │ ~/.agenttrader/data  │                         │ ~/.agenttrader/backtest_index.duckdb
   └──────────┬──────────┘                         └──────────┬───────────┘
              │ used by (fallback)                              │ used by (fastest)
              └──────────────────────────────┬──────────────────┘
                                             ▼
                                   validate_and_backtest
                                (strategy development loop)

Tools automatically select the best available source: DuckDB index > raw parquet > SQLite cache. You don't need to specify which source to use.


Market Capabilities

When researching markets, each result includes capability annotations that tell you upfront what's possible:

{
  "capabilities": {
    "backtest": { "index_available": true, "index_start": "2024-06-01", "index_end": "2025-02-15" },
    "history":  { "cache_available": true, "last_point_timestamp": "2026-02-27T18:00:00+00:00" },
    "sync":     { "can_attempt_live_sync": true }
  }
}
  • backtest — whether this market has indexed historical data and the date range covered
  • history — whether this market has cached price data in SQLite
  • sync — whether live data sync is possible (false for resolved markets)

This eliminates trial-and-error discovery — agents know immediately which markets can be backtested, which have cached data, and which need a sync first.


Writing a Strategy

Create a Python file with a class that extends BaseStrategy:

from agenttrader import BaseStrategy

class MyStrategy(BaseStrategy):

    def on_start(self):
        # Choose which markets to trade
        self.subscribe(platform="polymarket", category="politics")

    def on_market_data(self, market, price, orderbook):
        # Called on every price update for subscribed markets
        history = self.get_history(market.id, lookback_hours=48)
        if len(history) < 2:
            return

        avg = sum(p.yes_price for p in history) / len(history)

        if price < avg - 0.08 and self.get_position(market.id) is None:
            self.buy(market.id, contracts=20)

        elif price > avg + 0.05 and self.get_position(market.id):
            self.sell(market.id)

    def on_schedule(self, now, market):
        # Called on a regular interval (default every 15 min)
        pass

    def on_resolution(self, market, outcome, pnl):
        self.log(f"{market.title} resolved {outcome} — PnL: {pnl:.2f}")

Available methods inside your strategy:

Method What it does
subscribe(platform, category, market_ids) Declare which markets to trade
search_markets(query, platform) Find markets by keyword
get_price(market_id) Current mid price (0.0–1.0)
get_history(market_id, lookback_hours) Recent price history
get_orderbook(market_id) Live orderbook
get_position(market_id) Current open position
get_cash() Available cash
get_portfolio_value() Total portfolio value
buy(market_id, contracts, side) Open a position
sell(market_id) Close a position
log(message) Append to strategy log
set_state / get_state Persist values across ticks

Backtesting

# Basic backtest
agenttrader backtest ./strategy.py --from 2024-01-01 --to 2024-12-31

# With JSON output (useful for agents)
agenttrader backtest ./strategy.py --from 2024-01-01 --to 2024-12-31 --json

# View full results (equity curve + trade log)
agenttrader backtest show <run_id> --json

Backtest output includes:

  • metrics — Sharpe, return %, max drawdown, win rate, trade count
  • resolution_accuracy — did you buy YES when the market actually resolved YES?
  • by_category — performance breakdown by market category
  • data_source — which data backend was used

Optional flags for faster exploratory runs:

# Limit to 100 markets
agenttrader backtest ./strategy.py --from 2024-01-01 --to 2024-12-31 --max-markets 100

# Use hourly bars instead of every trade (much faster, less precise)
agenttrader backtest ./strategy.py --from 2024-01-01 --to 2024-12-31 --fidelity bar_1h

By default, backtests run on all subscribed markets with full trade fidelity. These flags are opt-in.

Execution Modes

Backtests support three execution modes that control how trades are filled and whether orderbook data is used:

Mode Default? Fill behavior Orderbook access
strict_price_only Yes Fills at observed price, zero slippage get_orderbook() returns None
observed_orderbook No Uses real stored orderbook snapshots Raises if no observed OB exists
synthetic_execution_model No Synthesizes orderbooks for approximate fill modeling Always available (modeled)

Why strict is the default: Historical orderbook data is not available in the parquet dataset. Synthetic orderbooks can produce misleadingly optimistic backtest results. strict_price_only forces strategies to trade on price signals alone, producing conservative and reproducible results.

# Default: strict price-only fills
agenttrader backtest ./strategy.py --from 2024-01-01 --to 2024-12-31

# Opt-in to synthetic execution modeling (use with caution)
agenttrader backtest ./strategy.py --from 2024-01-01 --to 2024-12-31 --execution-mode synthetic_execution_model

Strategies that call get_orderbook() should handle None gracefully:

def on_market_data(self, market, price, orderbook):
    if orderbook is not None:
        # Use orderbook-aware logic
        best_bid = orderbook.bids[0].price if orderbook.bids else price
    else:
        # Fall back to price-only logic
        best_bid = price

Paper Trading

# Start a strategy
agenttrader paper start ./strategy.py --cash 10000 --json

# Check status
agenttrader paper status <portfolio_id> --json

# List all running strategies
agenttrader paper list --json

# Stop a strategy
agenttrader paper stop <portfolio_id> --json
agenttrader paper stop --all --json

Strategies hot-reload on file save — edit your strategy while it's running and it picks up changes within a second.

Run multiple strategies in parallel and compare them:

agenttrader paper compare <portfolio_id_1> <portfolio_id_2> --json
agenttrader paper compare --all --json

Experiment Tracking

Log backtest runs as experiments to build memory across sessions:

# Log a backtest run
agenttrader experiments log <run_id> --note "baseline — threshold 0.10" --tags "politics,mean-reversion"

# Compare two experiments side by side
agenttrader experiments compare <exp_id_1> <exp_id_2> --json

# List all experiments (most recent first)
agenttrader experiments list --json

This lets your agent reconstruct the full research history — what was tried, what changed, and whether it helped — across separate sessions.


Market Screener

Find markets matching specific price conditions:

# Markets significantly below their 7-day average (mean reversion candidates)
agenttrader markets screen --condition "price_vs_7d_avg < -0.10" --json

# Cheap markets with volume
agenttrader markets screen --condition "current_price < 0.25" --min-volume 50000 --json

# Markets closing soon
agenttrader markets screen --condition "days_until_close < 7" --json

Supported condition metrics: price_vs_7d_avg, current_price, volume, days_until_close, price_change_24h


Reference

Document Description
COMMANDS.md Full MCP tool reference — every tool, parameter, type, default, and example
SCHEMA.md Database schemas — SQLite tables, DuckDB index, parquet dataset layout

CLI Reference

Setup
agenttrader init
agenttrader config show
agenttrader config set <key> <value>
agenttrader config get <key>
Dataset
agenttrader dataset verify
agenttrader dataset download
agenttrader dataset build-index [--force] [--json]
Sync (live data)
agenttrader sync --platform all --days 7 --limit 100
agenttrader sync --resolved --platform polymarket --days 365
agenttrader sync --markets <id1> --markets <id2>
Markets
agenttrader markets list --platform all --limit 100 --json
agenttrader markets price <market_id> --json
agenttrader markets history <market_id> --days 30 --json
agenttrader markets screen --condition "..." --json
agenttrader markets match --polymarket-slug "..." --json
agenttrader markets match --kalshi-ticker "..." --json
Backtests
agenttrader validate ./strategy.py --json
agenttrader backtest ./strategy.py --from 2024-01-01 --to 2024-06-01 --json
agenttrader backtest list --json
agenttrader backtest show <run_id> --json
Paper trading
agenttrader paper start ./strategy.py --cash 10000 --json
agenttrader paper status <portfolio_id> --json
agenttrader paper list --json
agenttrader paper stop <portfolio_id> --json
agenttrader paper compare --all --json
Experiments
agenttrader experiments log <run_id> --note "..." --tags "..." --json
agenttrader experiments list --json
agenttrader experiments show <exp_id> --json
agenttrader experiments note <exp_id> "updated note" --json
agenttrader experiments compare <exp_id_1> <exp_id_2> --json

Local Storage Layout

~/.agenttrader/
├── config.yaml
├── db.sqlite                      # market metadata, paper trading state
├── data/                          # raw parquet dataset (if downloaded)
├── backtest_index.duckdb          # normalized index (if built)
├── backtest_artifacts/            # compressed backtest results
├── experiments.json               # experiment memory
└── logs/
    └── performance.jsonl

Development

git clone https://github.com/finnfujimura/agenttrader
cd agenttrader
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pytest -q

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agenttrader-0.4.1.tar.gz (119.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agenttrader-0.4.1-py3-none-any.whl (132.8 kB view details)

Uploaded Python 3

File details

Details for the file agenttrader-0.4.1.tar.gz.

File metadata

  • Download URL: agenttrader-0.4.1.tar.gz
  • Upload date:
  • Size: 119.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for agenttrader-0.4.1.tar.gz
Algorithm Hash digest
SHA256 6bcd9cfb8f550788bbb0932c1e02b9e733ef98ff3111a0ed76a1a0e7f65513e4
MD5 f34a8aeed3f846882b7c7c2b7505df6b
BLAKE2b-256 aeb044091d8e78ef46b32c5eed5d8ef926709222c8c12127cbdac7a1b0d4c9b4

See more details on using hashes here.

Provenance

The following attestation bundles were made for agenttrader-0.4.1.tar.gz:

Publisher: publish.yml on finnfujimura/agenttrader

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file agenttrader-0.4.1-py3-none-any.whl.

File metadata

  • Download URL: agenttrader-0.4.1-py3-none-any.whl
  • Upload date:
  • Size: 132.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for agenttrader-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 243211cc0302f4cb2eaa750a75b7fb64533cad813632a10346274021d0f7001c
MD5 bb2a1c6471fc3cf52dd8cdce0d94fce6
BLAKE2b-256 7a77496d938aafce60df00c3005cff5019b58b13fbcc91d91c43211d49c304e8

See more details on using hashes here.

Provenance

The following attestation bundles were made for agenttrader-0.4.1-py3-none-any.whl:

Publisher: publish.yml on finnfujimura/agenttrader

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page