Files
poly-maker/README.md
T
Daniel Sapkota c7b686116e Getting there
2026-07-05 17:50:04 -04:00

5.7 KiB

poly-maker (v2)

A maker-only market-making bot for Polymarket CLOB V2, focused on political markets. Single async process, local-file config (no Google Sheets), typed and tested. This is a ground-up rewrite of v1 — see docs/scoping/ for the design and docs/scoping/06-migration-plan.md for the plan. The original v1 code has been removed; see the git history (branch main) if you need to reference it.

Warning

Market making on Polymarket is competitive and can lose money. This is a reference implementation and a research harness, not a guaranteed-profitable product. Test in --paper mode first; go live with small size.

What it does

  • Discovers political markets via the Gamma API (seconds, not the v1 hour-long crawl) and ranks them by reward + rebate income vs. volatility/spread risk.
  • Maintains a live order book per token from the market WebSocket.
  • Quotes maker-only (every order is post-only): a fair-value + inventory-skew strategy that posts BUY-YES and BUY-NO as the canonical two-sided quote, with live volatility/toxicity estimation and a regime machine that pulls quotes during news events. See docs/scoping/04-strategy.md.
  • Reconciles a target quote set against live orders with churn tolerances; runs the exchange heartbeat dead-man switch; enforces risk caps and a daily-loss kill switch.
  • Config, market selection, and state are local files + SQLite. An operator with the repo, a .env, and a funded wallet is a complete deployment.

Install

Uses uv and Python 3.12+.

uv sync --extra dev          # install deps + dev tools
uv run polymaker --help

Configure

cp .env.example .env         # then edit: PK + BROWSER_ADDRESS (same wallet as the UI)

Which wallet address?

Polymarket's current deposit-wallet architecture (rolled out ~June 2026) shows several addresses in the UI, and the labels are inconsistent. What matters:

  • BROWSER_ADDRESS = the funder — the smart-contract wallet that actually holds your pUSD and positions. Depending on the account it may be shown as the "deposit" or "developer" address; the reliable test is which one holds the money. polymaker doctor reads the balance so you can confirm.
  • PK = the private key of your signer — the EOA (e.g. your MetaMask account) that owns/controls that wallet. This is a different address than the funder, and that's correct: your key signs on behalf of the wallet that holds the funds. (A "deployer" / factory address, if shown, is Polymarket's shared contract — ignore it.)

Set signature_type in config/config.toml to match how the account was made: 3 = POLY_1271 deposit wallet (current default), 2 = older browser-wallet Gnosis Safe, 1 = email/magic proxy, 0 = plain EOA. A wrong type fails loudly (polymaker doctor / livetest report it). Approvals must have been granted from the funding wallet — trading once in the UI does this. See docs/scoping/03-api-layer.md §1/§9.

Everything else is TOML under config/:

  • config.toml — wallet/engine/risk/execution settings
  • strategy.toml — named parameter profiles (political-longdated, political-hot)
  • markets.toml — the trade list (populated via the CLI below)

Use

# 1. discover + rank political markets (writes to state.db)
uv run polymaker scan
uv run polymaker markets

# 2. add markets to the trade list
uv run polymaker markets-add <slug> --profile political-longdated

# 3. dry run: full pipeline against the live feed, no orders posted
uv run polymaker run --paper

# 4. preflight the wallet before going live
uv run polymaker doctor

# 5. one safe live round-trip (~$5 post-only order, placed deep and cancelled)
uv run polymaker livetest

# 6. go live
uv run polymaker run

# ops
uv run polymaker status        # positions / open orders
uv run polymaker cancel-all    # panic button

Architecture

market WS ─▶ OrderBook ─▶ (wake) ─▶ Quoter ─▶ strategy (pure) ─▶ reconcile ─▶ ExecutionGateway
user WS   ─▶ StateStore                                         RiskManager ┘   (post-only, heartbeat)
Gamma     ─▶ Catalog/scanner ─▶ SQLite            periodic REST reconcile ┘

The strategy layer is a pure function (book, inventory, params, clock) → TargetQuotes — deterministic and unit-tested. The engine owns all I/O and state around it. Full component map in docs/scoping/02-architecture.md.

Develop

uv run pytest                 # unit suite (offline)
POLYMAKER_LIVE=1 uv run pytest tests/test_live_marketdata.py   # live WS integration
uv run ruff check src tests   # lint
uv run mypy src               # types (strict)

Status / roadmap

Implemented: config, catalog/scanner, order book + analytics, strategy (FV, vol/toxicity, regime, quoting), state store + lifecycle, execution gateway + reconciler + heartbeat, market/user websockets, risk manager, merger (EOA path), engine, CLI, paper mode, journal capture. 83 tests; the market-data path is verified live.

Spike-gated (need the live wallet — see docs/scoping/03-api-layer.md §9): V2 order signing with a Safe/proxy wallet (livetest is the probe), pUSD wrap/allowance mechanics, exact user-WS field names, native Safe merge execution.

Deferred (scoped, not built): replay backtester over captured journals, external data feeds (polls/news/cross-venue — docs/scoping/07-future-external-data.md).

License

MIT