← กลับไปยังบทความ
August 13, 2026
อ่าน 5 นาที

Updating the Volume Curve Intraday: Does Adaptive Forecasting Actually Help?

Updating the Volume Curve Intraday: Does Adaptive Forecasting Actually Help?
#microstructure
#liquidity
#execution
#prediction
#order-book

ใน TWAP, VWAP และ POV เราเปรียบเทียบตัวจัดตารางทั้งสามแบบโดยตรงบนการรีเพลย์ L2 ของ BTCUSDT เป็นเวลา 90 วัน และได้ข้อสรุปที่ตั้งใจเปิดทิ้งไว้: ในคริปโต จุดอ่อนที่สุดของไปป์ไลน์คือเส้นโค้งปริมาณ ไม่ใช่การแบ่งคำสั่ง บทความนั้นใช้เวอร์ชันเรียบง่ายโดยตั้งใจ — เส้นโค้งค่ามัธยฐานตามวันในสัปดาห์ × ช่วงเวลาของวัน ปรับฟิตใหม่ทุกสัปดาห์และคงที่ตลอดวันเทรด และพบว่าข้อได้เปรียบทั้งหมดของ VWAP เหนือ TWAP อยู่ที่คุณภาพการพยากรณ์: เมื่อแบ่งตามความคลาดเคลื่อนของเส้นโค้งปริมาณจริง VWAP ชนะ TWAP ราว 4 bps ในกลุ่มวันที่พยากรณ์ดีที่สุด และช่องว่างหายไปใน noise ในกลุ่มที่แย่ที่สุด

ผลลัพธ์นี้นำไปสู่การติดตามผลที่เฉพาะเจาะจงและตรวจสอบหักล้างได้ หาก VWAP ชนะเฉพาะวันที่เส้นโค้งบังเอิญถูกต้อง นักพยากรณ์ที่ แก้ไขตัวเองขณะวันดำเนินไป ควรเปลี่ยนวันที่อยู่ในกลุ่มแย่บางส่วนให้เป็นวันที่ดีได้ หรือไม่ควรทำได้ — และเวอร์ชันที่น่าสนใจของบทความนี้คือกรณีที่ทำไม่ได้ เพราะกลุ่มแย่ของคริปโตคือวัน cascade และวันข่าว ซึ่งเป็นวันที่ข้อมูลปริมาณสองชั่วโมงแรกให้ข้อมูลเกี่ยวกับสองชั่วโมงถัดไปน้อยที่สุดพอดี

บทความนี้นำตัวอัปเดตระหว่างวันไปใช้งาน รันกับ harness เดิม และรายงาน IS delta เทียบกับเส้นโค้งคงที่ — พร้อมการแจกแจงและตัวเลขควอร์ไทล์สุดท้าย ไม่ใช่แค่ค่าเฉลี่ย

สิ่งที่กำลังทดสอบ

การอัปเดต prior ของเส้นโค้งปริมาณแบบปรับตัวจากกิจกรรมการเทรดที่สังเกตได้

เส้นโค้งคงที่คือ prior: เวกเตอร์คงที่ u={u1,,uB}u = \{u_1, \ldots, u_B\} ของสัดส่วนปริมาณที่คาดไว้ต่อ bucket ซึ่งประมาณค่าจากข้อมูลออฟไลน์ เวอร์ชันปรับตัวมองมันเป็น prior ที่ต้องอัปเดต หลังผ่านไป cc bucket และสังเกตปริมาณจริง V1,,VcV_1, \ldots, V_c แล้ว คุณจะมีข้อมูลใหม่สองส่วนที่เส้นโค้งคงที่ทิ้งไป:

  1. การประมาณระดับ หาก prior ระบุว่า bucket 1..c1..c ควรมีสัดส่วน icui\sum_{i \le c} u_i ของทั้งวัน และมีปริมาณ icVi\sum_{i\le c} V_i หน่วย ยอดรวมทั้งวันที่อนุมานได้คือ V^=icVi/icui\hat{V} = \sum_{i \le c} V_i \big/ \sum_{i \le c} u_i นี่คือสัญญาณ today-is-a-heavy-day / today-is-a-dead-day และมีให้ใช้ตั้งแต่ bucket แรก
  2. การแก้รูปทรง หากรูปทรงจริงของ bucket ที่ผ่านไปเบี่ยงเบนจากรูปทรง prior อย่างเป็นระบบ bucket ที่เหลืออาจเบี่ยงเบนด้วย — แต่เฉพาะเมื่อข้อผิดพลาดของเส้นโค้งปริมาณระหว่างวันมี autocorrelation ภายในวัน ซึ่งเป็นคำถามเชิงประจักษ์ ไม่ใช่สมมติฐานที่เราจะถือเอาได้ฟรี

