Polymarket Bot Tutorial · บทที่ 29 จาก 32

สร้าง Polymarket paper trading engine ก่อนใช้งานจริง: จำลองออเดอร์เทียบกับราคาจริง ติดตาม P&L บังคับใช้ 30-trade gate (win rate >=55%, +PnL) ก่อนนำเงินจริงเข้าระบบ และโค้ด skeleton

บทนี้ครอบคลุมอะไรบ้าง

Paper trading คือขั้นตอนที่ข้ามไม่ได้ระหว่างไอเดียกลยุทธ์กับการ deploy จริง บทนี้คือ paper engine แบบง่ายที่ใช้เป็น gate สำหรับทุก live bot ที่เราเคยปล่อย-ใช้ Python ไม่ถึง 200 บรรทัด ติดตามทุกเทรดใน JSONL diary และใช้ fee/slippage เหมือนเส้นทาง live

  • ทำไมต้อง paper ก่อน live (เสมอ)
  • 30-trade gate (ยืนยันแล้วว่า +55% WR และ positive PnL)
  • การสร้าง paper engine แบบง่าย
  • ติดตาม paper diary ควบคู่กับ live diary
  • เมื่อ paper แตกต่างจาก live (และทำไม)
  • ก้าวสู่ live: ฝากเงินจริงก้อนแรกแบบเล็ก ๆ
  • Code: minimal paper engine

ทำไมต้อง paper ก่อน live (เสมอ)

30-trade paper gate คือวินัยเดียวที่แยก Polymarket traders ที่ทำกำไรได้ 7.6% ออกจาก 84.1% ที่ขาดทุน คนสร้างบอทส่วนใหญ่ข้ามขั้นนี้แล้วต้องจ่ายค่าเรียนรู้เอง เหตุผลที่แท้จริงที่มันเวิร์กคือ paper trading เผย win rate จริงของกลยุทธ์เมื่อมีตัวอย่างมากพอให้แยกสัญญาณออกจากความบังเอิญ

การข้าม paper มีต้นทุนมากกว่าที่ประหยัดได้ กลยุทธ์ที่ดูเหมือนกำไรจาก backtest แต่จริง ๆ แล้วเป็นแค่ coin flip จะเผาผลาญเงิน live $200-500 ก่อนจะได้ข้อมูล live ครบ 30 ตัวอย่าง แต่ถ้า paper-trade เทรดเดียวกัน 30 ครั้ง ต้นทุนคือ $0

paper engine ไม่จำเป็นต้องซับซ้อน สิ่งที่ต้องมีคือความซื่อสัตย์-fee เดียวกัน slippage เดียวกัน และ fill latency เดียวกันกับเส้นทาง live ยิ่งเรียบง่ายยิ่งดี เพราะสิ่งใดที่ไม่จำเป็นมักถูกตัดทิ้ง และทำให้บอทถูกปล่อย live เร็วกว่าที่ควร

30-trade gate (ยืนยันแล้วว่า +55% WR และ positive PnL)

gate นี้เป็นแบบ binary: ต้องมี paper trades ที่ปิดแล้ว 30 ครั้ง, มีเกณฑ์ความสำเร็จที่กำหนดไว้ล่วงหน้า (โดยทั่วไป WR ≥ 55% สำหรับกลยุทธ์ที่มี positive EV) ไม่เช่นนั้นก็ห้าม deploy live

30 คือ sample size ขั้นต่ำที่ช่วงความเชื่อมั่น 95% ของ win rate จริงแคบพอจะบอกได้ว่านี่คือสัญญาณหรือ noise หากต่ำกว่า 30 อัตรา observed 60% อาจสอดคล้องกับอัตราจริง 45-75% ได้ แต่ที่ 30+ ช่วงจะหดลงเหลือราว 50-70%-ยังไม่แคบมาก แต่พอที่จะตัดข้ออ้างว่า "กลยุทธ์นี้ก็แค่ coin flip"

เกณฑ์ความสำเร็จต้องตั้งไว้ก่อนเริ่ม paper run เท่านั้น ถ้ามาตั้งทีหลังจะกลายเป็น post-hoc rationalization (คุณจะหาวิธีตีความเทรด 30 ครั้งว่า "พอใช้ได้" จนได้)

การสร้าง paper engine แบบง่าย

paper engine จริง ๆ ก็คือโค้ด live trading ที่เปลี่ยนฟังก์ชันส่งออเดอร์ให้เป็น simulated fill แทน การจำลองนี้:

  • อ่าน live order book: ใช้ call เดียวกับที่ live bot จะใช้
  • จำลอง fill: ถ้าซื้อแบบ FOK ด้วยราคา ≥ best ask จะ fill ตาม volume-weighted average ของ asks ที่ถูก consume และบันทึก fill ลง paper diary
  • คำนวณ fee: หัก fee เดียวกับที่เส้นทาง live จะจ่าย
  • ติดตาม inventory: เก็บ paper-balance และ paper-positions dictionary แยกต่างหาก

