V2 support
This commit is contained in:
@@ -1,11 +1,8 @@
|
||||
# poly-maker (v2)
|
||||
# poly-maker
|
||||
|
||||
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/`](docs/scoping/00-overview.md)
|
||||
for the design and [`docs/scoping/06-migration-plan.md`](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.
|
||||
tested.
|
||||
|
||||
> [!WARNING]
|
||||
> Market making on Polymarket is competitive and can lose money. This is a
|
||||
@@ -14,13 +11,13 @@ for the plan. The original v1 code has been removed; see the git history (branch
|
||||
|
||||
## 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.
|
||||
- Discovers political markets via the **Gamma API** (seconds) 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`](docs/scoping/04-strategy.md).
|
||||
- Quotes **maker-only** — every order is post-only. Fair-value + inventory-skew
|
||||
strategy that posts BUY-YES and BUY-NO as a two-sided quote, with live
|
||||
volatility/toxicity estimation and a regime machine that pulls quotes during
|
||||
news events (see [Strategy](#strategy)).
|
||||
- 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.
|
||||
@@ -39,13 +36,13 @@ uv run polymaker --help
|
||||
## Configure
|
||||
|
||||
```bash
|
||||
cp .env.example .env # then edit: PK + BROWSER_ADDRESS (same wallet as the UI)
|
||||
cp .env.example .env # then edit: PK + BROWSER_ADDRESS
|
||||
```
|
||||
|
||||
### 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:
|
||||
Polymarket's current **deposit-wallet** architecture 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
|
||||
@@ -61,8 +58,7 @@ 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`](docs/scoping/03-api-layer.md) §1/§9.
|
||||
from the funding wallet — trading once in the UI does this.
|
||||
|
||||
Everything else is TOML under [`config/`](config/):
|
||||
|
||||
@@ -105,10 +101,41 @@ user WS ─▶ StateStore RiskManager
|
||||
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`](docs/scoping/02-architecture.md).
|
||||
One async event loop. 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; the `ExecutionGateway` wraps `py-clob-client-v2`
|
||||
(which handles the V2 EIP-712 signing) and offloads its blocking calls to a
|
||||
thread pool so the hot path never stalls. State (positions, orders, PnL, catalog)
|
||||
lives in one SQLite file; raw WS/order events are journaled to `journal/` for
|
||||
replay.
|
||||
|
||||
## Strategy
|
||||
|
||||
Maker-only, quoting both sides of each market as USDC-collateralized bids:
|
||||
|
||||
- **Fair value** — depth-weighted microprice off the live book, nudged by an
|
||||
EWMA of signed trade flow.
|
||||
- **Quote construction** — reservation price `r = FV − skew(inventory)`;
|
||||
half-spread `δ = base + c_vol·σ + c_tox·toxicity`. Post **BUY-YES at `r − δ`**
|
||||
and **BUY-NO at `(1 − r) − δ`**. Because both legs are bids that sum below 1,
|
||||
a filled pair merges back to USDC at locked edge `1 − p − q` — a maker-only
|
||||
exit that never crosses the spread.
|
||||
- **Inventory skew** — net position leans both quotes: long YES → bid YES lower,
|
||||
bid NO higher (acquire the offsetting leg). Size tapers as inventory approaches
|
||||
a soft cap, then the adding side is pulled entirely.
|
||||
- **Volatility / toxicity** — realized-vol and per-fill markout (adverse
|
||||
selection) EWMAs widen the spread and shrink size in markets that pick us off.
|
||||
- **Regime machine** — per market: `QUIET` (farm rewards in-band), `TRENDING`
|
||||
(lean + widen + half size), `EVENT` (sweep/jump detected → pull quotes, cool
|
||||
off), `REDUCE_ONLY` (inventory cap / near end date → exits only), `HALTED`
|
||||
(stale data / resolved / kill switch → cancel all).
|
||||
- **Rewards + rebates** — quotes stay inside the liquidity-rewards band in QUIET;
|
||||
the market selector also scores the new maker-rebate program (a share of taker
|
||||
fees rebated to makers).
|
||||
- **Risk** — per-market notional cap, neg-risk event-group worst-case cap, total
|
||||
exposure cap, daily-loss kill switch, WS-staleness halt.
|
||||
|
||||
Tune it all via profiles in `config/strategy.toml`.
|
||||
|
||||
## Develop
|
||||
|
||||
@@ -119,20 +146,18 @@ uv run ruff check src tests # lint
|
||||
uv run mypy src # types (strict)
|
||||
```
|
||||
|
||||
## Status / roadmap
|
||||
## Status
|
||||
|
||||
Implemented: config, catalog/scanner, order book + analytics, strategy (FV,
|
||||
Implemented and live-verified end to end (auth → book → strategy → sign → post →
|
||||
cancel): 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.
|
||||
engine, CLI, paper mode, journal capture. 83 tests; ruff + mypy strict clean.
|
||||
|
||||
Spike-gated (need the live wallet — see [`docs/scoping/03-api-layer.md`](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`](docs/scoping/07-future-external-data.md)).
|
||||
Not yet built: a replay backtester over the captured journals, and external data
|
||||
feeds (polls / news / cross-venue). Merging through a Safe/proxy wallet routes a
|
||||
tx via the relayer and isn't wired yet — until then inventory exits via limit
|
||||
sells rather than merging.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
Reference in New Issue
Block a user