DCC-GARCH: สหสัมพันธ์แบบพลวัตสำหรับการเทรดคู่และความเสี่ยงพอร์ต
ลองถามเดสก์เทรดคริปโตส่วนใหญ่ว่าสหสัมพันธ์ระหว่าง BTC กับ ETH คือเท่าไร คุณจะได้ตัวเลขเดียว — 0.8 หรืออาจจะ 0.75 — ที่คำนวณจากช่วงเวลาที่ไม่มีใครจำได้ว่าทำไมถึงเลือก ตัวเลขนั้นคือคำโกหก หรืออย่างน้อยก็เป็นการทำให้เรื่องซับซ้อนดูง่ายเกินไปอย่างอันตราย สหสัมพันธ์แบบตัวอย่าง (sample correlation) เป็นค่าเฉลี่ยตลอดช่วงเวลาที่โครงสร้างความสัมพันธ์ที่แท้จริงเคลื่อนไหวอยู่ตลอด ในตลาดที่สงบ BTC กับ ETH จะแยกตัวออกจากกันมากพอที่จะทำให้คู่เทรดแบบ market-neutral ดูน่าสนใจ แต่ในเหตุการณ์ liquidation cascade มันจะล็อกเข้าหากันและเข้าหาทุกสิ่งทุกอย่าง และความหลากหลาย (diversification) ที่คุณจ่ายเงินไปเพื่อให้ได้มาก็จะระเหยหายไปในช่วงเวลาที่คุณต้องการมันที่สุดพอดี
นี่ไม่ใช่ผลกระทบที่ละเอียดอ่อนแต่อย่างใด ลองดูช่วงตลาดร่วงในปี 2022 ช่วงไหนก็ได้ — การล่มสลายของ LUNA ในเดือนพฤษภาคม การคลี่คลายสถานะของ 3AC ในเดือนมิถุนายน หรือการล่มสลายของ FTX ในเดือนพฤศจิกายน — คุณจะเห็นสหสัมพันธ์เฉลี่ยแบบคู่ (average pairwise correlation) ของ 20 โทเคนอันดับต้น ๆ เคลื่อนจากช่วง 0.4-0.6 ไปสู่ 0.9+ ภายในไม่กี่วัน สหสัมพันธ์ไม่ใช่ค่าคงที่ที่บางครั้งถูกประมาณผิดพลาด แต่มันคืออนุกรมเวลาที่มีพลวัตของตัวมันเอง มีการรวมกลุ่ม (clustering) ของตัวมันเอง และมีระบอบ (regime) ของตัวมันเอง การปฏิบัติต่อมันเป็นสเกลาร์คือความผิดพลาดแบบหลายตัวแปรที่เทียบเท่ากับการสมมติว่าความผันผวนคงที่ — ความผิดพลาดที่เราใช้เวลาไปแล้วใน ตอนที่ 1 ของซีรีส์นี้ เพื่อรื้อทำลายมันสำหรับสินทรัพย์เดี่ยว
บทความนี้เป็นตอนที่ 3 ของซีรีส์ความผันผวนสี่ตอน ตอนที่ 1 สร้างแบบจำลอง GARCH(1,1) แบบตัวแปรเดี่ยวด้วยไลบรารี arch และแสดงให้เห็นว่าความผันผวนรวมกลุ่มและกลับสู่ค่าเฉลี่ย (mean-revert) อย่างไร ตอนที่ 2 เพิ่มความไม่สมมาตร (GJR-GARCH, EGARCH) และ Student-t innovations เพื่อจับ leverage effect และหางอ้วน (fat tails) ในตอนนี้เราจะขยับไปสู่แบบหลายตัวแปร เราจะสร้างแบบจำลองของ เมทริกซ์ความแปรปรวนร่วมแบบมีเงื่อนไขทั้งหมด ขณะที่มันวิวัฒนาการ โดยใช้แบบจำลอง Dynamic Conditional Correlation (DCC) ของ Engle สิ่งนี้ให้สองอย่างที่สหสัมพันธ์แบบสเกลาร์ไม่มีทางให้ได้ — อัตราส่วนป้องกันความเสี่ยงแบบพลวัตสำหรับการเทรดคู่ และความแปรปรวนของพอร์ตที่แปรผันตามเวลาอย่างตรงไปตรงมาสำหรับการจัดสรรตามความเสี่ยง ตอนที่ 4 จะปิดท้ายซีรีส์ด้วยการทดสอบย้อนหลัง (backtest) แบบ volatility-targeted ที่ผูกการพยากรณ์แบบตัวแปรเดี่ยวและหลายตัวแปรเข้ากับกฎการกำหนดขนาดสถานะ (position-sizing)
เราสมมติว่าคุณได้อ่านตอนที่ 1 และ 2 มาแล้ว ดังนั้นเราจะไม่อนุพันธ์ GARCH แบบตัวแปรเดี่ยวซ้ำอีก หากคุณต้องการพฤติกรรม หาง (tail) ร่วม — ความน่าจะเป็นที่สินทรัพย์สองตัวจะทะลุควอนไทล์ 1% ของมันพร้อมกัน — นั่นเป็นคำถามของ copula ซึ่งเราครอบคลุมไว้ใน แบบจำลอง Copula สำหรับความเสี่ยงร่วม DCC และ copula เสริมกันและกัน copula ให้โครงสร้างการพึ่งพากันของหาง (tail-dependence) แบบคงที่แต่ยืดหยุ่น ในขณะที่ DCC ให้ อนุกรมเวลาที่จัดการได้ ของเมทริกซ์สหสัมพันธ์ทั้งหมด บทความนี้ว่าด้วยอย่างหลัง
ทำไมสหสัมพันธ์แบบคงที่ถึงพังในคริปโต
ก่อนเข้าเรื่องกลไก มาระบุให้ชัดเจนว่าอะไรที่ล้มเหลว สหสัมพันธ์แบบตัวอย่างเดี่ยว ตลอดหน้าต่าง ประมาณค่า
สิ่งนี้แฝงข้อสมมติสามข้อไว้ ซึ่งทั้งหมดผิดสำหรับคริปโต
- ความคงที่ของการพึ่งพากัน (stationarity) หน้าต่างมี ที่แท้จริงเพียงค่าเดียว ในความเป็นจริงการพึ่งพากันมีระบอบ (regimes) — ระบอบตลาดสงบใกล้ 0.5 และระบอบตึงเครียดใกล้ 0.95 — และ ผสมสิ่งเหล่านี้เข้าด้วยกันจนกลายเป็นค่ากลางที่ไม่มีความหมาย
- ความผันผวนของขอบเขต (marginal) คงที่ สหสัมพันธ์แบบ Pearson คือความแปรปรวนร่วมที่ถูกทำให้เป็นมาตรฐาน (normalized covariance) ถ้า และ เองก็เคลื่อนไหวอยู่ (ซึ่งมันเคลื่อนไหว — นี่คือสมมติฐานทั้งหมดของตอนที่ 1 และ 2) ดังนั้นแม้แต่ความแปรปรวนร่วม คงที่ ก็ยังผลิตสหสัมพันธ์ ที่แปรผันตามเวลา และในทางกลับกัน คุณไม่สามารถแยกทั้งสองออกจากกันได้โดยไม่มีแบบจำลองความผันผวนอยู่ข้างใต้
- ความสมมาตรข้ามทิศทางตลาด สหสัมพันธ์เพิ่มขึ้นในช่วงตลาดร่วงมากกว่าในช่วงตลาดขึ้น นี่คือญาติแบบหลายตัวแปรของ leverage effect หน้าต่างแบบ rolling ไม่สามารถแสดงสิ่งนี้ได้โดยไม่ต้องสั้นลงจนกลายเป็นสัญญาณรบกวนล้วน ๆ
การแก้ปัญหาแบบ rolling-window — คำนวณ ใหม่ตลอด 30 หรือ 60 วันที่ผ่านมา — เป็นการแลกปัญหาหนึ่งกับอีกปัญหาหนึ่ง หน้าต่างสั้นตอบสนองไว แต่มีสัญญาณรบกวนมากและตามหลังจุดเปลี่ยนที่แท้จริง หน้าต่างยาวมีเสถียรภาพแต่ล้าสมัย ที่แย่กว่านั้น เมทริกซ์สหสัมพันธ์แบบ rolling ตลอด สินทรัพย์ ไม่ได้รับประกันว่าจะยังคง positive semi-definite เมื่อคุณเริ่ม shrink หรือแก้ไขมัน ซึ่งทำให้ตัวจัดสรรที่ใช้งานต่อจากมันพังทั้งหมด เราต้องการแบบจำลองที่ (ก) ขับเคลื่อนด้วยกระบวนการความผันผวนที่เหมาะสมต่อสินทรัพย์แต่ละตัว (ข) ผลิตเมทริกซ์สหสัมพันธ์ที่ถูกต้องในทุกขั้นตอนโดยธรรมชาติของโครงสร้าง และ (ค) มีพารามิเตอร์ที่เราสามารถประมาณด้วย maximum likelihood แทนที่จะเลือกความยาวหน้าต่างแบบสุ่มเดา แบบจำลองนั้นคือ DCC-GARCH
ปัญหาแบบหลายตัวแปร: เมทริกซ์ความแปรปรวนร่วมแบบมีเงื่อนไข
ให้ เป็นเวกเตอร์ของผลตอบแทนสำหรับ สินทรัพย์ ณ เวลา โดยมีค่าเฉลี่ยแบบมีเงื่อนไข (มักเป็นเพียงค่าคงที่หรือเทอม AR เล็ก ๆ) และส่วนตกค้าง เราสมมติว่า
โดยที่ คือ เมทริกซ์ความแปรปรวนร่วมแบบมีเงื่อนไข ขนาด ที่กำหนดโดยชุดข้อมูล และ คือการแจกแจงแบบมีเงื่อนไขบางแบบ (Gaussian หรือดีกว่าสำหรับคริปโตคือ multivariate Student-t) ทุกอย่างในการสร้างแบบจำลองความผันผวนแบบหลายตัวแปรคือคำตอบที่แตกต่างกันสำหรับคำถามเดียว: คุณจะกำหนดพารามิเตอร์พลวัตของ อย่างไรให้มันยังคง symmetric positive definite ในทุกขั้นตอนโดยไม่มีการระเบิดของจำนวนพารามิเตอร์?
คำตอบแบบคลาสสิกสองแบบแสดงให้เห็นว่าทำไมปัญหานี้ถึงยาก
VECH
แบบจำลอง VECH (Bollerslev, Engle, Wooldridge 1988) เขียน half-vectorization ของ เป็นฟังก์ชันเชิงเส้นของส่วนตกค้างยกกำลังสองในอดีตและความแปรปรวนร่วมในอดีต
โดยที่ เรียงสามเหลี่ยมล่างของเมทริกซ์สมมาตรเข้าเป็นเวกเตอร์ที่มีความยาว นี่เป็นแบบทั่วไปที่สุด — ทุกความแปรปรวนและความแปรปรวนร่วมขึ้นกับทุกความแปรปรวนและความแปรปรวนร่วมในอดีต — และไร้ประโยชน์ที่สุดเมื่อเกิน สำหรับ สินทรัพย์ และ แต่ละตัวมีขนาด ที่ นั่นคือเมทริกซ์ สองตัว ประมาณ 450 พารามิเตอร์ บวกกับข้อจำกัด positive-definiteness ที่ลำบากแม้แต่จะเขียนออกมา พื้นผิว likelihood เป็นหนองน้ำเลยทีเดียว
BEKK
แบบจำลอง BEKK (Engle & Kroner 1995) รับประกัน positive definiteness โดยธรรมชาติของโครงสร้างด้วยรูปแบบกำลังสอง (quadratic form)
โดยที่ เป็นสามเหลี่ยมบน เนื่องจากทุกเทอมเป็น quadratic form โดยอัตโนมัติตราบใดที่ BEKK ประหยัดพารามิเตอร์มากกว่า VECH แต่ก็ยังขยายตามขนาดเป็น พารามิเตอร์ — เมทริกซ์ และ แต่ละตัวมีขนาด สำหรับ คุณกำลังประมาณพารามิเตอร์ราว 200+ ตัวพร้อมกันด้วย MLE บนข้อมูลคริปโตรายวันที่มีสัญญาณรบกวนสูง โดยไม่มีการรับประกันว่าตัวหาค่าเหมาะสมที่สุดจะลู่เข้าสู่สิ่งที่มีความหมายใด ๆ ในทางปฏิบัติ BEKK แบบเต็มรูปแบบจำกัดอยู่ที่ และแม้กระทั่งตอนนั้นผู้คนก็ใช้ข้อจำกัดแบบ "diagonal" หรือ "scalar" ซึ่งทิ้งพลวัตข้ามสินทรัพย์ส่วนใหญ่ไป
นี่คือ คำสาปแห่งมิติ (curse of dimensionality) สำหรับ GARCH แบบหลายตัวแปร: จำนวนพารามิเตอร์เพิ่มขึ้นแบบกำลังสอง แต่ปริมาณข้อมูลในข้อมูลไม่ได้เพิ่มตาม คุณจะหมดองศาความอิสระ (degrees of freedom) นานก่อนที่จะหมดสินทรัพย์ที่คุณสนใจ พอร์ตคริปโตใด ๆ ที่มี 10-30 โทเคนอยู่นอกเหนือความสามารถของ VECH หรือ BEKK โดยสิ้นเชิง
ทางออก ซึ่งเป็นผลงานของ Engle คือการหยุดพยายามสร้างแบบจำลอง โดยตรง และแทนที่ด้วยการ แยกตัวประกอบ (factor) มันออกเป็นส่วนที่เรารู้วิธีประมาณได้อย่างประหยัดอยู่แล้ว
DCC ของ Engle (2002): การแยกส่วนสองขั้นตอน
แบบจำลอง Constant Conditional Correlation (CCC) ของ Bollerslev (1990) เป็นการแยกตัวประกอบที่ประหยัดพารามิเตอร์ตัวแรก มันเขียนว่า
โดยที่ คือเมทริกซ์แนวทแยงของส่วนเบี่ยงเบนมาตรฐานแบบมีเงื่อนไข — GARCH แบบตัวแปรเดี่ยวหนึ่งตัวต่อสินทรัพย์หนึ่งตัว — และ คือเมทริกซ์สหสัมพันธ์ที่ คงที่ นี่เป็นการทำให้ง่ายขึ้นอย่างมาก คุณปรับ (fit) แบบจำลอง GARCH แบบตัวแปรเดี่ยวอิสระ ตัว จากนั้นประมาณเมทริกซ์สหสัมพันธ์แบบตัวอย่างเดี่ยวของส่วนตกค้างที่ถูกทำให้เป็นมาตรฐานแล้ว positive definiteness เกิดขึ้นโดยอัตโนมัติตราบใดที่ เป็นเมทริกซ์สหสัมพันธ์ที่ถูกต้อง และ ทั้งหมด
ปัญหาของ CCC อยู่ตรงชื่อของมันเลย — สหสัมพันธ์นั้น คงที่ ซึ่งเป็นข้อสมมติที่เราปฏิเสธไปแล้วตั้งแต่ต้นบทความนี้ Dynamic Conditional Correlation ของ Engle (2002) เก็บการแยกตัวประกอบที่สวยงามของ CCC ไว้ แต่ปล่อยให้เมทริกซ์สหสัมพันธ์หายใจได้
ตอนนี้ แปรผันตามเวลา ความเฉียบแหลมอยู่ที่การที่ความผันผวนและสหสัมพันธ์ถูกประมาณในสองขั้นตอนแยกกัน ดังนั้นเราจึงไม่ต้องเผชิญกับการหาค่าเหมาะสมที่สุดร่วม (joint optimization) แบบ เต็มรูปแบบเลย
ขั้นตอนที่ 1: GARCH แบบตัวแปรเดี่ยวต่อสินทรัพย์
สำหรับสินทรัพย์แต่ละตัว ให้ปรับแบบจำลอง GARCH แบบตัวแปรเดี่ยวเหมือนในตอนที่ 1 และ 2 — GARCH(1,1), GJR-GARCH หรือ EGARCH ที่มี Student-t innovations แล้วแต่ว่าอะไรเหมาะกับอนุกรมนั้นที่สุด สิ่งนี้ให้ความแปรปรวนแบบมีเงื่อนไข และดังนั้น
จากแบบจำลองที่ปรับแล้ว เราสกัด ส่วนตกค้างที่ถูกทำให้เป็นมาตรฐาน (standardized residuals)
โดยธรรมชาติของโครงสร้าง แต่ละ มีความแปรปรวนแบบมีเงื่อนไขเป็นหน่วย (unit) โดยประมาณ นำมาเรียงเป็นเวกเตอร์ ส่วนตกค้างที่ถูกทำให้เป็นมาตรฐานเหล่านี้คือวัตถุดิบสำหรับขั้นตอนสหสัมพันธ์ — พลวัตความผันผวนเฉพาะตัวของแต่ละตัวถูกดึงออกไปแล้ว ดังนั้นการเคลื่อนไหวร่วมที่เหลืออยู่คือการพึ่งพากันล้วน ๆ ไม่ใช่สิ่งประดิษฐ์จากความผันผวน (นี่เป็นตรรกะแบบ PIT เดียวกับที่บทความ copula ใช้ก่อนปรับขอบเขต (margins) เพียงแต่ที่นี่เราหยุดที่การทำให้เป็นมาตรฐานแทนที่จะไปไกลถึงการแปลงเป็น uniforms)
ขั้นตอนที่ 2: การวนซ้ำสหสัมพันธ์ของ DCC
เราสร้างแบบจำลองของกระบวนการเสริม ซึ่งเป็นเมทริกซ์สมมาตร positive-definite ขนาด ด้วยการวนซ้ำแบบ GARCH ที่ขับเคลื่อนโดย outer products ของส่วนตกค้างที่ถูกทำให้เป็นมาตรฐาน
โดยที่
- คือเมทริกซ์สหสัมพันธ์ไร้เงื่อนไข (unconditional) ของส่วนตกค้างที่ถูกทำให้เป็นมาตรฐาน (นี่คือ correlation targeting — รายละเอียดเพิ่มเติมด้านล่าง)
- ควบคุมว่าสัญญาณช็อกในวันนี้ ดึงสหสัมพันธ์แรงแค่ไหน
- ควบคุมความคงอยู่ (persistence) — ว่า ของเมื่อวานพาต่อมาเท่าไร
- และข้อจำกัดการกลับสู่ค่าเฉลี่ยคือ (โดยที่ ) ซึ่งคล้ายคลึงโดยตรงกับ ใน GARCH แบบตัวแปรเดี่ยว
สังเกตว่าโครงสร้างนี้เหมือนกับการวนซ้ำ GARCH(1,1) แบบสเกลาร์ทุกประการ แต่บนเมทริกซ์: จุดยึดระยะยาว เทอมช็อก และเทอมความคงอยู่ เนื่องจากมันคือ convex combination ของเมทริกซ์ positive-semi-definite (, outer product แบบ rank-1, และ ก่อนหน้า) จึงคงความ positive definite ไว้ตราบใดที่ และน้ำหนักทั้งหมดไม่เป็นลบ นี่คือสิ่งที่ทำให้เราได้เมทริกซ์ความแปรปรวนร่วมที่ถูกต้องโดยไม่มีค่าใช้จ่ายเพิ่ม
เกือบจะ เป็นเมทริกซ์สหสัมพันธ์แล้ว แต่ยังไม่เชิง — แนวทแยงของมันไม่เท่ากับ 1 พอดี ดังนั้นเราจึงทำให้เป็นมาตรฐาน (normalize)
ในระดับสมาชิก (elementwise) สหสัมพันธ์แบบมีเงื่อนไขระหว่างสินทรัพย์ และ คือ
นี้คือเมทริกซ์สหสัมพันธ์ที่ถูกต้อง — แนวทแยงเป็นหน่วย นอกแนวทแยงอยู่ใน positive definite — ในทุกช่วงเวลา โดยธรรมชาติของโครงสร้าง ประกอบกลับเป็นความแปรปรวนร่วมแบบมีเงื่อนไขเต็มรูปแบบ
รูปแบบ elementwise สุดท้ายนั้นคือสิ่งที่คุณจะใช้อยู่เป็นประจำ ความแปรปรวนร่วมแบบมีเงื่อนไขของสองสินทรัพย์คือสหสัมพันธ์แบบพลวัตของมันคูณด้วยความผันผวนแบบพลวัตของแต่ละตัว ทุกส่วนประกอบทางด้านขวามือแปรผันตามเวลาและมาจากแบบจำลองที่คุณสามารถประมาณได้
แบบจำลองทั้งหมดมีพารามิเตอร์สหสัมพันธ์เพียง สอง ตัว คือ และ ไม่ว่า หรือ ด้านความผันผวนขยายตามขนาดแบบเชิงเส้น (GARCH แบบตัวแปรเดี่ยวหนึ่งตัวต่อสินทรัพย์ แต่ละตัวมีพารามิเตอร์ประมาณ 4-5 ตัว ปรับแยกกันอิสระและขนานได้อย่างง่ายดาย) นี่คือเหตุผลที่ DCC ขยายตามขนาดได้ในที่ที่ BEKK และ VECH ทำไม่ได้ คำสาปแห่งมิติถูกจำกัดอยู่ที่ ซึ่งถูก กำหนดเป้าหมาย (targeted) (ใส่เข้าไปเป็นค่าประมาณแบบตัวอย่าง) แทนที่จะถูก หาค่าเหมาะสมที่สุด (optimized)
ข้อจำกัดแบบสเกลาร์และค่าใช้จ่ายของมัน
สเกลาร์ หมายความว่าคู่สินทรัพย์ ทุกคู่ มีพลวัตสหสัมพันธ์เดียวกัน — ความเร็วในการปรับตัวเดียวกันและความคงอยู่เดียวกัน สหสัมพันธ์ BTC-ETH และสหสัมพันธ์ DOGE-SHIB เคลื่อนไหวในจังหวะเดียวกันแม้ว่าเศรษฐศาสตร์ของมันจะแตกต่างกัน นี่คือราคาของความจัดการได้ (tractability) และโดยปกติเป็นราคาที่ยอมรับได้ การขยายผล (Generalized DCC ด้วยเมทริกซ์ ; asymmetric DCC ของ Cappiello-Engle-Sheppard) ผ่อนคลายข้อจำกัดนี้โดยแลกกับพารามิเตอร์และเสถียรภาพในการประมาณ เราจะกล่าวถึง aDCC ด้านล่าง
Quasi-Log-Likelihood ของ DCC
การประมาณ และ ต้องการ likelihood ผลลัพธ์สำคัญของ Engle คือ log-likelihood แบบ Gaussian แยกส่วน ออกเป็นส่วนความผันผวนและส่วนสหสัมพันธ์ ซึ่งเป็นสิ่งที่ทำให้ตัวประมาณสองขั้นตอนนี้สมเหตุสมผล โดยสมมติ ส่วนสนับสนุน log-likelihood ณ เวลา คือ
แทนที่ แล้ว และ และใช้
ตอนนี้แยกมันโดยการบวกและลบ
ส่วนความผันผวน ขึ้นอยู่กับพารามิเตอร์ GARCH แบบตัวแปรเดี่ยวเท่านั้น (ผ่าน ) — การหาค่าสูงสุดของมันคือการปรับแบบจำลอง GARCH แบบตัวแปรเดี่ยวอิสระ ตัว ซึ่งเราทำในขั้นตอนที่ 1 ส่วนสหสัมพันธ์ ขึ้นอยู่กับ และ (ผ่าน ) เมื่อกำหนด ส่วนตกค้างที่ถูกทำให้เป็นมาตรฐานจากขั้นตอนที่ 1 ดังนั้นในขั้นตอนที่ 2 เราหาค่าสูงสุดเพียง
(เทอม ไม่ขึ้นกับ ดังนั้นเราจึงตัดมันทิ้ง) นี่คือการหาค่าเหมาะสมที่สุดแบบ สองพารามิเตอร์ ไม่ว่าจะมีสินทรัพย์กี่ตัว — นั่นคือประเด็นทั้งหมด มันถูกเรียกว่า quasi-likelihood เพราะตัวประมาณสองขั้นตอนมีความสม่ำเสมอ (consistent) แต่ไม่มีประสิทธิภาพเต็มที่ (fully efficient) ค่าความคลาดเคลื่อนมาตรฐาน (standard errors) ต้องการการปรับแก้ (Engle & Sheppard 2001) แต่สำหรับการสร้างสัญญาณเทรด ค่าประมาณจุด (point estimates) คือสิ่งที่สำคัญ
สำหรับคริปโต Gaussian innovations ประเมินความเสี่ยงหางต่ำเกินไป การเปลี่ยนไปใช้ multivariate Student-t likelihood เป็นการเปลี่ยนแปลงที่ทำได้ทันทีสำหรับ (แทนที่ Gaussian kernel ด้วย multivariate- density และเพิ่มพารามิเตอร์องศาความอิสระ ) เราคงใช้ Gaussian quasi-likelihood ในตัวประมาณด้านล่างเพื่อความชัดเจน และระบุจุดที่ เข้ามา — การทำให้เป็นมาตรฐานจากตอนที่ 1-2 ใช้ t-innovations บนขอบเขต (margins) อยู่แล้ว ซึ่งจับประโยชน์ด้านหางไว้ส่วนใหญ่แล้ว
การทำใช้จริงด้วย Python
ข้อเท็จจริงที่ตรงไปตรงมาและสำคัญ ไลบรารี arch ไม่รองรับ GARCH หรือ DCC แบบหลายตัวแปร arch เป็นเอนจินแบบตัวแปรเดี่ยวที่ยอดเยี่ยม (เราพึ่งพามันสำหรับสิ่งนั้นโดยเฉพาะ) แต่ไม่มี dcc_model อยู่ในนั้น ทางเลือกที่ใช้งานได้จริงของคุณคือ
- สร้าง DCC เองบนพื้นฐานของ
arch— ปรับแบบจำลองตัวแปรเดี่ยวด้วยarchสกัดส่วนตกค้างที่ถูกทำให้เป็นมาตรฐาน ทำการวนซ้ำ และ quasi-likelihood ของสหสัมพันธ์ใน NumPy/SciPy แล้วหาค่าเหมาะสมที่สุดของสเกลาร์ทั้งสอง นี่คือสิ่งที่เราทำด้านล่าง มันมีประมาณ 60 บรรทัดและโปร่งใสอย่างสมบูรณ์ - แพ็กเกจ PyPI
mgarch— การทำ DCC-GARCH แบบ pure-Python ที่เบา สะดวกสำหรับการปรับแบบเร็ว แต่ยืดหยุ่นน้อยกว่าถ้าคุณต้องการ GJR margins หรือ t-innovations ที่ต่อสายอย่างแม่นยำ rmgarchของ R (Alexios Galanos) — การทำใช้จริงแบบอ้างอิงdccspec/dccfitรองรับ DCC, aDCC, GARCH-copula, Student-t และค่าความคลาดเคลื่อนมาตรฐานที่ถูกต้อง ถ้าคุณกำลังทำวิจัยความผันผวนแบบหลายตัวแปรอย่างจริงจังrmgarch(เรียกจาก Python ผ่านrpy2หากจำเป็น) คือมาตรฐานทองคำ
เราจะสร้างทางเลือกที่ 1 เพราะมันทำให้ทุกส่วนที่เคลื่อนไหวชัดเจนและนำทักษะแบบตัวแปรเดี่ยวจากตอนที่ 1-2 กลับมาใช้ใหม่
ขั้นตอนที่ 1: ปรับขอบเขต (margins) GARCH แบบตัวแปรเดี่ยวด้วย arch
import numpy as np
import pandas as pd
from arch import arch_model
from scipy.optimize import minimize
def fetch_returns(symbols, start="2022-01-01", end="2025-12-31"):
"""
Daily log returns for a list of crypto symbols.
Replace with your data source (ccxt for 24/7 exchange data,
yfinance for a quick sketch).
"""
import yfinance as yf
px = yf.download([f"{s}-USD" for s in symbols],
start=start, end=end)["Close"]
px.columns = symbols
rets = np.log(px / px.shift(1)).dropna()
return rets
symbols = ["BTC", "ETH", "SOL", "BNB"]
returns = fetch_returns(symbols)
def fit_univariate(series, dist="t"):
"""
Fit GJR-GARCH(1,1) with Student-t innovations (Part 2 model).
Returns the fitted result and the *scaled* series it was fit on.
We scale returns by 100 for the optimizer's numerical health,
exactly as in Parts 1 and 2.
"""
scaled = series * 100.0
model = arch_model(scaled, mean="Constant",
vol="GARCH", p=1, o=1, q=1, dist=dist)
res = model.fit(disp="off")
return res
fits = {s: fit_univariate(returns[s]) for s in symbols}
Z = pd.DataFrame({s: fits[s].std_resid for s in symbols}).dropna()
Sigma = pd.DataFrame({s: fits[s].conditional_volatility
for s in symbols}).loc[Z.index]
print(Z.describe())
การตรวจสอบความสมเหตุสมผลอย่างรวดเร็วของส่วนตกค้างที่ถูกทำให้เป็นมาตรฐานนั้นสำคัญ ถ้าคอลัมน์ใดมีส่วนเบี่ยงเบนมาตรฐานห่างจาก 1 มาก หรือมี autocorrelation ที่เหลืออยู่มากในค่ากำลังสองของมัน (Ljung-Box บน ) ขอบเขต (margin) แบบตัวแปรเดี่ยวนั้นถูกกำหนดสเปคผิด และขั้นตอน DCC จะสืบทอดความผิดพลาดนั้นไป แก้ไขขอบเขตก่อน — นั่นคือสิ่งที่ตอนที่ 2 มีไว้เพื่อจุดประสงค์นี้
ขั้นตอนที่ 2: การวนซ้ำ DCC และ quasi-log-likelihood
def dcc_negloglik(params, Z):
"""
Negative DCC quasi-log-likelihood (Gaussian) in (a, b).
Z : (T, d) array of standardized residuals from Step 1.
Implements:
Q_t = (1-a-b) Qbar + a z_{t-1} z_{t-1}' + b Q_{t-1}
R_t = diag(Q_t)^{-1/2} Q_t diag(Q_t)^{-1/2}
LL = -1/2 sum_t ( log|R_t| + z_t' R_t^{-1} z_t )
with correlation targeting: Qbar = sample corr of Z.
"""
a, b = params
if a <= 0 or b <= 0 or a + b >= 1.0:
return 1e10
Z = np.asarray(Z)
T, d = Z.shape
Qbar = np.cov(Z, rowvar=False, bias=True) # unconditional (targeted)
dinv = np.diag(1.0 / np.sqrt(np.diag(Qbar)))
Qbar = dinv @ Qbar @ dinv
Q = Qbar.copy() # initialize Q_1 at the target
ll = 0.0
for t in range(T):
q_diag = np.sqrt(np.diag(Q))
R = Q / np.outer(q_diag, q_diag)
sign, logdet = np.linalg.slogdet(R)
if sign <= 0:
return 1e10
z = Z[t]
Rinv_z = np.linalg.solve(R, z)
ll += -0.5 * (logdet + z @ Rinv_z)
Q = (1 - a - b) * Qbar + a * np.outer(z, z) + b * Q
return -ll
def fit_dcc(Z):
"""Estimate (a, b) by maximizing the DCC quasi-log-likelihood."""
res = minimize(
dcc_negloglik, x0=[0.03, 0.94], args=(np.asarray(Z),),
method="L-BFGS-B",
bounds=[(1e-6, 0.5), (1e-6, 0.999)],
)
a, b = res.x
print(f"DCC estimates: a = {a:.4f}, b = {b:.4f}, a+b = {a+b:.4f}")
print(f"log-likelihood: {-res.fun:.2f}")
return a, b
a_hat, b_hat = fit_dcc(Z)
การรันสิ่งนี้บนพอร์ต BTC/ETH/SOL/BNB ตลอดข้อมูลรายวันหลายปีจะให้ผลลัพธ์ในรูปแบบดังต่อไปนี้ (ตัวเลขด้านล่างเป็น ตัวอย่างประกอบ ไม่ได้มาจากการทดลองที่มีวันที่เฉพาะเจาะจง — รันบนข้อมูลของคุณเอง)
DCC estimates: a = 0.0287, b = 0.9401, a+b = 0.9688
log-likelihood: -3812.44
วิธีอ่านผลลัพธ์
- มีค่าน้อย — เมทริกซ์สหสัมพันธ์ไม่กระโดดตามช็อกของวันเดียว แต่ละวันดัน เข้าหา outer product เพียง ~3% เท่านั้น
- มีค่าสูง — สหสัมพันธ์มีความคงอยู่สูง เมื่อพอร์ตเชื่อมโยงกันในเหตุการณ์ตึงเครียด มันจะคงเชื่อมโยงกันไปสักพัก แล้วจึงค่อย ๆ ลดกลับสู่ อย่างช้า ๆ สิ่งนี้ตรงกับประสบการณ์จริงของตลาดคริปโตร่วง สหสัมพันธ์ไม่ได้ดีดกลับทันทีที่ราคาเริ่มนิ่ง
- ยืนยันการกลับสู่ค่าเฉลี่ย กระบวนการสหสัมพันธ์มีระดับระยะยาวที่คงที่ () ที่มันกลับไปหา โดยมีครึ่งชีวิต (half-life) ประมาณ วัน ถ้าคุณเคยประมาณค่า ที่เท่ากับ 1 พอดี กระบวนการสหสัมพันธ์นั้น integrated — ไม่มีจุดยึดระยะยาว มักเป็นอาการของความเปลี่ยนแปลงเชิงโครงสร้าง (structural break) ในตัวอย่างของคุณที่แบบจำลองกำลังดูดซับเป็นความคงอยู่แบบไม่มีที่สิ้นสุด
ความคงอยู่ใกล้หน่วยและการโหลดช็อกที่เล็กมากคือลายนิ้วมือ (fingerprint) มาตรฐานของ DCC ในทุกกลุ่มสินทรัพย์ และคริปโตก็ไม่ใช่ข้อยกเว้น นี่ยังเป็นเหตุผลที่สหสัมพันธ์แบบ rolling 30 วันเป็นตัวทดแทนที่ไม่ดี หน้าต่างแบบ rolling สมมติ และ โดยนัยที่ไม่ตรงกับโครงสร้างการสลายตัวนี้เลย
หมายเหตุการทำใช้จริงบางประการที่ช่วยประหยัดเวลาดีบักได้จริง
- การกำหนดค่าเริ่มต้น (initialization) การเริ่มที่
[0.03, 0.94]สะท้อนค่าประมาณทั่วไปของคริปโต คือ เล็ก (สหสัมพันธ์ตอบสนองต่อช็อกแต่ไม่รุนแรง) ใหญ่ (สหสัมพันธ์มีความคงอยู่) ถ้าตัวหาค่าเหมาะสมที่สุดของคุณเลื่อนไปที่ กระบวนการสหสัมพันธ์นั้น integrated — มักเป็นสัญญาณของความเปลี่ยนแปลงเชิงโครงสร้างในตัวอย่าง (การเปลี่ยนระบอบที่แบบจำลองกำลังพยายามอย่างหนักที่จะปรับให้พอดีเป็นความคงอยู่) - หลักการเรื่องเวลา (timing convention) ภายในลูปเราให้คะแนน เทียบกับ แล้ว จากนั้น อัปเดต ด้วย สำหรับขั้นตอนถัดไป สิ่งนี้ทำให้ เป็นฟังก์ชันของข้อมูลผ่าน เท่านั้น — ไม่มีการมองล่วงหน้า (look-ahead) การทำผิดพลาดแบบ off-by-one นี้เป็นบั๊ก DCC ที่พบบ่อยที่สุดเพียงหนึ่งเดียว และมันจะพองค่า fit ใน-ตัวอย่าง (in-sample) อย่างเงียบ ๆ
- Correlation targeting เราใส่ เข้าไปเป็นสหสัมพันธ์แบบตัวอย่างแทนที่จะประมาณมัน นี่คือสิ่งที่ทำให้การหาค่าเหมาะสมที่สุดเป็นแบบสองมิติ ค่าใช้จ่ายคือ ใช้ตัวอย่างทั้งหมด ดังนั้นใน walk-forward ที่เข้มงวด คุณต้องประมาณมันใหม่บนหน้าต่างการฝึกเท่านั้น (ดูด้านล่าง)
ขั้นตอนที่ 3: สร้างเส้นทางสหสัมพันธ์และความแปรปรวนร่วมขึ้นใหม่
เมื่อ ถูกกำหนดคงที่แล้ว ให้รันการวนซ้ำอีกครั้ง คราวนี้ เก็บ เส้นทาง (และ ) เต็มรูปแบบ เพื่อให้กลยุทธ์ปลายทางใช้งานได้
def dcc_filter(Z, Sigma, a, b):
"""
Run the DCC recursion with fixed (a,b) and return the full paths:
R_path : (T, d, d) conditional correlation matrices
H_path : (T, d, d) conditional covariance matrices (scaled units)
Sigma : (T, d) conditional volatilities aligned with Z.
"""
Z = np.asarray(Z); Sig = np.asarray(Sigma)
T, d = Z.shape
Qbar = np.cov(Z, rowvar=False, bias=True)
dinv = np.diag(1.0 / np.sqrt(np.diag(Qbar)))
Qbar = dinv @ Qbar @ dinv
Q = Qbar.copy()
R_path = np.empty((T, d, d))
H_path = np.empty((T, d, d))
for t in range(T):
q_diag = np.sqrt(np.diag(Q))
R = Q / np.outer(q_diag, q_diag)
R_path[t] = R
Dt = np.diag(Sig[t]) # D_t = diag(sigma_i,t)
H_path[t] = Dt @ R @ Dt # H_t = D_t R_t D_t
z = Z[t]
Q = (1 - a - b) * Qbar + a * np.outer(z, z) + b * Q
return R_path, H_path
R_path, H_path = dcc_filter(Z, Sigma, a_hat, b_hat)
i, j = symbols.index("BTC"), symbols.index("ETH")
rho_btc_eth = pd.Series(R_path[:, i, j], index=Z.index, name="rho_BTC_ETH")
print(rho_btc_eth.describe())
print("min/max correlation:", rho_btc_eth.min().round(3),
rho_btc_eth.max().round(3))
อนุกรม rho_btc_eth คือผลตอบแทนของแบบฝึกหัดทั้งหมด แทนที่จะเป็นตัวเลขเดียว ตอนนี้คุณมีสหสัมพันธ์รายวันที่คุณสามารถพล็อต ตั้งเกณฑ์ หรือป้อนเข้ากลยุทธ์ได้ ในข้อมูลคริปโตจริงคุณมักจะเห็นมันแปรผันจากประมาณ 0.5 ในช่วงเงียบสงบไปจนถึงเหนือ 0.9 ในช่วงตึงเครียด — ช่วงที่แม่นยำที่สหสัมพันธ์แบบตัวอย่างเดี่ยวเฉลี่ยเอาไป
การพยากรณ์แบบหนึ่งขั้นล่วงหน้า
สำหรับการเทรดสด คุณต้องการ หนึ่งขั้นล่วงหน้าจากข้อมูลที่มีอยู่ตอนนี้ ด้านความผันผวนมาจากการพยากรณ์หนึ่งขั้นของแบบจำลอง arch แต่ละตัว ด้านสหสัมพันธ์คือการวนซ้ำอีกหนึ่งรอบ
def dcc_forecast_next(Z, a, b, fits, symbols):
"""One-step-ahead H_{t+1} using info through the last observation."""
Z = np.asarray(Z); T, d = Z.shape
Qbar = np.cov(Z, rowvar=False, bias=True)
dinv = np.diag(1.0 / np.sqrt(np.diag(Qbar)))
Qbar = dinv @ Qbar @ dinv
Q = Qbar.copy()
for t in range(T):
z = Z[t]
Q = (1 - a - b) * Qbar + a * np.outer(z, z) + b * Q
q_diag = np.sqrt(np.diag(Q))
R_next = Q / np.outer(q_diag, q_diag)
sig_next = np.array([
np.sqrt(fits[s].forecast(horizon=1, reindex=False)
.variance.iloc[-1, 0])
for s in symbols
])
Dt = np.diag(sig_next)
H_next = Dt @ R_next @ Dt
return R_next, H_next, sig_next
R_next, H_next, sig_next = dcc_forecast_next(Z, a_hat, b_hat, fits, symbols)
จำไว้ว่าทุกอย่างอยู่ในหน่วยที่ถูกสเกล (×100) เพราะเราปรับ arch บน series * 100 หารความผันผวนด้วย 100 (และความแปรปรวนร่วมด้วย ) เพื่อกลับไปสู่หน่วยผลตอบแทนดิบก่อนที่จะป้อนเข้ากลยุทธ์ การรักษาการสเกลให้ถูกต้องนั้นน่าเบื่อแต่เป็นแหล่งบั๊กเงียบที่พบบ่อย
การประยุกต์ที่ 1: อัตราส่วนป้องกันความเสี่ยงแบบพลวัตสำหรับการเทรดคู่
คู่เทรดแบบ market-neutral คลาสสิก — ซื้อสินทรัพย์หนึ่งตัว ขายสินทรัพย์อีกตัวในปริมาณที่ถ่วงน้ำหนักด้วยเบต้า — อยู่รอดหรือตายด้วยอัตราส่วนป้องกันความเสี่ยง ประมาณมันด้วย OLS แบบคงที่ตลอดหน้าต่างการฝึก แล้วคุณจะสืบทอดปัญหาสหสัมพันธ์ล้าสมัยที่บทความทั้งหมดนี้พูดถึงพอดี การป้องกันความเสี่ยงที่ทำให้เป็นกลางต่อการเปิดรับตลาดในไตรมาสที่แล้วผิดในไตรมาสนี้
DCC ให้อัตราส่วนป้องกันความเสี่ยงแก่คุณในรูปอนุกรมเวลา การป้องกันความเสี่ยงแบบความแปรปรวนต่ำสุด (minimum-variance hedge) ของการเปิดรับ ETH โดยใช้ BTC คือสัมประสิทธิ์การถดถอยแบบมีเงื่อนไข
ทุกเทอมทางด้านขวาเป็นผลลัพธ์ของ DCC อัตราส่วนป้องกันความเสี่ยงเคลื่อนไหวด้วยสองสาเหตุที่แตกต่างกัน และ DCC แยกมันออกจากกันได้อย่างชัดเจน สหสัมพันธ์ เปลี่ยนไป (สินทรัพย์เชื่อมโยงหรือแยกจากกัน) และอัตราส่วนความผันผวน เปลี่ยนไป (สินทรัพย์หนึ่งผันผวนมากขึ้นเมื่อเทียบกัน) เบต้าแบบ rolling-OLS จะเบลอผลกระทบทั้งสองเข้าด้วยกันพร้อมความล่าช้า ในขณะที่ DCC ระบุแต่ละสาเหตุได้
def dynamic_hedge_ratio(R_path, Sigma, base="BTC", target="ETH",
symbols=symbols, index=Z.index):
"""
beta_t to hedge `target` exposure with `base`:
beta_t = rho_t * sigma_target,t / sigma_base,t
(Scaling cancels in the ratio, so scaled units are fine here.)
"""
i = symbols.index(target)
j = symbols.index(base)
rho = R_path[:, i, j]
sig = np.asarray(Sigma)
beta = rho * sig[:, i] / sig[:, j]
return pd.Series(beta, index=index, name=f"beta_{target}_{base}")
beta_t = dynamic_hedge_ratio(R_path, Sigma)
print(beta_t.describe())
spread = (returns["ETH"] - beta_t.shift(1) * returns["BTC"]).dropna()
ป้อน spread เข้าไปในเอนจินคู่เทรดใดก็ตามที่คุณใช้งาน การป้องกันความเสี่ยงแบบพลวัตไม่ได้สร้างความได้เปรียบด้วยตัวมันเอง — มันทำให้ สเปรดที่คุณเทรด เป็นกลางต่อตลาดอย่างแท้จริงตลอดเวลา ดังนั้นสัญญาณการกลับสู่ค่าเฉลี่ยของคุณจึงไม่ถูกปนเปื้อนด้วยการเปิดรับทิศทางที่เลื่อนไหล ถ้าคุณสร้างกลยุทธ์คู่เทรด สิ่งนี้เสียบเข้ากับกรอบงานใน Statistical Arbitrage และการเทรดคู่ในคริปโต และ แนวทางระยะทางสำหรับคู่เทรด โดยตรง แทนที่อัตราส่วนป้องกันความเสี่ยงคงที่ของมัน อนุกรมสหสัมพันธ์เองก็เป็นข้อมูลนำเข้าที่สะอาดกว่าสำหรับ สัญญาณคู่เทรดตามสหสัมพันธ์ มากกว่าหน้าต่าง rolling ใด ๆ — คุณจะได้ ที่เรียบและสอดคล้องกับแบบจำลองแทนที่จะเป็นค่าประมาณที่มีสัญญาณรบกวนจากหน้าต่าง
ข้อควรระวังสองข้อเฉพาะสำหรับการใช้ ในการเทรดสด ข้อแรก ให้ล่าช้า (lag) มัน — เทรดบน ไม่เคยใช้ ร่วมสมัย มิฉะนั้นคุณกำลังแอบดูล่วงหน้า ข้อสอง อัตราส่วนป้องกันความเสี่ยงที่แกว่งไปมาทุกวันสร้างการหมุนเวียน (turnover) และค่าธรรมเนียม ในตลาดคริปโตที่เปิด 24/7 พร้อมต้นทุน funding บนขาช็อต การป้องกันความเสี่ยงที่ตอบสนองมากเกินไปอาจเสียมากกว่าดริฟต์ที่มันแก้ไข ทำให้ เรียบ (EWMA หรือปรับสมดุลการป้องกันความเสี่ยงเมื่อมันเคลื่อนพ้นแถบเท่านั้น) และกำหนดขนาดทั้งหมดอย่างสมเหตุสมผล การกำหนดขนาดสถานะจากสัญญาณที่มีสัญญาณรบกวนเป็นวินัยของตัวมันเอง ครอบคลุมใน การกำหนดขนาดด้วยเกณฑ์เคลลี่
การประยุกต์ที่ 2: ความแปรปรวนของพอร์ตที่แปรผันตามเวลา
สำหรับพอร์ตที่มีเวกเตอร์น้ำหนัก ความแปรปรวนแบบมีเงื่อนไขคือ
ด้วยเมทริกซ์ความแปรปรวนร่วมแบบคงที่ — ค่าเริ่มต้นของ Markowitz — ตัวเลขนี้คือค่าคงที่ที่คุณคำนวณครั้งเดียวและแสร้งทำเป็นว่ายังคงเป็นจริงอยู่ ซึ่งไม่จริง ความเสี่ยงของพอร์ตหายใจไปตามตลาด และมันหายใจ หนักที่สุด พอดีเมื่อสหสัมพันธ์พุ่งขึ้น เพราะในตลาดร่วง ทั้งเทอม และเทอม เพิ่มขึ้นพร้อมกันและคูณกัน พอร์ตที่ดูเหมือนมีความผันผวนรายปี 40% ในตลาดสงบอาจวิ่งอยู่ที่ 80%+ ในสัปดาห์ตึงเครียด และเมทริกซ์ความแปรปรวนร่วมแบบคงที่จะบอกคุณว่าไม่มีอะไรเปลี่ยนแปลง
def portfolio_vol_path(H_path, weights, index=Z.index, unscale=1e4):
"""
Conditional portfolio volatility sigma_{p,t} = sqrt(w' H_t w).
H_path is in scaled (x100) units, so covariances carry a 100^2
factor: divide by unscale=1e4 to return to raw-return variance.
"""
w = np.asarray(weights)
var_t = np.einsum("i,tij,j->t", w, H_path, w) / unscale
return pd.Series(np.sqrt(var_t), index=index, name="port_vol")
w = np.array([0.4, 0.3, 0.2, 0.1]) # BTC, ETH, SOL, BNB
pv = portfolio_vol_path(H_path, w)
pv_annual = pv * np.sqrt(365)
print(pv_annual.describe())
ที่แปรผันตามเวลานี้คือข้อมูลนำเข้าที่ตรงไปตรงมาที่การจัดสรรตามความเสี่ยงต้องการ การหาค่าเหมาะสมที่สุดแบบ mean-variance (Markowitz สำหรับคริปโต) ด้วยความแปรปรวนร่วมแบบตัวอย่างที่ คงที่ คือการหาค่าเหมาะสมที่สุดกับเรื่องแต่ง การป้อน (หรือการพยากรณ์ระยะสั้นของมัน) เข้าไปทำให้ frontier ที่มีประสิทธิภาพเองแปรผันตามเวลา และบังคับให้ตัวหาค่าเหมาะสมที่สุดลดความเสี่ยงเข้าสู่ระบอบสหสัมพันธ์ที่กำลังเพิ่มขึ้นแทนที่จะทำหลังจากมัน แนวทาง risk-parity และแบบลำดับชั้น — ไปป์ไลน์ HRP + CVaR — ยังไวต่อข้อมูลนำเข้าความแปรปรวนร่วมมากกว่าอีก เพราะการจัดสรรทั้งหมด คือ ฟังก์ชันของเมทริกซ์ความเสี่ยง และถ้าคุณกำลังเปรียบเทียบตัวจัดสรรแบบเทียบกันตรง ๆ อย่างใน อัลกอริทึมการหาค่าเหมาะสมที่สุดของพอร์ตเปรียบเทียบกัน ว่ามันใช้ความแปรปรวนร่วมแบบคงที่หรือแบบพลวัต มักเป็นตัวขับเคลื่อนความเสี่ยงที่เกิดขึ้นจริง (realized risk) ที่ใหญ่กว่าการเลือกอัลกอริทึมเสียอีก
การประยุกต์ตรงคือ การกำหนดเป้าหมายความผันผวน (volatility targeting) ของพอร์ตทั้งหมด เลือกเป้าหมายความผันผวนรายปี และปรับขนาดการเปิดรับรวม (gross exposure) ด้วย ในแต่ละช่วงเวลา เพื่อให้ความเสี่ยงที่เกิดขึ้นจริงคงที่โดยประมาณแทนที่จะพองตัวในช่วงวิกฤต นั่นปิดวงจรกับ ตอนที่ 4 ซึ่งสร้างและทดสอบย้อนหลังกฎนี้อย่างแม่นยำ
การประยุกต์ที่ 3: สหสัมพันธ์ในฐานะสัญญาณระบอบ (Regime Signal)
นอกเหนือจากการป้องกันความเสี่ยงและการกำหนดขนาด เมทริกซ์สหสัมพันธ์ยังพกพาสัญญาณระดับมหภาค สเกลาร์ที่มีประโยชน์ที่สุดที่คุณสามารถสกัดได้คือ สหสัมพันธ์เฉลี่ยแบบคู่ (average pairwise correlation)
เมื่อ เพิ่มขึ้นทั่วทั้งพอร์ต ตลาดกำลังเข้าสู่ระบอบ risk-off — เรื่องราวเฉพาะตัว (idiosyncratic) หยุดมีความสำคัญ และทุกอย่างเทรดเหมือนเป็นเบต้ามหภาคเดียว นี่คือลายนิ้วมือเชิงปริมาณของ "สหสัมพันธ์ไปที่ 1 ในวิกฤต" มันมักจะ นำหน้า หรือเกิดพร้อมกับตลาดร่วง ทำให้มันเป็นตัวชี้วัดระบอบที่ใช้งานได้มากกว่าการชันสูตรหลังเหตุการณ์ (postmortem) ที่ตามหลัง
def avg_pairwise_corr(R_path, index=Z.index):
T, d, _ = R_path.shape
iu = np.triu_indices(d, k=1) # upper-triangle off-diagonals
avg = R_path[:, iu[0], iu[1]].mean(axis=1)
return pd.Series(avg, index=index, name="avg_corr")
avg_corr = avg_pairwise_corr(R_path)
roll_q = avg_corr.rolling(365, min_periods=90).quantile(0.80)
risk_off = (avg_corr > roll_q)
คุณสามารถใช้ risk_off เป็นตัวควบคุมแบบสแตนด์อโลน (ลดการเปิดรับรวม กว้างสต็อป หยุดกลยุทธ์ mean-reversion ที่จะถูกวิ่งทับเมื่อทุกอย่างเทรนด์ไปด้วยกัน) หรือเป็นฟีเจอร์ในแบบจำลองระบอบที่เป็นทางการมากขึ้น มันจับคู่ได้ตามธรรมชาติกับแนวทาง hidden-Markov ใน การตรวจจับระบอบด้วย HMM สหสัมพันธ์ DCC เฉลี่ยเป็นหนึ่งในตัวแปรสังเกต (observation variables) ที่ให้ข้อมูลมากที่สุดที่คุณสามารถส่งให้ HMM ได้ เพราะมันมองไปข้างหน้าเกี่ยวกับความเครียดเชิงระบบในแบบที่ผลตอบแทนย้อนหลังทำไม่ได้ คำเตือนที่ตรงไปตรงมา สหสัมพันธ์ที่เพิ่มขึ้นบอกคุณว่าความหลากหลายกำลังล้มเหลว ไม่ใช่ตลาดจะไปทิศทางไหน มันเป็นสัญญาณความเสี่ยง ไม่ใช่สัญญาณอัลฟา และควรถูกกำหนดขนาดตามนั้น — ดู ความไม่สมมาตรของกำไรขาดทุน ว่าทำไมการปฏิบัติต่อระบอบความเสี่ยงเป็นการเดิมพันเชิงทิศทางถึงจบลงไม่ดี
ข้อพิจารณาในทางปฏิบัติ
เสถียรภาพในการประมาณและจำนวนสินทรัพย์
DCC ขยายตามขนาดได้ดีกว่า BEKK มาก แต่ "ขยายตามขนาดได้" ไม่ได้แปลว่า "ฟรี" เมทริกซ์ correlation-targeting คือสหสัมพันธ์แบบตัวอย่างขนาด และเมทริกซ์สหสัมพันธ์แบบตัวอย่างจะมีสภาพไม่ดี (ill-conditioned) เมื่อ เข้าใกล้จำนวนการสังเกต ด้วย 4 สินทรัพย์และ 1000 วัน คุณสบายดี ด้วย 60 สินทรัพย์และ 400 วัน เกือบจะ singular การผกผัน (inverse) ของมันใน likelihood จะระเบิด และ อาจเบี่ยงเบนออกจาก PD จากสัญญาณรบกวนเชิงตัวเลข การแก้ไข เรียงตามความถี่ที่คุณจะต้องใช้
- Shrink เข้าหาเป้าหมายที่มีโครงสร้าง (Ledoit-Wolf หรือเข้าหา identity / เมทริกซ์สหสัมพันธ์คงที่) ก่อนรันการวนซ้ำ นี่คือการแก้ไขที่มีประสิทธิภาพสูงสุดสำหรับพอร์ตขนาดใหญ่
- จัดกลุ่มสินทรัพย์ เป็นไม่กี่ภาคส่วน (majors, L1s, DeFi, memes) สร้างแบบจำลองภายในและข้ามที่ระดับภาคส่วน หรือรัน DCC บนปัจจัยจากองค์ประกอบหลัก (principal components) แทนสินทรัพย์ดิบ
- เลือกข้อมูลมากกว่าสินทรัพย์มาก DCC มีความหิวกระหายประวัติที่ยาว สะอาด และร่วมสมัยอย่างไม่มีที่สิ้นสุด — ซึ่งเป็นสิ่งที่โทเคนใหม่ ๆ ไม่มีพอดี
ในทางปฏิบัติ ให้จำกัด DCC โดยตรงไว้ที่ไม่กี่สิบสินทรัพย์เป็นอย่างมาก สำหรับจักรวาลขนาดใหญ่ DCC บนผลตอบแทนของปัจจัย (factor returns) บวกกับส่วนตกค้างเฉพาะตัว (idiosyncratic residuals) คือวิธีแก้ปัญหามาตรฐาน
Correlation targeting คือทางลัดที่มีค่าใช้จ่าย
การกำหนดเป้าหมาย ทำให้การประมาณจัดการได้ แต่ฝัง สหสัมพันธ์ไร้เงื่อนไขแบบ เต็มตัวอย่าง ไว้ใน ทุกตัว ในการทดสอบย้อนหลังที่เข้มงวด นี่คือการรั่วไหลของการมองล่วงหน้า (look-ahead leak) เมทริกซ์สหสัมพันธ์ของวัน- ของคุณ "รู้" สหสัมพันธ์เฉลี่ยของตัวอย่างทั้งหมด รวมถึงอนาคตด้วย สำหรับการประเมินที่ตรงไปตรงมา คุณต้องประมาณ ใหม่บนหน้าต่างการฝึกเท่านั้นและตรึงมันไว้คงที่นอกตัวอย่าง หรือเลื่อนมันไปข้างหน้า นี่คือวินัยเดียวกันกับที่กรอบงาน walk-forward optimization ทั้งหมดบังคับใช้ และมันง่ายมากที่จะละเมิดโดยไม่ตั้งใจด้วย np.cov(Z) ที่สะดวกตลอดอาร์เรย์เต็ม — เหมือนที่โค้ดสอนของเราด้านบนทำ แก้ไขมันก่อนที่คุณจะเชื่อตัวเลข P&L ใด ๆ
ความถี่ในการปรับใหม่และวินัยเรื่องการมองล่วงหน้า
คุณไม่จำเป็นต้องหาค่าเหมาะสมที่สุดของ ใหม่ทุกวัน — มันเป็นพารามิเตอร์ที่เสถียร ความถี่การใช้งานจริงที่สมเหตุสมผล
- ประมาณ และพารามิเตอร์ GARCH แบบตัวแปรเดี่ยวใหม่ ทุกสัปดาห์หรือทุกเดือน
- รันตัวกรอง (filter) (อัปเดต , ) ทุกช่วงเวลา ด้วยพารามิเตอร์ที่ตรึงไว้ เพื่อให้ได้ และ ใหม่ การกรองมีต้นทุนถูก การปรับ (fitting) ไม่ถูก
- พยากรณ์เสมอ อย่าทำให้เรียบ (smooth) เด็ดขาด ใช้ ที่สร้างจากข้อมูลผ่าน เพื่อเทรดที่ โครงสร้างสองรอบ (fit บนหน้าต่าง แล้วกรองไปข้างหน้า) คือสิ่งที่ทำให้คุณตรงไปตรงมา
ช่องว่างระหว่างการทดสอบย้อนหลัง DCC และประสิทธิภาพการเทรดสดมักเป็นการรั่วไหลของการมองล่วงหน้าเสมอ — แบบเต็มตัวอย่าง ร่วมสมัย หรือการปรับใหม่บนข้อมูลที่รวมการเทรดที่คุณกำลังประเมิน วินัยของการจับคู่การทดสอบย้อนหลังกับสภาพการเทรดสดเป็นหัวข้อของตัวมันเองใน ความเท่าเทียมระหว่างการทดสอบย้อนหลังและการเทรดสด และ DCC เป็นแบบจำลองที่ลงโทษความหละหลวมตรงนี้มากกว่าส่วนใหญ่ ถ้าหลังจากการประเมิน walk-forward ที่สะอาดแล้ว สหสัมพันธ์แบบพลวัตไม่ได้เพิ่มอะไรเลยเหนือค่าประมาณ rolling ธรรมดาสำหรับกลยุทธ์ ของคุณ นั่นคือผลลัพธ์เชิงลบที่แท้จริงและตีพิมพ์ได้ — แนวคิดใน ผลลัพธ์เชิงลบที่ตรงไปตรงมา ใช้ได้โดยตรง
Asymmetric DCC (aDCC)
เช่นเดียวกับ leverage effect แบบตัวแปรเดี่ยว (ตอนที่ 2) ที่ข่าวร้ายเพิ่มความผันผวนมากกว่าข่าวดี สหสัมพันธ์เพิ่มขึ้นมากกว่าหลังช็อกทางลบร่วมกัน (joint negative) มากกว่าหลังช็อกทางบวกร่วมกัน Cappiello, Engle & Sheppard (2006) จับสิ่งนี้ด้วย asymmetric DCC เพิ่มเทอมที่ขับเคลื่อนโดย outer product ของส่วนตกค้างที่ถูกทำให้เป็นมาตรฐานส่วน ทางลบ
โดยที่ และ วัดแรงกระตุ้นสหสัมพันธ์พิเศษจากการเคลื่อนไหวขาลงร่วมกัน สำหรับคริปโต ที่สหสัมพันธ์แบบล่ม (crash-correlation) เป็นความเสี่ยงหลัก เทอมความไม่สมมาตรมักมีนัยสำคัญและคุ้มค่ากับพารามิเตอร์เพิ่มเติมหนึ่งตัว rmgarch ปรับ aDCC ได้ทันที (model="aDCC") การเพิ่มเทอม เข้าไปในตัวประมาณ NumPy ของเราเป็นแบบฝึกหัดที่ตรงไปตรงมา
การเปรียบเทียบ: DCC เทียบกับทางเลือกอื่น
DCC อยู่ตรงไหนในบรรดาวิธีต่าง ๆ ที่คุณอาจได้เมทริกซ์ความแปรปรวนร่วมสำหรับพอร์ตคริปโต สรุปแบบตรงไปตรงมา
| แนวทาง | พารามิเตอร์ | ขยายไปถึง | สหสัมพันธ์แปรผันตามเวลาไหม? | รับประกัน PD ไหม? | การพึ่งพากันของหางไหม? |
|---|---|---|---|---|---|
| Sample / rolling covariance | 0 (ความยาวหน้าต่าง) | ใดก็ได้ | หยาบ (ล่าช้า มีสัญญาณรบกวน) | ไม่ (ต้องแก้ไข) | ไม่ |
| EWMA (RiskMetrics) | 1 () | ใดก็ได้ | ใช่ (การสลายตัวเดียว) | ใช่ | ไม่ |
| CCC-GARCH | margins ตัว + | หลายสิบ | ไม่ ( คงที่) | ใช่ | ไม่ |
| DCC-GARCH | margins ตัว + 2 | หลายสิบ | ใช่ | ใช่ | ไม่ |
| aDCC-GARCH | margins ตัว + 3 | หลายสิบ | ใช่ ไม่สมมาตร | ใช่ | บางส่วน |
| BEKK | ใช่ (สมบูรณ์) | ใช่ | ไม่ | ||
| VECH | ใช่ (สมบูรณ์ที่สุด) | ลำบาก | ไม่ | ||
| GARCH-copula | margins ตัว + copula | หลายสิบ (vines) | copula คงที่ | ใช่ | ใช่ |
การอ่านตารางนี้ไม่กี่ประเด็น
- EWMA เป็นเกณฑ์พื้นฐานราคาถูกที่ทุกคนควรเอาชนะให้ได้ก่อนอ้างว่า DCC ช่วย มันเป็นกรณีพิเศษแบบพารามิเตอร์เดียวในเชิงจิตวิญญาณ — การสลายตัวแบบเอ็กซ์โพเนนเชียลเดี่ยวที่ใช้กับความแปรปรวนร่วมโดยตรง — และสำหรับหลายพอร์ตมันยากอย่างน่าประหลาดใจที่จะปรับปรุงนอกตัวอย่าง ถ้า DCC ไม่เอาชนะ EWMA ใน walk-forward ที่สะอาด ให้ใช้ EWMA
- CCC เทียบกับ DCC คือประเด็นทั้งหมดของบทความนี้ การแยกตัวประกอบเดียวกัน แต่ CCC ตรึง ไว้ และ DCC ปล่อยให้มันเคลื่อนไหว พารามิเตอร์เพิ่มเติมสองตัว () คือความแตกต่างทั้งหมด และในคริปโตพวกมันคุ้มค่าที่จะมี
- BEKK/VECH ซื้อพลวัตที่สมบูรณ์กว่า — ทุกความแปรปรวนร่วมสามารถตอบสนองต่อทุกช็อกในอดีตได้ — แต่ต้นทุนพารามิเตอร์จำกัดมันไว้ที่พอร์ตขนาดเล็กมาก สำหรับเกิน 4 สินทรัพย์มันไม่ใช่ทางเลือกที่แท้จริง
- GARCH-copula เป็นแถวเดียวที่มี "ใช่" ภายใต้การพึ่งพากันของหาง นั่นคือความเสริมกันอีกครั้ง DCC สร้างแบบจำลอง ศูนย์กลาง แบบพลวัตของการแจกแจงร่วม copula สร้างแบบจำลอง หาง แบบคงที่ของมัน ถ้าคำถามความเสี่ยงของคุณคือ "จะเกิดอะไรขึ้นเมื่อทุกอย่างพังพร้อมกัน" ให้หยิบ ไปป์ไลน์ copula ถ้าคือ "อัตราส่วนป้องกันความเสี่ยง/ความแปรปรวนของพอร์ตของฉันตอนนี้คือเท่าไร" ให้หยิบ DCC
ค่าเริ่มต้นในทางปฏิบัติสำหรับเดสก์คริปโตเชิงระบบ DCC (หรือ aDCC) สำหรับอัตราส่วนป้องกันความเสี่ยงและความแปรปรวนร่วมแบบพลวัตในตัวหลัก ชั้นซ้อน copula สำหรับความเสี่ยงหางและ CVaR และ EWMA เป็นเกณฑ์พื้นฐานตรวจสอบความสมเหตุสมผลที่ทำให้คุณตรงไปตรงมาว่ากลไกเพิ่มเติมนั้นคุ้มค่ากับตัวมันเองหรือไม่
ข้อจำกัด
- พลวัตแบบสเกลาร์ และ ตัวเดียวสำหรับทุกคู่เป็นข้อจำกัดที่แข็งแกร่ง BTC-ETH และอัลต์คอยน์ที่ไม่ค่อยมีคนรู้จักสองตัวใช้ความเร็วการปรับตัวเดียวกัน Generalized DCC ผ่อนคลายสิ่งนี้แต่นำการระเบิดของพารามิเตอร์ที่ DCC ถูกออกแบบมาเพื่อหลีกเลี่ยงกลับมา
- การสูญเสียประสิทธิภาพแบบสองขั้นตอน ตัวประมาณ quasi-likelihood มีความสม่ำเสมอแต่ไม่มีประสิทธิภาพเต็มที่ และค่าความคลาดเคลื่อนมาตรฐานแบบไร้เดียงสาผิดพลาด ใช้การปรับแก้ของ Engle-Sheppard ถ้าคุณสนใจการอนุมานเชิงสถิติ สำหรับการสร้างสัญญาณ ค่าประมาณจุดก็เพียงพอ
- หางแบบ Gaussian โดยค่าเริ่มต้น quasi-likelihood แบบ Gaussian ธรรมดาประเมินความเสี่ยงหางร่วมต่ำเกินไป Student-t innovations ช่วยได้ สำหรับ การพึ่งพากัน ของหางที่แท้จริง (ความน่าจะเป็นของการเคลื่อนไหวสุดขั้วพร้อมกัน) DCC เป็นเครื่องมือที่ผิด และ แบบจำลอง copula คือเครื่องมือที่ถูกต้อง DCC ให้ ตัวหลัก (body) แบบพลวัตของสหสัมพันธ์ copula ให้ หาง แบบคงที่ เดสก์ที่จริงจังใช้ทั้งสองอย่าง
- สหสัมพันธ์ไม่ใช่เหตุปัจจัย และไม่ใช่ทิศทาง ที่เพิ่มขึ้นเตือนว่าความหลากหลายกำลังล้มเหลว มันไม่ได้บอกอะไรเกี่ยวกับทิศทางตลาด อย่าใส่ความคาดหวังเชิงทิศทางลงในสัญญาณความเสี่ยงมากเกินไป
- ความหิวกระหายข้อมูล ทุกอย่างข้างต้นสมมติประวัติที่ยาว สะอาด และตรงกันตามเวลา โทเคนคริปโตที่ใหม่และน่าสนใจที่สุดละเมิดทั้งสามข้อ
สรุป
- สหสัมพันธ์แบบคงที่คือคำโกหกในคริปโต สหสัมพันธ์รวมกลุ่ม คงอยู่ และพุ่งเข้าใกล้ 1 ในตลาดร่วง — พอดีในช่วงที่ความหลากหลายควรจะช่วยได้ สหสัมพันธ์แบบตัวอย่างเดี่ยว เฉลี่ยกระบวนการที่เปลี่ยนระบอบเข้าเป็นค่ากลางที่ไม่มีความหมาย
- GARCH แบบหลายตัวแปรเต็มรูปแบบ (VECH, BEKK) ไม่ขยายตามขนาด จำนวนพารามิเตอร์เพิ่มขึ้นเป็น ทั้งสองแบบถูกจำกัดไว้ที่สินทรัพย์ไม่กี่ตัวในทางปฏิบัติ
- DCC (Engle 2002) แยกตัวประกอบปัญหา โดยที่ มาจากการปรับ GARCH แบบตัวแปรเดี่ยวอิสระ (นำตอนที่ 1-2 กลับมาใช้) และ มาจากการวนซ้ำแบบสองพารามิเตอร์ มันขยายไปถึงหลายสิบสินทรัพย์เพราะมีเพียง เท่านั้นที่ถูกหาค่าเหมาะสมที่สุด
- การวนซ้ำ ที่ถูกทำให้เป็นมาตรฐานเป็น ผลิตเมทริกซ์สหสัมพันธ์ positive-definite ที่ถูกต้องในทุกขั้นตอน โดยมี ,
archไม่รองรับ DCC ปรับขอบเขต (margins) ด้วยarchแล้วทำใช้จริงตัวประมาณ NumPy/SciPy ~60 บรรทัดในที่นี้ หรือใช้mgarch(Python) หรือrmgarch(R เป็นตัวอ้างอิง)- ผลตอบแทนที่จับต้องได้สามอย่าง อัตราส่วนป้องกันความเสี่ยงแบบพลวัต สำหรับการเทรดคู่ ความแปรปรวนของพอร์ตที่แปรผันตามเวลาอย่างตรงไปตรงมา สำหรับการจัดสรรตามความเสี่ยง และสหสัมพันธ์เฉลี่ยแบบคู่เป็นสัญญาณระบอบ risk-off
- วินัยคือทุกสิ่ง Correlation targeting รั่วไหลค่าเฉลี่ยแบบเต็มตัวอย่าง ดังนั้นให้ประมาณ ใหม่บนข้อมูลฝึกเท่านั้น ล่าช้าอัตราส่วนป้องกันความเสี่ยงทุกตัว กรองไปข้างหน้า ไม่เคยทำให้เรียบ การประเมิน walk-forward ไม่สามารถต่อรองได้
- aDCC เพิ่มเทอมความไม่สมมาตรขาลงและมักคุ้มค่าในคริปโต ที่สหสัมพันธ์แบบล่มครอบงำ
- ตอนที่ 4 ใช้การพยากรณ์เหล่านี้เพื่อสร้างและทดสอบย้อนหลังกลยุทธ์ที่กำหนดเป้าหมายความผันผวน
เอกสารอ้างอิง:
- Engle, R. (2002). Dynamic Conditional Correlation: A Simple Class of Multivariate Generalized Autoregressive Conditional Heteroskedasticity Models. Journal of Business & Economic Statistics, 20(3), 339-350. DOI
- Engle, R. & Sheppard, K. (2001). Theoretical and Empirical Properties of Dynamic Conditional Correlation Multivariate GARCH. NBER Working Paper 8554. DOI
- Bollerslev, T. (1990). Modelling the Coherence in Short-Run Nominal Exchange Rates: A Multivariate Generalized ARCH Model. Review of Economics and Statistics, 72(3), 498-505. DOI
- Cappiello, L., Engle, R., & Sheppard, K. (2006). Asymmetric Dynamics in the Correlations of Global Equity and Bond Returns. Journal of Financial Econometrics, 4(4), 537-572. DOI
- Engle, R. & Kroner, K. (1995). Multivariate Simultaneous Generalized ARCH. Econometric Theory, 11(1), 122-150. DOI
- Bollerslev, T., Engle, R., & Wooldridge, J. (1988). A Capital Asset Pricing Model with Time-Varying Covariances. Journal of Political Economy, 96(1), 116-131. DOI
- Galanos, A. (2022). rmgarch: Multivariate GARCH Models. R package. CRAN.
MarketMaker.cc Team
การวิจัยและกลยุทธ์เชิงปริมาณ