Công cụ duy nhất là rolling walk-forward, và thứ nó kiểm không phải là một bộ tham số.
Bạn đã đọc đúng câu này trong sách giáo khoa, thậm chí trong chính bài Cách đọc kết quả backtest của chúng tôi: đừng tối ưu trên toàn bộ dữ liệu, hãy giữ lại ít nhất 20–30% để kiểm định ngoài mẫu. Rồi bạn mở workspace, bấm qua từng tab một, và không tìm thấy cái thiết lập tỷ lệ đó đâu cả.
Không tìm thấy là bình thường, sản phẩm không có chức năng đó. Chuyện ngoài mẫu trên Blave chỉ có một cách hiện thực: rolling walk-forward ở tab thứ năm, mà thứ điền vào đó là số ngày, và thứ nó kiểm cũng hơi khác với việc chia đôi đơn giản. Bài này nói rõ khác ở đâu, và từng con số trên tab đó đọc thế nào.
Trong Cách tránh overfitting chiến lược có một bảng xếp hạng ba cách làm: tối ưu trên toàn bộ dữ liệu (vô dụng), 70% đầu huấn luyện 30% cuối kiểm định (hữu ích nhưng có hạn), và chọn lại theo cửa sổ trượt (sát thực tế nhất). Bảng đó là phán đoán ở tầng khái niệm; sự thật ở tầng sản phẩm là — chỉ cách thứ ba mới có nút bấm.
| Cách làm | Trên lý thuyết | Trên Blave |
|---|---|---|
| Tối ưu trên toàn bộ lịch sử, báo cáo trên toàn bộ lịch sử | Trong mẫu, tất yếu lạc quan | Tab Backtest vốn dĩ tính thành tích trên cả đoạn lịch sử, nên mới cần kiểm thêm |
| Cắt một nhát: đoạn đầu huấn luyện, đoạn sau kiểm định | Hữu ích nhưng chỉ dùng được một lần | Không có chức năng này, không tìm thấy thiết lập tỷ lệ |
| Rolling walk-forward: mỗi vòng chọn lại, kiểm đoạn kế tiếp | Cách sát với giao dịch thật nhất | Tab thứ năm của workspace, «Kiểm định ngoài mẫu» |
Khác biệt không chỉ ở giao diện. Chia đôi đơn giản kiểm chuyện «bộ tham số này có tốt trên đoạn dữ liệu sau không»; rolling walk-forward kiểm chuyện bản thân cách làm «lấy lịch sử chọn tham số» có còn đứng vững trên chiến lược này hay không — nó lặp lại hành động «lấy một đoạn lịch sử để chọn tham số» n lần, mỗi lần đều chấm điểm bằng đoạn kế tiếp chưa từng thấy.
Một câu: trong mỗi cửa sổ huấn luyện thì chọn lại tham số, áp vào cửa sổ kiểm định ngay sau đó, rồi nối tất cả các cửa sổ kiểm định thành một đường.
| Vòng | Cửa sổ huấn luyện | Cửa sổ kiểm định |
|---|---|---|
| 1 | 2022-01-05 → 2024-12-30 | 2024-12-31 → 2025-01-29 |
| 2 | 2022-02-04 → 2025-01-29 | 2025-01-30 → 2025-02-28 |
| 3 | 2022-03-06 → 2025-02-28 | 2025-03-01 → 2025-03-30 |
| … | (các vòng ở giữa cũng nhích lên một cửa sổ kiểm định mỗi lần, tổng cộng 20 vòng) | |
| 20 | 2023-07-29 → 2026-07-23 | 2026-07-24 → 2026-08-22 |
Các cửa sổ kiểm định nối đầu nối đuôi tới từng ngày: vòng 1 dừng ở 2025-01-29, vòng 2 nối tiếp từ 2025-01-30, ở giữa không có khe hở cũng không chồng lấn — 20 đoạn nối lại chính là chuỗi ngoài mẫu đó.
Còn các cửa sổ huấn luyện thì chồng lấn rất nhiều: cửa sổ ba năm mỗi vòng chỉ nhích lên 30 ngày, nên giai đoạn huấn luyện của hai vòng bất kỳ gần như là cùng một đoạn dữ liệu. Thứ chồng lấn nhau thì không ghép thành một đường liền được — đó là lý do trên biểu đồ chỉ có mỗi đường ngoài mẫu.
Về hiện thực thì nó chạy hai lượt: lượt đầu tính tín hiệu của từng bộ tham số ứng viên trên toàn bộ lịch sử đúng một lần, rồi cắt ra định giá cho lát huấn luyện của từng vòng; lượt sau chỉ tính lại bộ thắng cuộc của mỗi vòng, xâu các lát kiểm định thành một chuỗi và định giá cả đoạn trong một lần. Nên nó nhanh hơn hẳn so với «chạy n lượt quét đầy đủ» — ví dụ 20 vòng, khung giờ 4.7 năm bên dưới chạy xong trong 3.5 giây ở lần chạy 2026-09-17 (hộp thoại xác nhận của giao diện đưa ra trường hợp chung: «Thường chạy xong trong khoảng hai phút; kết quả sẽ hiện ở thẻ này.»).
Rolling là cửa sổ huấn luyện mỗi vòng trượt nguyên khối về phía trước; anchored là cố định điểm bắt đầu và cửa sổ huấn luyện càng lăn càng dài. Sản phẩm chỉ cung cấp rolling, anchored là cố ý không cung cấp. Bạn đòi agent làm anchored, nó sẽ đáp lại một câu cố định rồi vẫn chạy rolling:
Cũng đừng nghĩ tới chuyện đi đường vòng: cái lib chạy walk-forward là chỉ đọc, tiến trình thường trú sẽ từ chối thẳng việc chỉnh sửa; hơn nữa trong tệp kết quả không có trường nào để đánh dấu «đây là chạy anchored», nên có sửa thật thì màn hình vẫn hiển thị theo kiểu rolling.
Trên tab chỉ có hai ô nhập: cửa sổ huấn luyện và cửa sổ kiểm định, đơn vị đều là ngày, bên cạnh hiện ngay số vòng sẽ cắt ra được. Để trống cả hai thì chạy theo bảng mặc định này:
| Độ dài dữ liệu (ngày) | Cửa sổ huấn luyện (ngày) | Cửa sổ kiểm định (bao lâu chọn lại một lần, ngày) |
|---|---|---|
| ≥ 1185 | 1095(ba năm) | 30 |
| 455–1184 | 365(một năm) | 30 |
| < 455 | 4 lần cửa sổ kiểm định | tổng số ngày ÷ 12, tối thiểu 30 |
Bậc ba năm có lý do của nó: nó gần với cách làm thật của người dùng, tức là chọn một bộ tham số cố định từ cả đoạn backtest. Lịch sử dài vừa phải mà áp thẳng công thức tỷ lệ thì cửa sổ huấn luyện sẽ ngắn hơn một năm, nên ở giữa mới bù thêm bậc 365 / 30.
Hai giới hạn cứng sẽ chặn ngay, không trao cho bạn kết quả nửa vời: dưới 3 vòng thì không chạy, cũng không ghi tệp kết quả («Dữ liệu chỉ đủ cho {n} vòng — cần tối thiểu 3 vòng mới đọc được kết quả ngoài mẫu»); trên 1000 vòng cũng chặn y như vậy («hãy tăng cửa sổ kiểm định»). Dữ liệu ở đuôi không đủ một vòng thì không bị ghép cố, phía dưới biểu đồ sẽ chú thích «{d} ngày cuối không đủ một vòng nên không được tính».
Thẻ kết luận chỉ nhìn một con số:
WFE = Sharpe ngoài mẫu ÷ Sharpe trung bình trong mẫu
Tử số là Sharpe của cả đoạn sau khi nối lại của chuỗi ngoài mẫu; mẫu số là trung bình Sharpe của chính ô được chọn trong cửa sổ huấn luyện của từng vòng. Bốn nhãn chia theo các mốc này (đều là «nhỏ hơn», nên 0.5 rơi vào «vừa vượt ngưỡng» và 0.7 rơi vào «trên ngưỡng»):
| WFE | Thẻ kết luận hiển thị |
|---|---|
| Không tính ra được | Hiệu suất ngoài mẫu: không thể đánh giá |
| < 0.2 | Hiệu suất ngoài mẫu: thấp hơn ngưỡng rất nhiều |
| < 0.5 | Hiệu suất ngoài mẫu: dưới ngưỡng |
| < 0.7 | Hiệu suất ngoài mẫu: vừa vượt ngưỡng |
| ≥ 0.7 | Hiệu suất ngoài mẫu: trên ngưỡng |
Còn phần diễn giải bên cạnh con số đó, xin hãy đọc đúng theo nghĩa đen:
Một mẫu số rất nhỏ hoặc âm sẽ lật ngược cả chẩn đoán: một chiến lược vốn chưa bao giờ mạnh trong mẫu lại được «hiệu suất» rất cao chỉ vì nó «chẳng có gì để nhả ra». Vì thế có hai lớp phòng vệ:
Chiến lược mẫu hướng dẫn btc_sma_cross (BTCUSDT 1h, từ 2022-01-01, tổng cộng 1,720 ngày, SMA 45 / 100, không sửa một chữ tham số nào). Dữ liệu rơi vào bậc đầu tiên nên áp cửa sổ mặc định 1095 / 30, cắt ra 20 vòng (cửa sổ kiểm định cộng lại 600 ngày); 25 ngày cuối không đủ một vòng nên không được tính.
| Mục | Ngoài mẫu (các cửa sổ kiểm định nối lại, 600 ngày) | Trong mẫu (20 cửa sổ huấn luyện tính riêng rồi lấy trung bình) |
|---|---|---|
| Sharpe | −0.45 | 1.3471 |
| Lợi nhuận hằng năm | −16.55% | +50.16% |
| Sụt giảm tối đa | −46.57% | — |
| Số giao dịch | 183 | — |
Hiệu suất ngoài mẫu WFE = −0.45 ÷ 1.3471 = −0.334 → thấp hơn ngưỡng rất nhiều
Có ba điều đáng chỉ ra. Thứ nhất, không có vòng nào bị loại — Sharpe cửa sổ huấn luyện của cả 20 vòng đều lớn hơn 0, nên mẫu số là trung bình đầy đủ của 20 vòng, chứ không phải phần còn lại sau khi sàng.
Thứ hai, mẫu số 1.3471 cao hơn 0.25 rất nhiều nên lớp phòng vệ thứ hai không kích hoạt, phép chia có hiệu lực: «WFE âm» và «WFE không thể đánh giá» là hai chuyện khác nhau, cái trước là kết quả tính ra được, cái sau là từ chối trả lời.
Thứ ba, hai cột đó vốn dĩ phủ những giai đoạn khác nhau — trong mẫu là trung bình của 20 cửa sổ huấn luyện chồng lấn nhau, ngoài mẫu là 600 ngày sau đó, nên đây không phải một đối chiếu cùng kỳ sạch sẽ; và chính khoảng chênh ấy mới là thứ WFE muốn đo.
Cùng ngày, cùng một bản mã, giá trị p MCPT của chiến lược này là 0.0160 (n = 2000), stdout tự in ra significant edge at 95% — chiếu theo tiêu chuẩn của cổng lên sàn thì là đạt.
| Kiểm định | Câu hỏi nó đặt ra | Kết quả |
|---|---|---|
| MCPT | Trên chuỗi vị thế cố định này, kết quả đó có phân biệt được thực lực với may mắn không? | p = 0.0160 → Đạt |
| Walk-forward | Bản thân việc chọn tham số theo lịch sử còn dùng được ở đoạn tiếp theo không? | WFE = −0.334 → thấp hơn ngưỡng rất nhiều |
Cả hai đều không tính sai, bởi chúng không trả lời cùng một câu hỏi. Đây cũng là lý do giá trị p đẹp tới đâu cũng không thể coi là đã qua kiểm định ngoài mẫu (xem Cách đọc giá trị p của MCPT). Tiện thể nói rõ: đây không phải là nói chiến lược này hỏng — nó là mẫu hướng dẫn đi kèm workspace, và thứ được minh họa ở đây là khác biệt về ý nghĩa giữa hai kiểm định.
Mỗi vòng chọn tham số bằng trung bình lân cận 3×3 (cùng một quy tắc với quét tham số, tức là cách chọn cao nguyên chứ không chọn đỉnh nhọn nói trong Cách tránh overfitting chiến lược), nhưng Sharpe huấn luyện được báo cáo trên bảng vòng lại là con số của chính ô được chọn. Đây là cố ý:
| Mẫu số dùng gì | Hậu quả |
|---|---|
| Sharpe của chính ô đó (hiện hành) | Mẫu số thiên cao, WFE thiên về thận trọng |
| Trung bình lân cận 3×3 | Trung bình lân cận về mặt cấu trúc tất yếu thấp hơn chính ô mà nó bao quanh → mẫu số bị ép nhỏ lại → WFE bị thổi phồng, cả tab đọc lên thành lạc quan quá mức |
Chẩn đoán với mẫu số bị thổi phồng thì thà đừng làm còn hơn.
Ở chỗ giáp ranh hai vòng, chuỗi mang theo vị thế của chính vòng mới — nó bị cắt ra, chứ không bị đưa về không. Ép đóng vị thế ở mọi chỗ nối thì chẳng khác nào bịa ra n−1 lệnh thoát mà chưa ai từng giao dịch.
Chi phí đổi tham số cũng không bị bỏ sót: ở chỗ nối tỷ trọng thay đổi, và khi định giá vẫn thu phí giao dịch đầy đủ. Cũng vì con số của mỗi vòng đều được cắt ra từ cùng một chuỗi đã nối sẵn chứ không định giá lại, nên cộng bảng vòng lại đúng bằng tổng của cả đoạn.
Tín hiệu được tính trên toàn bộ lịch sử (chỉ báo rolling có thế mới chuẩn), nhưng mỗi lát huấn luyện đều tự bỏ qua số nến khởi động ở đầu của chính nó — không phải chỉ mỗi vòng đầu tiên. Không có bước này thì vòng 1 sẽ huấn luyện trên những cây nến mà chỉ báo chưa kịp nóng và nhặt phải nhiễu, độ dài hữu hiệu của các vòng cũng khác nhau và không so được. Chính bảng vòng ở trên là bằng chứng: START của chiến lược ghi là 2022-01-01, nhưng cửa sổ huấn luyện của vòng 1 mãi tới 2022-01-05 mới bắt đầu — mấy ngày chênh đó chính là WARMUP = 100 cây nến giờ (khoảng 4.2 ngày) bị trừ đi.
Cửa sổ kiểm định thì không bị cắt xén, vì nó đã nóng sẵn rồi, và vì nó buộc phải liên tục mới nối được. Tiện thể trả lời một câu hỏi mà bạn đọc nâng cao hay hỏi: ở đây không cần giai đoạn cách ly embargo — cửa sổ kiểm định nằm sát ngay sau cửa sổ huấn luyện đã chọn tham số cho nó, còn dữ liệu sau nó thì hoàn toàn không được dùng tới.
Chạy xong không có nút «áp dụng tham số đề xuất» nào, và agent cũng không được phép sửa mã chiến lược của bạn vì kết quả này. Trạng thái rỗng đã nói thẳng ngay từ đầu:
Vì sao không chép được? Hãy nhìn độ trôi dạt tham số của lần chạy đó. Qua 20 vòng chỉ chọn ra 4 bộ tham số khác nhau:
(45,100) ×14 → (55,80) → (45,100) → (45,80) ×3 → (35,80)
14 vòng đầu đều đứng yên ở cùng một ô. Cho dù «phần lớn thời gian đều chọn 45 / 100» trông có vẻ là một kết luận, thì đường cong ngoài mẫu −0.45 kia cũng không phải thành tích của 45 / 100 — nó là cả một đoạn do 4 bộ tham số chạy tiếp sức, không thuộc về bộ nào, nên không có bộ nào để mà «áp dụng». Khi bạn đòi áp dụng, agent sẽ đáp lại một câu cố định:
Lưới trôi dạt tham số sẽ vẽ ra mỗi vòng chọn ô nào và ô đó được chọn bao nhiêu vòng, khung nét đứt đánh dấu tham số hiện tại của bạn, chú giải cũng ghi rõ «tham số của vòng cuối chỉ để tham khảo, không phải giá trị khuyến nghị» — vòng cuối của lần chạy đó chọn 35 / 80, điều đó chỉ có nghĩa «cửa sổ huấn luyện của đúng vòng cuối ấy tình cờ rơi vào ô này». Ngoài ra, tab này không hiển thị giá trị p và cũng không bao giờ chạy MCPT; chạy một lượt walk-forward được tính là một vòng lặp trong quy tắc làm việc của agent.
Số vòng có đủ không? Dưới 3 vòng thì nó không chạy chút nào. Khi số vòng quá ít, WFE chỉ là vận may của một hai cửa sổ kiểm định.
Có vòng nào bị loại không? Phần chi tiết từng vòng sẽ chú thích những vòng nào có Sharpe cửa sổ huấn luyện ≤ 0. Lần chạy ở trên không có vòng nào bị loại; càng nhiều vòng bị loại thì càng có nghĩa chiến lược này ngay trong chính cửa sổ huấn luyện của nó cũng thường chẳng chọn được gì.
WFE là «không thể đánh giá» hay là một số âm? Khác nhau. «Không thể đánh giá» nghĩa là trung bình trong mẫu dưới 0.25 và tỷ số này vô nghĩa; số âm nghĩa là phép chia đã làm, và đoạn ngoài mẫu thì lỗ.
Tham số trôi dạt dữ tới đâu? Hãy xem dòng «{n} vòng chọn ra {u} bộ tham số khác nhau». Lần chạy ở trên là 20 vòng ra 4 bộ; nếu mỗi vòng đều nhảy sang một ô hoàn toàn khác thì mỗi lần chọn lại là một lần đuổi theo một thứ khác nhau.
Bạn có đang đi tìm tham số đề xuất không? Không có đâu. Muốn đổi tham số thì dùng điểm ổn định của quét tham số, chứ không phải chép vòng cuối.
Chạy thử một lần rồi mà WFE rơi thảm hại thì vấn đề thường không nằm ở bước ngoài mẫu này, mà ở bước chọn tham số — đó là phạm vi của Cách tránh overfitting chiến lược. Nếu bạn còn chưa có chiến lược nào đáng đem đi kiểm, thì mỗi chiến lược chính thức trong Thư viện chiến lược đều kèm backtest thật và kết quả các tiêu chí chất lượng, xem số trước rồi hãy quyết: Thư viện chiến lược.