策略設計的上界由執行層決定。一個需要 50 毫秒反應的策略,在一個每秒只能送 40 筆訂單的帳號上不成立;一個需要 0.5¢ 精度的策略,在一個 tick size 是 1¢ 的市場上不存在。這篇把執行層的硬邊界列清楚,後面所有策略的可行性都以此為準。
混合式架構:鏈下撮合、鏈上結算
Polymarket 的 CLOB 是中心化撮合 + 鏈上結算:
- 你用私鑰簽署一筆訂單(EIP-712 結構化簽章),送到 Polymarket 的撮合引擎。
- 撮合在鏈下完成,延遲是網路延遲等級,不是區塊時間。
- 撮合後的成交非同步地在 Polygon 上結算。
第三點對程式設計是關鍵:下單回應成功 ≠ 部位已存在。 你必須等待結算完成才能查到正確持倉。任何「下單後立刻依持倉決定下一步」的邏輯,都會在高頻情境下讀到過期狀態。正確做法是維護一份本地的樂觀部位帳本(下單即扣、失敗即回沖),並用鏈上狀態定期對帳,而不是每次都查鏈。
這也意味著:你的競爭對手不是在跟你比誰的鏈上交易先被打包,而是比誰的訂單先到撮合引擎。這讓地理位置與連線品質變成真實的因素,但也讓「搶跑 mempool」這類鏈上策略在 CLOB 上不適用(在 UMA 預言機那一層則適用,見 提案信譽搶跑)。
Tick size:不是一個常數
不同市場有不同的最小報價單位:0.1、0.01、0.001、0.0001。此外部分高流動性體育市場(世界盃晉級、讓分、大小分、獨贏)被進一步細分到 0.0025(0.25¢)。
三個實務後果:
一、tick size 決定策略的最小 edge。 在 1¢ tick 的市場上,任何小於 0.5¢ 的 edge 都無法透過改善報價來表達——你要嘛跟現有最佳價同價排隊,要嘛跨一整個 tick。這直接與 手續費門檻 交互:政治類在 50¢ 的費用門檻是 1¢,剛好等於一個 tick。「門檻等於一個 tick」代表沒有安全邊際的空間。
二、tick size 會變,而且客戶端會快取錯。 py-clob-client 有一個已知問題(issue 122):客戶端會在本地快取 tick size,市場調整後仍用舊值送單,導致訂單被拒。任何生產系統都要把「tick size 被拒」當成正常路徑處理,而不是例外——收到拒絕就重查、重算、重送。
三、細 tick 的市場適合做市,粗 tick 的市場適合方向。 0.25¢ tick 的體育市場可以做出有意義的兩側報價;0.1 tick 的市場(通常是極冷門或極端價格)連掛單都沒有意義。
最小單量與尾巴部位
CLOB 有 5 股的最小訂單量。這產生一個容易被忽略的問題:
部分成交後留下的殘餘部位若小於 5 股,你無法透過 CLOB 平掉它。
唯一的出路是持有到結算,或者用 merge(若你同時有 YES 和 NO)。對做市策略來說,這代表每個市場都會累積一層無法清理的沉澱部位。這不致命,但做市系統必須把「殘餘部位」當成一個獨立的會計科目,否則你的部位限制計算會慢慢失真。
設計上的解法:把訂單量對齊到 5 的倍數,並且在部分成交後,主動把殘餘量湊到可交易的規模再平倉,而不是試圖平掉零頭。
速率限制:分層的令牌桶
這是很多人第一次做系統時撞到的牆。Polymarket 有兩層限制。
第一層:IP 層(Cloudflare)
| 端點群組 | 限制 |
|---|---|
| CLOB 一般 | 9,000 / 10 秒 |
CLOB 市場資料(/book、/price、/midprice)單筆 | 1,500 / 10 秒 |
| CLOB 市場資料 批次 | 500 / 10 秒 |
| Gamma API 一般 | 4,000 / 10 秒 |
Gamma /events | 500 / 10 秒 |
Gamma /markets | 300 / 10 秒 |
| Gamma 搜尋 | 350 / 10 秒 |
| Data API | 1,000 / 10 秒 |
Gamma /markets 的 300/10s 是最緊的一條,也是最容易撞到的一條——因為掃描全市場找機會的策略(條款掃描、LP 套利)正是靠這個端點。結論很明確:市場元資料要建本地快取+增量更新,不能每輪重抓。
第二層:簽章者層(令牌桶,依做市量分級)
下單與撤單有各自獨立的桶,按近 30 天累計 maker 錢包成交量分級,每三小時重新評估:
| 層級 | 下單持續速率 | 下單爆發容量 | 撤單持續速率 | 撤單爆發容量 |
|---|---|---|---|---|
| Standard | 40 /s | 60 | 80 /s | 120 |
| Copper | 60 /s | 90 | 120 /s | 180 |
| Bronze | 80 /s | 120 | 160 /s | 240 |
| Silver | 200 /s | 300 | 400 /s | 600 |
| Gold | 400 /s | 600 | 800 /s | 1,200 |
| Platinum | 450 /s | 675 | 900 /s | 1,350 |
| Diamond | 525 /s | 787 | 1,050 /s | 1,575 |
| Elite | 600 /s | 900 | 1,200 /s | 1,800 |
三個策略層面的推論:
推論一:撤單額度恰好是下單額度的兩倍。 這不是隨意的設計——它讓「掛單後撤掉」的成本低於「掛單」,也就是交易所在結構上鼓勵做市者頻繁調整報價而非留著陳舊報價。做市策略應該利用這個不對稱:以高頻撤改換取更緊的報價,而不是掛遠一點的單少調整。
推論二:分層是按 maker 量,這是一個正回饋迴圈。 你做市越多,能下越多單,越能做市。對新進者來說 Standard 的 40/s 是硬牆——一個要同時報 100 個市場兩側的做市系統,光是每分鐘更新一輪就要 200 次下單 + 200 次撤單,在 40/s 下是 5 秒一輪。這決定了新系統應該集中在少數市場做深,而不是廣撒。
推論三:爆發容量 ÷ 持續速率 = 1.5 秒,所有層級一致。這是你能維持全速下單的最長時間。任何「事件觸發、瞬間重報所有市場」的設計,都必須在 1.5 秒的爆發預算內完成,之後降到持續速率。這應該直接寫進執行層的排程器:優先權隊列 + 令牌桶模擬,重要的市場先送。
WebSocket vs 輪詢
官方明確建議:即時資料用 WebSocket,不要輪詢;能用批次端點就用批次;追蹤 rate limit 標頭。
這在架構上的意思是訂閱與查詢要分離:
- WebSocket:訂單簿變動、自己的成交回報。這是熱路徑。
- REST 批次:定期對帳、快取重建。這是冷路徑。
- 絕不用 REST 輪詢當作即時價格來源——會撞 IP 限制,而且延遲不可控。
WebSocket 帶來的最大風險是靜默斷線:連線看似還在,但沒有訊息進來,你的系統以為市場沒動,繼續用陳舊的報價掛單,而市場已經跑掉了。這是做市系統最典型的死法。解法是 heartbeat + dead-man switch,見 系統藍圖。
訂單類型與生命週期
- 限價單(GTC):掛在簿上,是 maker,零手續費,且有資格領流動性獎勵。
- 市價單 / FOK 型:對現有流動性成交,未成交部分直接取消而非留在簿上。是 taker,付費。
- 撮合成功後非同步鏈上結算,需等待結算完成才能驗證持倉。
maker/taker 的區分在 Polymarket 上比在多數交易所重要得多,因為費率差是 0 vs φ·p(1−p),而且 maker 還有回饋與流動性獎勵兩層收入。這在 下一篇 會量化成一個明確的決策式:掛單的價值恰好等於 φ·p(1−p) 加上獎勵,所以你願意為了掛單承受的「不成交風險」有一個精確上限。
這篇的重點
| 硬邊界 | 數值 | 策略含意 |
|---|---|---|
| tick size | 0.1 / 0.01 / 0.001 / 0.0001,部分體育 0.0025 | 決定最小可表達 edge;會變,客戶端會快取錯 |
| 最小訂單 | 5 股 | 殘餘部位無法平倉,要獨立記帳 |
Gamma /markets | 300 / 10s | 全市場掃描必須快取+增量 |
| 下單(Standard) | 40 /s,爆發 60 | 新系統只能做深、不能做廣 |
| 爆發持續時間 | 1.5 秒(所有層級) | 事件觸發的重報必須有優先權排程 |
| 撤單 : 下單 | 2 : 1 | 結構上鼓勵高頻改價 |
| 結算 | 非同步 | 下單成功 ≠ 持倉存在,要維護樂觀帳本 |
下一步:手續費即變異數稅。