Đường cong slippage, không phải hằng số slippage: mô hình chi phí sống sót khi tiếp xúc với giao dịch thực
Dòng đắt giá nhất trong hầu hết các backtest là slippage_bps = 5. Không phải vì con số 5 sai — tính trung bình trên một năm các lệnh khớp thì nó thậm chí có thể đúng — mà vì một hằng số sai có điều kiện, và quy trình chọn chiến lược của bạn chính là một cỗ máy chuyên tìm và khai thác những sai số có điều kiện đó. Slippage là hàm số của quy mô lệnh, spread, biến động và thanh khoản khả dụng. Một hằng số chỉ là giá trị của hàm số đó tại một điểm rồi bị ngoại suy ra khắp mọi nơi, kể cả vào lúc 3 giờ sáng khi thác thanh lý xảy ra, đúng lúc tín hiệu đảo chiều trung bình (mean-reversion) của bạn kích hoạt mạnh nhất và độ sâu sổ lệnh chỉ còn một phần mười mức thông thường. Backtest vẫn tính phí 5 bps ở đó. Giao dịch thực sẽ không như vậy.
Bài viết này nói về mô hình chi phí bên trong vòng lặp backtest: hàm số cost(size, market_state) được trừ khỏi mỗi giao dịch mô phỏng. Nó cố tình không bàn về việc dự đoán impact trước để lên lịch thực thi — đó là bài toán song hành, được đề cập từ góc độ mô hình trong mô hình hóa price impact và từ góc độ lên lịch tối ưu trong Almgren-Chriss. Ở đây câu hỏi hẹp hơn và, với bất kỳ ai chọn chiến lược bằng backtest, cấp thiết hơn: hàm số nào nên đứng ở vị trí hằng số của bạn hiện tại, làm sao khớp nó từ dữ liệu bạn thực sự có, và câu trả lời thay đổi bao nhiêu quyết định bạn cuối cùng chạy chiến lược nào. Phần cuối có một câu trả lời thực nghiệm rõ ràng: xếp hạng lại 20 biến thể của một họ chiến lược dưới bốn mô hình chi phí và chứng kiến bảng xếp hạng đảo lộn hoàn toàn.
Bậc thang mô hình chi phí

