Polymarket Bot Tutorial · 32개 중 10장

Bot builder를 위한 Polymarket order type 설명: Fill-or-Kill (FOK), Fill-and-Kill (FAK), Good-til-Cancelled (GTC), 그리고 limit-vs-market 트레이드오프. production-grade decision rule 포함.

이 장에서 다루는 내용

order-type 혼동은 새로운 bot builder에게 가장 비싼 버그 유형입니다. GTC가 필요한데 FOK를 보내면 진입 기회를 놓치고, FOK가 필요한데 GTC를 보내면 몇 시간 뒤 끔찍한 가격에 체결되는 resting order가 남습니다. 이 장은 그 decision tree와, 수천 건의 order를 통해 검증된 production default를 정리합니다.

  • Quick decision tree
  • FOK: 반드시 fill되거나 건너뛰어야 할 때
  • FAK: partial fill이 허용될 때
  • GTC: book에 남겨둘 때
  • Limit vs market와 spread tax
  • 우리의 production defaults (FOK buys, GTC sells)
  • Code: 각 order type을 배치하는 방법

Quick decision tree

모든 order placement는 세 가지 질문으로 결정됩니다.

  1. 지금 반드시 fill되어야 하며, 지금 못 받으면 아예 안 되는가? → FOK.
  2. 지금 가능한 만큼만 받고, partial fill을 허용하며, resting order는 원하지 않는가? → FAK.
  3. 원하는 price에 book에 남겨두고 누군가 오기를 기다릴 것인가? → GTC.

그게 전부입니다. order type과 관련된 대부분의 bot bug는 #1이 필요했는데 #3을 선택해서 생깁니다. ("buy"가 "spread가 너무 넓어서 position 없음"으로 바뀜) 또는 #3이 필요했는데 #1을 선택해서 생깁니다. ("buy"가 몇 시간 뒤 잘못된 순간에 체결되는 resting order가 됨)

FOK: 반드시 fill되거나 건너뛰어야 할 때

Fill-or-Kill은 요청한 price 또는 더 나은 price로 전체 order를 즉시 매칭합니다. 전체 size를 즉시 fill할 수 없으면 order는 reject되고 아무 일도 일어나지 않습니다. resting도 없고, partial도 없습니다.

다음과 같은 경우에 FOK를 사용합니다: news-arbitrage 진입(현재가가 아니라 news price에서만 진입하고 싶을 때); partial이 bookkeeping을 흐리게 만들 수 있는 특정 target의 take-profit exit; 전략이 atomic execution을 가정하는 모든 경우.

트레이드오프: FOK는 다른 order type보다 더 자주 reject됩니다. 특히 illiquid book에서는 더 그렇습니다. 항상 fallback path를 두세요-strategy condition을 다시 평가하고 여전히 유효하면 retry하거나, 아니면 넘어가세요.

FAK: partial fill이 허용될 때

Fill-and-Kill(“immediate or cancel”라고도 함)은 지금 가능한 만큼만 매칭한 뒤, fill되지 않은 나머지를 취소합니다. 전체 size를 받을 수도 있고, partial일 수도 있고, 전혀 못 받을 수도 있습니다.

다음과 같은 경우에 FAK를 사용합니다: 특정 price ceiling이 있는 market-buy(mid보다 N cents 위까지 ask를 올려 받기); inventory를 급히 줄여야 할 때 book을 훑는 sweep-the-book sell; "아무 포지션도 없는 것보다 일부 포지션이 낫다"는 전략.

운영상 FOK보다 더 까다롭습니다. bot이 다음 단계를 결정하기 전에 100%를 받았는지 30%만 받았는지 알아야 하기 때문입니다. fill response에는 filled_size 필드가 포함됩니다-항상 읽으세요.

GTC: book에 남겨둘 때

Good-til-Cancelled는 fill되거나 직접 취소할 때까지 price 그대로 book에 남아 있습니다. timeout은 없습니다(v2 API의 다른 order type에는 expiry가 있는 GTD가 포함됩니다).

다음과 같은 경우에 GTC를 사용합니다: entry 대비 +Nc에서 take-profit sell; entry 대비 -Nc에서 stop-loss sell(주의 사항 있음-아래 참조); 양방향 quote를 내는 market-making; bot이 더 좋은 price를 기다릴 의향이 있는 모든 position.

중요한 규칙: GTC는 ≥ 5 shares가 필요합니다. 5 shares 미만의 order는 CLOB에서 Size (X) lower than the minimum: 5로 reject됩니다. 4-share GTC sell을 올리는 bot은 exit 설정에 조용히 실패하고 position을 resolution까지 끌고 가게 됩니다. GTC를 올리기 전에 항상 inventory가 ≥ 5인지 확인하세요; 더 작으면 FAK 또는 ride-to-resolve로 대체하세요.

Limit vs market와 spread tax

모든 Polymarket order는 기술적으로 limit order입니다-bot이 "market buy"라고 부르는 것도 price ceiling을 지정합니다. 차이는 그 price가 best ask인지(사실상 market order처럼 book을 치며 fill됨) 아니면 그보다 낮은지(책에 남음)입니다.

Spread tax는 crossing의 비용입니다-bid 0.45, ask 0.47, mid 0.46. ask를 사고 bid를 파는 왕복 거래는 share당 2 cents를 지불합니다. +3c/-4c target의 60% win-rate 전략에서는 그 2c spread가 profit과 loss를 가르는 차이입니다.

