Polymarket Bot Tutorial · บทที่ 17 จาก 32
ใช้ order book imbalance ของ Polymarket เป็นสัญญาณราคาในระยะสั้น: อัตราส่วนปริมาณ bid-ask, การคำนวณ microprice, signal half-life และเมื่อไรที่ imbalance bots เอาชนะการส่งคำสั่งแบบสุ่มได้
บทนี้ครอบคลุมอะไรบ้าง
Order-book imbalance คืออัตราส่วนของความลึกฝั่ง buy ต่อความลึกฝั่ง sell บน limit order book บน Polymarket มันมี edge จริงแต่มีอายุสั้น-โดยทั่วไป 5-30 วินาทีก่อนที่ mid จะเคลื่อน บทนี้จะอธิบายรูปแบบการคำนวณและเงื่อนไขที่สัญญาณนี้อาจหลอกเรา
- order book imbalance คืออะไร
- การคำนวณ microprice
- imbalance ในฐานะสัญญาณทิศทาง
- signal half-life บน Polymarket
- เมื่อไรที่ imbalance signals หลอก
- Code: คำนวณ imbalance ทุก WS tick
order book imbalance คืออะไร
Order book imbalance คืออัตราส่วนของ total buy-side depth ต่อ total sell-side depth บน limit order book เมื่อคำนวณที่ top-N levels (โดยทั่วไป N=5) มันจะจับแรงกดดันรวมของเทรดเดอร์ที่ mid-price ยังสะท้อนไม่ถึง
สูตร: imbalance = (Σ bid[i].price × bid[i].size for i in [0..N]) − (Σ ask[i].price × ask[i].size) / (Σ both). ช่วงค่า -1 ถึง +1; ค่าบวกหมายถึงแรงซื้อมากกว่า ค่าลบหมายถึงแรงขายมากกว่า
สัญญาณนี้มีจริงเชิงประจักษ์บน Polymarket แต่มี noise สูง วาฬตัวเดียวสามารถสร้าง imbalance ปลอมได้ 30-60 วินาทีก่อนที่จะถูก arb ออกไป ใช้เป็นหนึ่งในหลาย ๆ feature จะมีประโยชน์ แต่ถ้าใช้เป็น trigger เดียวถือว่าเสี่ยงมาก
การคำนวณ microprice
Microprice คือการปรับปรุงจาก simple mid: เป็นค่าเฉลี่ยถ่วงน้ำหนักของ best bid และ best ask โดยถ่วงด้วยขนาดฝั่งของแต่ละด้าน
microprice = (best_bid × ask_size + best_ask × bid_size) / (bid_size + ask_size)
เมื่อคิวฝั่ง bid ใหญ่มากกว่าฝั่ง ask มาก microprice จะอยู่ใกล้ ask มากกว่า ความคิดคือ: ถ้ามีผู้ซื้อรอมากกว่า โอกาสที่การซื้อถัดไปจะดันราคาไปแตะ ask มีสูงกว่า ดังนั้น fair value จึงควรอยู่ใกล้ ask
Microprice เป็นตัวชี้นำล่วงหน้า 5-30 วินาทีของ mid ที่จะเคลื่อนจริง บอทใน production ใช้มันเป็น reference price สำหรับการตัดสินใจ take-profit แทน mid แบบ naive
imbalance ในฐานะสัญญาณทิศทาง
จากการสังเกตใน production: เมื่อ imbalance พลิกจาก -0.3 ไปเป็น +0.5 ภายใน 10 วินาทีโดยไม่มีข่าวประกอบ mid จะขยับขึ้น 1-2 เซนต์ภายใน 30-60 วินาทีถัดไปประมาณ 65% ของเวลา
นั่นคือ edge จริง แต่จะหายไปอย่างรวดเร็วเมื่อขนาดโพซิชันเล็กเกินไปหลังหักค่าธรรมเนียม ถ้าจะทำกำไร บอทต้อง size ให้พอที่จะเก็บการเคลื่อนไหวลบค่าธรรมเนียมได้ แต่ต้องเล็กพอที่จะไม่ขยับ book เอง โดยทั่วไป order book ของ Polymarket บางพอที่คำสั่งเกิน 50 shares ก็ขยับตลาดได้แล้ว
ควรผสม imbalance กับ feature อื่น ๆ: trade velocity (ยิ่งเทรดเยอะ = สัญญาณจริงมากขึ้น), best-bid เคลื่อนขึ้นจริง (ไม่ใช่แค่ depth เปลี่ยน), ตลาดไม่ได้อยู่ในโหมดที่ขับเคลื่อนด้วยข่าว
signal half-life บน Polymarket
สัญญาณ imbalance เสื่อมลงตามเวลา ข้อมูล production จาก trader ของเรา: imbalance > 0.6 → คาดว่าจะเกิด mid move 1.2c ภายใน 60s, half-life ประมาณ ~30s หลัง 90 วินาที value เชิงพยากรณ์จะกลายเป็นศูนย์
ผลกระทบต่อการออกแบบบอท: ต้องตอบสนองเร็วหรือไม่ก็ข้ามไป บอทที่ใช้เวลา 15 วินาทีในการตัดสินใจเท่ากับกิน edge ไปครึ่งหนึ่งก่อนจะส่งคำสั่ง budget ด้าน latency สำหรับกลยุทธ์ imbalance ควรต่ำกว่า 5 วินาทีตั้งแต่รับสัญญาณจนส่ง FOK
กลยุทธ์ที่ถือโพซิชันนานกว่า half-life (1-2 นาที) กำลังพนันกับสัญญาณถัดไป ไม่ใช่สัญญาณปัจจุบัน ต้องระบุเรื่องนี้ให้ชัดเจน อย่าเผลอถือโพซิชันที่ขับเคลื่อนด้วย imbalance ไปจนถึงวันตัดสินผล
เมื่อไรที่ imbalance signals หลอก
สัญญาณนี้ทำให้เข้าใจผิดเมื่อมีหนึ่งในสามเงื่อนไขต่อไปนี้
- ข่าวขับเคลื่อนราคา: imbalance เป็นผลของข่าวที่คุณยังไม่เห็น การเทรดสวนมันจะขาดทุน; การเทรดตามมันคือ news arbitrage ซึ่งเป็นกลยุทธ์คนละแบบ
- Whale spoofing: คำสั่งขนาดใหญ่ที่วางแล้วลบอย่างรวดเร็วสร้าง imbalance ปลอมชั่วคราว ให้กรองโดยเช็กว่า imbalance คงอยู่ 10+ วินาทีก่อน trigger
- End-of-period rebalancing: market makers ถอน quote เพราะเหตุผลด้าน inventory ไม่ใช่เหตุผลด้านข้อมูล หลายนาทีต่อมาเมื่อ MM re-quote imbalance จะกลับทิศ
ฟิลเตอร์แบบผสมคือ: imbalance > threshold AND trade velocity > baseline AND ไม่มีข่าวใน 5 นาทีที่ผ่านมา ฟิลเตอร์แต่ละตัวลำพังมี false positive มากเกินไป
Code: คำนวณ imbalance ทุก WS tick
อ้างอิง: subscribe การอัปเดต order book ผ่าน WebSocket แล้วคำนวณ imbalance ใหม่ทุก tick
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 แยกตาม token cooldown ช่วยป้องกันการยิงซ้ำจากสัญญาณเดียวกัน ฟิลเตอร์ (ตรวจข่าว, trade velocity) จะเป็นตัว gate การเทรดจริง





