DeepLOB: การเรียนรู้เชิงลึกบนสมุดคำสั่งซื้อขายแบบจำกัดราคา
สมุดคำสั่งซื้อขายแบบจำกัดราคา (limit order book) คือโครงสร้างข้อมูลหลักของตลาดอิเล็กทรอนิกส์สมัยใหม่ ทุกคำสั่งเสนอซื้อ ทุกคำสั่งเสนอขาย ทุกการยกเลิก — ทั้งหมดอยู่ใน LOB เป็นเวลาหลายทศวรรษที่นักวิจัยเชิงปริมาณได้สร้างคุณลักษณะ (feature) จากข้อมูลนี้ด้วยมือ ไม่ว่าจะเป็นอัตราส่วนความไม่สมดุลของคำสั่ง (order imbalance ratio) ราคากลางถ่วงน้ำหนัก และสัญญาณตำแหน่งในคิว DeepLOB เลือกเส้นทางที่แตกต่างออกไป — มันเรียนรู้คุณลักษณะเหล่านี้โดยตรงจากภาพถ่ายสมุดคำสั่งดิบโดยใช้สถาปัตยกรรมแบบผสม CNN-LSTM
เผยแพร่โดย Zhang, Zohren และ Roberts ที่ Oxford-Man Institute ในปี 2019 DeepLOB แสดงให้เห็นว่าเครือข่ายเชิงลึกเดียวที่ฝึกแบบ end-to-end บนข้อมูลสมุดคำสั่งดิบนั้นสามารถแข่งขันได้หรือดีกว่า baseline แบบดั้งเดิมที่แข็งแกร่งในการทำนายการเคลื่อนไหวของราคากลาง อย่างไรก็ตาม เราควรแม่นยำเกี่ยวกับหลักฐาน ชุดข้อมูลมาตรฐาน FI-2010 เป็นชุดที่งานวิจัยส่วนใหญ่อ้างอิงถึง แต่ผู้เขียนเองกลับเรียกมันว่าไม่เพียงพอ — "สั้นเกินไป ถูกลดอัตราการสุ่มตัวอย่าง (downsampled) และนำมาจากตลาดที่มีสภาพคล่องน้อยกว่า" — และนำเสนอการประเมินผลครั้งที่สองที่ใหญ่กว่ามากบนข้อมูลของตลาดหลักทรัพย์ลอนดอน (LSE) เป็นผลลัพธ์ที่แข็งแกร่งกว่า การศึกษา LSE นั้นครอบคลุมข้อมูลหุ้นฝึกห้าตัวและหุ้นทดสอบห้าตัวประมาณหนึ่งปี มีตัวอย่างในระดับ 100 ล้านตัวอย่างขึ้นไป และแสดงให้เห็นการเรียนรู้แบบถ่ายโอน (transfer learning) นั่นคือ โมเดลที่ฝึกบนหุ้นชุดหนึ่งยังคงทำนายหุ้นที่ไม่เคยเห็นได้ ผลลัพธ์ของการถ่ายโอนนั้น ไม่ใช่ตารางคะแนน FI-2010 ต่างหากที่เป็นพาดหัวข่าวจริงของงานวิจัยนี้ บทความนี้จะวิเคราะห์สถาปัตยกรรม คณิตศาสตร์ ตัวเลขจริง และการสร้างใหม่ด้วย PyTorch ที่ใช้งานได้จริง
สมุดคำสั่งซื้อขายแบบจำกัดราคาในฐานะโครงสร้างข้อมูล