Giống như bậc thang mô phỏng khớp lệnh, các mô hình chi phí tạo thành một bậc thang độ trung thực, trong đó mỗi bậc cần nhiều dữ liệu hơn và loại bỏ một thiên lệch hệ thống cụ thể. Các bậc mang tính tích lũy: mỗi bậc giữ lại các số hạng của bậc dưới và thêm một số hạng mới.
M0: hằng số bps
Một con số duy nhất, áp dụng cho mọi giao dịch. Ba kiểu thất bại, theo thứ tự thiệt hại tăng dần:
- Mù về quy mô. Một lệnh 10 nghìn đô và một lệnh mẹ 5 triệu đô trả cùng một mức phí. Mọi so sánh chiến lược qua các mức capacity khác nhau trở nên vô nghĩa.
- Mù về regime. Một chiều thứ Ba yên bình và sự sụp đổ của FTX trả cùng một mức phí. Sai số này không phải nhiễu; nó tương quan nghịch chính xác với những trạng thái mà các chiến lược event-driven tập trung giao dịch nhiều nhất.
- Độc hại cho việc chọn lựa. Khi bạn quét 200 tổ hợp tham số, bộ tối ưu hóa phát hiện ra rằng dưới chi phí phẳng, turnover rẻ hơn thực tế và kéo toàn bộ quá trình tìm kiếm về phía các biến thể tần suất cao. Sai số chi phí trở thành một lực có hướng lên việc chọn mô hình, chứ không phải một lực đối xứng lên PnL.
M1: tỷ lệ theo spread
Tính phí bằng nửa spread đo được tại thời điểm ra quyết định (cộng thêm phí giao dịch, vốn mang tính xác định và luôn nên là một dòng riêng). Đây là mô hình đầu tiên phản ứng với thị trường theo bất kỳ cách nào: spread nới rộng khi có tin tức, khi mở phiên, ở các altcoin mỏng thanh khoản, nên chi phí giờ đây biến động cùng ít nhất một biến thanh khoản. Điều nó vẫn bỏ sót: spread chỉ định giá cho một lệnh khớp ở top-of-book. Bất cứ thứ gì lớn hơn sẽ "đi bộ" xuyên qua sổ lệnh, và bước đi đó vô hình đối với .
M2: điều chỉnh theo biến động
Thêm một số hạng tỷ lệ với biến động ngắn hạn. Cơ sở lý luận vừa mang tính thực nghiệm vừa mang tính cấu trúc: spread và độ sâu được thiết lập bởi các nhà tạo lập thị trường, mà rủi ro lựa chọn bất lợi (adverse-selection) và rủi ro tồn kho của họ tỷ lệ với (logic báo giá Avellaneda-Stoikov chạy ngược), nên chi phí đòi hỏi thanh khoản tự nhiên được đo bằng đơn vị biến động. Khi bạn không có dữ liệu sổ lệnh nào cả — chỉ có nến ngày, lịch sử dài — thì với khoảng 0,05–0,1 lần biến động ngày đã là một mô hình tốt hơn hẳn so với bất kỳ hằng số nào, vì ít nhất nó "thở" theo regime.
M3: căn bậc hai theo tỷ lệ tham gia
Số hạng quy mô. là kích thước lệnh của bạn, là khối lượng thị trường trong khung thời gian liên quan, là biến động trong cùng khung thời gian đó. Dạng hàm số này không phải là một sự thuận tiện; nó là một trong những kết quả thực nghiệm được tái lập nhiều nhất trong vi cấu trúc thị trường, và đáng để làm rõ nó bắt nguồn từ đâu.
Xuất phát điểm lý thuyết là Kyle (1985), "Continuous auctions and insider trading" (Econometrica 53(6), 1315–1335). Trong mô hình của Kyle, nhà tạo lập thị trường đặt giá là hàm tuyến tính của dòng lệnh ròng, , với
— impact trên mỗi đơn vị dòng lệnh tỷ lệ với độ bất định về giá trị chia cho khối lượng giao dịch nhiễu (noise trading). Kyle's lambda đã cho lĩnh vực này đơn vị đo thanh khoản (độ sâu là ) và khẳng định kiểm chứng được đầu tiên: chi phí trên mỗi đô la giao dịch phụ thuộc vào tỷ lệ giữa thông tin và thanh khoản, chứ không phải một hằng số. Nhưng mô hình này tuyến tính theo quy mô, còn dữ liệu lại nói khác.
Dữ liệu cho thấy dạng lõm (concave). Almgren, Thum, Hauptmann và Li (2005), "Direct estimation of equity market impact" (Risk, tháng 7/2005), khớp khoảng 700.000 lệnh cổ phiếu Mỹ từ các bàn giao dịch của Citigroup và phát hiện impact tạm thời tăng theo lũy thừa của tỷ lệ tham gia — họ đã kiểm định rõ ràng và bác bỏ cả dạng tuyến tính lẫn căn bậc hai thuần túy để chọn — trong khi impact vĩnh viễn cho ra , không thể phân biệt về mặt thống kê với dạng tuyến tính (điều này khá yên tâm, vì Huberman và Stanzl (2004) đã chỉ ra rằng impact vĩnh viễn phi tuyến sẽ mở đường cho thao túng giá). Tóth et al. (2011), "Anomalous price impact and the critical nature of liquidity in financial markets" (Physical Review X 1, 021006), sử dụng gần 500.000 metaorder từ Capital Fund Management trên các thị trường hợp đồng tương lai, phát hiện với có bậc độ lớn bằng một — và đưa ra lời giải thích nay đã trở thành chuẩn mực: sổ lệnh nhìn thấy được chỉ là một phần nhỏ không đáng kể của thanh khoản tiềm ẩn, vốn tuyến tính cục bộ theo giá quanh mức giá giữa (mid), khiến chi phí ăn xuyên qua nó tỷ lệ theo căn bậc hai. Các nghiên cứu sau này tinh chỉnh thêm ở các biên: Zarinelli, Treccani, Farmer và Lillo (2015), "Beyond the square root" (Market Microstructure and Liquidity 1(2)), đã chỉ ra trên bảy triệu metaorder tổ chức từ ANcerno rằng căn bậc hai khớp tốt trên khoảng hai bậc độ lớn của kích thước lệnh, nhưng dạng logarit mở rộng được trên năm bậc; Bucci et al. (2019, Physical Review Letters 122, 108302) ghi nhận sự chuyển tiếp từ impact tuyến tính (kiểu Kyle) ở mức tham gia rất nhỏ sang căn bậc hai ở mức cao hơn. Và Frazzini, Israel và Moskowitz (2018), "Trading Costs" (SSRN 3229719), sử dụng 1,7 nghìn tỷ đô la lệnh thực thi trực tiếp từ AQR trong 19 năm, phát hiện chi phí thực tế thấp hơn một bậc độ lớn so với các ước lượng học thuật trước đó — một lời cảnh báo rằng các hệ số khớp trên dòng lệnh của người khác, với mức độ khẩn cấp và hàm lượng thông tin khác, không thể chuyển giao trực tiếp sang dòng lệnh của bạn.
Đối với vòng lặp backtest, tóm tắt thực dụng gồm ba mệnh đề. Impact tỷ lệ với biến động. Impact lõm theo quy mô, với số mũ bạn nên coi là cho đến khi dữ liệu của chính bạn chứng minh nên dùng . Hệ số có bậc độ lớn bằng một nhưng thay đổi theo sàn giao dịch, tài sản, và — quan trọng nhất — phong cách giao dịch của chính bạn, đó là lý do phần tiếp theo nói về việc khớp nó thay vì sao chép nó. Việc hiệu chỉnh sâu (kernel phân rã, phân tách impact tạm thời và vĩnh viễn, cross-impact) thuộc về bài viết mô hình hóa impact; backtest chỉ cần đường cong.
Một con số minh họa để cố định trực giác về độ lớn. BTC perp, biến động ngày bps, khối lượng ngày trên sàn tỷ đô, , :
| Kích thước lệnh | Số hạng impact | + nửa spread (0,5 bp) | ||
|---|---|---|---|---|
| 50 nghìn đô | 0,0008% | 0,0029 | 0,5 bp | 1,0 bp |
| 500 nghìn đô | 0,008% | 0,0091 | 1,7 bp | 2,2 bp |
| 5 triệu đô | 0,083% | 0,0289 | 5,4 bp | 5,9 bp |
| 50 triệu đô | 0,83% | 0,0913 | 17,1 bp | 17,6 bp |
Ba bậc độ lớn về quy mô kéo theo hệ số ~18 lần về chi phí. Không hằng số nào bao phủ được bảng này, và mọi so sánh chiến lược thay đổi kích thước vị thế trong khi giữ nguyên slippage_bps đang âm thầm so sánh táo ở mức 50 nghìn đô với cam ở mức 5 triệu đô.
Khớp đường cong: dữ liệu fill của bạn, hoặc của không ai cả
Từ dữ liệu fill của chính bạn
Dữ liệu đúng đắn là hồ sơ TCA của chính bạn: một dòng cho mỗi lệnh mẹ với mid tại thời điểm phát lệnh, VWAP khớp thực tế, kích thước lệnh và trạng thái thị trường tại thời điểm ra quyết định — chính là tập dữ liệu mà đo lường implementation shortfall tạo ra như một sản phẩm phụ. Shortfall tính bằng bps so với giá tại thời điểm phát lệnh, chuẩn hóa theo biến động cùng thời điểm, hồi quy theo tỷ lệ tham gia, sẽ cho bạn trực tiếp và .
Cạm bẫy là nhiễu. Shortfall của một lệnh đơn lẻ là impact cộng với nhiễu giá trong suốt cửa sổ thực thi, và nhiễu chiếm ưu thế: với một lệnh thực thi trong 10 phút ở mức biến động ngày 250 bps, số hạng nhiễu là bps so với tín hiệu impact chỉ khoảng 3 bps. Tỷ lệ tín hiệu trên nhiễu chỉ 0,15 mỗi quan sát là lý do vì sao Almgren et al. cần đến 700 nghìn lệnh và vì sao bạn phải khớp trên trung vị theo nhóm (bucket), không bao giờ trên điểm dữ liệu thô:
import numpy as np
import pandas as pd
def fit_sqrt_curve(orders: pd.DataFrame) -> tuple[float, float]:
"""orders: one row per parent order.
is_bps -- implementation shortfall vs arrival mid, bps, cost-positive
sigma_bps -- volatility at arrival (same window used at simulation time)
q_over_v -- parent size / market volume over the execution window
Fits I = Y * sigma * (Q/V)^delta on participation-bucket medians."""
df = orders.query("q_over_v > 0 and sigma_bps > 0").copy()
df["i_norm"] = df.is_bps / df.sigma_bps # impact in vol units
df["bucket"] = pd.qcut(np.log10(df.q_over_v), 12, duplicates="drop")
b = (df.groupby("bucket", observed=True)
.agg(i=("i_norm", "median"), qv=("q_over_v", "median")))
b = b[b.i > 0] # noisy buckets can go negative; drop, don't clip
delta, log_y = np.polyfit(np.log(b.qv), np.log(b.i), 1)
return float(np.exp(log_y)), float(delta)
Trên vài nghìn lệnh mẹ crypto, phép khớp này đã ổn định ở mức khoảng ±30% cho và ±0,1 cho — thô, nhưng khác biệt giữa một đường cong đã khớp và một hằng số đoán chừng không phải là 30%, mà là toàn bộ hình dạng. Hãy khớp lại theo quý; sự trôi dạt trong tự nó là một chỉ báo chẩn đoán (nếu tăng ở cùng mức tham gia nghĩa là hoặc regime thanh khoản của sàn đã thay đổi, hoặc dòng lệnh của bạn trở nên có thông tin/dễ bị phát hiện hơn).
Khởi động lạnh: chưa có fill nào
Trước lệnh sống đầu tiên, bạn chỉ có dữ liệu công khai, và có hai lựa chọn trung thực.
Đi bộ qua độ sâu sổ lệnh (depth-walk). Lấy trung bình chi phí của việc đi bộ qua các snapshot L2 ở từng kích thước, giống hệt cách bộ mô phỏng khớp lệnh làm cho từng giao dịch, nhưng tổng hợp thành một đường cong. Đây là một cận dưới với dấu đã biết: snapshot chỉ cho thấy thanh khoản sống sót sau dòng lệnh của mọi người khác, động lực bổ sung lại (refill) là vô hình, và các lệnh con trước đó của chính bạn sẽ đã dịch chuyển sổ lệnh trước khi các lệnh con sau đến.
def curve_from_book(snapshots, sizes_usd, safety=1.75):
"""snapshots: iterable of (mid, asks), asks = [(price, qty), ...] best-first.
Depth-walk cost is a LOWER bound on realized cost -- scale it."""
rows = []
for q_usd in sizes_usd:
costs = []
for mid, asks in snapshots:
rem, paid, got = q_usd / mid, 0.0, 0.0
for p, q in asks:
x = min(q, rem)
paid += x * (p - mid); got += x; rem -= x
if rem <= 0:
break
if rem <= 0:
costs.append(paid / got / mid * 1e4)
rows.append((q_usd, safety * float(np.median(costs))))
return pd.DataFrame(rows, columns=["q_usd", "cost_bps"])
Truy vết dấu chân từ các giao dịch công khai. Chia các giao dịch aggressor theo kích thước, đo mức dịch chuyển của mid vài giây sau mỗi giao dịch, và đọc ra một đường cong impact thực nghiệm. Cách này khôi phục được hình dạng lõm và tương đối đúng tỷ lệ theo , nhưng mức độ tuyệt đối bị thiên lệch theo một hướng bạn không thể xác định trước: các lệnh công khai là quyết định của người khác, nên các lệnh lớn có điều kiện mang thông tin (làm impact đo được thiên lệch cao hơn so với việc tái cân bằng vô thông tin của bạn), trong khi những trader nhạy cảm nhất với thanh khoản lại chia nhỏ lệnh chính xác để che giấu (làm nó thiên lệch thấp hơn). Hãy dùng nó cho hình dạng, không phải cho mức độ.
Dù theo cách nào, quy trình khởi động lạnh là: lấy đường cong từ dữ liệu công khai, áp hệ số an toàn 1,5–2, giao dịch nhỏ, và bắt đầu lấp đầy bảng TCA để thay thế nó. Đường cong công khai là giàn giáo, không phải bức tường chịu lực.
Sự phụ thuộc vào regime: cùng một lệnh, chi phí gấp năm lần

