Polymarket Bot Tutorial · 32개 중 3장
Polymarket bot stack를 선택하세요: Python(py-clob-client 0.34.6), Node.js(@polymarket/clob-client-v2 v1.0.6), 또는 Rust(공식 SDK 없음, ethers-rs 기반). 장단점, latency, code samples.
이 장에서 다루는 내용
language choice는 대부분의 builder들이 생각하는 것보다 훨씬 덜 중요합니다. Polymarket는 모든 언어에 동일한 REST 및 WebSocket endpoint를 제공하므로, SDK 선택은 주로 얼마나 많은 glue code를 직접 작성해야 하는지를 결정합니다. Python과 Node에는 모두 공식적으로 유지보수되는 SDK가 있고, Rust에는 없지만 hot path에서는 충분히 사용할 수 있습니다. 이 장에서는 이러한 trade-off를 살펴보고, 각 언어에서 같은 "fetch order book" task를 보여 주어 차이를 구체적으로 확인한 뒤, 대부분의 production bot이 실제로 채택하는 mixed-stack pattern으로 마무리합니다.
- Decision framework
- Python (default choice)
- Node.js (full-stack devs)
- Rust (latency-critical hot path)
- stack별 setup commands
- Code skeleton: 3개 언어로 order book fetch
- 언제 stack을 섞을지 (Python control plane + Rust hot path)
Decision framework
세 가지 질문이면 stack 선택의 90%가 정리됩니다.
- 이미 강한 skill이 있나요? 매일 Python을 쓴다면 bot도 Python으로 작성하세요. 매일 TypeScript를 쓴다면 bot도 Node로 작성하세요. 아래의 SDK quality 차이는 실제로 존재하지만, 익숙하지 않은 언어와 싸우는 비용보다는 작습니다.
- strategy가 latency-critical인가요? 50ms 이내에 반응하는 것이 edge의 핵심이라면(5-minute crypto market, news 중 market making 등), hot path는 Rust나 Go가 유리합니다. 대부분의 strategy에는 그 정도가 필요하지 않습니다.
- 하나 이상의 strategy를 운영할 건가요? 단일 Python process 하나로도 10-20개 market은 충분히 관리할 수 있습니다. 그 이상이면 async Node 또는 split-process Python이 더 잘 확장됩니다.
첫 bot의 가장 솔직한 default는 Python입니다. 측정된 constraint가 이를 강제할 때만 바꾸세요.
Python (default choice)
Python이 default인 이유는 SDK가 가장 완성도가 높고 반복 개발 loop가 가장 빠르기 때문입니다. 0.34.6 버전(2026년 5월)의 py-clob-client는 중요한 모든 CLOB v2 endpoint를 지원합니다: market 및 limit order, FOK/FAK/GTC variant, order book read, balance/allowance read, 그리고 web3.py를 통한 direct chain operation까지 포함합니다.
장점: mature SDK, pandas를 활용한 쉬운 data analysis, 큰 community, on-chain read를 위한 web3.py. 단점: JavaScript에 비해 async ergonomics가 어색하고, GIL이 multi-core speedup을 제한하며(대부분 I/O-bound bot에서는 크게 중요하지 않음), cold container에서 startup time이 느립니다.
추천 대상: builder의 80%. 특히 strategy에 backtesting, statistical analysis, 또는 execution과 함께하는 어떤 data work라도 포함되는 경우에 적합합니다.
Node.js (full-stack devs)
Node.js는 두 번째로 지원이 좋은 stack입니다. 1.0.6 버전의 @polymarket/clob-client-v2는 Python SDK와 동일한 endpoint를 TypeScript type과 함께 제공합니다. async는 native이며 빠르고, WebSocket handling도 뛰어납니다.
장점: 최고의 async story, native TypeScript types, HTTP + WS를 위한 큰 ecosystem, web dashboard와 같은 Node runtime에서 쉽게 deploy 가능. 단점: 큰 token ID(ERC-1155 ID는 256-bit)에 대해서는 정밀도 처리를 위해 BigInt 또는 string handling이 필요하고, pandas에 상응하는 data tool은 약합니다.
추천 대상: 이미 JavaScript stack을 유지하고 있고 하나의 runtime을 원하시는 builder. 또한 bot과 함께 dashboard를 만드는 사람에게도 적합합니다. bot core와 Next.js dashboard 사이에서 type을 공유하면 한 종류의 bug를 없앨 수 있습니다.
Rust (latency-critical hot path)
Rust에는 공식 Polymarket SDK가 없습니다. 대신 reqwest(HTTP), tokio-tungstenite(WebSocket), 그리고 signing을 위한 ethers-rs 또는 alloy를 사용해 V2 REST 및 WebSocket API에 직접 연결합니다. Python에서 30분 걸릴 작업이 대략 이틀 정도 걸립니다.
장점: JS subprocess 없이 native EIP-712 signing 가능, sub-millisecond order construction, 부하가 걸려도 deterministic한 memory profile, GC pause 없음. 단점: SDK가 없기 때문에 Python 사용자가 무료로 얻는 것들을 직접 다시 구현해야 합니다(clobToken ID parsing, response schema validation, salt/nonce management). latency 이득은 tuned Python 대비 20-100ms 수준이며, sub-second strategy에서만 의미가 있습니다.
추천 대상: market-making bot의 hot path, 또는 news-arb bot의 trade-firing leg. bot 전체를 Rust로 만드는 경우는 거의 없습니다.
stack별 setup commands
mainnet에 대해 working signed order를 만들기 위한 최소 commands입니다(single CLOB v2 endpoint).
Python:
python -m venv venv && source venv/bin/activate
pip install py-clob-client==0.34.6 web3 python-dotenv
# Set POLYGON_RPC, PRIVATE_KEY, POLY_FUNDER in .env
Node:
npm init -y
npm install @polymarket/[email protected] ethers dotenv
# Set POLYGON_RPC, PRIVATE_KEY, POLY_FUNDER in .env
Rust:
cargo new --bin pmt
cd pmt
cargo add tokio reqwest serde serde_json ethers alloy tungstenite tokio-tungstenite
# Hand-write signer + endpoint client; no SDK shortcut.
Time-to-first-order: Python 약 10분, Node 약 15분, Rust 약 4-8시간.
Code skeleton: 3개 언어로 order book fetch
같은 task-Polymarket token의 order book을 fetch하기-를 각 stack에서 보여드립니다. 세 언어 모두 동일한 CLOB v2 REST endpoint를 호출합니다.
Python (py-clob-client):
from py_clob_client.client import ClobClient
client = ClobClient(host="https://clob.polymarket.com", chain_id=137)
book = client.get_order_book("<token_id>")
print(book.bids[:3], book.asks[:3])
Node (@polymarket/clob-client-v2):
import { ClobClient } from "@polymarket/clob-client-v2";
const c = new ClobClient({ host: "https://clob.polymarket.com", chain: 137 });
const book = await c.getOrderBook("<token_id>");
console.log(book.bids.slice(0,3), book.asks.slice(0,3));
Rust (direct HTTP):
let url = format!("https://clob.polymarket.com/book?token_id={}", token);
let book: serde_json::Value = reqwest::get(&url).await?.json().await?;
println!("{:?} {:?}", &book["bids"][..3], &book["asks"][..3]);
세 경우 모두 response shape는 동일합니다. Rust의 비용은 read path가 아니라 그 외 모든 부분, 즉 signing, order construction, error handling에 있습니다.
언제 stack을 섞을지 (Python control plane + Rust hot path)
많은 production bot이 수렴하는 pattern은 다음과 같습니다: decision이 필요한 모든 작업은 Python, millisecond execution leg는 Rust.
Architecture: Python process가 market state를 읽고, strategy logic을 실행한 뒤, 작은 command file(예: {"action":"buy","token":"...","size":10,"price":0.45})을 Unix socket에 씁니다. Rust daemon이 그 socket을 listen하고, order를 sign한 뒤 CLOB에 post합니다. Python process는 느리지만 편리할 수 있고, Rust daemon은 빠르고 minimal합니다.
핸드오프가 핵심입니다. signed-order step을 분리하면 latency를 희생하지 않으면서 Python crash budget을 회복할 수 있습니다. 우리는 production bot에서 정확히 이 pattern을 사용합니다-Python이 intention을 내보내고, /tmp/clob.sock의 Node daemon이 signing을 처리합니다. Node version의 daemon은 sub-100ms에서는 충분히 좋고, Rust는 50ms 이하에서만 진가를 발휘합니다.












