Tránh overfitting trong backtest chiến lược

Vì sao một backtest đẹp có thể chẳng nói lên điều gì — và cách phân biệt giữa lợi thế thật và ảo giác do khớp đường cong.

Cập nhật lần cuối 2026-09
Điểm chính
  • Overfit là chiến lược học thuộc nhiễu của quá khứ thay vì học được một quy tắc: backtest nhìn xuất sắc còn khi chạy thật thì không khác gì ngẫu nhiên.
  • Quét 100 tổ hợp tham số thì dù chiến lược không có chút lợi thế nào, ở mức ý nghĩa 5% cũng sẽ có khoảng 5 tổ hợp cho ra Sharpe dương thuần túy do tình cờ.
  • Đừng chọn đỉnh, hãy chọn cao nguyên: find_plateau của Blave Agent lấy ô có Sharpe trung bình cao nhất trên vùng lân cận 3×3, chứ không lấy điểm cực đại đơn lẻ.
  • Dải quét mọc ra từ chính phân bố của chỉ báo: lấy p5 và p95 làm hai đầu, trung điểm số học làm ranh giới, ngưỡng vào lệnh quét nửa trên còn ngưỡng thoát lệnh quét nửa dưới.
  • Năm dấu hiệu overfit: đỉnh nhọn đơn độc, sụt mạnh khi ra ngoài mẫu, số giao dịch chưa tới 30–50, hiệu suất chỉ đến từ một chế độ thị trường duy nhất, và thêm tham số để "gọt bỏ" một giai đoạn thua lỗ.

Bạn quét xong tham số, chọn tổ hợp có Sharpe cao nhất, và đường cong backtest đẹp tới mức khó tin. Đến khi chạy thật, hiệu suất của nó không khác gì ngẫu nhiên. Thứ đã xảy ra ở giữa có một cái tên.

Overfitting là gì?

Một chiến lược bị overfit khi các tham số của nó được tinh chỉnh khớp với dữ liệu lịch sử chính xác đến mức chiến lược thực chất đang học thuộc quá khứ thay vì học một quy tắc có thể tổng quát hóa. Nó trông xuất sắc trong backtest và chạy kém — hoặc ngẫu nhiên — khi giao dịch thật.

Overfitting không phải lúc nào cũng là cố ý. Nó xảy ra một cách tự nhiên bất cứ khi nào bạn:

  • Quét nhiều tổ hợp tham số rồi chọn tổ hợp có Sharpe cao nhất
  • Sửa chiến lược sau khi đã thấy kết quả backtest, rồi kiểm tra lại trên chính bộ dữ liệu đó
  • Thêm điều kiện chỉ để né những giai đoạn thua lỗ mà bạn nhìn thấy trên biểu đồ
  • Dùng giai đoạn backtest ngắn, nơi một tổ hợp tham số may mắn vượt trội hoàn toàn do tình cờ
Vấn đề cốt lõi: Mọi bộ dữ liệu backtest đều chứa cả quy luật thật lẫn nhiễu. Một chiến lược đủ phức tạp luôn có thể khớp được phần nhiễu. Phần nhiễu đó sẽ không lặp lại trong tương lai.

Cái bẫy của quét tham số

Giả sử bạn quét 100 tổ hợp tham số. Ngay cả khi chiến lược của bạn không có lợi thế nào, vẫn có một số tổ hợp cho ra Sharpe dương thuần túy do tình cờ — khoảng 5 trên 100 ở mức ý nghĩa 5%. Nếu bạn chọn tổ hợp tốt nhất rồi báo cáo nó như hiệu suất của chiến lược, bạn đang báo cáo nhiễu như thể đó là tín hiệu.

Vấn đề này càng tệ hơn khi bạn quét càng nhiều tham số. Một chiến lược có 2 tham số độc lập trên lưới 20×20 có 400 tổ hợp. Một chiến lược có 4 tham số trên lưới 10×10×10×10 có 10,000. Mỗi chiều thêm vào lại nhân lên khả năng vô tình vấp phải một đỉnh may mắn.