Mọi số hạng trong đều phụ thuộc trạng thái, và trong một đợt tăng vọt biến động, tất cả chúng cùng lúc chuyển động bất lợi cho bạn. Spread tỷ lệ với biến động ngắn hạn, nên nới rộng gấp 5–10 lần. đi trực tiếp vào số hạng impact. Khối lượng cũng tăng — điều này thoạt nhìn làm giảm tỷ lệ tham gia — nhưng nó tăng ít hơn ở tử số, và sự bù trừ này che giấu một hiệu ứng còn tệ hơn: độ sâu báo giá gần mid sụp đổ nhanh hơn nhiều so với khối lượng giao dịch, khiến đường cong thực tế dốc hơn những gì công thức đã khớp dự đoán chỉ từ các đầu vào bị căng thẳng.
Cụ thể, với đường cong đã khớp ở trên, một lệnh BTC 3 triệu đô:
- Ngày bình lặng: bps, spread 1 bp, tỷ đô. Chi phí bps.
- Ngày khủng hoảng (mức độ LUNA, FTX): bps, spread 6 bps, tỷ đô. Chi phí bps.
Công thức cho ra 3,3 lần. TCA thực tế vào những ngày căng thẳng luôn cho kết quả cao hơn công thức — sự sụp đổ độ sâu mà số hạng căn bậc hai không nhìn thấy — đây chính là nơi một hệ số nhân căng thẳng đã đo lường được cần có chỗ đứng. Trong dữ liệu fill của chúng tôi, phần dư (residual) ở nhóm khủng hoảng dao động 1,4–1,8 lần trên nền công thức đã căng thẳng hóa đầu vào, đưa tổng chi phí căng thẳng lên 4,5–6 lần chi phí ngày bình lặng cho cùng một lệnh. Đó là nguồn gốc trung thực của câu "cùng một lệnh tốn gấp 5 lần trong đợt tăng vọt biến động": khoảng 2 lần từ đã trừ đi hiệu ứng khối lượng, 2 lần từ spread, và phần còn lại từ độ sâu bốc hơi nhanh hơn những gì thống kê khối lượng thừa nhận.
Cách triển khai là một mô hình chi phí có điều kiện: khớp đường cong theo từng nhóm regime, hoặc tương đương, khớp một đường cong duy nhất cùng một bảng hệ số nhân được đánh chỉ số theo một phân vị biến động thực tế tính toán tại thời điểm ra quyết định (chỉ cửa sổ trượt về sau — một nhãn regime tính trên toàn bộ mẫu là look-ahead bias được lén đưa vào qua mô hình chi phí):
| Regime (phân vị biến động trượt 1 giờ) | Tần suất | Hệ số nhân spread | Hệ số nhân đường cong (đã đo) |
|---|---|---|---|
| Yên tĩnh (< p25) | 25% | 0,6x | 0,7x |
| Bình thường (p25–p75) | 50% | 1,0x | 1,0x |
| Tăng cao (p75–p95) | 20% | 1,8x | 1,6x |
| Căng thẳng (> p95) | 5% | 5–10x | 3–6x |
Frazzini, Israel và Moskowitz (2018) ghi nhận hiện tượng tương tự trong dữ liệu tổ chức của họ: chi phí thực tế biến động cùng chiều mạnh mẽ với biến động cùng thời điểm, và một mô hình chi phí không có số hạng biến động theo thời gian sẽ định giá sai chính xác ở các đuôi phân phối. Lý do bảng này quan trọng hơn nhiều so với dòng căng thẳng 5% của nó gợi ý là do tương quan: các chiến lược không lấy mẫu các dòng này một cách đồng đều. Một hệ thống vol-breakout thực hiện phần lớn giao dịch của nó ở hai dòng dưới cùng. Một market maker bình lặng kiếm lời ở dòng trên cùng và bị stop-out qua dòng dưới cùng. Việc gia quyền các giao dịch của mỗi chiến lược theo biểu đồ regime của chính nó — thay vì tính phí cho mọi người theo mức trung bình vô điều kiện — là hiệu chỉnh PnL lớn nhất trên toàn bộ trang này đối với các hệ thống event-driven, đáng giá hơn cả sự khác biệt giữa hai bậc liền kề bất kỳ của bậc thang.
Thí nghiệm độ nhạy: bốn mô hình chi phí, một bảng xếp hạng bị đảo lộn
Nếu mô hình chi phí thay đổi PnL theo một mức bù trừ hằng số, thì điều này sẽ không quan trọng gì cho việc chọn lựa — mọi biến thể sẽ dịch chuyển đều nhau và giá trị argmax vẫn sống sót. Nhưng không phải vậy, vì độ nhạy chi phí thay đổi giữa các biến thể theo cả một bậc độ lớn. Thí nghiệm sau đây cụ thể hóa điều này:
Thiết lập. Một họ chiến lược — đảo chiều trung bình theo z-score và breakout Donchian trên BTC và ETH perp, nến 1 phút, 18 tháng — với một lưới quét trên khung thời gian nắm giữ (15 phút / 1 giờ / 4 giờ / 24 giờ) và ngưỡng vào lệnh: 20 biến thể, turnover một chiều từ 0,4x đến 11x sổ sách mỗi ngày, lệnh 250 nghìn đô thực thi trong 5 phút. Mỗi biến thể được backtest một lần cho mỗi mô hình chi phí:
- M0: chỉ phí giao dịch;
- M1: phí giao dịch + hằng số 5 bps;
- M2: phí giao dịch + nửa spread + ;
- M3: phí giao dịch + đường cong đã khớp , với bảng hệ số nhân regime ở trên.
Cùng dữ liệu fill, cùng tín hiệu, cùng đường code — mô hình chi phí được truyền vào backtester như một tham số constructor, giống như bất kỳ tham số hạng nhất nào:
from dataclasses import dataclass
@dataclass(frozen=True)
class SqrtCost:
y: float = 0.75 # fitted impact coefficient
delta: float = 0.5 # fitted exponent
fee_bps: float = 2.5 # taker fee, always separate
def cost_bps(self, q_usd: float, st) -> float:
part = q_usd / st.window_volume_usd
return (self.fee_bps + st.stress_mult *
(st.spread_bps / 2 + self.y * st.sigma_bps * part ** self.delta))
for model in [ZeroCost(), ConstCost(5.0), VolCost(0.08), SqrtCost()]:
for variant in grid:
results[(model, variant)] = backtest(variant, cost_model=model)
Kết quả (lần chạy tiêu biểu; lợi nhuận ròng đã quy năm):
| Biến thể | Turnover/ngày | M0 | M1 (5 bp) | M2 | M3 (đường cong) | Hạng M1 → M3 |
|---|---|---|---|---|---|---|
| MR-15m, z=1.0 | 11,4x | +187% | +61% | +9% | −14% | 1 → 17 |
| MR-15m, z=1.5 | 7,9x | +141% | +52% | +15% | −2% | 2 → 13 |
| BO-1h, k=2 | 3,1x | +74% | +43% | +28% | +19% | 3 → 4 |
| MR-1h, z=2.0 | 2,4x | +58% | +38% | +25% | +21% | 4 → 2 |
| BO-4h, k=3 | 0,9x | +39% | +33% | +29% | +26% | 7 → 1 |