การใช้งานด้านล่างใช้ (1) อย่างเต็มที่และไม่ใช้ (2) เลย: มันปรับสเกลหาง prior ที่ยังไม่แตะต้องให้เข้ากับยอดรวมที่อัปเดต นี่คือเวอร์ชันแบบอนุรักษ์นิยมและเป็นการทดลองแรกที่ถูกต้อง เพราะหากการอัปเดตระดับอย่างเดียวจับ delta ที่มีอยู่ได้เกือบทั้งหมด กลไกแก้รูปทรงก็เป็นความซับซ้อนที่ไม่มีเหตุผล

import numpy as np
from typing import Optional


class AdaptiveVolumePredictor:
    """
    Bayesian-style adaptive volume profile predictor.

    Combines a prior (the offline day-of-week x time-of-day curve)
    with volume observed so far today to produce an updated forecast
    for the remaining buckets.
    """

    def __init__(self, historical_profiles: np.ndarray):
        """
        Args:
            historical_profiles: shape (n_days, n_buckets), each row sums to 1.0.
                Use the median-based, day-of-week-conditioned curve from the
                TWAP/VWAP/POV article -- a pooled mean curve is misspecified
                and will make the adaptive version look better than it is by
                giving it a weaker baseline to beat.
        """
        self.prior_profile = np.median(historical_profiles, axis=0)
        self.prior_profile /= self.prior_profile.sum()
        self.prior_iqr = np.subtract(*np.percentile(historical_profiles, [75, 25], axis=0))
        self.n_buckets = len(self.prior_profile)

    def predict(
        self,
        observed_volumes: np.ndarray,
        current_bucket: int,
        total_volume_estimate: Optional[float] = None,
    ) -> np.ndarray:
        """
        Predict absolute volume for every bucket: realized values for elapsed
        buckets, forecasts for the remainder.

        Args:
            observed_volumes: actual volumes in buckets 0..current_bucket-1
            current_bucket: index of the current bucket (0-based)
            total_volume_estimate: external ADV estimate (optional prior on level)
        """
        profile = np.zeros(self.n_buckets)

        if current_bucket == 0:
            base = total_volume_estimate if total_volume_estimate else 1.0
            return self.prior_profile * base

        profile[:current_bucket] = observed_volumes[:current_bucket]
        observed_total = observed_volumes[:current_bucket].sum()

        expected_fraction_so_far = self.prior_profile[:current_bucket].sum()
        if expected_fraction_so_far > 0.01:
            implied_total = observed_total / expected_fraction_so_far
        else:
            implied_total = observed_total * self.n_buckets

        if total_volume_estimate:
            w_obs = expected_fraction_so_far
            implied_total = w_obs * implied_total + (1 - w_obs) * total_volume_estimate

        remaining_prior = self.prior_profile[current_bucket:]
        remaining_sum = remaining_prior.sum()
        if remaining_sum > 0:
            remaining_volume = max(0.0, implied_total - observed_total)
            profile[current_bucket:] = remaining_prior / remaining_sum * remaining_volume

        return profile