Quy tắc kinh nghiệm: Cứ mỗi tham số tự do trong chiến lược, bạn cần khoảng 10× số giao dịch trong backtest để kết quả có ý nghĩa thống kê. Hai tham số = bạn cần rất nhiều giao dịch. Bốn tham số = độ dài backtest cần có thường là phi thực tế.

Đỉnh nhọn hay cao nguyên

Kỹ thuật thực hành quan trọng nhất để tránh overfitting là đừng chọn cái đỉnh.

Hãy nhìn một heatmap Sharpe từ một lần quét tham số. Ô tốt nhất tuyệt đối có thể cho Sharpe 1.8. Dịch một bước sang trái: 0.4. Dịch một bước lên trên: 0.3. Cái đỉnh đó rất mong manh — nó tồn tại vì đúng tổ hợp tham số ấy tình cờ khớp với vài sự kiện thị trường cụ thể trong dữ liệu huấn luyện của bạn.

Thay vào đó, hãy tìm cao nguyên: vùng mà Sharpe luôn cao trên nhiều tổ hợp tham số lân cận. Nếu Sharpe là 1.2 trên cả một lân cận 3×3 các giá trị tham số, đó là tín hiệu bền vững — lợi thế tồn tại trên cả một dải tham số, chứ không chỉ tại một điểm cụ thể.

# find_plateau của Blave Agent: chọn lân cận có Sharpe
# trung bình cao nhất trong cửa sổ 3×3 quanh mỗi ô —
# không phải ô đơn lẻ có giá trị lớn nhất.
best_idx = argmax(neighborhood_average_sharpe)

Đây là lý do script quét tham số — chính là scan.py nằm trong thư mục của từng chiến lược — dùng find_plateau thay vì chỉ lấy Sharpe tốt nhất. Một bộ tham số nằm trên một cao nguyên phẳng có khả năng tổng quát hóa cao hơn nhiều so với bộ nằm trên một đỉnh nhọn bị bao quanh bởi hiệu suất kém.

Trong mẫu và ngoài mẫu

Cách hợp lệ duy nhất để đo hiệu suất thật của một chiến lược là kiểm tra nó trên dữ liệu nó chưa từng thấy. Nếu bạn tối ưu tham số bằng dữ liệu 2020–2023 rồi đánh giá trên 2024, hiệu suất 2024 là ước lượng ngoài mẫu thực sự.

Nếu bạn tối ưu trên 2020–2024 rồi báo cáo hiệu suất 2020–2024: đó là trong mẫu. Ngay cả khi bạn không có ý overfit, quá trình tối ưu đã ngầm dùng kết quả của 2020–2024 để chọn tham số. Sharpe được báo cáo đã bao gồm lợi thế của việc biết trước.

Phương phápHợp lệ?Ghi chú
Tối ưu trên toàn bộ lịch sử, báo cáo hiệu suất toàn bộ lịch sử✗Trong mẫu — chắc chắn overfit
Tối ưu trên 70% đầu, báo cáo hiệu suất 30% cuối✓Chia train/test đơn giản — hợp lệ nhưng hạn chế
Walk-forward: tối ưu trên cửa sổ trượt, báo cáo kỳ kế tiếp✓✓Sát thực tế nhất — cùng cách làm như giao dịch thật

Dải quét ngăn được giá trị cực đoan

Một cái bẫy overfitting phổ biến khác là quét toàn bộ dải giá trị tham số có thể có, kể cả những giá trị cực đoan tình cờ cho Sharpe cao trên một giai đoạn lịch sử bất thường.

Blave Agent dùng cách khác cho các chiến lược dựa trên ngưỡng: suy ra dải quét từ chính phân bố của chỉ báo. Nó lấy p5 và p95 trong phân bố lịch sử của chỉ báo làm hai đầu, rồi lấy trung điểm số học của hai giá trị đó — không phải trung vị — làm ranh giới; ứng viên vào lệnh nằm ở nửa trên (từ trung điểm tới p95), ứng viên thoát lệnh nằm ở nửa dưới (từ p5 tới trung điểm). Cách này giữ cả hai ngưỡng bám vào dải dữ liệu đã quan sát được, tránh những giá trị cực đoan rõ ràng là phi thực tế.

Dấu hiệu chiến lược của bạn đã overfit

1

