Backtest là thí nghiệm, không phải bằng chứng rằng tương lai sẽ lặp lại quá khứ. Một kết quả lịch sử có thể rất đẹp chỉ vì mô hình đã nhìn thấy tương lai, bỏ qua tài sản thất bại, thử quá nhiều biến thể hoặc giả định chi phí không thực tế.
Nội dung mang tính nghiên cứu và giáo dục, không phải khuyến nghị đầu tư.
Vì sao backtest dễ khiến chúng ta tự tin quá mức?
Thị trường có nhiễu lớn, số quan sát hữu ích thường ít hơn tưởng tượng và các mẫu dữ liệu theo thời gian không độc lập hoàn toàn. Nếu thử đủ nhiều tham số, gần như chắc chắn sẽ xuất hiện một cấu hình có Sharpe cao chỉ do may mắn.
Nghiên cứu “The Probability of Backtest Overfitting” của Bailey, Borwein, López de Prado và Zhu đề xuất một khung định lượng xác suất backtest bị overfit. Thông điệp thực hành rất rõ: một lần chia train/test đơn giản có thể không đủ khi chiến lược được chọn từ nhiều lần thử; cần tính đến cả quá trình lựa chọn mô hình.
Bảy sai lệch phổ biến nhất
1. Look-ahead bias: dùng thông tin của tương lai
Look-ahead xảy ra khi backtest sử dụng dữ liệu chưa thể biết tại thời điểm ra quyết định. Ví dụ: dùng giá đóng cửa để tạo tín hiệu rồi giả định cũng khớp được tại chính giá đóng cửa đó; dùng báo cáo tài chính theo ngày kết thúc kỳ thay vì ngày công bố; hoặc tính indicator bằng dữ liệu của toàn bộ mẫu.
Cách kiểm tra: mỗi biến cần một “availability timestamp”. Tín hiệu tại thời điểm t chỉ được phép dùng thông tin có sẵn trước lúc đặt lệnh.
2. Survivorship bias: chỉ nghiên cứu những tài sản còn tồn tại
Nếu universe hôm nay được áp ngược về quá khứ, các công ty phá sản, hủy niêm yết hoặc bị sáp nhập có thể biến mất khỏi dữ liệu. Kết quả thường được cải thiện giả tạo vì mẫu chỉ còn lại những người sống sót.
Cách kiểm tra: dùng universe theo từng thời điểm, lưu lịch sử thêm/xóa thành phần và xử lý đầy đủ delisting return khi nguồn dữ liệu hỗ trợ.
3. Data leakage: test set ảnh hưởng tới quá trình học
Leakage không chỉ đến từ nhãn tương lai. Một lỗi phổ biến là chuẩn hóa, điền dữ liệu thiếu hoặc chọn feature bằng toàn bộ dataset trước khi chia train/test. Tài liệu scikit-learn khuyến nghị chia dữ liệu trước và chỉ fit các bước tiền xử lý trên tập train; pipeline giúp giảm nguy cơ dùng nhầm test data.
Cách kiểm tra: đưa mọi phép biến đổi học từ dữ liệu vào pipeline và chạy lại toàn bộ pipeline trong từng fold thời gian.
4. Data snooping và overfitting do thử quá nhiều
Giả sử bạn thử 20 indicator, 10 cửa sổ thời gian và 5 ngưỡng vào lệnh. Chỉ riêng lưới này đã tạo 1.000 biến thể. Nếu sau đó chỉ báo cáo biến thể tốt nhất, Sharpe quan sát được không còn phản ánh một giả thuyết độc lập.
Cách kiểm tra: ghi nhật ký toàn bộ lần thử, khóa tập test cuối cùng, ưu tiên vùng tham số ổn định thay vì một điểm cực đại và so sánh với baseline đơn giản.
5. Chi phí giao dịch và slippage quá lạc quan
Phí môi giới chỉ là một phần. Chiến lược còn chịu bid-ask spread, slippage, market impact, funding, borrow cost và cơ hội không khớp lệnh. Turnover cao có thể biến lợi nhuận gộp thành thua lỗ ròng.
net_pnl = gross_pnl
- commission
- spread_cost
- slippage
- financing_cost
- borrow_costCách kiểm tra: chạy ít nhất ba kịch bản chi phí: cơ sở, thận trọng và stress. Giá khớp phải phù hợp với thanh khoản và thời điểm tín hiệu.
6. Chia dữ liệu sai thứ tự thời gian
Random split có thể đưa dữ liệu tương lai vào train và dữ liệu quá khứ vào test. Với chuỗi thời gian, nên dùng holdout theo thời gian, walk-forward hoặc TimeSeriesSplit. Tham số gap có thể chừa khoảng cách giữa train và test khi nhãn hoặc feature chồng lấn.
Cách kiểm tra: vẽ timeline của từng fold. Nếu bất kỳ quan sát train nào xảy ra sau quan sát test, quy trình chia mẫu cần được sửa.
7. Regime dependence: mô hình chỉ hợp một giai đoạn
Quan hệ từng tồn tại trong thị trường biến động thấp có thể mất đi khi thanh khoản cạn, lãi suất đổi hướng hoặc cấu trúc người tham gia thay đổi. Trung bình toàn giai đoạn dễ che khuất sự phụ thuộc này.
Cách kiểm tra: phân rã kết quả theo năm, volatility regime, xu hướng thị trường, mức thanh khoản và nhóm tài sản. Một chiến lược không nhất thiết thắng ở mọi chế độ, nhưng nhà nghiên cứu phải biết nó đang phụ thuộc vào điều gì.
Một quy trình backtest tối thiểu nhưng nghiêm túc
- Đăng ký giả thuyết: viết logic, universe, kỳ quan sát, kỳ nắm giữ và tiêu chuẩn thất bại trước khi chạy.
- Đóng băng dữ liệu: lưu phiên bản file, nguồn và thời điểm tải.
- Tách tập test cuối: không mở để chỉnh feature hoặc tham số.
- Xây baseline: quy tắc đơn giản nhất có thể kiểm tra luận điểm.
- Walk-forward: huấn luyện trên quá khứ, đánh giá trên giai đoạn kế tiếp rồi cuộn cửa sổ.
- Mô phỏng thực thi: delay tín hiệu, giá khớp, thanh khoản và chi phí.
- Stress test: tăng chi phí, đổi nhẹ tham số, bỏ giai đoạn tốt nhất và kiểm tra dữ liệu khác.
- Lưu toàn bộ thí nghiệm: không xóa kết quả xấu khỏi lịch sử nghiên cứu.
Đọc báo cáo backtest như thế nào?
| Câu hỏi | Dấu hiệu cần cảnh giác |
|---|---|
| Lợi nhuận đến từ đâu? | Một vài giao dịch hoặc một giai đoạn tạo gần như toàn bộ P&L |
| Kết quả có ổn định không? | Thay đổi nhỏ tham số làm hiệu quả sụp đổ |
| Có giao dịch được không? | Turnover lớn, tài sản kém thanh khoản, giả định khớp tại giá lý tưởng |
| Đã thử bao nhiêu mô hình? | Chỉ công bố mô hình thắng, không có nhật ký các lần thử |
| Tập test có thật sự “chưa thấy”? | Dùng test set nhiều lần để chỉnh quy tắc |
| Có cơ sở kinh tế không? | Không giải thích được vì sao tín hiệu có thể tồn tại sau chi phí |
AI giúp kiểm tra backtest, nhưng cũng có thể làm overfit nhanh hơn
Mô hình ngôn ngữ có thể hỗ trợ viết unit test, rà soát thứ tự thời gian, tạo báo cáo giao dịch và tìm điểm bất thường. Machine learning có thể nhận diện quan hệ phi tuyến hoặc tương tác feature. Tuy nhiên, AI cũng giúp tạo hàng trăm biến thể rất nhanh; nếu không ghi số lần thử và khóa tập test, tốc độ đó chỉ làm data snooping nghiêm trọng hơn.
Một nguyên tắc hữu ích là: AI được phép đề xuất, nhưng dữ liệu ngoài mẫu phải quyết định. Mọi đoạn mã do AI tạo cần được kiểm tra bằng test nhỏ có kết quả biết trước, đặc biệt với shift, rolling window, resample và căn chỉnh timestamp.
Checklist trước khi tin một đường equity
- Universe có bao gồm tài sản đã biến mất không?
- Mọi feature có timestamp khả dụng không?
- Tiền xử lý có được fit riêng trên train không?
- Đã ghi tổng số mô hình và tham số từng thử chưa?
- Giá khớp và độ trễ có khả thi không?
- Đã trừ đủ phí, spread, slippage và financing chưa?
- Test set có còn nguyên vẹn sau quá trình phát triển không?
- Kết quả có tồn tại trên nhiều giai đoạn và kịch bản stress không?
- Có điều kiện dừng nếu paper trading lệch xa backtest không?
Kết luận
Mục tiêu của backtest không phải chứng minh một ý tưởng đúng, mà tìm cách làm nó thất bại trước khi thị trường làm điều đó bằng tiền thật. Một kết quả kém nhưng trung thực có giá trị hơn một đường lợi nhuận hoàn hảo được xây từ dữ liệu tương lai và giả định không thể giao dịch.

