Polymarket Bot Tutorial · 32개 중 17장
Polymarket order book imbalance를 단기 가격 신호로 활용하는 방법: bid-ask volume ratio, microprice 계산, signal half-life, 그리고 imbalance bots가 random execution보다 유리한 경우.
이 장에서 다루는 내용
Order-book imbalance는 limit order book에서 매수 측 depth와 매도 측 depth의 비율입니다. Polymarket에서는 실제로 유효하지만 수명이 짧은 predictive edge가 있으며, 보통 mid가 움직이기 5~30초 전에 나타납니다. 이 장에서는 이 신호를 계산하는 방식과, 어떤 조건에서 신호가 틀리는지 다룹니다.
- order book imbalance란 무엇인가
- microprice 계산
- 방향성 신호로서의 imbalance
- Polymarket에서의 signal half-life
- imbalance 신호가 틀리는 경우
- Code: 모든 WS tick마다 imbalance 계산
order book imbalance란 무엇인가
Order book imbalance는 limit order book에서 총 매수 측 depth와 총 매도 측 depth의 비율입니다. top-N level에서 계산하며(일반적으로 N=5), 아직 mid-price에 반영되지 않은 집단적인 trader pressure를 포착합니다.
Formula: imbalance = (Σ bid[i].price × bid[i].size for i in [0..N]) − (Σ ask[i].price × ask[i].size) / (Σ both). 범위는 -1에서 +1까지이며, 양수는 매수 압력이 더 크다는 뜻이고 음수는 매도 압력이 더 크다는 뜻입니다.
이 신호는 Polymarket에서 실증적으로 실제로 존재하지만 noisy합니다. 단 하나의 whale이 30~60초 동안 imbalance를 fake-print한 뒤 arb로 사라질 수 있습니다. 단독 트리거로 쓰기에는 위험하고, 여러 feature 중 하나로는 유용합니다.
microprice 계산
Microprice는 단순한 mid를 개선한 값으로, best bid와 best ask를 각각의 size로 가중한 weighted average입니다.
microprice = (best_bid × ask_size + best_ask × bid_size) / (bid_size + ask_size)
bid-side queue가 ask side보다 훨씬 크면 microprice는 ask에 더 가까워집니다. 직관은 이렇습니다. 기다리는 buyers가 더 많다는 것은 다음 trade가 ask를 끌어올릴 가능성이 더 높다는 뜻이므로, fair value는 ask 쪽에 더 가깝습니다.
Microprice는 실제 mid가 움직이기 5~30초 전의 leading indicator입니다. production bots는 naive mid 대신 take-profit decision의 reference price로 이것을 사용합니다.
방향성 신호로서의 imbalance
production observation에 따르면, news event가 동반되지 않은 상태에서 10초 안에 imbalance가 -0.3에서 +0.5로 바뀌면, 다음 30~60초 내에 mid가 1~2센트 올라갈 확률이 약 65%입니다.
실제로 edge는 있지만, fee를 제하면 작은 position size에서는 금방 사라집니다. 수익화하려면 bot이 움직임에서 fee를 뺀 만큼은 잡을 수 있을 정도로 충분히 size를 가져야 하지만, 동시에 book 자체를 움직일 정도로 크면 안 됩니다. Polymarket의 book은 대체로 얇아서 50 shares를 넘으면 시장에 영향을 주는 경우가 많습니다.
imbalance는 다른 feature와 함께 결합해야 합니다: trade velocity(거래가 많을수록 실제 신호), best-bid가 실제로 올라가는지 여부(단순히 depth만 바뀌는 것이 아님), market이 news-driven mode가 아닌지 여부입니다.
Polymarket에서의 signal half-life
imbalance 신호는 시간이 지나면 decay합니다. 우리 trader의 production data에 따르면, imbalance > 0.6이면 60초 내에 expected mid move는 1.2c이며, half-life는 약 30초입니다. 90초가 지나면 predictive value는 0이 됩니다.
bot 설계에 대한 시사점은 명확합니다. 빠르게 반응하거나, 아니면 건너뛰어야 합니다. 판단에 15초가 걸리는 bot은 order를 내기 전에 edge의 절반을 소모하는 셈입니다. imbalance strategy의 latency budget는 signal에서 FOK fired까지 5초 미만이어야 합니다.
half-life(1~2분)보다 오래 position을 보유하는 전략은 현재 신호가 아니라 다음 신호에 베팅하는 것입니다. 이 점을 명확히 해야 합니다. imbalance-driven position을 실수로 resolution까지 보유하지 않도록 하세요.
imbalance 신호가 틀리는 경우
다음 세 가지 조건 중 하나가 성립하면 신호가 오도됩니다.
- News-driven move: imbalance가 아직 보지 못한 news의 결과일 때입니다. 이를 거슬러 거래하면 손해를 봅니다. 반대로 따라가는 것은 news arbitrage이며, 다른 전략입니다.
- Whale spoofing: 큰 order를 넣었다가 빠르게 취소해 지속 시간 동안 fake imbalance를 만드는 경우입니다. 트리거를 걸기 전에 imbalance가 10초 이상 지속되는지 확인해 필터링하세요.
- End-of-period rebalancing: 정보 때문이 아니라 inventory 이유로 market makers가 quotes를 철수하는 경우입니다. 이때 imbalance는 몇 분 후 MM이 다시 quote를 내면서 반전됩니다.
결합 필터는 다음과 같습니다: imbalance > threshold AND trade velocity > baseline AND 지난 5분 내 news event 없음. 각 필터를 단독으로 쓰면 false positive가 너무 많습니다.
Code: 모든 WS tick마다 imbalance 계산
Reference: WebSocket book updates를 구독하고, 모든 tick마다 imbalance를 다시 계산합니다.
def on_book_message(msg):
bids = msg.get("bids", [])[:5]
asks = msg.get("asks", [])[:5]
bid_usd = sum(float(b["price"]) * float(b["size"]) for b in bids)
ask_usd = sum(float(a["price"]) * float(a["size"]) for a in asks)
total = bid_usd + ask_usd
if total < 100: return # illiquid
imb = (bid_usd - ask_usd) / total
state[msg["asset_id"]] = {
"imb": imb,
"best_bid": float(bids[0]["price"]) if bids else 0,
"best_ask": float(asks[0]["price"]) if asks else 1,
"ts": time.time()
}
# decision logic with cooldown + filters
if imb > 0.6 and time.time() - last_fired.get(msg["asset_id"], 0) > 60:
check_filters_and_maybe_fire(msg["asset_id"])
State는 토큰별로 관리합니다. Cooldown은 같은 신호에 대해 과도하게 발화되는 것을 막습니다. Filters(news check, trade velocity)는 실제 trade를 실행할지 여부를 결정합니다.