รายละเอียดสองอย่างในโค้ดนี้เป็นแกนของการทดลอง prior คือเส้นโค้ง ค่ามัธยฐาน ที่มีเงื่อนไขตามวันในสัปดาห์ ไม่ใช่ค่าเฉลี่ยรวม — ดู ส่วนเส้นโค้งปริมาณของบทความ VWAP เพื่อดูว่าทำไมเรื่องนี้สำคัญในตลาดที่ cascade การชำระบัญชีครั้งเดียวอาจกินปริมาณทั้งวันถึง 15% ในสิบนาที และการอัปเดตระดับถูก หดเข้าหาค่าประมาณ ADV ภายนอก โดยให้น้ำหนักเท่ากับสัดส่วน prior ที่ผ่านไป เพราะใน bucket แรก implied_total คือการสังเกตหนึ่งครั้งหารด้วยจำนวนที่ใกล้ศูนย์ ตัวอัปเดตที่ไม่หดเข้าหาค่าอ้างอิงจะทำงานแย่ที่สุดพอดีเมื่อยังเหลือเวลาส่วนใหญ่ของวันให้ทำลายผลลัพธ์

Harness การทดสอบ

เส้นทางการดำเนินการแบบขนานใน harness วิจัยการพยากรณ์แบบปรับตัว

เหมือนกับการรัน TWAP/VWAP/POV ทุกประการ ดังนั้นตัวเลขจึงเปรียบเทียบกันได้ทีละบรรทัด:

  • เครื่องมือ/ข้อมูล: perpetual BTCUSDT, การรีเพลย์ L2 90 วัน (20 ระดับบนสุด, 100 ms) และเทปการเทรด ใช้ UTC ตลอด; ทำเครื่องหมาย timestamp ของ funding
  • คำสั่งแม่: 500 รายการ, horizon T=4T = 4h, ขนาด 0.75% ของ ADV ย้อนหลัง 30 วัน, ฝั่งซื้อ, decision price = mid ตอนเริ่มต้น ใช้เวลาเริ่มต้นแบบสุ่มเดียวกับการรันที่เผยแพร่
  • แขนการทดลอง: (A) VWAP บนเส้นโค้งคงที่ที่ refit รายสัปดาห์ — baseline ที่เผยแพร่; (B) VWAP บน prior เดิมพร้อมการอัปเดตระหว่างวัน; (C) TWAP เป็นพื้นฐาน
  • เมตริก: IS เป็น bps ของ decision price รวมค่าธรรมเนียม เทียบกับตอนมาถึง — รายงานค่าเฉลี่ย มัธยฐาน ส่วนเบี่ยงเบนมาตรฐาน เปอร์เซ็นไทล์ที่ 95 และ IS ของควอร์ไทล์สุดท้ายของแต่ละคำสั่งแม่ บันทึก slippage ของ VWAP เป็นเพียงการวินิจฉัย ไม่ใช้เป็น scoreboard เด็ดขาด; ส่วน benchmark ของบทความ VWAP แสดงกรณีตัวอย่างที่ slippage ของ VWAP และ arrival IS จัดอันดับอัลกอริทึมสองแบบในลำดับตรงข้าม การแยกส่วน IS แบบเต็ม รวมต้นทุนโอกาส อยู่ใน implementation shortfall และ TCA

ผลลัพธ์

มันช่วยในจุดที่ต้องการหรือไม่?

ค่าเฉลี่ย headline เป็นตัวเลขที่น่าสนใจน้อยที่สุด ผลลัพธ์ที่เผยแพร่แสดงว่า gap ระหว่าง VWAP–TWAP เพิ่มตามความผิดพลาดของเส้นโค้งปริมาณจริงแบบ monotone ดังนั้นแขนการทดลองแบบปรับตัวต้องให้คะแนนในแบบเดียวกัน: แบ่ง 90 วันเป็น tercile ตามระยะ L1L_1 ระหว่าง forecast แบบ คงที่ กับปริมาณ bucket จริง แล้วรายงาน IS delta แบบ adaptive-minus-static ในแต่ละ tercile

