ตลาดพยากรณ์ดูเหมือนเป็นสิ่งที่ง่ายที่สุดในโลกสำหรับการแบ็กเทสต์ ราคาอยู่ระหว่าง [0, 1] ผลตอบแทนคือ 1 ดอลลาร์หรือไม่จ่ายเลย ไม่มีเลเวอเรจ ไม่มีฟันดิง ไม่มีเบซิส ไม่มีความประหลาดของ perpetual swap ตอน 00:00 UTC เรามีแบ็กเทสเตอร์ที่รองรับคริปโตเพิร์ป พร้อมค่าธรรมเนียม ฟันดิง และอิมแพกต์อยู่แล้ว แผนคือใช้เวลา 2 วันปรับมัน แล้วเริ่มสร้างกลยุทธ์
แต่ใช้เวลาไป 8 วัน นี่คือบันทึกตามลำดับคร่าว ๆ รวมถึงวันที่เส้นทุนดูยอดเยี่ยม และยอดเยี่ยมนั้นก็เป็นภาพลวงตา
วันที่ 1: อะแดปเตอร์ที่น่าจะทำได้ง่าย ๆ
การแมปขั้นแรกเป็นแบบหนึ่งต่อหนึ่งและดูลงตัว ตลาดหนึ่งแห่งคือหนึ่งตราสาร ราคา YES ก็คือราคา ซื้อ YES คือเปิดสถานะ Long ซื้อ NO คือเปิดสถานะ Short การตัดสินผลคือการปิดสถานะโดยบังคับที่ 1.00 หรือ 0.00 ป้อนอนุกรมราคาทุกชั่วโมงเข้า event loop เดิม เท่านี้ก็เสร็จ
การแมปนี้อยู่รอดได้ประมาณ 90 นาทีหลังได้สัมผัสข้อมูลจริง สิ่งแรกที่พังคืออนุกรมผลตอบแทน ชั้นบริหารความเสี่ยงทั้งหมดของเรา ทั้งการกำหนดขนาดสถานะ การกำหนดเป้าความผันผวน และการรายงาน Sharpe ตั้งอยู่บนสมมติฐานว่ามี log return ของตราสารที่ดำเนินต่อเนื่อง ตลาดที่ราคาจาก 0.04 ลงไป 0.00 มี log return ที่นิยามไม่ได้ แต่มีการขาดทุนทั้งหมดที่นิยามได้ และตลาดที่ราคาอยู่ 0.04 เมื่อเหลือ 3 วันก่อนตัดสินผล เป็นคนละสิ่งกับตลาดที่ราคา 0.04 เมื่อเหลือ 4 นาที แม้ทั้งสองแถวจะระบุว่า 0.04
สุดท้ายเราเปลี่ยนพารามิเตอร์ของอนุกรมทั้งหมดให้ยึดเวลาที่เหลือก่อนตัดสินผลแทนเวลาตามนาฬิกา และคิด PnL เป็นผลลัพธ์ปลายทางแทนการตีราคาตามตลาด นั่นเป็นทางเลือกที่ถูกต้อง และทำให้โค้ดรายงานทุกส่วนที่ต่อจากนั้นใช้ไม่ได้
วันที่ 2: สูตรค่าธรรมเนียมคือกลยุทธ์
ค่าธรรมเนียมซื้อขายของ Kalshi ไม่ใช่การหักเป็น basis point แต่แปรผันตามกำลังสองของราคา โดยประมาณ 0.07 × contracts × P × (1−P) และปัดขึ้นเป็นเซนต์ในระดับคำสั่งซื้อขาย นั่นหมายความว่าค่าธรรมเนียมสูงสุดตรงจุดที่ตลาดเสี่ยงหัวก้อยน่าสนใจที่สุด และแทบไม่เสียอะไรเมื่อราคาอยู่ใกล้ปลายช่วง
| ราคา | ค่าธรรมเนียมต่อสัญญา | Edge ที่ต้องมี (จุดความน่าจะเป็น) | ค่าธรรมเนียมคิดเป็น % ของเงินเดิมพัน |
|---|---|---|---|
| 5¢ | 0.33¢ | 0.33 | 6.7% |
| 10¢ | 0.63¢ | 0.63 | 6.3% |
| 25¢ | 1.31¢ | 1.31 | 5.3% |
| 50¢ | 1.75¢ | 1.75 | 3.5% |
| 75¢ | 1.31¢ | 1.31 | 1.8% |
| 90¢ | 0.63¢ | 0.63 | 0.7% |
| 95¢ | 0.33¢ | 0.33 | 0.35% |
ดูคอลัมน์ที่ 3 ซึ่งเป็นตัวเลขสำคัญ: ถ้าซื้อที่ 50¢ แล้วถือจนตัดสินผล การจะคุ้มทุนต้องประเมินความน่าจะเป็นให้สูงกว่าตลาด 1.75 จุด ไม่ใช่สูงกว่า 1.75 เปอร์เซ็นต์เมื่อเทียบสัดส่วน แต่สูงกว่า 1.75 จุดเต็ม ๆ ถ้าออกจากสถานะก่อนตัดสินผลแทนการถือไว้ คุณจะเสียค่าธรรมเนียมนี้สองครั้ง บวกสเปรดอีก
ในอดีต CLOB ของ Polymarket มีโครงสร้างค่าธรรมเนียมที่ต่างออกไปมาก โดยค่าธรรมเนียมในการซื้อขายแทบเป็นศูนย์ ทำให้ต้นทุนทั้งหมดไปอยู่ที่สเปรดและความลึกของตลาด ดังนั้นกลยุทธ์ตรรกะเดียวกันจึงมีเศรษฐศาสตร์ต่างกันอย่างสิ้นเชิงตามแพลตฟอร์ม และการเปรียบเทียบข้ามแพลตฟอร์มที่ใช้โมเดลค่าธรรมเนียมเดียวกันก็เป็นเรื่องแต่ง ตอนนี้เราใช้ฟังก์ชันค่าธรรมเนียมแยกตามแพลตฟอร์ม แทนการใช้ค่าคงที่ตัวเดียว
ถ้าจะอ่านเพียงบรรทัดเดียวในรายงานแบ็กเทสต์ตลาดพยากรณ์ ให้อ่านบรรทัดค่าธรรมเนียมที่ระบุเป็นจุดความน่าจะเป็น กลยุทธ์ที่อ้างว่าพยากรณ์ได้เปรียบ 1.2 จุดในตลาดราคา 50¢ คือกลยุทธ์ที่ขาดทุนบน Kalshi ตั้งแต่ยังไม่รวมต้นทุนอื่นแม้แต่รายการเดียว ข้อมูลนี้ควรแสดงให้เห็นตั้งแต่หน้าแรก ไม่ใช่ปล่อยให้ผู้อ่านคำนวณเอง
วันที่ 3: สมุดคำสั่งซื้อขายเป็นขั้นบันได และมีระดับสั้น ๆ
โมเดลอิมแพกต์ของเราเป็นฟังก์ชันรากที่สองซึ่งปรับเทียบกับสมุดคำสั่งซื้อขาย BTC perp รูปร่างของโมเดลนี้ใช้ไม่ได้กับตลาดนี้ เมื่อสินทรัพย์ราคา $1 มี tick 1¢ ระดับราคาที่เป็นไปได้ทั้งสมุดมีเพียง 99 ระดับ และตลาดสภาพคล่องปานกลางอาจมีสัญญาค้างอยู่บนระดับราคาสูงสุดเพียงไม่กี่ร้อยสัญญา ก่อนจะเจอช่องว่างของราคา
นี่คือตัวอย่างภาพสมุดคำสั่งซื้อขายฝั่ง YES จากตลาดข้อมูลเศรษฐกิจที่เราสุ่มเก็บไว้ ก่อนตัดสินผลประมาณ 30 ชั่วโมง:
| ระดับราคา | ขนาด (สัญญา) | ต้นทุนสะสมของการซื้อ |
|---|---|---|
| 42¢ | 310 | 310 สัญญา @ ราคาเฉลี่ย 42.0¢ |
| 43¢ | 85 | 395 สัญญา @ ราคาเฉลี่ย 42.2¢ |
| 45¢ | 140 | 535 สัญญา @ ราคาเฉลี่ย 42.9¢ |
| 49¢ | 600 | 1,135 สัญญา @ ราคาเฉลี่ย 46.1¢ |
คำสั่งซื้อ 1,000 สัญญา หรือความเสี่ยง 500 ดอลลาร์ ซึ่งเป็นเศษเสี้ยวเล็กน้อยในโลกคริปโต ทำให้ราคาเฉลี่ยที่ได้ขยับไป 4 เซนต์ 4 เซนต์นั้นมากกว่าค่าธรรมเนียมถึงสองเท่า ไม่มีฟังก์ชันเรียบ ๆ ให้ปรับเข้ากับข้อมูลตรงนี้ คุณต้องไล่ซื้อทีละระดับในสมุดคำสั่ง ไม่อย่างนั้นก็เป็นการเดาสุ่ม เราลบโมเดล sqrt สำหรับสินทรัพย์ประเภทนี้ทิ้ง แล้วเขียนตัวไล่ระดับราคาในสมุดขึ้นมาโดยตรง ซึ่งทำงานช้ากว่าแต่ถูกต้อง
ช่วงหนึ่งผมจับได้ว่าตัวเองหงุดหงิดที่ตลาดพวกนี้ "เล็กจนไม่มีความหมาย" ตลาดเล็กเพราะสิ่งที่กำลังตั้งราคาคือคำถามจริงในโลกจริงเพียงข้อเดียวที่มีเส้นตาย และคนที่มีความเห็นเรื่องจำนวนผู้ขอรับสวัสดิการว่างงานครั้งแรกของสหรัฐฯ ในวันพุธก็มีอยู่จำกัด ขนาดคือตัวตลาด การบ่นเรื่องนี้ก็เหมือนบ่นว่าโต๊ะโป๊กเกอร์นั่งได้แค่ 9 คน
วันที่ 4: วันที่เส้นทุนสวยงามเหลือเกิน
Sharpe 4.1 จากตลาด 1,400 แห่ง เส้นเรียบเนียน นักวิจัยทุกคนควรรู้สึกใจหายเมื่อเห็นตัวเลขนี้ และในที่สุดผมก็รู้สึกแบบนั้น หลังจากแคปหน้าจอไปแล้วประมาณ 40 นาที
บั๊กอยู่ในตัวรีแซมเพิล ประวัติราคาของตลาดสภาพคล่องต่ำกลับมาพร้อมเวลาที่ไม่สม่ำเสมอ เราจึงจัดดัชนีใหม่ให้ลงกริดรายชั่วโมงสม่ำเสมอ จุดสุดท้ายของอนุกรมที่เก็บถาวรทุกชุดคือราคาชำระตลาด 1.00 หรือ 0.00 การจัดดัชนีใหม่ของเราใช้การเติมค่าจากเพื่อนบ้านที่ใกล้ที่สุดโดยไม่จำกัดทิศทาง ดังนั้นตลาดใดก็ตามที่ซื้อขายครั้งสุดท้ายก่อนตัดสินผลหลายชั่วโมง ราคาชำระตลาดจึงถูกส่งต่อย้อนกลับข้ามช่วงว่าง โมเดลอ่านคำตอบของวันพรุ่งนี้ในแถวของวันนี้พอดี สำหรับตลาดสภาพคล่องต่ำที่สามารถเพิ่มขนาดสถานะได้โดยไม่ชนข้อจำกัดความลึก
การเติมค่าจากเพื่อนบ้านที่ใกล้ที่สุดใช้ได้กับตราสารที่ซื้อขายต่อเนื่อง แต่ถ้าค่าที่สังเกตได้ครั้งสุดท้ายคือค่าความจริงสุดท้าย มันก็กลายเป็นเครื่องจักรที่มองอนาคต เราเพิ่ม assert ให้แน่ใจว่าการเติมค่าทุกครั้งเดินหน้าเท่านั้น และติดแท็กแถวราคาชำระตลาดพร้อมตัดแถวนั้นออกจากการคำนวณฟีเจอร์ทั้งหมด assert นี้ยาว 9 บรรทัด และเป็นโค้ดที่มีค่าที่สุดที่เราเขียนตลอดสัปดาห์
วันที่ 5–6: ตลาด 1,412 แห่ง แต่มีการเดิมพันจริงราว 180 ครั้ง
ขนาดตัวอย่างในตลาดพยากรณ์เป็นกับดักที่หน้าตาน่าไว้ใจ เมื่อตลาด 1,412 แห่งตัดสินผล คุณก็รู้สึกเหมือนมีข้อมูลสังเกต 1,412 จุด แล้วคำนวณ t-stat ตามนั้น แต่เกม NFL 14 เกมในวันอาทิตย์เดียวกันเผชิญสภาพอากาศ รายงานผู้เล่นบาดเจ็บ และกระแสเงินเดิมพันร่วมกัน ตลาดเลือกตั้งระดับรัฐ 51 แห่งต่างก็รับผลจากกระแสการเมืองระดับชาติเดียวกัน ส่วนคำถาม "X จะเกิดขึ้นภายใน 31 มีนาคมไหม" กับ "X จะเกิดขึ้นภายใน 30 มิถุนายนไหม" ก็เป็นการเดิมพันเดียวกันที่มีวันหมดอายุต่างกันและตัดสินผลพร้อมกัน
เราจัดกลุ่มตลาดตามแหล่งที่มาของเหตุการณ์และวันที่ตัดสินผล แล้วได้จำนวนตัวอย่างอิสระที่แท้จริงประมาณ 180 ซึ่งไม่พอจะแยก Edge จริงออกจากสัญญาณรบกวนในระดับผลกระทบที่เรากำลังศึกษา และการทำ bootstrap แยกตามตลาดก็แก้ปัญหานี้ไม่ได้ เพราะต้องสุ่มตัวอย่างคลัสเตอร์ใหม่แทนการสุ่มแต่ละแถว ถ้าทำพลาด ความมีนัยสำคัญจะสูงเกินจริง 2 หรือ 3 เท่าโดยไม่มีใครสังเกต
วันที่ 7: การตัดสินผลก็มีการกระจายความน่าจะเป็นเช่นกัน
เรื่องที่เราไม่ได้จำลองไว้เลยและต้องเรียนรู้จากประสบการณ์ตรง:
- การตัดสินผลก่อนกำหนด. ตลาดคำถามว่า "จะเกิดขึ้นภายใน 31 ธันวาคมไหม" อาจตัดสินผลตั้งแต่ 4 สิงหาคม หากเหตุการณ์เกิดขึ้นจริง เงินทุนของคุณจะกลับมาเร็วขึ้น และระยะเวลาถือครองก็ไม่เคยเป็นไปตามที่ชื่อสัญญาบอกไว้
- ข้อพิพาท. ตลาดที่ตัดสินผลโดย oracle มีช่วงเวลาให้ยื่นคัดค้าน สถานะอาจค้างอยู่หลายวันหลังเกิดเหตุการณ์ และในบางกรณีผลลัพธ์อาจพลิกจากการอ่านที่ดูชัดเจน
- การยกเลิกสัญญา. หากข้อมูลจากแหล่งอ้างอิงคลุมเครือ ตลาดจะถูกยกเลิกและคืนเงินให้ทุกคน ในตัวอย่างของเรามีไม่ถึง 1% ของตลาด แต่กรณีเหล่านี้กระจุกตัวอยู่ในคำถามคลุมเครือแบบที่โมเดลมองว่าตั้งราคาผิดพอดี
- เงินทุนถูกล็อก. Edge 3 จุดที่ทำได้จริงใน 90 วัน เทียบกับ Edge 3 จุดที่ทำได้ใน 6 ชั่วโมงไม่ได้ และแบ็กเทสต์ที่รายงาน Edge รวมโดยไม่หารด้วยเวลาที่เงินทุนถูกใช้ จะเลือกแบบที่ใช้เวลานานกว่าเสมอ
เราเพิ่มต้นทุนการถือครองและการสุ่มคลาดเคลื่อนของวันที่ตัดสินผลเข้าไปในตัวจำลอง ไม่มีอย่างไหนแม่นยำ แต่ทั้งคู่ดีกว่าการสมมติโดยปริยายว่าการตัดสินผลเกิดตรงวันที่ระบุเป๊ะอย่างแน่นอน
วันที่ 8: สิ่งที่เราจะข้าม และสิ่งที่เราจะทำก่อน
- ข้ามโครงสร้างพื้นฐานที่อิงผลตอบแทนไปเลย. อย่าปรับชั้นบริหารความเสี่ยงแบบกำหนดเป้าความผันผวนให้เข้ากับตราสารที่มีผลตอบแทนปลายทาง เขียนชั้นกำหนดขนาดเดิมพันที่คิดเป็นความน่าจะเป็นและเงินเดิมพัน เราเสียเวลาไป 2 วันเพื่อพยายามดัดของเดิมให้ใช้ได้
- สร้างฟังก์ชันค่าธรรมเนียมก่อนสร้างกลยุทธ์. พิมพ์กราฟ Edge คุ้มทุนสำหรับทุกแพลตฟอร์มที่ตั้งใจจะซื้อขาย แล้วติดไว้เหนือโต๊ะทำงาน มันตัดไอเดียได้ประมาณครึ่งหนึ่งก่อนจะเสียเวลาแบ็กเทสต์
- ไล่ระดับราคาในสมุดคำสั่งตั้งแต่วันแรก. โมเดลอิมแพกต์แบบพาราเมตริกที่ยกมาจากตลาดซื้อขายต่อเนื่องจะผิดในแบบที่ทำให้คุณคิดว่าผลงานดีกว่าความจริง
- จัดกลุ่มก่อนนับ. ตัดสินใจว่าจะใช้คีย์ใดจัดกลุ่มเพื่อหาขนาดตัวอย่างที่แท้จริงพร้อมกับกำหนดตลาดที่จะศึกษา อย่ารอจนได้ Sharpe ที่ชอบแล้วค่อยคิด
- ตั้ง assert ตรวจทิศทางการเติมค่า. ใส่ 1 บรรทัดต่อการ join หากอนุกรมจบด้วยค่าความจริง ให้ถือว่าการเติมค่าย้อนหลังเป็นบั๊กตั้งแต่ต้น แทนที่จะหวังว่าจะสังเกตเห็นตอนรีวิว
8 วันที่ใช้ไปคุ้มค่า ส่วนใหญ่เป็นเพราะตลาดพยากรณ์ตัดความคลุมเครือที่ทำให้เราหลอกตัวเองกับแบ็กเทสต์คริปโตได้ง่ายออกไป ไม่มีอัตราฟันดิงให้ปัดเรื่อง ไม่มีข้อถกเถียงเรื่องธรรมเนียมการใช้ mark price มีเพียงคำถาม เส้นตาย และคำตอบ เมื่อแบ็กเทสต์ผิดในตลาดนี้ เราชี้ได้เลยว่าผิดตรงไหน
← บทความทั้งหมด