Đỉnh nhọn trên heatmap Sharpe. Tổ hợp tham số tốt nhất bị bao quanh bởi những giá trị thấp hơn hẳn. Dịch một bước tham số theo bất kỳ hướng nào cũng làm Sharpe giảm 0.5+. Lợi thế đó không bền vững — nó chỉ mang tính cục bộ.

2

Sharpe của backtest không sống sót ngoài mẫu. Chiến lược cho Sharpe 2.0 trên giai đoạn huấn luyện, 0.2 trên giai đoạn kiểm tra được giữ riêng. Khoảng cách càng lớn thì chiến lược càng bị overfit.

3

Quá ít giao dịch. Một chiến lược có 12 giao dịch trong 3 năm backtest gần như không có sức mạnh thống kê. Vài giao dịch may mắn có thể tạo ra Sharpe 2.0+ hoàn toàn do tình cờ. Hãy đòi hỏi ít nhất 30–50 giao dịch hoàn tất trước khi coi các chỉ số backtest là có ý nghĩa.

4

Tham số tròn một cách đáng ngờ. Nếu tham số tốt nhất của bạn là SMA(50) / SMA(200) hoặc RSI(14) hoặc đúng bằng 1.0 / −1.0, đó thường là kết quả của việc quét rồi may mắn rơi vào một giá trị "mặc định" quen thuộc. Chúng có thể chạy được vì lý do sai.

5

Chiến lược chỉ chạy được trong một chế độ thị trường. Nếu hiệu suất backtest hoàn toàn do một giai đoạn tăng hoặc giảm tạo ra, còn đi ngang hoặc âm ở mọi giai đoạn khác, có thể chiến lược đã học đúng chế độ thị trường đó chứ không phải một quy tắc chung.

Bao nhiêu tham số là quá nhiều?

Không có ngưỡng phổ quát nào, nhưng có một nguyên tắc hữu ích: mỗi tham số tự do thêm vào đều phải có một lý do tiên nghiệm để tồn tại trong logic chiến lược. Đừng thêm một tham số vì nó giúp bạn khớp dữ liệu tốt hơn — hãy thêm vì nó đại diện cho một chiều thực sự của cơ chế thị trường mà bạn đang khai thác.

Một chiến lược có hai tham số đại diện cho những khái niệm có ý nghĩa (ví dụ một cửa sổ tín hiệu nhanh và một cửa sổ xác nhận chậm) dễ bảo vệ hơn nhiều so với một chiến lược sáu tham số, trong đó vài tham số được thêm vào để "gọt bỏ" những giai đoạn thua lỗ cụ thể nhìn thấy trên biểu đồ.

Những gì các cách làm này không cứu được

  • Cách chọn cao nguyên xử lý câu hỏi “ô bạn chọn có phải may mắn không”; nó không xử lý câu hỏi “chiến lược này rốt cuộc có lợi thế hay không”. Suy dải quét từ phân bố cũng vậy — nó chỉ ngăn bạn đi kiểm những giá trị cực đoan gần như chưa từng xảy ra trong lịch sử, chứ không biến một quy tắc không có lợi thế thành có lợi thế.
  • Bảng trong mẫu / ngoài mẫu phía trên là phán đoán ở tầng khái niệm. Ở tầng sản phẩm phải nói thêm một câu: trên Blave không có thiết lập «giữ 30% làm tập kiểm định», công cụ ngoài mẫu duy nhất là rolling walk-forward ở tab thứ năm của workspace, và hai ô nhập điền vào đó là số ngày. Thứ nó kiểm không giống với việc chia đôi đơn giản — xem Cách kiểm định ngoài mẫu hoạt động: vì sao ở đây không có «giữ 30% làm tập kiểm định».
  • Còn một câu hỏi bài này không trả lời: kể cả khi đã qua được ngoài mẫu, thành tích đó có phải may mắn không? Đó là việc của kiểm định ý nghĩa thống kê — xem Lãi trong backtest là thực lực hay may mắn: cách đọc giá trị p của MCPT. Ngoài mẫu và ý nghĩa thống kê không hỏi cùng một chuyện, và hai công cụ đó cũng không đảm bảo sẽ cho bạn cùng một câu trả lời.