Polymarket Bot Tutorial · 32개 중 18장
Polymarket에서의 UMA dispute prediction bots: Optimistic Oracle proposals를 감지하고, dispute 가능성을 예측하며, dispute 전후의 price asymmetry를 활용하고, disputed-market death spiral을 피합니다.
이 장에서 다루는 내용
UMA의 Optimistic Oracle은 Polymarket markets를 resolve하며, dispute는 발생 전후에 price anomalies를 만듭니다. dispute의 양쪽 모두에서 tradeable patterns가 존재하지만, 이 전략은 운영적으로 복잡하고 지금까지 수많은 bots를 손상시켰습니다. 이 장은 그 현실적인 playbook입니다.
- UMA Optimistic Oracle 작동 방식
- on-chain proposal 감지
- Dispute predictors (volume, ambiguity, history)
- Dispute 전 price asymmetry
- Dispute 후 trade setups
- disputed markets를 거래하면 안 되는 경우
- Code: UMA proposed/disputed events 구독하기
UMA Optimistic Oracle 작동 방식
UMA의 Optimistic Oracle(OO)은 Polymarket의 dispute resolution layer입니다. 모든 market resolution은 OO를 거치며, 대부분은 contest 없이 자동으로 settle됩니다. contest된 것들-disputes-은 24~72시간의 voting period를 트리거하고, 그동안 UMA token holders가 outcome을 결정합니다.
라이프사이클은 다음과 같습니다. Polymarket의 resolver가 price를 propose합니다(0 = NO가 이김, 1 = YES가 이김). 2시간의 challenge window 이후 아무도 dispute하지 않으면 price가 finalized 되고 CTF contract가 payouts를 분배합니다. 누군가 dispute하면 market은 voting window로 들어가며, UMA holders가 투표하고 majority가 승리합니다.
bot 관점에서 중요한 event는 ProposePrice(proposal이 들어오고 challenge window가 열림)와 DisputePrice(dispute가 제출되고 voting period가 시작됨)입니다. 이를 subscribe해서 market resolution state를 실시간으로 추적하세요.
on-chain에서 proposal 감지하기
Polygon의 UMA OO contract는 ProposePrice event를 (requester, identifier, timestamp, ancillaryData, proposer, proposedPrice) 파라미터와 함께 emit합니다. Polymarket의 알려진 requester address로 filter하면 관련 proposal만 좁혀 볼 수 있습니다.
POLY_REQUESTER = "0x..." # Polymarket Adjudicator
filt = oo_contract.events.ProposePrice.create_filter(
fromBlock="latest",
argument_filters={"requester": POLY_REQUESTER}
)
for event in filt.get_new_entries():
market_id = decode_ancillary(event.args.ancillaryData)
proposed = "YES" if event.args.proposedPrice == 1e18 else "NO"
print(f"PROPOSE: market {market_id} → {proposed}")
ancillaryData 필드는 market question을 설명하는 hex-encoded JSON입니다. 이를 디코딩하면 open positions와 대조할 수 있는 market identifier를 얻을 수 있습니다.
Dispute predictors (volume, ambiguity, history)
Dispute 전에 나타나는 세 가지 signal은 나중의 실제 dispute와 상관관계를 보입니다.
- Total volume: lifetime volume이 $1M를 넘는 markets는 작은 markets보다 dispute 비율이 4배 높습니다. 걸린 capital이 많을수록 challenge할 유인이 커집니다.
- Ambiguous wording: "or similar", "officially confirmed", 또는 복합 조건(date AND specific outcome)이 있는 market은 dispute rate가 더 높습니다.
- 같은 event에 대한 과거 dispute: 이전 proposal이 이미 dispute되었고 다시 proposal되었다면, 두 번째 proposal은 정상 대비 2~3배 높은 비율로 dispute됩니다.
bot은 이러한 feature로부터 "dispute probability" score를 계산하고, resolution에 가까운 시장에서는 threshold를 넘는 경우 포지션을 잡지 않도록 할 수 있습니다.
Dispute 전 price asymmetry
Dispute가 일어날 가능성이 높은 몇 시간 전에는 market price가 종종 비대칭적으로 움직입니다. proposer가 YES라고 지목한 쪽은 dispute가 이를 뒤집을까 두려워 내려가고, 반대쪽은 올라갑니다.
어느 방향으로 dispute가 resolve될지에 대한 방향성 view가 있다면, 이 구간은 tradeable합니다. 위험은 dispute가 실제로 발생하지 않을 때입니다. challenge window가 무사히 닫히면 비대칭이 반전되고 price는 제안된 방향으로 되돌아갑니다.
솔직히 말해, 대부분의 pre-dispute asymmetry trade는 손실입니다. 왜냐하면 대부분의 challenge는 original proposal에 유리하게 resolve되기 때문입니다. 이 전략은 해당 dispute가 sustain될 이유에 대한 구체적인 정보가 있을 때만 작동합니다.
Dispute 후 trade setups
Dispute가 제출되면 market은 24~72시간 동안 "limbo" 상태에서 거래됩니다-dispute는 되었지만 outcome은 투표로 결정됩니다. 여기에는 두 가지 setup이 있습니다.
UMA consensus로의 convergence: dispute resolution이 초기에 신호되는 경우(예: 유명한 UMA voter가 공개적으로 한쪽 편을 듦), price는 그 resolution 쪽으로 움직입니다. UMA Discord / Twitter signal + price action을 보는 bot은 이를 30~60% 정도의 경우 포착할 수 있습니다.
Volatility farming: limbo 기간에는 spread가 넓습니다. 인내심 있는 market maker는 voting window 동안 들어오고 나가는 여러 traders를 상대로 spread tax를 벌 수 있습니다. inventory risk가 높으므로 규모를 조절해야 합니다.
둘 다 본인 포지션과 반대로 resolve될 가능성을 실제로 감수해야 합니다. dispute 기간 inventory는 최대 절반 규모로만 취급하세요.
disputed markets를 거래하면 안 되는 경우
Dispute trade가 기본적으로 잘못되는 세 가지 상황입니다.
- UMA-specific view가 없는 경우. edge가 "원래 proposal이 맞아 보인다"뿐이라면, original proposer보다 유리할 이유가 없고-dispute filer는 반대로 생각합니다. voting outcome은 예측 불가능한 coin flip입니다.
- Dispute가 ambiguous wording에 대한 것인 경우. UMA voters는 일반적으로 question을 엄격하게 해석하는 쪽에 섭니다. market이 "by January 31"라고 했고 이벤트가 2월 1일에 발생했다면, trader population의 직감과 상관없이 UMA는 NO로 resolve할 것입니다.
- Dispute 이전부터 inventory를 보유하고 있는 경우. limbo를 버티며 기존 포지션에 "average down"을 위해 추가하는 것은 전형적인 capital-destruction 패턴입니다. 보유하거나 청산하세요. 절대 추가하지 마세요.
Code: UMA proposed/disputed events 구독하기
Reference: Polymarket requester로 필터링된 UMA OO events의 WebSocket subscription.
from web3 import Web3
w3 = Web3(Web3.WebsocketProvider(POLYGON_WSS))
oo = w3.eth.contract(address=UMA_OO_ADDR, abi=UMA_OO_ABI)
POLY = "0x...".lower()
dispute_filter = oo.events.DisputePrice.create_filter(fromBlock="latest")
propose_filter = oo.events.ProposePrice.create_filter(fromBlock="latest")
while True:
for event in dispute_filter.get_new_entries():
if event.args.requester.lower() == POLY:
on_dispute(event)
for event in propose_filter.get_new_entries():
if event.args.requester.lower() == POLY:
on_propose(event)
time.sleep(2)
def on_dispute(event):
market_q = decode_ancillary_to_question(event.args.ancillaryData)
send_telegram(f"DISPUTE: {market_q}")
# If we hold a position in this market, alert + consider exit
if market_q in our_positions:
flag_position_for_review(market_q)
패턴은 다음과 같습니다. subscribe, decode, alert. Dispute에 algorithmically 대응하는 것은 고위험입니다. bot의 역할은 보통 해당 event를 사람 reviewer에게 전달하는 것입니다.





