Polymarket Bot Tutorial · 32개 중 20장
Polymarket 고래 wallet을 추적하고 top performer를 프로그램matically copy-trade하세요: leaderboard와 on-chain analysis를 통해 수익성 있는 wallets를 식별하고, size와 timing rules로 그들의 trades를 mirror합니다.
이 장에서 다루는 내용
성공하는 Polymarket wallets를 복사하는 것은 인기 있는 아이디어지만, 실제 Polymarket의 whales는 대부분 방향성 bets가 아니라 resolved markets에서 late-window arb를 하고 있습니다. 이 장은 on-chain analysis를 바탕으로 한 솔직한 research입니다: 실제로 어떤 wallets를 copy해야 하는지, 왜 대부분은 copy할 가치가 없는지, 그리고 position-sizing math는 어떻게 되는지 다룹니다.
- 수익성 있는 wallets 식별
- On-chain trade detection
- Whale 대비 position sizing
- Latency: 얼마나 늦으면 너무 늦은가
- Filters: 검증된 edge가 있는 wallets만 따라가기
- Code: whale buy event 감지, size를 반영한 copy 주문 실행
수익성 있는 wallets 식별
Whale-copying의 전제는 일부 wallets가 일관되게 수익을 내고 있으며, 그들의 entries를 복사하면 그 edge의 일부를 확보할 수 있다는 것입니다. 2025~26년 Polymarket의 top wallets에 대한 on-chain analysis 결과는 냉정했습니다. 눈에 보이는 whales 대부분은 방향성 trading이 아니라 resolved markets에서 late-window arbitrage를 하고 있었습니다.
우리가 측정한 세 개의 후보 whale wallet의 프로필:
- "hhhhhh6" (98.5% win rate, $n M volume)-entries의 88%가 가격 ≥0.95에서 발생, median entry timestamp는 300초 window의 226초. 순수한 tail-yield arb이며 방향성은 아님.
- "anonymous" (20% win rate)-degenerate gambler. Copy하면 돈을 잃습니다.
- "Jkim123" (53.5% win rate)-coin-flip 수준. 따라갈 만한 signal이 아닙니다.
이 whales의 trades 중 어떤 것도 5분 window의 처음 120초 안에 발생하지 않았습니다. 예측 신호가 있다면(있다 하더라도) 그것은 EARLY-window의 큰 entries에서 나올 텐데, 그런 wallets는 어렵기 때문에 leaderboard 상단에 있는 wallets가 아닙니다.
On-chain trade detection
대상 wallet의 trades를 감지하려면 Polymarket의 data-api를 polling하거나 on-chain CTF transfer events를 subscribe해야 합니다. data-api 방식이 더 간단합니다.
def watch_wallet(wallet_addr, last_seen_ts=0):
while True:
url = f"https://data-api.polymarket.com/activity?user={wallet_addr}&limit=100"
events = requests.get(url).json()
for ev in events:
ts = int(ev.get("timestamp", 0))
if ts <= last_seen_ts: continue
if ev["type"] == "TRADE":
process_whale_trade(ev)
last_seen_ts = max(last_seen_ts, ts)
time.sleep(5)
data-api에서는 5초 polling이 사실상 최저선입니다. 이보다 짧으면 rate limits에 걸립니다. sub-second detection이 필요하다면, whale의 proxy address로 필터링된 CTF contract의 on-chain ERC-1155 TransferSingle events를 subscribe하세요.
Whale 대비 position sizing
복사 비중을 whale의 trade에 대한 일정 비율로 정하면 그들의 risk profile을 그대로 물려받게 됩니다. 실무적으로는 두 가지 대안이 있습니다.
- Cap-based: whale size와 무관하게 각 copy를 고정된 달러 금액($10-50)으로 설정합니다. 복리 효과는 느리지만 trade당 손실이 제한됩니다.
- Win-rate-weighted: whale의 최근 win rate 함수로 copy size를 정합니다. 60%+ WR → full-size copy; 40-60% → half-size; 40% 미만 → skip.
Cap-based 접근이 더 안전한 첫 배포입니다. 실제로는 늦게 도착하기 때문에, whale의 headline number보다 낮은 경우가 대부분인 당신의 copy 기준 실제 win rate를 측정한 뒤에만 win-rate-weighted 방식으로 넘어가세요.
Latency: 얼마나 늦으면 너무 늦은가
Whale의 trade는 실행 후 1~2초 내에 공개적으로 보입니다. 이를 copy하려면 read side에서 그보다 더 빠른 latency가 필요하고, 여기에 본인의 order placement latency까지 더해집니다.
일반적인 copy bot의 end-to-end는 5~10초 polling + 200ms order placement = 총 5~15초입니다. 당신의 copy가 실행될 무렵에는 whale의 signal이 이미 가격에 반영되어 있습니다.
Polymarket의 좁은 markets에서는 99%의 copies에 대해 이것은 너무 늦습니다. Whale의 entry로 mid가 1~2센트 움직였고, 당신은 그들이 진입한 가격보다 1~2센트 비싼 프리미엄을 지불합니다. 그들의 edge가 3c였다면, 도착했을 때 이미 절반은 사라진 셈입니다.
실제로 작동하는 copy bot은 (a) 30초 latency가 의미 없는 느리게 움직이는 markets를 타깃으로 하거나, (b) on-chain event subscription을 사용해 sub-second timeframe으로 반응합니다.
Filters: 검증된 edge가 있는 wallets만 따라가기
어떤 wallet이든 copy list에 추가하기 전에 세 가지 필터를 적용합니다.
- wallet 이력에 30개 이상의 closed trades가 있어야 합니다. 더 작은 sample은 noise입니다.
- 평생 win rate가 60% 초과이거나, entry price 기준으로 trade당 positive expected value가 있어야 합니다. 둘 중 하나면 되며, 둘 다면 더 좋습니다.
- late-window arb 패턴이 아니어야 합니다. 진입 시점의 resolution까지 남은 median seconds를 확인하세요. 0에 가깝다면, 그 wallet은 재현할 수 없는 tail-yield arb를 하고 있는 것입니다.
대부분의 후보 whales는 이 세 조건 중 하나를 통과하지 못합니다. 실제로 copy 가능한 wallets의 pool은 작습니다. 목록을 유지하려면 정기적으로 재검토해야 합니다. 지난달에 수익성이 있던 wallet이 이번 달에도 그렇다는 보장은 없습니다.
Code: whale buy event 감지, size를 반영한 copy 주문 실행
참고: 감시 중인 whale의 CTF TransferSingle event를 감지하고, size를 반영한 copy buy를 실행합니다.
from web3 import Web3
w3 = Web3(Web3.WebsocketProvider(POLYGON_WSS))
ctf = w3.eth.contract(address=CTF_ADDR, abi=CTF_ABI)
WHALES = {"0xabc...": {"fraction": 0.05, "cap": 50}}
def on_transfer(event):
to = event.args["to"].lower()
if to not in WHALES: return
cfg = WHALES[to]
token_id = event.args.id
whale_size = event.args.value / 1e6
copy_size = min(cfg["cap"], whale_size * cfg["fraction"])
if copy_size < 5: return # not worth fees
book = fetch_book(str(token_id))
if book.best_ask:
place_fok(str(token_id), "BUY", book.best_ask + 0.01, copy_size)
# subscribe to ERC-1155 TransferSingle events from CTF
filt = ctf.events.TransferSingle.create_filter(fromBlock="latest")
while True:
for ev in filt.get_new_entries(): on_transfer(ev)
time.sleep(0.5)
from이 zero address면 mint이므로 whale이 bought 한 것이고, to가 zero address면 burn이므로 sold 한 것으로 구분하세요.