สมุดคำสั่งซื้อขายแบบจำกัดราคาจะเก็บรายการสองชุดที่เรียงลำดับไว้ — คำสั่งเสนอซื้อ (bid) และคำสั่งเสนอขาย (ask) — โดยแต่ละชุดจัดเรียงตามระดับราคา ในแต่ละระดับ สมุดคำสั่งจะบันทึกราคาและปริมาณรวมของคำสั่งที่ค้างอยู่
สำหรับสมุดคำสั่งที่มี ระดับ ภาพถ่าย (snapshot) เดียว ณ เวลา คือเวกเตอร์ของค่า ค่า:
โดยที่ และ คือราคาและปริมาณเสนอขายที่ระดับ และ , คือค่าที่สอดคล้องกันในฝั่งเสนอซื้อ ระดับ 1 เก็บคำสั่งเสนอซื้อที่ดีที่สุดและคำสั่งเสนอขายที่ดีที่สุด (BBO) ส่วนต่างของทั้งสองคือสเปรด (bid-ask spread)
ในชุดข้อมูลมาตรฐาน FI-2010 ค่า ทำให้มี 40 คุณลักษณะต่อหนึ่งภาพถ่าย FI-2010 สร้างจากข้อความคำสั่งจำกัดราคาดิบประมาณ 4 ล้านข้อความจากหุ้นฟินแลนด์ห้าตัวบน NASDAQ Nordic (Kesko, Outokumpu, Sampo, Rautaruukki, Wartsila) ตลอดสิบวันทำการติดต่อกันคือวันที่ 1-14 มิถุนายน 2010 ที่สำคัญคือ DeepLOB ไม่ได้ฝึกบนภาพถ่าย 4 ล้านภาพ ชุดข้อมูลมาตรฐานนี้ลดอัตราการสุ่มตัวอย่างข้อความเหล่านั้น (ทุก 10 เหตุการณ์) ให้เป็นรูปแบบที่ทำให้เป็นมาตรฐานแล้วจำนวน 394,337 ตัวอย่าง รูปแบบที่ถูกลดอัตราการสุ่มและทำให้เป็นมาตรฐานนี้คือสิ่งที่โมเดลเห็นจริง ๆ — เป็นหนึ่งในเหตุผลที่ผู้เขียนเตือนไม่ให้ถือว่า FI-2010 เป็นคำตอบสุดท้าย
ราคากลางและการเคลื่อนไหวของมัน
ราคากลาง ณ เวลา คือค่าเฉลี่ยของคำสั่งเสนอซื้อและเสนอขายที่ดีที่สุด:
DeepLOB ทำนายทิศทางการเคลื่อนไหวของราคากลางในช่วงเวลาในอนาคต เหตุการณ์ ป้ายกำกับ (label) คือผลตอบแทนที่ผ่านการปรับเรียบ (smoothed return) แต่พึงระวังว่ามีแบบแผนการปรับเรียบสองแบบในวรรณกรรม และทั้งสองไม่สามารถใช้แทนกันได้:
- ค่าเฉลี่ยอนาคตเทียบกับราคาปัจจุบัน (Tsantekidis et al.): เปรียบเทียบราคากลางเฉลี่ยในช่วง เหตุการณ์ถัดไปกับราคากลางปัจจุบันแบบดิบ
- ค่าเฉลี่ยอนาคตเทียบกับค่าเฉลี่ยก่อนหน้า (Ntakaris et al. ซึ่งเป็นป้ายกำกับมาตรฐานของ FI-2010 และเป็นแบบที่ DeepLOB ใช้สำหรับข้อมูล LSE ของตน): ทั้งค่าอ้างอิงและค่าเป้าหมายต่างผ่านการปรับเรียบ
การปรับเรียบค่าอ้างอิง (ไม่ใช่แค่อนาคต) ช่วยลดสัญญาณรบกวนของป้ายกำกับจากการแกว่งตัวของราคาเพียงหนึ่งทิคได้อย่างมีนัยสำคัญ ซึ่งเป็นเหตุผลที่รูปแบบค่าเฉลี่ยก่อนหน้า/ถัดไปเป็นที่นิยมมากกว่า ไม่ว่าจะใช้แบบใด ผลตอบแทนแบบต่อเนื่องจะถูกแบ่งออกเป็นสามคลาส — ขึ้น (up), ลง (down), คงที่ (stationary) — โดยใช้เกณฑ์คงที่ :
ชุดข้อมูล FI-2010 ให้ป้ายกำกับสำหรับช่วงเวลาการทำนายห้าช่วง: เหตุการณ์
คุณลักษณะ LOB แบบดั้งเดิม
ก่อนการเรียนรู้เชิงลึก นักวิจัยพึ่งพาคุณลักษณะที่สร้างด้วยมือ การทำความเข้าใจสิ่งเหล่านี้เป็นสิ่งจำเป็น เพราะ DeepLOB ถูกออกแบบโครงสร้างขึ้นมาโดยตั้งใจให้คล้ายกับคุณลักษณะเหล่านี้หลายตัว — สถาปัตยกรรมของมันได้รับแรงบันดาลใจจากปริมาณเหล่านี้ แม้ในจุดที่มันไม่ได้สร้างสิ่งเหล่านี้ขึ้นมาใหม่อย่างแม่นยำก็ตาม
ความไม่สมดุลของสมุดคำสั่ง (Order Book Imbalance - OBI)
สัญญาณโครงสร้างจุลภาค (microstructure) ที่ใช้กันแพร่หลายที่สุด ที่ส่วนบนสุดของสมุดคำสั่ง:
ปริมาณเสนอซื้อที่มากกว่าเมื่อเทียบกับปริมาณเสนอขายบ่งชี้ถึงแรงกดดันขาขึ้น ความไม่สมดุลแบบหลายระดับจะรวมค่าตลอด ระดับ:
ราคากลางถ่วงน้ำหนักด้วยปริมาณ
ราคากลางมาตรฐานถ่วงน้ำหนักทั้งสองฝั่งเท่ากัน ราคากลางถ่วงน้ำหนักด้วยปริมาณ (เรียกอีกอย่างว่า weighted mid หรือ VAMP) เอนเอียงไปทางฝั่งที่หนักกว่าของสมุดคำสั่ง เมื่อเขียนความไม่สมดุลที่ส่วนบนสุดเป็น มันคือค่าเฉลี่ยถ่วงน้ำหนักด้วยความไม่สมดุลของราคาทั้งสอง:
สังเกตการถ่วงน้ำหนักไขว้: ราคาเสนอขายถูกถ่วงน้ำหนักด้วยปริมาณเสนอซื้อ และในทางกลับกัน เมื่อปริมาณเสนอซื้อมีอิทธิพลเหนือกว่า () ราคากลางถ่วงน้ำหนักจะเลื่อนไปทางฝั่งเสนอขาย — สะท้อนความคาดหวังว่าสมุดคำสั่งที่ไม่สมดุลจะคลี่คลายโดยการเคลื่อนไปทางฝั่งที่หนักกว่า
ขอเตือนเรื่องการตั้งชื่อ ราคากลางถ่วงน้ำหนักด้วยปริมาณแบบสถิตนี้ ไม่ใช่ microprice ของ Stoikov micro-price ของ Stoikov (2018) เป็นตัวประมาณค่าที่ปรับด้วยมาร์ติงเกล (martingale-adjusted estimator) ซึ่งได้มาจากการแก้ไขแบบเรียกซ้ำสำหรับวิธีที่สเปรดและความไม่สมดุลพัฒนาไป — ประเด็นหลักของเขาคือราคากลางถ่วงน้ำหนักแบบไร้เดียงสานั้นมีอคติและไม่ใช่มาร์ติงเกล ทั้งสองเป็นวัตถุที่แตกต่างกันสองชนิด เราใช้ราคากลางถ่วงน้ำหนักในที่นี้เพราะความเรียบง่ายของมัน ไม่ใช่ในฐานะตัวแทนของ microprice
ความไม่สมดุลของความลึก (Depth Imbalance)
วัดรูปร่างของสมุดคำสั่งที่ลึกเกินกว่า BBO:
สเปรดและสเปรดสัมพัทธ์
คุณลักษณะเหล่านี้ทรงพลังแต่ก็มีข้อจำกัด พวกมันต้องอาศัยความเชี่ยวชาญเฉพาะด้านในการออกแบบ ไม่สามารถจับปฏิสัมพันธ์แบบไม่เชิงเส้นที่ซับซ้อนได้ และละเลยพลวัตเชิงเวลาตลอดภาพถ่ายที่ต่อเนื่องกัน DeepLOB จัดการกับข้อจำกัดทั้งสามข้อนี้
สถาปัตยกรรมของ DeepLOB

