Polymarket Bot Tutorial · 32장 중 22장
Polymarket의 NegRisk multi-outcome bot: sum-to-1 mechanics, YES legs가 1을 합산하지 않을 때의 leg arbitrage, legs 간 hedging, 그리고 multi-outcome market에 특화된 execution pitfalls.
이 장에서 다루는 내용
Multi-outcome NegRisk market는 상호 배타적입니다. 정확히 하나만 YES로 resolve됩니다. 이 장은 11장의 execution mechanics 위에 얹는 strategy layer입니다. legs 간 hedge하는 방법, sum-to-1 arb가 실제로 성립하는 경우, 그리고 대부분의 NegRisk bot이 첫 배포에서 맞닥뜨리는 버그를 다룹니다.
- NegRisk vs binary 요약
- Sum-to-1 invariant와 arbitrage
- Leg별 hedge 구성
- Execution: orders의 neg_risk flag
- NegRisk bot의 흔한 버그
- Code: 모든 leg snapshot 및 under-1.00 sum 감지
NegRisk vs binary 요약
Binary: 하나의 yes/no market, 두 개의 token, 합은 1.0입니다. NegRisk: N개의 상호 배타적 outcome, N개의 token, 모든 YES leg의 합은 이벤트 전반에서 약 1.0입니다.
Execution 측면에서 NegRisk는 모든 order에 negRisk: true가 필요하며(11장), 별도의 exchange contract를 통해 라우팅됩니다. Strategy 측면에서 NegRisk는 binary에는 없는 두 가지 고유한 기회를 제공합니다. 합이 1.0에서 벗어날 때의 cross-leg arb, 그리고 여러 YES leg를 매수해 hedge를 구성하는 방법입니다.
NegRisk에만 있는 비용: leg가 많을수록 spread tax도 커집니다(거래하는 각 leg마다 약 0.5~1c의 spread 비용). 또한 유동성이 낮은 이벤트에서는 sum-to-1 deviation이 더 크게 벌어지며, arb 기회는 더 자주 나타나지만 규모는 더 작습니다.
Sum-to-1 invariant와 arbitrage
Arb의 전제는 이렇습니다. 모든 N개의 YES leg를 사는 비용이 $1.00 미만이면, resolve 시점에 확정 수익이 잠깁니다. 반드시 하나의 leg는 $1.00을 지급하고, 나머지는 $0으로 가기 때문입니다.
실전에서는 arb gap이 보통 0~3c 수준이며, 각 leg의 spread와 fee에 의해 대부분 사라집니다. 또한 개장 후 몇 분 안에 없어집니다. 용량은 가장 얇은 leg의 liquidity에 의해 제한됩니다.
이 arb는 특정 resolution failure mode의 영향을 받기도 합니다. 예를 들어 명시적으로 "none of the above" outcome가 있고, 어떤 명명된 후보도 해당되지 않을 때 YES로 resolve되는 경우입니다. 이벤트에 그런 leg가 있는데 그걸 사지 않았다면, 당신의 "완전 hedge"는 실제 payout을 놓치게 됩니다.
Leg별 hedge 구성
한 NegRisk leg에 position을 보유하고 있다면, 비례해서 경쟁 leg들의 YES를 매수하여 hedge할 수 있습니다. Trump-YES를 0.50에 보유하고 있고 Trump 패배에 대비해 hedge하고 싶다면, 나머지 명명된 leg들의 포트폴리오를 매수합니다.
Leg당 hedge weight는 대략 Trump가 지는 조건부 상황에서의 현재 implied probability와 같습니다. 근사식은 다음과 같습니다. weight_i = price_i / (1 - trump_price).
이 hedge는 point-in-time price를 사용하고, 뉴스가 들어오면 conditional probability가 변하기 때문에 완벽하지 않습니다. Hedge는 매주 또는 큰 뉴스가 있을 때 재조정하세요. 지나치게 복잡하게 만들 필요는 없습니다. hedge의 목적은 variance를 줄이는 것이지, 완전히 없애는 것이 아니기 때문입니다.
Execution: orders의 neg_risk flag
NegRisk 전용으로 가장 흔한 버그는 order placement payload에 negRisk: true를 빼먹는 것입니다. API에서는 order가 받아들여지지만, standard CTF exchange가 아니라 NegRisk exchange로 라우팅되어야 하는데 잘못 settlement됩니다.
// CORRECT for NegRisk markets:
await client.createAndPostOrder(
{ tokenID, price, size, side: Side.BUY },
{ tickSize: '0.01', negRisk: true }, // <-- REQUIRED
OrderType.FOK
);
Source of truth는 Gamma API의 market.negRisk입니다. 이를 읽고 그대로 전달하세요. 추측으로 flag를 hardcode하지 마세요.
NegRisk bot의 흔한 버그
여러 bot의 production debug logs에서 나온 내용입니다.
- negRisk flag 누락: order는 받아들여지지만 settlement가 실패합니다. 해결: 모든 wrapper에서 flag를 강제하세요.
- "Other" leg 없이 hedge하기: "None of the above" outcome가 있는 이벤트에서 이를 제외한 hedge portfolio는 불완전합니다. 해결: hedge를 구성할 때 항상 Other leg가 있는지 확인하세요.
- Sum-to-1 arb의 규모를 너무 작게 잡음: arber가 1c edge는 알아냈지만 leg당 5 shares만 거래합니다. 총 profit은 spread 전 5센트에 불과하고, net 기준으로는 마이너스입니다. 해결: headline percentage를 쫓지 말고, 의미 있는 절대 달러 수익이 나오도록 arb 규모를 잡으세요.
- 오래된 leg pricing: bot이 3개 leg 가격을 가져오는 데 총 200ms가 걸리고, 마지막 leg 가격은 그 사이에 변합니다. 해결: 모든 leg를 parallel로 가져오고, snapshot을 하나의 observation으로 취급하세요.
Code: 모든 leg snapshot 및 under-1.00 sum 감지
참고: NegRisk 이벤트의 모든 YES leg를 병렬로 snapshot하고 arb를 감지합니다.
import asyncio, aiohttp
async def fetch_leg_ask(session, token_id):
async with session.get(f"https://clob.polymarket.com/book?token_id={token_id}") as r:
d = await r.json()
asks = d.get("asks", [])
return float(asks[0]["price"]) if asks else None
async def check_arb(event_slug):
event = await fetch_event(event_slug)
if not event["markets"][0]["negRisk"]: return None
legs = []
for m in event["markets"]:
toks = json.loads(m["clobTokenIds"])
yes_token = toks[0]
legs.append(yes_token)
async with aiohttp.ClientSession() as s:
asks = await asyncio.gather(*[fetch_leg_ask(s, t) for t in legs])
if any(a is None for a in asks): return None
total = sum(asks)
if total < 0.97:
return {"edge": 1 - total, "legs": list(zip(legs, asks))}
return None
모든 leg의 atomic execution은 더 어려운 문제이며, leg별 FOK와 부분 체결 시 rollback이 필요합니다(16장의 stat-arb code와 유사한 패턴).