engine ทั้งหมดใส่ได้ใน Python 100-200 บรรทัด วินัยสำคัญคือ ทุก assumption ที่เส้นทาง live ใช้ (fill rate, latency, fee) ต้องถูกจำลองใน paper ด้วย แม้จะดูแย่กว่าความจริงเล็กน้อยก็ตาม-paper ควรเป็น floor ไม่ใช่ ceiling

ติดตาม paper diary ควบคู่กับ live diary

paper trading run จะสร้าง JSONL diary ที่โครงสร้างแยกไม่ออกจาก live diary ที่บอทจะเขียนในภายหลัง ฟิลด์เหมือนกัน: timestamp, action, market_slug, side, size, price, expected_fill_price, simulated_pnl_at_exit

มีสองเหตุผลที่ใช้ format เดียวกัน อย่างแรก เครื่องมือวิเคราะห์ที่อ่าน live trades อยู่แล้ว (PnL reports, win-rate calculators) จะใช้กับ paper ได้โดยไม่ต้องแก้ไข อย่างที่สอง การนำ paper มาเทียบกับ live ภายหลังจะช่วยจับความแตกต่างที่บ่งชี้บั๊ก

เคล็ดลับเชิง production: ให้ paper engine เขียนไปที่ per_trade_paper.jsonl ในไดเรกทอรีเดียวกับ live per_trade.jsonl คำสั่งเดียวเทียบทั้งสองไฟล์ได้: diff -y <(jq -r .market_slug per_trade.jsonl) <(jq -r .market_slug per_trade_paper.jsonl)

เมื่อ paper แตกต่างจาก live (และทำไม)

ความแตกต่างระหว่าง paper กับ live เป็นเรื่องที่หลีกเลี่ยงไม่ได้ มี 3 แบบที่พบบ่อย

  • Slippage: paper fill ที่ snapshot ของ ask แต่ live จะไล่กิน book และอาจ fill แย่ลง 1-2c ในตลาดที่บาง วิธีแก้: จำลอง slippage ใน paper โดยเพิ่มค่าปรับต่อเทรดเท่ากับครึ่งหนึ่งของ spread
  • Fill latency: paper fill ทันที แต่ live ใช้เวลา 200-500ms ซึ่งในช่วงนั้นราคาอาจขยับ วิธีแก้: จำลองโดยรอและอ่าน book ใหม่ก่อนจะ "fill" ใน paper
  • Adverse selection: paper สมมติว่าคุณได้ best ask แต่ live ต้องแข่งกับบอทอื่นที่อาจ lift ask นั้นไปแล้ว วิธีแก้: จำลองได้ยากกว่า; ต้องยอมรับกับตัวเองอย่างตรงไปตรงมาว่า paper มักประเมินผลลัพธ์สูงกว่าความจริง

เมื่อ paper บอกว่า +5%/เดือน แต่ live กลับรันที่ -2%/เดือน ช่องว่างนี้มักมาจากหนึ่งในสามข้อด้านบน ให้ audit ทีละข้อ แทนที่จะสรุปว่ากลยุทธ์ผิดตั้งแต่แรก

ก้าวสู่ live: ฝากเงินจริงก้อนแรกแบบเล็ก ๆ

paper ผ่าน 30 เทรดแล้ว แผน deploy live คือ:

  1. ฝาก $25-50 เป็น smoke-test capital ให้มองว่าเป็นค่าเรียน ถ้าขาดทุน บทเรียนก็คุ้มค่า
  2. รันบอทใน live mode เป็น 5-10 เทรด โดยใช้ขนาด position ขั้นต่ำ (5 shares)
  3. ตรวจว่า fill แต่ละครั้งตรงกับความคาดหวังจาก paper ภายใน 2c หรือไม่ หากต่างมากกว่านั้นให้สืบสวนก่อนเดินต่อ
  4. ถ้า 5-10 live trades ตรงกับ paper ให้ฝากเพิ่ม $200-500 แล้วรัน position ขนาดปกติ
  5. ถ้าไม่ตรง ให้หยุด แก้บั๊ก แล้วเริ่มใหม่จากขั้นตอน 1

ช่องว่างระหว่าง live กับ paper ที่พบบ่อยที่สุดในการ deploy ครั้งแรกคือ fee ที่ลืมคำนวณหรือประเมิน slippage ผิด การแก้ปัญหาเหล่านี้ตรงไปตรงมา สิ่งสำคัญคือจับช่องว่างให้ได้ก่อนขยาย capital

Code: minimal paper engine

Reference: simple paper engine that reads live book + simulates FOK fill.