ผลลัพธ์ทั้งสองแบบเผยแพร่ได้ และมีความหมายตรงข้ามกัน:

  • Delta กระจุกอยู่ใน tercile ดี ตัวอัปเดตกำลังปรับปรุงวันที่เดิมก็ง่ายอยู่แล้ว ผลสุทธิต่อการแจกแจงต้นทุนเป็นเพียง cosmetic; หาง — ซึ่งคำสั่งแม่ที่ขับเคลื่อนด้วย alpha และมี horizon ตายตัวต้องจ่ายจริง — ไม่เปลี่ยน นี่หมายความว่าตัวอัปเดตระหว่างวันไม่ใช่ทางแก้ของจุดอ่อนที่สุด และควรไปดูการแก้รูปทรงกับแนวทาง cross-asset ต่อ
  • Delta กระจุกอยู่ใน tercile แย่ ตัวอัปเดตกำลังทำหน้าที่ตามที่สร้างมา: จับวัน cascade และวันข่าวที่เส้นโค้งคงที่ผิดพลาดมากที่สุด นี่คือผลลัพธ์ที่จะให้เหตุผลกับการเพิ่ม state ในลูปการดำเนินการ

ผลลัพธ์เชิงลบเป็นสิ่งที่คาดไว้และควรรายงานอย่างตรงไปตรงมา กลไกที่ทำให้เส้นโค้งปริมาณคริปโตยาก — cascade คือ regime break ไม่ใช่การเลื่อนระดับ — ก็คือกลไกที่เอาชนะตัวพยากรณ์แบบอัปเดตระดับ: กว่า bucket ที่ผ่านไปจะบอกว่าวันนี้มีปริมาณสูง ส่วนที่มีปริมาณสูงอาจจบไปแล้ว ดู ผลลัพธ์เชิงลบอย่างซื่อสัตย์ เพื่อดูว่าทำไมบล็อกนี้จึงเผยแพร่ผลลัพธ์เหล่านั้น

ความชันของสมุดคำสั่งซื้อ: มันเพิ่มอะไรได้บ้าง?

ภูมิทัศน์ความลึกและความชันสภาพคล่องของสมุดคำสั่งซื้อแบบลิมิตเชิงนามธรรม

ฟีเจอร์หนึ่งในชุดฟีเจอร์ฉบับร่างที่ยังไม่มีที่อื่นในบล็อกนี้พูดถึงคือ ความชันของสมุดคำสั่งซื้อ หรือความเร็วที่ความลึกสะสมเพิ่มขึ้นเมื่อเคลื่อนออกจาก touch ให้ฟิต CumVol(d)=α+βd\text{CumVol}(d) = \alpha + \beta d บน KK ระดับบนสุด; β\beta ขนาดใหญ่หมายถึงความลึกกระจุกที่ touch ส่วน β\beta ขนาดเล็กหมายถึงมันกระจายบาง ๆ ทั่วทั้งสมุด

def book_slope(prices: np.ndarray, volumes: np.ndarray, mid: float) -> float:
    """Slope of cumulative depth vs. distance from mid. One side only."""
    distances = np.abs(prices - mid)
    return float(np.polyfit(distances, np.cumsum(volumes), 1)[0])

เวอร์ชันเดียวของข้ออ้างนี้ที่ควรพูดคือเวอร์ชันที่วัดแล้ว: การเพิ่ม book_slope ในชุดฟีเจอร์เดิมทำให้ forecast ปริมาณหรือ IS ที่ได้เกิน baseline AR/EWMA หรือไม่? บทความ spread modeling กำหนดมาตรฐานไว้ — รายงาน skill ที่ เหนือกว่า baseline แบบง่ายพร้อมระบุ horizon เพราะซีรีส์เหล่านี้ถูกครอบงำด้วย persistence และ R² ในพาดหัวส่วนใหญ่เป็นการวัด autocorrelation

สิ่งที่บทความนี้ตั้งใจไม่อนุมานซ้ำ

