Research into “the fastest possible way to put trades into Polymarket.” Bottom line: submission is already sub-second — the real latency lives upstream in DETECTION, and the highest-leverage fix is Phase 2 first-mover, not submission tuning. Full source report: /Users/levander/coding/pmv2/position_manager/docs/research/2026-06-20-fastest-polymarket-trade-submission.md.
For Agents
Live trade code is in the sibling repo
/Users/levander/coding/polymarket_fetch/, NOTposition_manager/(an empty shell, deferred future home after theautotrade → position_managerrename). CLOB client = vendoredPolymarket/rs-clob-client-v2(alloy). Order type = FAK marketable-limit. Read-over-WS, write-over-REST is the target pattern.
Punchline
- Order submission is already fast and is NOT the bottleneck. The live path signs an EIP-712 order and
POSTs to the CLOB in well under a second. Warm pooled client, L1 signed once at connect, L2 creds cached (only HMAC per request), FAK order, allowances preflighted at startup. - Real end-to-end latency is upstream DETECTION (~15 min mean), not execution. The ~20–38 min signal→fill lag is dominated by a REST-poll detector on a ~30-min timer. Fix = Phase 2 first-mover: real-time on-chain
OrderFilledWSS trigger publishing tocohort.signalsthe instant a tracked trader fills. Minutes → seconds (~3 orders of magnitude). Single highest-leverage lever; dwarfs every micro-optimization below. See cohort-firstmover-nats-migration and autotrade-alert-latency-and-run-timeouts.
Submission-path wins (ranked)
Biggest win — kill the 3 uncached per-trade GETs (~150–600 ms)
Before the order is even built, the hot path does 3 synchronous, uncached GETs (each ~50–200 ms): market metadata (tick_size, neg_risk, token_ids, min_order_size), order book (best bid/ask), and gamma resolution-status guard.
- Order book: subscribe to the CLOB WebSocket
marketchannel (wss://ws-subscriptions-clob.polymarket.com/ws/market, subscribe byassets_ids). Apply thebooksnapshot +price_change/tick_size_changedeltas to mirror top-of-book locally; read the local book at trade time — noGET /bookround-trip. The vendoredrs-clob-client-v2already has awsfeature, currently disabled. - Market metadata: static per market — fetch once on first sight and cache; refresh
tick_sizeonly on atick_size_changeevent or a rejection (tick changes when price >0.96 or <0.04). - Resolution status: stream/cache rather than a synchronous gamma GET per signal.
- WS is read-only — placement stays REST. Pattern: read-over-WS, write-over-REST.
Second win — disable use_server_time on signing (~20–100 ms/order)
If use_server_time: true, each build_order fetches server time over the network. Sync the clock once at startup (or periodically) and stamp orders with local time. V2 uses an ms timestamp field for per-address uniqueness — local monotonic+wall time is fine. Trivial change.
Cannot go faster on-chain
Polymarket matches off-chain (operator book) and only settles on-chain. The CLOB API is the fast path; there is no on-chain shortcut for taking liquidity. Mempool/BDN/turbine tricks were evaluated and rejected (no Polygon analog, not worth it for minutes-of-window holds).
Warnings
V2 hard-cutover landmine — rejection, not slowness
CLOB V2 went live 2026-04-28 as a hard cutover; all V1 SDKs/orders are dead in prod. A stale-V1 order isn’t slow — it’s rejected (infinite latency). Verify the deployed path is fully V2:
- EIP-712 domain version
"2"(was"1"); Order struct dropstaker/expiration/nonce/feeRateBps, addstimestamp/metadata/builder.- Collateral is pUSD (ERC-20, backed by USDC; wrap USDC.e→pUSD via Collateral Onramp
0x93070a847efEf7F70739046A929D47a521F5B8ee), not USDC.e.- V2 exchange addresses (re-verify byte-for-byte vs live docs /
ctf-exchange-v2): Standard CTF Exchange0xE111180000d2663C0091e4f400237545B87B996B; Neg Risk CTF Exchange0xe2222d279d744050d28e00520010520000310F59.neg_riskis a hard runtime branch —verifyingContract, domain version, and collateral all differ; mismatch → valid-but-rejected signature. Engine already asserts built order’sverifyingContractmatches market’sneg_riskand refuses LIVE on collateral mismatch — keep it.
Proxied reqwest MUST set BOTH
timeoutANDconnect_timeoutAny reqwest client on this path must set both
.timeoutAND.connect_timeout. A missingconnect_timeoutpreviously caused a 75-minute silent hang. Preserve this if you swap or tune the HTTP client (e.g. when enabling HTTP/2).
Don’t-bother list (look like wins, aren’t)
- sigType Proxy(1) → EOA(0) for speed: signing-overhead difference is sub-millisecond; switching requires the EOA to custody pUSD+CTF directly (a funding/custody change, not a latency change). Keep the proxy wallet.
- Hand-rolling EIP-712 in Rust: unnecessary — official
rs-clob-client-v2already does it and is vendored/pinned. - Pre-signing orders: signing is already sub-ms; negligible upside.
Colocation — verify region before spending
Currently deployed GCP europe-west3-a (Frankfurt). Polymarket origin region is NOT officially documented (DNS is Cloudflare anycast). Community inference → AWS eu-west-2 (London), not us-east-1. Frankfurt→London is already only ~10–15 ms, so upside is small unless moving to London/Dublin. Independently verify the true origin region (traceroute / TCP-RTT probes from candidate regions) before any colocation spend. Do not assume us-east-1.
Gaps / open items
- No p50/p99 submit-latency measurement exists today — instrument before any HTTP/2 or colocation spend.
- Vendored SDK uses HTTP/1.1; HTTP/2 (multiplexing, header compression, pre-warmed TLS) is an untested lever — no benchmark exists yet, measure before/after. (Respect the
connect_timeoutwarning above when swapping the client.) - V2 operator match/ack latency is unpublished (V1 cited ~250 ms taker hold). After WS/cache + server-time fixes, the binding constraint becomes the operator’s server-side hold — outside our control.
- Batch
POST /orders(max 15/request) only helps orders-per-request, not single-order latency; single-order path is nowhere near rate limits.
Recommended priority order
- Phase 2 first-mover (on-chain
OrderFilledWSS →cohort.signals) — the real end-to-end win; already designed. - WS market-channel book mirror + cached static market metadata — removes the 3 per-trade GETs (~150–600 ms), biggest submission-path win.
- Disable
use_server_time— ~20–100 ms, trivial. - Verify full V2 conformance — correctness/liveness (rejection = infinite latency).
- Measure p50/p99 submit latency before any HTTP/2 or colocation spend.
- HTTP/2 keep-alive tuning + region-verified London/Dublin colocation — only after measurement justifies it.