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/, NOT position_manager/ (an empty shell, deferred future home after the autotrade → position_manager rename). CLOB client = vendored Polymarket/rs-clob-client-v2 (alloy). Order type = FAK marketable-limit. Read-over-WS, write-over-REST is the target pattern.

Punchline

  1. 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.
  2. 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 OrderFilled WSS trigger publishing to cohort.signals the 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 market channel (wss://ws-subscriptions-clob.polymarket.com/ws/market, subscribe by assets_ids). Apply the book snapshot + price_change/tick_size_change deltas to mirror top-of-book locally; read the local book at trade time — no GET /book round-trip. The vendored rs-clob-client-v2 already has a ws feature, currently disabled.
  • Market metadata: static per market — fetch once on first sight and cache; refresh tick_size only on a tick_size_change event 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 drops taker/expiration/nonce/feeRateBps, adds timestamp/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 Exchange 0xE111180000d2663C0091e4f400237545B87B996B; Neg Risk CTF Exchange 0xe2222d279d744050d28e00520010520000310F59.
  • neg_risk is a hard runtime branch — verifyingContract, domain version, and collateral all differ; mismatch → valid-but-rejected signature. Engine already asserts built order’s verifyingContract matches market’s neg_risk and refuses LIVE on collateral mismatch — keep it.

Proxied reqwest MUST set BOTH timeout AND connect_timeout

Any reqwest client on this path must set both .timeout AND .connect_timeout. A missing connect_timeout previously 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-v2 already 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_timeout warning 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.
  1. Phase 2 first-mover (on-chain OrderFilled WSS → cohort.signals) — the real end-to-end win; already designed.
  2. WS market-channel book mirror + cached static market metadata — removes the 3 per-trade GETs (~150–600 ms), biggest submission-path win.
  3. Disable use_server_time — ~20–100 ms, trivial.
  4. Verify full V2 conformance — correctness/liveness (rejection = infinite latency).
  5. Measure p50/p99 submit latency before any HTTP/2 or colocation spend.
  6. HTTP/2 keep-alive tuning + region-verified London/Dublin colocation — only after measurement justifies it.