Polymarket Bot Tutorial · Chapter 18 of 32
Боты прогнозирования UMA dispute на Polymarket: обнаруживайте предложения Optimistic Oracle, предсказывайте вероятность dispute, используйте асимметрию цен до и после dispute и избегайте спиралей смерти на disputed markets.
Что охватывает эта глава
Optimistic Oracle (OO) от UMA - это слой разрешения споров для Polymarket, а disputes создают ценовые аномалии до и после их возникновения. Торгуемые паттерны существуют по обе стороны dispute, но стратегия операционно сложна и уже сожгла больше ботов, чем принесла прибыли. Эта глава - честный playbook.
- Как работает UMA Optimistic Oracle
- Обнаружение proposal on-chain
- Предикторы dispute (volume, ambiguity, history)
- Асимметрия цен до dispute
- Post-dispute trade setups
- Когда НЕ стоит торговать disputed markets
- Code: subscribe to UMA proposed/disputed events
Как работает UMA Optimistic Oracle
Optimistic Oracle (OO) от UMA - это слой разрешения споров для Polymarket. Каждое разрешение рынка проходит через OO; большинство случаев не оспариваются и закрываются автоматически. Оспариваемые случаи - disputes - запускают voting period на 24-72 часа, в течение которого holders токенов UMA решают исход.
Жизненный цикл такой: resolver Polymarket предлагает price (0 = NO выиграл, 1 = YES выиграл). После 2-часового challenge window, если никто не подает dispute, price становится final, и контракт CTF распределяет payouts. Если кто-то подает dispute, market переходит в voting window; holders UMA голосуют, побеждает majority.
Для bot релевантные события - это ProposePrice (proposal внесен, challenge window открыт) и DisputePrice (dispute подан, voting period начался). Подпишитесь на них, чтобы отслеживать state разрешения market в реальном времени.
Обнаружение proposal on-chain
Контракт UMA OO в Polygon генерирует событие ProposePrice с параметрами (requester, identifier, timestamp, ancillaryData, proposer, proposedPrice). Фильтруйте по известному requester адресу Polymarket, чтобы ограничиться релевантными 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 - это hex-encoded JSON, описывающий вопрос рынка. Раскодировав его, вы получите идентификатор market, который можно сопоставить с вашими открытыми позициями.
Предикторы dispute (volume, ambiguity, history)
Три сигнала до dispute коррелируют с последующими фактическими disputes.
- Total volume: markets с lifetime volume более $1M оспариваются в 4 раза чаще, чем small markets. Больше капитала на кону = больше стимулов оспорить.
- Ambiguous wording: любой market с формулировками вроде "or similar," "officially confirmed," или compound conditions (date AND specific outcome) имеет повышенную вероятность dispute.
- Past disputes on the same event: если более ранний proposal уже был disputed и был предложен заново, второй proposal оспаривается в 2-3 раза чаще обычного.
Bot может рассчитывать score "dispute probability" на основе этих признаков и избегать открытия позиций в markets выше порога, близкого к resolution.
Асимметрия цен до dispute
За несколько часов до вероятного dispute market price часто показывает асимметричное движение: сторона, которую proposer обозначил как YES, снижается (потому что traders боятся, что dispute перевернет исход), а другая сторона растет.
Если у вас есть directional view на то, как dispute будет resolved, это торговое окно. Риск: если dispute не произойдет, асимметрия развернется, когда challenge window завершится без событий, и prices резко вернутся к proposed direction.
Честно: большинство pre-dispute asymmetry trades убыточны, потому что большинство challenge решается в пользу original proposal. Стратегия работает только тогда, когда у вас есть конкретная информация о том, почему этот dispute, скорее всего, будет sustained.
Post-dispute trade setups
После подачи dispute market торгуется 24-72 часа в состоянии "limbo" - известно, что dispute есть, outcome будет определен голосованием. Существуют два setup.
Convergence to UMA consensus: если resolution dispute подается ранним сигналом (например, заметный UMA voter публично занимает сторону), price движется к этому resolution. Bot, отслеживающий сигналы UMA Discord / Twitter + price action, может поймать это в 30-60% случаев.
Volatility farming: в период limbo спреды широкие. Терпеливый market maker может зарабатывать spread tax на нескольких traders, которые входят и выходят в течение voting window. Inventory risk высокий; size подбирайте соответственно.
Оба сценария требуют готовности к реальной возможности resolution против вашей позиции. Рассматривайте inventory в период dispute максимум как половинный размер.
Когда НЕ стоит торговать disputed markets
Три ситуации, когда trade на dispute по умолчанию неверен.
- У вас нет UMA-specific view. Если ваше единственное преимущество - "мне кажется, original proposal выглядит правильно", у вас нет edge по сравнению с original proposer - а тот, кто подал dispute, считает наоборот. Итог voting - это coin flip, который вы не можете предсказать.
- Dispute связан с ambiguous wording. UMA voters обычно встают на сторону strict-reading-of-the-question. Если в market было сказано "by January 31", а событие произошло February 1, UMA закроет его как NO независимо от интуиции trader population.
- У вас уже есть inventory до dispute. Усреднение существующей позиции через limbo - классический pattern уничтожения капитала. Держите позицию или выходите, но никогда не добавляйте.
Code: subscribe to UMA proposed/disputed events
Reference: WebSocket subscription к событиям UMA OO, отфильтрованным по requester Polymarket.
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. Действовать на основе disputes алгоритмически - это высокий риск; задача bot обычно состоит в том, чтобы показать событие human reviewer.