โมดูลวิจัยที่มุ่งเน้นภายในไปป์ไลน์เชิงปริมาณที่มีขอบเขต

ทุกอย่างด้านล่างมีอยู่ในบล็อกนี้อย่างละเอียดกว่าแล้ว และการอธิบายซ้ำตรงนี้จะสร้างเพียงเวอร์ชันที่อ่อนแอกว่าอีกเวอร์ชัน:

  • การวัดสภาพคล่อง Roll estimator (พร้อม signed-root fix และกับดัก price-units-vs-returns) และ Kyle's lambda: spread modeling ด้วย machine learning Kyle's lambda ยังถูกปรับเทียบกับ Binance aggTrades จริงในฐานะค่าสัมประสิทธิ์ผลกระทบถาวรใน Almgren-Chriss ต้นทุนการกวาด walk-the-book: โมเดล slippage และต้นทุน
  • ฟีเจอร์สมุดคำสั่งซื้อ weighted mid (ซึ่ง ไม่ใช่ microprice ของ Stoikov — ตัวนั้นถูกปรับด้วย martingale) ความไม่สมดุลของสมุดหลายระดับ OFI และ taxonomy ฟีเจอร์ LOB ทั้งหมด: DeepLOB และ spread modeling
  • รูปแบบระหว่างวัน U-shape ของหุ้นเป็นโมเดลที่ผิดสำหรับตลาดที่ไม่มีเวลาปิด โครงสร้าง session/funding/รายสัปดาห์ของคริปโตที่มาแทน รวมถึงกริดวันในสัปดาห์ × ช่วงเวลาของวัน อยู่ใน บทความ VWAP การเข้ารหัสช่วงเวลาของวันแบบวัฏจักรอยู่ในตารางฟีเจอร์ของ บทความ spread
  • เหตุการณ์ตามกำหนดการ expiry ของ Deribit 08:00 UTC, ข้อมูลมหภาคสหรัฐเวลา 12:30/14:00 UTC, settlement ของ CME — ให้ปฏิบัติต่อสิ่งเหล่านี้เป็น dummy แทนที่จะปล่อยให้ปนเปื้อนเส้นโค้ง baseline ปฏิทินคริปโตที่เป็นรูปธรรมอยู่ใน บทความ VWAP ตัวอัปเดตระหว่างวันด้านบน ไม่ใช่ event handler และไม่ควรขอให้มันเป็นเช่นนั้น
  • โมเดล gradient boosting พร้อม purged, embargoed walk-forward CV (การใช้ TimeSeriesSplit แบบธรรมดาทำให้เกิดการรั่วไหลผ่าน target ของหน้าต่างอนาคตที่ทับซ้อนกัน) อยู่ใน spread modeling ส่วนตระกูล CNN-LSTM, input tensor 40 ฟีเจอร์/10 ระดับ, LOBFrame และการอภิปรายวิกฤตการทำซ้ำอยู่ใน DeepLOB โปรดสังเกตโดยเฉพาะว่าอย่ายุบแกนระดับก่อน recurrent layer
  • การตัดสินใจ child order passive เทียบกับ aggressive คือ break-even ที่คำนวณได้ p=δ/(Π+δ)p^* = \delta/(\Pi + \delta) ไม่ใช่ threshold สเปรดที่ hard-code: เทคนิคการดำเนินการ child order การกำหนดเป้าหมาย participation rate เป็น endogenous — fill ของคุณเองถูกพิมพ์ลงบน tape — และการแก้ไขอยู่ใน บทความ VWAP
  • การกระจายตัวของ venue การจัดเส้นทางคำสั่งอัจฉริยะในคริปโต พร้อม scorecard TCA ราย venue ใน implementation shortfall
  • เวลาแฝงในการผลิต ส่วน production ของ DeepLOB โปรดทราบว่าบทความ spread ได้ระบุเงื่อนไขของข้ออ้างเวลาอนุมานไว้แล้ว — LightGBM 2000 รอบพยากรณ์จาก Python ในระดับ หลายสิบไมโครวินาที และเหลือเพียงเลขหลักเดียวเมื่อใช้ predictor ที่คอมไพล์แล้ว