import json, time
PAPER_BAL = 10_000.0   # USD starting
positions = {}         # token_id -> shares

def paper_fok_buy(token_id, max_price, size):
    book = fetch_book(token_id)
    # Walk asks, fill what we can within max_price
    filled = 0; cost = 0
    for level in book.asks:
        px = float(level["price"])
        if px > max_price: break
        avail = float(level["size"])
        take = min(avail, size - filled)
        filled += take
        cost += take * px
        if filled >= size: break
    if filled < size:
        return {"status":"rejected","filled":0}  # FOK semantics

    global PAPER_BAL
    PAPER_BAL -= cost
    positions[token_id] = positions.get(token_id, 0) + filled

    log_paper({"ts": int(time.time()), "action":"buy",
               "token": token_id, "size": filled, "price": cost/filled})
    return {"status":"matched","filled":filled,"cost":cost}

สิ่งที่ควรเพิ่มใน production: ฟังก์ชัน paper sell (mirror ของ buy), paper GTC simulation (post on book ที่ราคา แล้วจำลอง fill เมื่อ mid ขยับมาถึงราคา), และการ reconcile ระหว่าง paper diary กับ diary ของ "would-have-been" live

คำถามที่พบบ่อย

30-trade gate คืออะไร?
กฎ gating ภายในของเราสำหรับการเปลี่ยนจาก paper ไป live: ต้องมี paper trades ที่ปิดแล้วอย่างน้อย 30 ครั้ง, win rate >= 55%, และ net PnL เป็นบวกหลังหัก slippage หากไม่ผ่านข้อใดข้อหนึ่งก็ต้องอยู่ใน paper ต่อไป เราคิดกฎนี้ขึ้นหลังจากลอง go-live เร็วเกินไปหลายครั้งจนพอร์ตพังในปี 2025
ทำไมต้อง 30 เทรด ไม่ใช่ 100?
เพื่อ statistical power เมื่อมี 30 เทรด win rate 55% จะมีโอกาสประมาณ 70% ที่จะเป็น edge จริงไม่ใช่ noise แต่ถ้ามี 100 เทรด ความมั่นใจจะเพิ่มเป็น 90%+ เราเลือก 30 เป็นขั้นต่ำเพราะการ paper นานเกินไปมักทำให้ overfitting-เทรดเดอร์จะปรับกลยุทธ์นานเกินกว่าจะทดสอบจริง
ถ้าฉันมั่นใจมาก จะข้าม paper trading ได้ไหม?
ช่วงที่มั่นใจนั่นแหละคือช่วงที่ไม่ควรข้าม บอทที่ทำผลงานดีที่สุดบน Polymarket คือบอทที่รันโดยคนที่เคยผิดมาก่อน 30-trade gate มีไว้เพื่อจับกลยุทธ์ที่ดูเหมือนใช่แต่ไม่ใช่ ส่วนกลยุทธ์ของเราเองส่วนใหญ่ตอนแรกก็ไม่ผ่าน paper-นั่นแหละคือคุณค่า
ผลลัพธ์ paper มักตรงกับ live ไหม?
โดยปกติใช่สำหรับกลยุทธ์ที่เคลื่อนไหวช้า (politics, weather) แต่ไม่ใช่สำหรับกลยุทธ์เร็ว (5-min crypto, sports microstructure) ช่องว่างหลักคือ "paper trading ไม่ต้องจ่าย slippage"-fill จริงมักแย่กว่าราคาที่คุณเห็น เรามักหัก discount ผลตอบแทนจาก paper 30-50% ก่อนจะเชื่อว่ามันใช้กับ live ได้ โดยเฉพาะกลยุทธ์เร็ว
จะ implement paper engine ใน Python ยังไง?
Subscribe ไปยัง real CLOB WebSocket ของตลาดที่คุณเทรด เมื่อกลยุทธ์ตัดสินใจ "place an order" ให้บันทึกลงไฟล์ JSONL พร้อมราคา fill ที่คาดว่าจะได้ (bid ปัจจุบันสำหรับ buy, ask ปัจจุบันสำหรับ sell) เก็บ positions แบบ virtual และ mark-to-market เทียบกับราคาจริง engine ทั้งหมดมีประมาณ 200 บรรทัด Python
ควร paper trade นานแค่ไหนก่อน live?
จนกว่าจะผ่าน 30-trade gate หรือ 2-4 สัปดาห์ แล้วแต่ว่าอย่างไหนนานกว่า ถ้าคุณไปถึง gate เร็วเกินไป แปลว่า overfitting ให้ช้าลงและตรวจสอบว่า win rate ทนต่อการเปลี่ยนพารามิเตอร์เล็กน้อยได้จริงหรือไม่ ถ้าหลายเดือนแล้วยังไม่ถึง gate ก็แปลว่ากลยุทธ์อาจไม่มี edge และควรหยุดใช้