Maker pattern(예: bid 또는 그 아래에 GTC를 걸고 hit되기를 기다림)은 spread를 지불하는 대신 spread를 가져갑니다. 비용은 fill의 불확실성입니다-아예 hit되지 않을 수도 있습니다. 확신이 높은 거래라면 spread를 지불하세요. passive accumulation이라면 book을 work하세요.

우리의 production defaults (FOK buys, GTC sells)

대부분의 production bot이 수렴하는 패턴은 다음과 같습니다:

  • Entries: ask + 0-2 cents에서 FOK. bot이 사기로 결정했다면, 지금 사거나 아니면 건너뛰어야 합니다. entry order를 resting 상태로 두는 일은 거의 가치가 없습니다-buy decision을 유발한 상황은 order가 resting하는 동안보다 더 빨리 변합니다.
  • Take-profit exits: target price에서 GTC. entry fill 직후 즉시 제출합니다. 우리는 시장이 우리에게 오기를 기다리며, bid를 따라 내려가지 않습니다. ≥ 5 shares 조건을 충족해야 합니다.
  • Stop-loss: case-by-case. 가격 변동이 제한적인 느린 전략에서는 GTC가 잘 맞습니다. 빠르게 움직이는 시장에서는 GTC stop이 price를 통과해 버려도 fill되지 않을 수 있습니다. 그런 경우 option-D 방식으로 resolution까지 유지합니다(기억: trader-gtc-sell.md).

이 패턴은 보수적입니다-fill은 줄고 slippage도 줄어듭니다. 더 공격적인 변형은 FAK entry와 FAK exit를 사용해 partial fill을 허용합니다. 하나를 선택하고 일관되게 유지하세요. trade마다 다르게 섞으면 혼란이 생깁니다.

Code: 각 order type을 배치하는 방법

py-clob-client(v0.34.6)로 Python에서 order placement를 참조합니다.

from py_clob_client.client import ClobClient
from py_clob_client.clob_types import OrderArgs, OrderType
c = ClobClient(host="https://clob.polymarket.com", chain_id=137,
               key=PRIVATE_KEY, signature_type=2, funder=PROXY)
c.set_api_creds(creds)

# FOK buy: fill 10 shares at price 0.45 or skip
args = OrderArgs(token_id=TOKEN, price=0.45, size=10, side="BUY")
resp = c.create_and_post_order(args, OrderType.FOK)

# FAK buy: take as much as you can at 0.45 or below
resp = c.create_and_post_order(args, OrderType.FAK)

# GTC sell: rest a sell at 0.85 for 10 shares
sell_args = OrderArgs(token_id=TOKEN, price=0.85, size=10, side="SELL")
resp = c.create_and_post_order(sell_args, OrderType.GTC)

@polymarket/clob-client-v2의 Node에서도 동일합니다: OrderType.FOKclob.OrderType.GTC 등으로 바꾸면 됩니다. method는 createAndPostOrder입니다. negRisk flag(11장)는 multi-outcome market의 두 번째 argument에 설정해야 합니다-빠뜨리면 잘못된 exchange contract로 라우팅됩니다.

자주 묻는 질문

Polymarket에서 FOK는 무엇인가요?
Fill-or-Kill입니다. order는 즉시 전량 fill되거나 취소되어야 하며, partial fill도 없고 book에 남지도 않습니다. 우리는 production trader에서 buy에 기본적으로 FOK를 사용합니다. phantom-fill ambiguity를 없애기 때문입니다(즉, order가 완전히 fill되거나 완전히 사라지며, 절반만 걸려 있지 않음).
Polymarket에서 FAK는 무엇인가요?
Fill-and-Kill입니다(IOC, Immediate-or-Cancel라고도 함). order는 즉시 가능한 liquidity를 모두 가져가고, fill되지 않은 나머지를 취소합니다. partial fill은 허용하지만 resting은 절대 원하지 않을 때 유용합니다. fragmented order book에서는 FOK보다 빠릅니다.
Polymarket에서 GTC는 무엇인가요?
Good-til-Cancelled입니다. order는 fill되거나 직접 취소할 때까지 book에 남습니다. GTC는 maker가 되기 위해(유동성 제공), rebate를 받기 위해, taker fee를 피하기 위해 사용합니다. 우리는 exits에서 spread를 확보하기 위해 production setup의 sell에 GTC를 사용합니다.
내 bot은 limit order와 market order 중 무엇을 사용해야 하나요?
거의 항상 limit order입니다. market order는 taker fee(0.75%~1.80%)와 spread를 지불하고, limit order는 maker rebate( taker fee의 20~25%)를 받습니다. market order를 써야 하는 좋은 이유는 news가 이미 들어왔고, limit이 fill되기 전에 price가 spread 너머로 움직일 것이 분명할 때뿐입니다.
Polymarket은 stop-loss order를 기본 지원하나요?
아니요. stop-loss는 client-side 개념입니다. bot이 price를 감시하다가 trigger condition에 도달하면 market 또는 FAK sell order를 넣습니다. exchange에는 native stop primitive가 없으므로, 로직을 bot 안에서 직접 구현해야 합니다.
order minimum은 어떻게 되나요?
Market order: 최소 notional 1 USD. Limit order: 최소 5 shares. 일부 얕은 market은 매우 작은 order를 reject합니다. SDK는 감지 가능한 특정 error code를 반환하며, 그에 맞춰 size를 다시 조정할 수 있습니다.