ไดนามิกเชิงปฏิปักษ์ สมควรมีหนึ่งย่อหน้า ไม่ใช่ทั้งส่วน ความลึกที่แสดงอยู่เป็นการแสดงบางส่วน และกลไกการตรวจจับ — อัตราการยกเลิก ความเร็วการก่อตัวของ wall พฤติกรรมเมื่อราคาเข้าใกล้ layering — มีวิธีที่อิง PIQ อย่างเป็นรูปธรรมใน การวิเคราะห์ตำแหน่งคิวและ wall สิ่งเดียวที่บทความนี้อาจเพิ่มคือถือว่าสิ่งเหล่านี้เป็น อินพุตของตัวพยากรณ์: อัตรา cancel-to-trade เวลา resting เฉลี่ยที่ touch และสัดส่วนความลึกที่ถูกยกเลิกภายใน 100 ms หลังปรากฏ แล้วป้อนให้โมเดลปริมาณควบคู่กับสัญญาณ bucket ที่ผ่านไป สิ่งเหล่านี้เพิ่ม skill เหนือชุดฟีเจอร์เดิมหรือไม่เป็นการวัดที่ยังเปิดอยู่ ไม่ใช่ข้ออ้าง

บทสรุป

เส้นทางหลักฐานจากความไม่แน่นอนไปสู่ผลการดำเนินการที่วัดได้

ข้ออ้างที่กำลังทดสอบนั้นแคบ และบล็อกได้กำหนดเงื่อนไขสำหรับการหักล้างไว้แล้ว: บทความ VWAP ยืนยันว่าข้อได้เปรียบของ VWAP มาจากคุณภาพการพยากรณ์ทั้งหมด และการพยากรณ์ล้มเหลวในวันที่มีต้นทุนสูงที่สุด ตัวอัปเดตระหว่างวันจะแก้ปัญหานั้นได้หรือไม่ คำตอบคือหนึ่งตัวเลขใน tercile ที่แย่ของการรีเพลย์คำสั่งแม่ 500 รายการ

บทความนี้จะไม่ผูกตัวเลข bps เข้ากับระบบ production โดยไม่มีการรีเพลย์รองรับ ข้ออ้างประเภท "การพยากรณ์สภาพคล่องที่ปรับจูนอย่างดีช่วยประหยัด 2–5 bps ซึ่งเป็นความแตกต่างระหว่าง Sharpe 1.5 กับ 2.0" คือประเภทเดียวกับที่ Sharpe ที่ลดทอนและ multiple testing มีไว้รื้อ: ไม่มีแหล่งที่มา ไม่มีเงื่อนไข และไม่เคยมาพร้อมการกระจาย ตัวเลขที่สำคัญที่นี่คือ IS ของควอร์ไทล์สุดท้ายในวันที่อยู่ tercile แย่ที่สุด วัดได้ก็รายงาน วัดไม่ได้ก็ไม่รายงาน

ข้อจำกัดความรับผิดชอบ: ข้อมูลที่ให้ไว้ในบทความนี้มีไว้เพื่อการศึกษาและให้ข้อมูลเท่านั้น และไม่ถือเป็นคำแนะนำทางการเงิน การลงทุน หรือการเทรด การเทรดสกุลเงินดิจิทัลมีความเสี่ยงสูงที่จะขาดทุน

ผู้เขียน

Eugen Soloviov
Eugen Soloviov

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.

Newsletter

ก้าวนำหน้าตลาด

สมัครรับจดหมายข่าวของเราเพื่อรับข้อมูลเชิงลึกการเทรดด้วย AI เฉพาะ การวิเคราะห์ตลาด และการอัปเดตแพลตฟอร์ม

เราเคารพความเป็นส่วนตัวของคุณ ยกเลิกการสมัครได้ทุกเมื่อ