สถาปัตยกรรมประกอบด้วยสามบล็อก แต่ละบล็อกมีบทบาทเฉพาะตัว:
- บล็อกคอนโวลูชัน (Convolutional block) — สกัดคุณลักษณะเชิงพื้นที่จากภาพถ่ายสมุดคำสั่ง
- โมดูล inception — จับรูปแบบเชิงเวลาแบบหลายสเกล
- บล็อก LSTM — สร้างแบบจำลองการพึ่งพาเชิงลำดับตลอดเวลา
อินพุตของเครือข่ายคือเทนเซอร์ที่มีรูปร่าง โดยที่ คือหน้าต่างมองย้อนหลัง (lookback window) (100 ขั้นเวลาในงานวิจัย) และ สำหรับ 10 ระดับของราคาและปริมาณทั้งสองฝั่ง
บล็อก 1: การสกัดคุณลักษณะแบบคอนโวลูชัน
เลเยอร์คอนโวลูชันแรกทำงานตามมิติคุณลักษณะเพื่อเรียนรู้ปฏิสัมพันธ์ระหว่างราคาและปริมาณในแต่ละระดับ
เลเยอร์ 1: คอนโวลูชันที่มีขนาดฟิลเตอร์ และสไตรด์ ที่ใช้กับแต่ละคู่ราคา-ปริมาณ สิ่งนี้สรุปแต่ละคู่ ให้เป็นคุณลักษณะเดียว — คล้ายกับการคำนวณ "ปฏิสัมพันธ์ราคา-ปริมาณ" ในแต่ละระดับ ความกว้างหดจาก 40 เหลือ 20
เลเยอร์ 2: คอนโวลูชัน สไตรด์ ที่ทำงานข้ามคู่เสนอซื้อ-เสนอขายที่จับคู่กันในระดับเดียวกัน สิ่งนี้จับข้อมูลสเปรดและความไม่สมดุลในแต่ละระดับ ความกว้างหดจาก 20 เหลือ 10
เลเยอร์ 3: คอนโวลูชัน ที่รวมข้ามทั้ง 10 ระดับ ยุบมิติความลึกให้เหลือความกว้าง 1 สิ่งนี้สร้างคุณลักษณะรวมเดียวต่อขั้นเวลาที่เข้ารหัสโปรไฟล์ความลึกทั้งหมด
แต่ละขั้น / ตามด้วยคอนโวลูชัน สองตัวตามแกนเวลา แต่ละตัวมีฟังก์ชันกระตุ้น LeakyReLU และ batch normalization โปรดสังเกตว่าคอนโวลูชัน เหล่านี้ที่มี padding=(1, 0) ไม่ได้ รักษามิติเวลาไว้: แต่ละตัวจะทำให้มันสั้นลงหนึ่งขั้น () ตลอดหกเลเยอร์ดังกล่าวในบล็อก 1-3 แกนเวลาหดจาก 100 เหลือ 94 ก่อนถึงโมดูล inception — สิ่งที่คอมเมนต์เกี่ยวกับรูปร่างในโค้ดด้านล่างทำให้ชัดเจน
การออกแบบหลีกเลี่ยงฟิลเตอร์เชิงพื้นที่ขนาดใหญ่โดยเจตนา ฟิลเตอร์ เคารพโครงสร้างการจับคู่ตามธรรมชาติของข้อมูล LOB — ราคากับปริมาณ เสนอซื้อกับเสนอขาย อคติเชิงอุปนัย (inductive bias) นี้สำคัญยิ่ง: ฟิลเตอร์ จะผสมระดับและฝั่งที่อยู่ติดกันในแบบที่ไม่มีความหมายทางการเงิน
บล็อก 2: โมดูล Inception
หลังจากบล็อกคอนโวลูชันลด 40 คุณลักษณะให้เป็นการแทนเชิงพื้นที่ที่กระชับ (ความกว้าง 1) โมดูล inception จะทำงานตามมิติเวลาเพื่อจับรูปแบบที่หลายสเกลเวลาพร้อมกัน
โมดูล inception ของ DeepLOB มีเส้นทางขนาน สี่ เส้นทาง แต่ละเส้นทางสร้าง 32 ช่อง (channel) ซึ่งทั้งหมดถูกต่อเชื่อม (concatenate) เข้าด้วยกัน:
- คอขวด คอนโวลูชันเชิงเวลา : รูปแบบเชิงเวลาระยะสั้น (3 ขั้นเวลา)
- คอขวด คอนโวลูชันเชิงเวลา : รูปแบบเชิงเวลาระยะกลาง (5 ขั้นเวลา)
- max-pool คอนโวลูชัน : เส้นทาง pooling ที่รักษามุมมองที่ผ่านการปรับเรียบและลดอัตราการสุ่มไว้
- (การลดขนาด ทำหน้าที่เป็นคอขวด ณ จุดเวลาก่อนคอนโวลูชันเชิงเวลา)
แต่ละเส้นทางเชิงเวลาใช้ padding แบบสมมาตรเพื่อรักษามิติเวลาไว้ภายในบล็อก inception (ต่างจากบล็อกคอนโวลูชันด้านบน) เอาต์พุตถูกต่อเชื่อมตามมิติช่อง ทำให้เครือข่ายเข้าถึงคุณลักษณะเชิงเวลาแบบหลายสเกลได้พร้อมกัน
สิ่งนี้ได้รับแรงบันดาลใจจากสถาปัตยกรรม inception ของ GoogLeNet แต่ปรับให้เข้ากับข้อมูลเชิงเวลาแบบ 1 มิติแทนที่จะเป็นภาพ 2 มิติ ข้อมูลเชิงลึกที่สำคัญคือ พลวัตของ LOB ดำเนินไปที่หลายสเกลเวลา: สัญญาณรบกวนแบบทิคต่อทิค โมเมนตัมระยะสั้น และการกลับสู่ค่าเฉลี่ย (mean reversion) ในช่วงเวลาที่ยาวกว่า ล้วนอยู่ร่วมกัน
การสร้างใหม่ด้วย PyTorch ด้านล่างนำเสนอ รูปแบบสามเส้นทางที่ทำให้เรียบง่ายขึ้น (คอนโวลูชันเชิงเวลาสองตัวบวกกับเส้นทาง ) เพื่อให้โค้ดอ่านง่าย ซึ่งละเว้นเส้นทาง max-pool เราชี้ให้เห็นสิ่งนี้อย่างชัดเจนเพราะมันเป็นการเบี่ยงเบนจากงานวิจัย ไม่ใช่โมดูลต้นฉบับ
บล็อก 3: การสร้างแบบจำลองลำดับด้วย LSTM
เอาต์พุตของโมดูล inception ถูกป้อนเข้าสู่เลเยอร์ LSTM ที่ประมวลผลลำดับความยาว ทั้งหมด LSTM จับการพึ่งพาเชิงเวลาระยะไกลที่คอนโวลูชันเพียงอย่างเดียวจะพลาดไป — การเปลี่ยนแปลงระบอบ (regime change) ผลกระทบของช่วงเวลาในวัน และสภาวะตลาดที่เปลี่ยนแปลง
สถานะซ่อน (hidden state) สุดท้ายของ LSTM ถูกส่งผ่านเลเยอร์เชื่อมต่อเต็มที่ (fully connected) ที่มีฟังก์ชันกระตุ้น softmax เพื่อสร้างการแจกแจงความน่าจะเป็นเหนือสามคลาส (ขึ้น ลง คงที่)
ฟังก์ชันการสูญเสีย (Loss Function)
โมเดลถูกฝึกด้วย categorical cross-entropy:
โดยที่ คือป้ายกำกับจริงที่เข้ารหัสแบบ one-hot และ คือความน่าจะเป็นที่ทำนายสำหรับคลาส
การสร้างใหม่ด้วย PyTorch
DeepLOB ต้นฉบับสร้างขึ้นใน Keras บนแบ็กเอนด์ TensorFlow ภายหลังคลังโค้ดของผู้เขียน (zcakhaa) ได้เพิ่มเวอร์ชันพอร์ตเป็น PyTorch โค้ดด้านล่างเป็นการสร้างใหม่ด้วย PyTorch เพื่อเป็นตัวอย่างของเราเอง ไม่ใช่ฉบับทางการ มันเบี่ยงเบนจากงานวิจัยในสองด้านที่เราระบุไว้แบบ inline: มันละเว้นเส้นทาง max-pool ของ inception (สามเส้นทางแทนที่จะเป็นสี่) และมันขยายจำนวนช่องขึ้น งานวิจัยใช้ 16 ฟิลเตอร์ ตลอดบล็อกคอนโวลูชันและ 32 ฟิลเตอร์ต่อเส้นทาง inception (อินพุตของ LSTM คือ ) ทำให้ได้โมเดลที่กระชับราว 60,000 พารามิเตอร์ ตัวอย่างโค้ดด้านล่างใช้คอนโวลูชัน 32 / ฟิลเตอร์ inception 64 (อินพุต LSTM 192) — สอดคล้องกันภายในและรันได้ แต่หนักกว่าต้นฉบับ เพื่อให้ตรงกับงานวิจัย ให้ตั้งค่าช่องคอนโวลูชันเป็น 16, ช่อง inception เป็น 32 และ input_size=96
import torch
import torch.nn as nn
class DeepLOB(nn.Module):
"""
DeepLOB-style CNN-Inception-LSTM for limit order books.
Reimplementation inspired by Zhang, Zohren, Roberts (2019),
IEEE Transactions on Signal Processing, arXiv:1808.03668.
NOTE: this is an illustrative reimplementation, NOT the official model.
Differences from the paper:
- inception has 3 paths here vs 4 in the paper (max-pool path omitted);
- channel counts are scaled up (paper: 16 conv / 32 inception, input 96).
Input shape: (batch_size, 1, T, 40)
T = lookback window (e.g. 100)
40 = 10 levels x 4 features (ask_price, ask_vol, bid_price, bid_vol)
"""
def __init__(self, num_classes: int = 3, T: int = 100):
super().__init__()
self.num_classes = num_classes
self.conv1 = nn.Sequential(
nn.Conv2d(1, 32, kernel_size=(1, 2), stride=(1, 2)),
nn.LeakyReLU(negative_slope=0.01),
nn.BatchNorm2d(32),
nn.Conv2d(32, 32, kernel_size=(4, 1), padding=(1, 0)), # time -1
nn.LeakyReLU(negative_slope=0.01),
nn.BatchNorm2d(32),
nn.Conv2d(32, 32, kernel_size=(4, 1), padding=(1, 0)), # time -1
nn.LeakyReLU(negative_slope=0.01),
nn.BatchNorm2d(32),
)
self.conv2 = nn.Sequential(
nn.Conv2d(32, 32, kernel_size=(1, 2), stride=(1, 2)),
nn.LeakyReLU(negative_slope=0.01),
nn.BatchNorm2d(32),
nn.Conv2d(32, 32, kernel_size=(4, 1), padding=(1, 0)), # time -1
nn.LeakyReLU(negative_slope=0.01),
nn.BatchNorm2d(32),
nn.Conv2d(32, 32, kernel_size=(4, 1), padding=(1, 0)), # time -1
nn.LeakyReLU(negative_slope=0.01),
nn.BatchNorm2d(32),
)
self.conv3 = nn.Sequential(
nn.Conv2d(32, 32, kernel_size=(1, 10)),
nn.LeakyReLU(negative_slope=0.01),
nn.BatchNorm2d(32),
nn.Conv2d(32, 32, kernel_size=(4, 1), padding=(1, 0)), # time -1
nn.LeakyReLU(negative_slope=0.01),
nn.BatchNorm2d(32),
nn.Conv2d(32, 32, kernel_size=(4, 1), padding=(1, 0)), # time -1
nn.LeakyReLU(negative_slope=0.01),
nn.BatchNorm2d(32),
)
self.inp1 = nn.Sequential(
nn.Conv2d(32, 64, kernel_size=(1, 1), padding=(0, 0)),
nn.LeakyReLU(negative_slope=0.01),
nn.BatchNorm2d(64),
)
self.inp2 = nn.Sequential(
nn.Conv2d(32, 64, kernel_size=(1, 1), padding=(0, 0)),
nn.LeakyReLU(negative_slope=0.01),
nn.BatchNorm2d(64),
nn.Conv2d(64, 64, kernel_size=(3, 1), padding=(1, 0)),
nn.LeakyReLU(negative_slope=0.01),
nn.BatchNorm2d(64),
)
self.inp3 = nn.Sequential(
nn.Conv2d(32, 64, kernel_size=(1, 1), padding=(0, 0)),
nn.LeakyReLU(negative_slope=0.01),
nn.BatchNorm2d(64),
nn.Conv2d(64, 64, kernel_size=(5, 1), padding=(2, 0)),
nn.LeakyReLU(negative_slope=0.01),
nn.BatchNorm2d(64),
)
self.lstm = nn.LSTM(
input_size=192, # 64 * 3 paths from the simplified inception
hidden_size=64,
num_layers=1,
batch_first=True,
)
self.fc = nn.Linear(64, num_classes)
def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
Args:
x: Tensor of shape (batch, 1, T, 40)
Returns:
Tensor of shape (batch, num_classes)
"""
h = self.conv1(x) # (batch, 32, T-2, 20)
h = self.conv2(h) # (batch, 32, T-4, 10)
h = self.conv3(h) # (batch, 32, T-6, 1) e.g. T=100 -> 94
h_inp1 = self.inp1(h) # (batch, 64, T-6, 1)
h_inp2 = self.inp2(h) # (batch, 64, T-6, 1)
h_inp3 = self.inp3(h) # (batch, 64, T-6, 1)
h = torch.cat([h_inp1, h_inp2, h_inp3], dim=1) # (batch, 192, T-6, 1)
h = h.squeeze(-1) # (batch, 192, T-6)
h = h.permute(0, 2, 1) # (batch, T-6, 192)
h, _ = self.lstm(h)
h = h[:, -1, :] # take last hidden state
out = self.fc(h)
return out
การประมวลผลข้อมูลก่อน (Data Preprocessing)
ชุดข้อมูล FI-2010 มาพร้อมการทำให้เป็นมาตรฐานแบบ z-score สำหรับข้อมูลสมุดคำสั่งแบบสด คุณต้องทำให้เป็นมาตรฐานในลักษณะเดียวกัน:
import numpy as np
from torch.utils.data import Dataset
class LOBDataset(Dataset):
"""Dataset for limit order book snapshots."""
def __init__(
self,
data: np.ndarray,
labels: np.ndarray,
T: int = 100,
):
"""
Args:
data: shape (num_snapshots, 40), raw LOB features
labels: shape (num_snapshots,), class labels {0, 1, 2}
T: lookback window length
"""
self.data = data
self.labels = labels
self.T = T
self.mean = data[:len(data) // 2].mean(axis=0)
self.std = data[:len(data) // 2].std(axis=0)
self.std[self.std == 0] = 1.0
self.data = (self.data - self.mean) / self.std
def __len__(self) -> int:
return len(self.data) - self.T
def __getitem__(self, idx: int):
x = self.data[idx : idx + self.T].reshape(1, self.T, 40)
y = self.labels[idx + self.T - 1]
return torch.tensor(x, dtype=torch.float32), torch.tensor(
y, dtype=torch.long
)
ลูปการฝึก (Training Loop)
def train_deeplob(
model: DeepLOB,
train_loader,
val_loader,
epochs: int = 50,
lr: float = 0.01,
device: str = "cuda",
):
model = model.to(device)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=lr, eps=1)
best_val_f1 = 0.0
for epoch in range(epochs):
model.train()
train_loss = 0.0
for x_batch, y_batch in train_loader:
x_batch = x_batch.to(device)
y_batch = y_batch.to(device)
optimizer.zero_grad()
logits = model(x_batch)
loss = criterion(logits, y_batch)
loss.backward()
optimizer.step()
train_loss += loss.item()
model.eval()
all_preds, all_labels = [], []
with torch.no_grad():
for x_val, y_val in val_loader:
x_val = x_val.to(device)
preds = model(x_val).argmax(dim=1).cpu()
all_preds.extend(preds.numpy())
all_labels.extend(y_val.numpy())
from sklearn.metrics import f1_score
val_f1 = f1_score(all_labels, all_preds, average="weighted")
print(
f"Epoch {epoch+1}/{epochs} | "
f"Train Loss: {train_loss/len(train_loader):.4f} | "
f"Val F1: {val_f1:.4f}"
)
if val_f1 > best_val_f1:
best_val_f1 = val_f1
torch.save(model.state_dict(), "deeplob_best.pt")
ไฮเปอร์พารามิเตอร์การฝึกที่สำคัญจากงานวิจัยต้นฉบับ:
- Optimizer: Adam ที่มี (ใหญ่ผิดปกติ — ช่วยทำให้การอัปเดตมีเสถียรภาพบนข้อมูลทางการเงินที่มีสัญญาณรบกวน)
- อัตราการเรียนรู้ (Learning rate): 0.01
- ขนาด batch: 32
- หน้าต่างมองย้อนหลัง: ขั้นเวลา
เราติดตามค่า weighted F1 มากกว่าความแม่นยำ (accuracy) ในการตรวจสอบ เพราะสามคลาสนั้นไม่สมดุล — และดังที่หัวข้อถัดไปแสดง F1 คือเมตริกที่งานวิจัยต้นฉบับเน้นย้ำด้วยเหตุผลนั้นพอดี
DeepLOB ถูกสร้างขึ้นเพื่อจับอะไร

แง่มุมที่น่าสนใจอย่างหนึ่งของ DeepLOB คือบล็อกของมัน ได้รับแรงบันดาลใจจาก คุณลักษณะที่สร้างด้วยมือข้างต้นอย่างใกล้ชิดเพียงใด เราต้องการระมัดระวังตรงนี้: งานวิจัยนำเสนอสิ่งเหล่านี้ในฐานะสัญชาตญาณการออกแบบ ไม่ใช่ในฐานะคุณสมบัติที่พิสูจน์แล้วของเครือข่ายที่ฝึกแล้ว มันไม่ได้เผยแพร่การแสดงภาพฟิลเตอร์ (filter visualization) ความสัมพันธ์ของการกระตุ้น-ความไม่สมดุล หรือการวิเคราะห์ว่า LSTM ให้ความสนใจกับสิ่งใด ดังนั้นโปรดอ่านสิ่งต่อไปนี้ในฐานะเจตนาเชิงสถาปัตยกรรม ไม่ใช่ผลการวัด
บล็อกคอนโวลูชันแรก ฟิลเตอร์ จับคู่ราคากับปริมาณในแต่ละระดับ ในเชิงโครงสร้าง นี่คือการดำเนินการเดียวกับที่ก่อตัวเป็นราคาถ่วงน้ำหนักด้วยปริมาณ — งานวิจัยอธิบายแรงจูงใจของเลเยอร์แรกโดยชี้ว่าแผนที่คุณลักษณะ (feature map) ของมันก่อตัวเป็นปริมาณที่คล้าย micro-price เครือข่าย ถูกสร้างขึ้นเพื่อ กู้คืนบางสิ่งในตระกูลนั้น เราไม่ได้อ้างว่ามันค้นพบตัวประมาณค่าใดโดยเฉพาะขึ้นมาใหม่ได้อย่างพิสูจน์ได้
บล็อกคอนโวลูชันที่สอง โดยการทำงานข้ามคู่เสนอซื้อ-เสนอขาย ฟิลเตอร์เหล่านี้อยู่ในตำแหน่งที่จะเรียนรู้คุณลักษณะที่คล้ายความไม่สมดุลในหลายระดับ — อีกครั้ง โดยการก่อสร้างมากกว่าโดยความสัมพันธ์ที่แสดงให้เห็นแล้ว
โมดูล inception คอนโวลูชันเชิงเวลาแบบหลายสเกลมีจุดมุ่งหมายเพื่อจับโมเมนตัมที่ความถี่ต่างกัน: เส้นทาง ตอบสนองต่อโครงสร้าง ณ จุดเวลา เส้นทาง ต่อแนวโน้มระยะสั้น เส้นทาง ต่อแนวโน้มที่ยาวกว่าเล็กน้อย และ (ในโมดูลเต็ม) เส้นทาง max-pool ต่อมุมมองที่ผ่านการปรับเรียบ
เลเยอร์ LSTM ส่วนประกอบแบบเรียกซ้ำ (recurrent) เพิ่มความจำของการพึ่งพาระยะไกลที่คอนโวลูชันไม่สามารถแทนได้ — การเปลี่ยนแปลงระบอบและผลกระทบของช่วงเวลาในวัน เราหลีกเลี่ยงการอ้างที่หนักแน่นกว่านี้ (เช่นว่า LSTM นำ "ความสนใจแบบปรับตัว (adaptive attention)" มาใช้ที่ถ่วงน้ำหนักข้อมูลล่าสุดใหม่ในระบอบที่ผันผวน) เพราะงานวิจัยไม่ได้แสดงสิ่งนี้
ประสิทธิภาพบน FI-2010
งานวิจัยต้นฉบับประเมินสองโปรโตคอล Setup 1 ใช้การแบ่งการทำให้เป็นมาตรฐานช่วงต้นของชุดข้อมูล Setup 2 คือชุดการเรียนรู้เชิงลึกที่งานในภายหลังส่วนใหญ่นำมาเปรียบเทียบ เนื่องจาก FI-2010 มีคลาสที่ไม่สมดุล งานวิจัยจึงเน้น F1 ไม่ใช่ความแม่นยำ และรายงานตัวเลขที่อิงกับ precision/recall สำหรับ baseline ที่ไม่ใช่นิวรัล (SVM, MLP) ต่อไปนี้คือตัวเลข Setup 2 จริง (F1, %):
| ช่วงเวลา (k) | SVM | MLP | CNN-I | LSTM | DeepLOB |
|---|---|---|---|---|---|
| 10 | 35.88 | 48.27 | 55.21 | 66.33 | 83.40 |
| 20 | — | — | — | — | 72.82 |
| 50 | — | — | — | — | 80.35 |
ที่ DeepLOB ยังรายงานความแม่นยำ 84.47% ควบคู่กับ F1 ที่ 83.40 ของมัน Setup 2 รายงานเฉพาะ — ไม่มีแถว ที่นี่ (Setup 1 รายงาน โดย DeepLOB มี F1 ที่ 77.66 / 74.96 / 76.58 ตามลำดับ) เครื่องหมายขีด (—) ข้างต้นบ่งบอกช่อง baseline ที่งานวิจัยไม่ได้จัดทำตารางในช่วงเวลาเหล่านั้นในโปรโตคอลนี้
มีข้อสังเกตหลายประการที่โดดเด่น:
- DeepLOB เอาชนะ baseline ด้วยส่วนต่างที่กว้างในช่วงเวลาสั้น ที่ F1 ของมัน (83.40) สูงกว่า LSTM (66.33), CNN-I (55.21), MLP (48.27) และ SVM (35.88) อย่างมาก การจัดอันดับเชิงคุณภาพ — โมเดลแบบ recurrent-convolutional เชิงลึกเหนือกว่า CNN ธรรมดา MLP และ SVM — คือบทสรุปที่แข็งแกร่ง
- แนวโน้มของช่วงเวลาไม่เป็นแบบเอกภาพ ไม่ใช่ "ยาวกว่าง่ายกว่า" ทั่ว Setup 2 F1 ของ DeepLOB เปลี่ยนเป็น เมื่อ เปลี่ยนเป็น — รูปแบบรูปตัว U โดย ยากที่สุด ไม่ใช่การไต่ขึ้นที่สะอาด ว่าช่วงเวลาใด "ง่ายกว่า" ขึ้นอยู่อย่างมากกับ setup เกณฑ์ และแบบแผนการปรับเรียบป้ายกำกับ เราไม่ควรอ่านกฎสากลจากตัวเลขเหล่านี้
- DeepLOB ไม่ได้เหนือกว่าทุกวิธีแบบดั้งเดิมในทุกช่อง เมื่อเทียบกับ baseline ที่แข็งแกร่งเช่น C(TABL) ส่วนต่างจะแคบลงในบางช่วงเวลา ดังนั้น "เหนือกว่าทุกแนวทางแบบดั้งเดิมทุกที่" จึงเป็นการกล่าวเกินจริง การอ้างที่ปกป้องได้คือมันแข่งขันได้ถึงดีที่สุด และดีที่สุดอย่างชัดเจนในช่วงเวลาสั้น
และอีกครั้ง: มุมมองของงานวิจัยเองคือ FI-2010 เล็กเกินไปและถูกลดอัตราการสุ่มมากเกินไปที่จะตัดสินคำถามนี้ หลักฐานที่แข็งแกร่งกว่าของมันคือการศึกษา LSE ที่ DeepLOB ฝึกบนหุ้นชุดหนึ่งและยังคงทำนายหุ้นที่กันไว้ (held-out stocks) — ผลลัพธ์การเรียนรู้แบบถ่ายโอนที่ FI-2010 ไม่สามารถแสดงได้
LOBFrame และวิกฤตการทำซ้ำ (Replication Crisis)

กรอบงานมาตรฐาน LOBFrame (Briola, Bartolucci, Aste, 2024) เป็นส่วนเสริมที่ทำให้เราตื่นตัวต่อผลลัพธ์เหล่านี้ แม้สถาปัตยกรรมของ DeepLOB จะมีความมั่นคง แต่กรอบงานนี้เน้นข้อควรระวังสำคัญหลายประการ:
การพึ่งพาโครงสร้างจุลภาค ประสิทธิภาพของโมเดลแปรปรวนอย่างมีนัยสำคัญข้ามหุ้นที่มีลักษณะโครงสร้างจุลภาคต่างกัน หุ้นสภาพคล่องสูงที่มีทิคขนาดใหญ่ทำนายได้ง่ายกว่าตราสารสภาพคล่องต่ำที่มีทิคขนาดเล็ก โมเดลที่ดูแข็งแกร่งบนหุ้นตัวหนึ่งอาจเสื่อมลงอย่างมากบนอีกตัวหนึ่ง
การทำนาย vs. กำไร ความแม่นยำในการจำแนกประเภทที่สูงไม่ได้แปลเป็นกำไรจากการเทรดโดยอัตโนมัติ LOBFrame เน้นเมตริกที่ผูกกับว่าการเคลื่อนไหวที่ทำนายนั้นใหญ่พอที่จะข้ามสเปรดหรือไม่ โมเดลต้องถูกต้องบ่อยพอ และบนการเคลื่อนไหวที่ใหญ่พอ เพื่อเอาชนะสเปรด — และสำหรับหุ้นที่สเปรดแคบ เกณฑ์นั้นสูง
ความไวต่อป้ายกำกับ การเลือกเกณฑ์ และช่วงเวลา ส่งผลอย่างมากต่อทั้งความแม่นยำที่รายงานและคุณค่าในทางปฏิบัติของการทำนาย ป้ายกำกับที่แคบเกินไปสร้างเป้าหมายที่มีสัญญาณรบกวน ป้ายกำกับที่กว้างเกินไปสร้างการทำนายที่ "แม่นยำ" อย่างไม่มีความหมายแต่ไร้ประโยชน์
เหนือกว่า DeepLOB: ภูมิทัศน์ปัจจุบัน

ตั้งแต่การเผยแพร่ DeepLOB มีส่วนขยายหลายอย่างปรากฏขึ้น:
Transformers สำหรับสมุดคำสั่งซื้อขายแบบจำกัดราคา (Wallbridge, 2020) มักถูกอ้างถึงอย่างหลวม ๆ ว่า "TransLOB" ในวรรณกรรมภายหลัง ตัวโมเดลเองเป็นตัวสกัดคุณลักษณะแบบ causal/dilated convolutional ตามด้วย masked multi-head self-attention — ไม่ใช่แค่ DeepLOB ที่สลับ LSTM เป็น Transformer มันไม่ได้นำสแต็ก inception+conv กลับมาใช้ใหม่ มันรายงาน state of the art ใหม่ของ FI-2010 สำหรับยุคนั้น
ตัวแปรในโดเมนคริปโต หลายกลุ่มนำสถาปัตยกรรมแบบ DeepLOB ไปใช้กับตลาดสกุลเงินดิจิทัล ที่ซึ่งพลวัตของสมุดคำสั่งแตกต่างจากหุ้นอย่างมาก — สเปรดที่กว้างกว่า การเทรดตลอด 24/7 และส่วนผสมของผู้เข้าร่วมที่ต่างกัน ซึ่งทั้งหมดต้องการการฝึกใหม่
ตัวแปรที่เสริมด้วย attention มีแนวงานวิจัยที่แทรก multi-head attention ระหว่างบล็อก inception และ LSTM ให้เครือข่ายโฟกัสไปที่ระดับหรือขั้นเวลาที่ให้ข้อมูลมากที่สุดสำหรับการทำนายปัจจุบัน
LOB-Bench (Nagy, Frey, Li, Sarkar, Vyetrenko, Zohren, Calinescu, Foerster, 2025) กรอบงานมาตรฐานนี้เปลี่ยนความสนใจจากการทำนายไปสู่การ สร้าง (generation) โดยให้คะแนนว่าโมเดลสร้าง (generative model) ของข้อมูลสมุดคำสั่งนั้นสมจริงเพียงใด — เกี่ยวข้องกับการทำ backtest และการฝึก agent มากกว่าการพยากรณ์ทิศทาง
ข้อพิจารณาเชิงปฏิบัติสำหรับการใช้งานจริง
หากคุณกำลังพิจารณาการนำโมเดลแบบ DeepLOB ไปใช้ในระบบเทรดสด จะมีข้อกังวลทางวิศวกรรมหลายประการเกิดขึ้น:
ความหน่วง (Latency)
โมเดลต้องสร้างการทำนายภายในงบประมาณความหน่วงของระบบเทรดของคุณ สำหรับระบบ HFT ที่ทำงานที่ความหน่วงระดับต่ำกว่ามิลลิวินาที แม้แต่การอนุมาน PyTorch ที่ปรับให้เหมาะสมแล้วก็อาจช้าเกินไป ทางเลือกได้แก่:
- การส่งออก ONNX พร้อมการปรับให้เหมาะสมด้วย TensorRT
- การทำ Quantization เป็น INT8
- การใช้งานบน FPGA สำหรับแอปพลิเคชันที่ไวต่อความหน่วงมากที่สุด
ไปป์ไลน์ข้อมูล (Data Pipeline)
โมเดลคาดหวังภาพถ่ายสมุดคำสั่งที่ทำให้เป็นมาตรฐานและจัดเรียงแล้วที่ความถี่คงที่ ในทางปฏิบัติ การอัปเดต LOB มาถึงแบบไม่ประสานเวลา (asynchronously) คุณต้องมี:
- เครื่องยนต์สร้างภาพถ่ายใหม่ที่รักษาสถานะสมุดคำสั่งปัจจุบัน
- ตัวสุ่มตัวอย่างความถี่คงที่ที่สร้างเทนเซอร์อินพุต
- การทำให้เป็นมาตรฐานแบบออนไลน์โดยใช้สถิติแบบเลื่อน (rolling statistics)
เสถียรภาพของคุณลักษณะ (Feature Stability)
พารามิเตอร์การทำให้เป็นมาตรฐานแบบ z-score ที่คำนวณบนข้อมูลฝึกจะเลื่อน (drift) ไปตามเวลา ราคาเปลี่ยน ระบอบความผันผวนเลื่อน โครงสร้างตลาดวิวัฒนาการ ระบบที่ใช้งานจริงต้องการ:
- หน้าต่างการทำให้เป็นมาตรฐานแบบเลื่อน (เช่น คำนวณสถิติใหม่ทุกวัน)
- การตรวจจับระบอบเพื่อกระตุ้นการฝึกโมเดลใหม่
- การติดตามการเลื่อนของการแจกแจงอินพุต
การ Overfit กับโครงสร้างจุลภาค
รูปแบบ LOB เป็นแบบเฉพาะตลาดและเฉพาะตราสาร โมเดลที่ฝึกบนหุ้น NASDAQ จะไม่ทำงานบน Binance BTC/USDT โดยไม่มีการฝึกใหม่ แม้แต่ภายในตลาดเดียวกัน โมเดลก็สามารถ overfit กับ:
- ระบอบขนาดทิค (หุ้นทิคใหญ่ vs. ทิคเล็ก)
- รูปแบบช่วงเวลาในวัน (การประมูลเปิด ช่วงซบเซากลางวัน การปิดแบบไขว้)
- พฤติกรรมของผู้ดูแลสภาพคล่อง (market maker) ที่เปลี่ยนไปตามเวลา
บทสรุป
DeepLOB เป็นตัวแทนของการประยุกต์ใช้การเรียนรู้เชิงลึกกับโครงสร้างจุลภาคของตลาดที่สะอาดและมีแรงจูงใจที่ดี สถาปัตยกรรมสามบล็อกของมัน — CNN สำหรับคุณลักษณะเชิงพื้นที่ inception สำหรับรูปแบบเชิงเวลาแบบหลายสเกล LSTM สำหรับการพึ่งพาเชิงลำดับ — ทาบลงบนโครงสร้างของข้อมูลสมุดคำสั่งซื้อขายแบบจำกัดราคาอย่างเป็นธรรมชาติ
ข้อมูลเชิงลึกที่สำคัญไม่ใช่แค่ว่าโมเดลเชิงลึกสามารถเทียบเท่าหรือเอาชนะคุณลักษณะที่สร้างด้วยมือ แต่อคติเชิงอุปนัยของสถาปัตยกรรม — ฟิลเตอร์ ความขนานของ inception ความจำแบบ recurrent — เข้ารหัสความรู้เฉพาะทางที่แท้จริงเกี่ยวกับวิธีที่สมุดคำสั่งทำงาน นี่ไม่ใช่เครือข่ายเชิงลึกทั่วไปที่โยนลงบนข้อมูลทางการเงิน มันเป็นสถาปัตยกรรมที่ออกแบบรอบเรขาคณิตเฉพาะของสมุดคำสั่งซื้อขายแบบจำกัดราคา และหลักฐานที่น่าเชื่อถือที่สุดของมันไม่ใช่ตารางคะแนน FI-2010 ที่ผู้เขียนเองไม่ไว้วางใจ แต่เป็นผลลัพธ์การเรียนรู้แบบถ่ายโอนบนข้อมูล LSE หนึ่งปี
สำหรับผู้ปฏิบัติงาน DeepLOB เป็น baseline ที่แข็งแกร่งและองค์ประกอบที่มีประโยชน์ในการสร้าง สำหรับนักวิจัย มันแสดงให้เห็นว่าการออกแบบสถาปัตยกรรมที่รอบคอบ — ไม่ใช่แค่ขนาดของโมเดล — เป็นตัวขับเคลื่อนประสิทธิภาพบนข้อมูลทางการเงินที่มีโครงสร้าง เพียงจำไว้ว่าให้อ้างอิงตัวเลขจริง เฝ้าดูแบบแผนของป้ายกำกับ และถือว่าความแม่นยำในการจำแนกประเภทยังห่างไกลจากกำไรในการเทรดมาก
เอกสารอ้างอิง
-
Zhang, Z., Zohren, S., & Roberts, S. (2019). DeepLOB: Deep Convolutional Neural Networks for Limit Order Books. IEEE Transactions on Signal Processing, 67(11), 3001-3012. arXiv:1808.03668
-
Ntakaris, A., Magris, M., Kanniainen, J., Gabbouj, M., & Iosifidis, A. (2018). Benchmark Dataset for Mid-Price Forecasting of Limit Order Book Data with Machine Learning Methods. Journal of Forecasting, 37(8), 852-866. arXiv:1705.03233
-
Briola, A., Bartolucci, S., & Aste, T. (2024). Deep Limit Order Book Forecasting (LOBFrame). arXiv:2403.09267
-
Wallbridge, J. (2020). Transformers for Limit Order Books. arXiv:2003.00130
-
Cont, R., Kukanov, A., & Stoikov, S. (2014). The Price Impact of Order Book Events. Journal of Financial Econometrics, 12(1), 47-88.
-
Stoikov, S. (2018). The Micro-Price: A High-Frequency Estimator of Future Prices. Quantitative Finance, 18(12), 1959-1966.
-
Nagy, P., Frey, S., Li, K., Sarkar, B., Vyetrenko, S., Zohren, S., Calinescu, A., & Foerster, J. (2025). LOB-Bench: Benchmarking Generative AI for Finance — an Application to Limit Order Book Data. ICML 2025. arXiv:2502.09172
-
DeepLOB code (original in Keras/TensorFlow; the repository also provides a PyTorch port): github.com/zcakhaa/DeepLOB-Deep-Convolutional-Neural-Networks-for-Limit-Order-Books
ผู้เขียน
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.