Tương quan hạng (Kendall ) giữa các bảng xếp hạng: — một hằng số hầu như không sắp xếp lại gì cả, nó là một loại thuế, không phải một mô hình. — sáu trong số mười biến thể đứng đầu của M1 rời khỏi top 10 dưới M3, và nhà vô địch của M1 chuyển từ +61% xuống âm. — chỉ riêng số hạng biến động đã khôi phục được phần lớn sự sắp xếp lại; số hạng quy mô hoàn thành nốt phần việc cho các biến thể giao dịch lớn tương đối so với khối lượng cửa sổ. Cơ chế chính xác là sự độc hại trong việc chọn lựa từ bậc M0: một mức 5 bps phẳng trợ cấp cho các giao dịch thực sự tốn 15 bps (lớn, nhanh, trong lúc căng thẳng) và đánh thuế quá mức những giao dịch tốn 2 bps (nhỏ, kiên nhẫn, trong lúc bình lặng), nên việc xếp hạng theo M1 một cách hệ thống đề cao các biến thể có chi phí thực bị đánh giá thấp nhất. Bộ tối ưu hóa không tìm thấy alpha; nó tìm thấy số hạng sai số của mô hình chi phí của bạn.
Đây là lý do vì sao mô hình chi phí thuộc cùng phạm trù tư duy với phép chia walk-forward hay hàm mục tiêu: một tham số hạng nhất của backtest mà bạn thay đổi, không phải một hằng số môi trường bạn thiết lập một lần. Nếu hạng của một biến thể ổn định qua M2 và M3, thì lợi thế của nó là thực so với chi phí. Nếu hạng của nó sụp đổ khi đi lên bậc thang, bạn vừa học được rằng đó là một sản phẩm giả tạo của mô hình chi phí — cùng một sự kiện nhận thức luận với một chiến lược chết đi khi ra ngoài mẫu (out-of-sample) trong tối ưu hóa walk-forward, và nó xứng đáng nhận cùng một phản ứng. Và nếu bạn đã chọn argmax của 200 biến thể dưới M1, thì logic deflated Sharpe áp dụng với một biến thể: bạn đã chạy một cuộc tìm kiếm kiểm định đa trọng (multiple-testing) mà bản thân thống kê kiểm định bị thiên lệch có lợi cho các mục tần suất cao.
Biên độ trung thực: PnL như một dải giá trị
Kỷ luật cuối cùng bắt nguồn từ việc thừa nhận mô hình chi phí vẫn bất định ngay cả sau khi đã khớp. có một khoảng tin cậy, các hệ số nhân căng thẳng được ước lượng từ một nhúm ngày đuôi phân phối, và tương lai tự vẽ ra regime riêng của nó. Vậy nên hãy ngừng báo cáo PnL ròng như một con số duy nhất. Hãy báo cáo nó như một dải giá trị qua các kịch bản chi phí có tên gọi:
- Lạc quan: cận dưới depth-walk, không có hệ số nhân căng thẳng. Không bao giờ báo cáo một mình; nhiệm vụ duy nhất của nó là giới hạn kịch bản tốt nhất.
- Thực tế: đường cong đã khớp, hệ số nhân regime đã khớp — ước lượng trung tâm của bạn.
- Bi quan: , spread , dòng căng thẳng luôn được áp dụng ở mức tối thiểu bằng phân vị p75 của nó. Đại khái: đường cong đã khớp được đánh giá tại biên bất lợi của khoảng tin cậy mỗi tham số.
Hai quy tắc quyết định làm cho dải giá trị này vận hành được. Thứ nhất: phân bổ vốn dựa trên kịch bản bi quan, báo cáo dựa trên kịch bản thực tế. Một chiến lược chỉ sống sót dưới mô hình thực tế là một cược rằng phép khớp chi phí của bạn không có sai số theo hướng đắt đỏ — một cược mà bạn chưa hề chủ ý đặt ra. Thứ hai: theo dõi tỷ lệ mong manh (fragility ratio) — độ rộng dải giá trị chia cho PnL gộp. Từ thí nghiệm ở trên: BO-4h ở turnover 0,9x cho PnL gộp +39%, dải giá trị [+22%, +29%], độ mong manh 0,44. MR-15m ở 11,4x cho PnL gộp +187%, dải giá trị [−31%, +34%] — độ mong manh 2,2, và dấu của chiến lược đảo chiều bên trong dải giá trị. Chiến lược thứ hai đó không có dấu xác định được ở trạng thái hiểu biết chi phí hiện tại của bạn; những phát biểu trung thực là "chúng ta không biết" và "giảm turnover cho đến khi biết". Một backtest in ra +34% mà bỏ qua cạnh −31% của dải giá trị không phải là lạc quan, đó là không thể kiểm chứng được (unfalsifiable).
Dải giá trị này không tốn thêm chi phí gì để tạo ra — chỉ thêm ba mục vào phép quét mô hình chi phí mà bạn đã đang chạy — và nó thay đổi các cuộc trò chuyện. "Chiến lược này kiếm được 20%" mời gọi niềm tin. "Chiến lược này kiếm được 11–19% qua các kịch bản chi phí của chúng tôi, và giữ dương ngay cả dưới kịch bản bi quan" mời gọi việc phân bổ vốn.
Vị trí kết nối
Trong công cụ backtest, mô hình chi phí nằm chính xác tại nơi bộ mô phỏng khớp lệnh trả lại khối lượng đã thực thi: các lệnh khớp xác định bạn nhận được gì, đường cong chi phí xác định bạn đã trả gì để có được nó, và các bậc trên L2 của bậc thang đó (depth-walk, mô hình hàng đợi) dần dần hấp thụ mô hình chi phí vào chính mô hình khớp lệnh — đường cong là vật thay thế mang tính tham số mà bạn dùng khi không mô phỏng trực tiếp sổ lệnh. Các tham số đến từ hồ sơ TCA của chính bạn khi bạn có một hồ sơ như vậy, và từ dữ liệu công khai đã được điều chỉnh an toàn khi bạn chưa có. Dạng hàm số đến từ bốn mươi năm lý thuyết và đo lường — Kyle (1985) cho lý do vì sao chi phí trên mỗi đô la phụ thuộc vào thanh khoản, Almgren et al. (2005) và Tóth et al. (2011) cho chính quy luật lõm đó, với Almgren-Chriss như đối tác về lên lịch và mô hình impact bằng mạng nơ-ron như biên giới dự đoán. Điều mà bài viết này bổ sung là quy trình làm việc: khớp đường cong, đặt điều kiện nó theo regime, quét nó như một tham số, và báo cáo dải giá trị. Không có gì trong số này là hào nhoáng. Tất cả đều rẻ hơn việc phát hiện, khi đang giao dịch thực, bạn thực sự đứng ở bên nào của slippage_bps = 5.
Tác Giả
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.