Kết quả của bạn đứng ở đâu sau khi lợi nhuận bị xáo trộn vài nghìn lần — và con số đó không trả lời điều gì.
Backtest chạy xong, Sharpe trông cũng được. Nhưng câu hỏi trong đầu bạn vẫn chưa được trả lời: chiến lược thật sự bắt được điều gì đó, hay bạn chỉ tình cờ chém vài nhát bừa bãi giữa một đoạn thị trường đang lên? Một cách trả lời là xáo trộn dữ liệu vài nghìn lần rồi xem kết quả của bạn xếp thứ mấy trong đống ngẫu nhiên đó — đúng là việc mà dòng «Giá trị p MCPT» trên tab Backtest của workspace đang làm. Bài này nói nó kiểm định cái gì, đọc thế nào, và câu hỏi mà nó vẫn chưa trả lời ngay cả khi đã đạt.
MCPT (Monte Carlo Permutation Test, kiểm định hoán vị Monte Carlo) là một kiểm định thống kê: nó sắp xếp lại ngẫu nhiên chuỗi lợi nhuận của giai đoạn backtest thật nhiều lần, mỗi lần đều tính lại Sharpe trên đúng bộ điểm vào và thoát lệnh đó, để dựng nên trọn một phân phối «nếu thuần may mắn thì trông thế nào», rồi xem kết quả thật của bạn rơi vào đâu trên phân phối ấy.
| Mục | Nội dung |
|---|---|
| Giả thuyết không | Những giai đoạn lợi nhuận mà chiến lược này chọn không tốt hơn những giai đoạn chọn ngẫu nhiên |
| Định nghĩa giá trị p | Tỷ lệ số lần Sharpe sau khi xáo trộn lớn hơn hoặc bằng Sharpe thật |
| Cách hiểu | p < 0.05 → Có lợi thế đạt ý nghĩa thống kê ở mức tin cậy 95% |
| Phạm vi kiểm định | Toàn bộ dữ liệu backtest, không chia huấn luyện / kiểm định |
Giá trị p càng nhỏ thì chuyện «xáo trộn bừa cũng thắng được bạn» càng hiếm. Lấy mặc định 2000 lần làm ví dụ, p = 0.05 nghĩa là trong 2000 lần đó có 100 lần kết quả ngẫu nhiên không thua bạn; p = 0.005 nghĩa là chỉ có 10 lần.
Đây là điểm mấu chốt nhất trong toàn bộ thiết kế, và cũng là điểm dễ hiểu nhầm nhất: thứ bị xáo trộn là chuỗi lợi nhuận tương lai, còn chuỗi vị thế của bạn thì cố định từ đầu đến cuối.
Mỗi lần hoán vị làm những gì: position(vị thế của bạn) ← cố định, chỉ tính một lần ngoài vòng lặp × vol_scalar(co giãn vị thế) ← cố định, chỉ tính một lần ngoài vòng lặp − fee_cost(phí giao dịch) ← cố định, chỉ tính một lần ngoài vòng lặp × chuỗi lợi nhuận sau khi xáo trộn ← chỉ mục này mới được rút lại mỗi lần = Sharpe của lần hoán vị này
Vì phí và co giãn vị thế đều đã tính xong ngoài vòng lặp, mỗi lần hoán vị đều chịu cùng một mức chi phí giao dịch và cùng một mức đòn bẩy. Biến số duy nhất còn lại là «thứ tự lợi nhuận xuất hiện» — tức là những thời điểm bạn chọn có tốt hơn những thời điểm chọn ngẫu nhiên không.
Vì như thế là cho điểm không. Xáo trộn một mảng vị thế nhị phân sẽ tạo ra số lần đảo chiều vào ra nhiều hơn hẳn bản thân chiến lược; với fee = 0.0005, mỗi lần hoán vị phải gánh khoảng 30 đến 40 lần mức phí, và mọi Sharpe sau khi xáo trộn đều bị ép xuống âm sâu. Dù chiến lược của bạn có lợi thế thật hay không, giá trị p vẫn sẽ đẹp đến mức vô nghĩa.
Nó là tự động, không phải tùy chọn. Mỗi lần chiến lược Type A chạy backtest là nó chạy một lần, kết quả ghi thẳng vào thống kê backtest và hiển thị trên tab Backtest của workspace.
| Thiết lập | Mặc định | Diễn giải |
|---|---|---|
| Số lần hoán vị | 2000 | Có thể ghi đè bằng MCPT_N trong chiến lược, nhưng vẫn chịu ràng buộc của công thức ngân sách bên dưới |
| Hạt giống ngẫu nhiên | 42 | Bộ sinh số riêng, không đụng tới hạt giống toàn cục — cùng một backtest luôn cho ra cùng một giá trị p |
| Phí giao dịch | FEE của chính chiến lược | Backtest dùng gì thì truyền vào cái đó |
| Tắt đi | MCPT = False | Bỏ qua toàn bộ, không ghi bất kỳ trường MCPT nào |
Hai hành vi đáng nhớ: khi quét tham số thì không chạy MCPT (một lượt quét là vài chục tới vài trăm backtest, thêm nó vào sẽ chậm tới mức không dùng được), nên giá trị p bạn thấy luôn đến từ «lần backtest chạy sau khi đã chọn tham số»; và sau khi chiến lược lên chạy thật, mỗi lần kích hoạt live hay theo lịch đều mang nguyên bộ trường MCPT đó đi theo — cùng mã, cùng tham số, nên giá trị p vẫn còn hiệu lực, vì thế chiến lược đang chạy sẽ luôn thấy nó.
Tab Backtest của workspace không phán đạt hay không đạt, nó chỉ hiện con số kèm một dòng diễn giải. Khi p < 0.05 nó viết:
Khi không đạt thì nó viết:
Chuyện «đạt hay không đạt» thật sự xuất hiện ở ba tiêu chí chất lượng của Thư viện chiến lược. Tiêu chí 2 tên là «Có ý nghĩa thống kê», phần mô tả viết «Kiểm định hoán vị MCPT p < 0.05», còn phán quyết thực tế đòi hai điều kiện đồng thời thành lập:
| Điều kiện | Ngưỡng |
|---|---|
| Giá trị p | < 0.05 |
| Số lần hoán vị | ≥ 1000 |
| Chiến lược danh mục (Type C) | Hiện «Không áp dụng MCPT (chiến lược danh mục)», không tính là trượt |
Phải qua hoặc không áp dụng cả ba tiêu chí thì chiến lược mới được gắn huy hiệu «Đã kiểm định». Nói thẳng về phân công: máy của bạn chỉ lo tính ra giá trị p và số lần hoán vị, còn «thế có tính là đạt không» là phán quyết của phía lên sàn.
Lấy chiến lược mẫu hướng dẫn btc_sma_cross đi kèm workspace chạy một lần (BTCUSDT 1h, từ 2022-01-01, SMA_FAST = 45 / SMA_SLOW = 100, không sửa một chữ tham số nào, 41,287 cây nến). Toàn bộ các con số dưới đây đều đến từ lần chạy ngày 2026-09-17 đó.
| Backtest | Giá trị |
|---|---|
| Tổng lợi nhuận | +123.95% |
| Chuẩn tham chiếu (mua và giữ) | +64.36% |
| Sụt giảm tối đa | −44.93% |
| Sharpe Ratio | 0.6751 |
| Số giao dịch | 478 |
| Phí đã trả (so với vốn gốc) | 23.90% |
| MCPT | Giá trị |
|---|---|
| Giá trị p | 0.0160 |
| Số lần hoán vị | 2000 |
| Đường đỏ trên biểu đồ tần suất «Sharpe thực tế» | 0.8985 |
| Khoảng phân phối | −0.8565 ~ 1.4218 |
Dòng mà chính backtest in ra stdout là:
MCPT p-value: 0.0160 (n=2000, significant edge at 95%)
Cách đọc: p = 0.0160 nghĩa là trong 2000 lần xáo trộn ngẫu nhiên có 32 lần cho Sharpe không thua nó — nói cách khác, bộ thời điểm vào ra này trên đoạn lịch sử đó trông không giống được chọn bừa. Số lần hoán vị 2000 cũng cao hơn yêu cầu 1000 của cổng, nên hạng mục này là đạt.
Đây là phần quan trọng nhất của bài. Cũng chiến lược đó, cùng ngày, cùng một bản mã, còn được chạy thêm một lượt kiểm định ngoài mẫu walk-forward:
| Kiểm định | Câu hỏi nó đặt ra | Lần chạy 2026-09-17 | 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(n = 2000) | Đạ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? | Hiệu suất ngoài mẫu −0.334(Sharpe ngoài mẫu −0.45) | Thấp hơn ngưỡng rất nhiều |
Một cái đạt, một cái không, mà cả hai đều không tính sai — bởi chúng vốn không trả lời cùng một câu hỏi. MCPT kiểm định chuyện «bộ vào ra đã chốt này, đặt trên đoạn lịch sử đó, trông không giống đoán mò»; walk-forward kiểm định chuyện «lấy lịch sử ra chọn tham số, đổi sang đoạn kế tiếp chưa từng thấy thì còn đứng vững không». Vế trước đạt không hàm ý vế sau.
Đâ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, trọng tâm nằm ở khác biệt về ý nghĩa giữa hai kiểm định. Xem đầy đủ các con số walk-forward và cách đọc chúng tại Cách kiểm định ngoài mẫu hoạt động.
Nếu bạn nhờ agent vẽ biểu đồ tần suất MCPT rồi gửi vào khung chat, phần chú giải của biểu đồ đó sẽ in một dòng:
Actual OOS Sharpe = ⟨con số của bạn⟩
OOS là viết tắt của out-of-sample (ngoài mẫu). Dòng chữ đó là nhãn còn sót lại từ một ghi chú cũ, đừng hiểu theo nghĩa đen. MCPT chạy trên toàn bộ dữ liệu backtest từ đầu đến cuối, không có bất kỳ cửa sổ huấn luyện, cửa sổ kiểm định hay tỷ lệ phân chia nào — nó không thể nào là thứ ngoài mẫu được, và bảng đối chiếu ở trên chính là ví dụ.
Biểu đồ trên tab Backtest của workspace thì không gặp vấn đề này, đường đỏ ở đó ghi là «Sharpe thực tế». Ngoài ra, biểu đồ trong khung chat được tạo ra từ một lần chạy lại thủ công, mà lần chạy lại thủ công không nhất thiết dùng đúng tham số như lần tự động, nên các con số trên biểu đồ cũng không nhất thiết bằng dòng trên tab.
MCPT tự động thật sự chạy bao nhiêu lần thì không hoàn toàn do bạn quyết. Nó có một công thức ngân sách thực thi:
số lần chạy thật = min( MCPT_N, 20000, max( 200, 4e8 ÷ số nến ) )
Càng nhiều nến thì 4e8 ÷ số nến càng nhỏ. Lần chạy ở trên có 41,287 cây nến, còn cách trần rất xa, nên 2000 lần không bị cắt lần nào. Nhưng bảng đối chiếu ghi trong tài liệu chính thức là: 40,000 nến → 2000 lần; 200,000 nến (5 phút trong hai năm) → 2000 lần; 1,000,000 nến (1 phút trong hai năm) → 400 lần.
Vấn đề là cổng lên sàn chặn ở số lần hoán vị ≥ 1000. Suy ra từ công thức, khi số nến vượt khoảng 400,000 thì số lần chạy thật sẽ xuống dưới 1000 — dù p = 0.001 thì tiêu chí vẫn phán là không qua. Mà màn hình hoàn toàn không gợi ý gì: thông báo bị cắt chỉ được ghi vào log của máy chủ, dòng diễn giải trên workspace vẫn thản nhiên điền con số đã bị cắt, và không hề có kiểu cảnh báo nào.
Nhìn lại hai bảng ở trên: cùng một backtest mà thẻ Sharpe Ratio ghi 0.6751, còn «Sharpe thực tế» của biểu đồ tần suất ghi 0.8985, lệch 0.22, mắt thường cũng thấy. Đây không phải lỗi, mà là hai cách tính khác nhau:
| Mục | Sharpe bên trong MCPT(0.8985) | Sharpe Ratio trên tab Backtest(0.6751) |
|---|---|---|
| Lợi nhuận tính thế nào | Lợi nhuận đơn giản, không tách đoạn mở cửa với đoạn đóng cửa | Đoạn qua đêm và đoạn trong phiên định giá riêng |
| Co giãn vị thế | Luôn được áp:30% biến động mục tiêu、2 lần trần đòn bẩy | Chỉ có khi chính chiến lược tự viết vào |
Mấu chốt nằm ở dòng thứ hai: MCPT tự động không truyền thiết lập biến động mục tiêu của chính chiến lược vào, nó luôn dùng giá trị mặc định của hàm. btc_sma_cross không hề nhắm mục tiêu biến động, nhưng Sharpe MCPT của nó vẫn là con số «sau khi đã áp 30% biến động mục tiêu và trần 2 lần» (biến động mục tiêu làm gì, xem Nhắm mục tiêu biến động hoạt động ra sao). Hai con số khác nhau là bình thường, hiện giao diện chưa giải thích chuyện này.
Khi thất bại thì nó im lặng: không có thông báo lỗi nào, backtest vẫn thành công như thường, chỉ là giao diện thiếu mất dòng đó. Có ít nhất bốn nguyên nhân, mà màn hình thì không phân biệt:
| Nguyên nhân | Chuyện gì đã xảy ra |
|---|---|
| Chiến lược có viết MCPT = False | Bỏ qua thẳng |
| Lần backtest này có 0 giao dịch | Không có vị thế nào để kiểm định nên bỏ qua |
| lib trên máy chủ là bản cũ | Nạp thất bại nên bỏ qua |
| Dữ liệu quá ngắn, Sharpe ra NaN, hoặc bất kỳ ngoại lệ nào | Bỏ qua, thống kê backtest vẫn ghi như thường |
Lý do thà không ghi còn hơn ghi sai rất thực tế: bất kỳ NaN hay inf nào cũng làm việc tải chiến lược của cả máy bị trả về, nên hễ con số chưa sạch là cả nhóm trường này không được ghi.
Backtest của Type C (chiến lược danh mục, N mã kèm một bộ tỷ trọng) không chạy MCPT. Lý do là cấu trúc của kiểm định này là «một chuỗi giá đối một chuỗi vị thế», mà chiến lược danh mục không có cấu trúc đó. Điều đáng nói thẳng là: không có kiểm định thay thế.
| Việc bạn muốn làm | Thực tế ra sao |
|---|---|
| Nén cả danh mục thành một chuỗi lợi nhuận rồi rút mẫu lại | Đó là bootstrap trên lợi nhuận đã thực hiện, nó trả lời một câu hỏi khác, mà lại không sinh ra được giá trị p — giá trị p mới chính là toàn bộ lý do MCPT tồn tại. Con đường này bị cấm bằng văn bản, và agent cũng không được tự tay nặn ra thứ gì để thế chỗ |
| Điều bạn mong thẻ tiêu chí hiển thị | «Không áp dụng MCPT (chiến lược danh mục)», chứ không phải «Chưa đạt» — nó không tính là trượt và không ảnh hưởng tới huy hiệu «Đã kiểm định» |
Số lần hoán vị là bao nhiêu? Nếu con số trong dòng diễn giải thấp hơn 1000 thì giá trị p này không qua nổi cổng lên sàn, nhỏ tới đâu cũng vậy. Xem số lần trước, xem giá trị p sau.
Đây là giá trị p của lần backtest nào? Quá trình quét tham số không chạy MCPT. Giá trị p trong tay bạn chỉ thuộc về «lần backtest chạy sau khi đã chọn tham số»; sửa mã ở giữa chừng thì phải chạy lại mới tính.
Đường đỏ và thẻ không khớp nhau? Bình thường. Lần chạy ở trên là 0.8985 so với 0.6751, chỉ là khác cách tính thôi, không cần đi debug.
Bạn có đang đọc «có ý nghĩa» thành «sẽ có lãi» không? Cùng một chiến lược có thể đạt ở p = 0.016 rồi thua đậm với hiệu suất ngoài mẫu −0.334. Giá trị p không phát biểu gì về tương lai cả.
Dòng đó biến mất hẳn? Trước hết xác định nó là cái nào trong bốn nguyên nhân (chiến lược tắt đi / 0 giao dịch / lib bản cũ / không đủ dữ liệu), đừng coi là «kiểm định không qua».
Hiểu giá trị p rồi thì câu hỏi kế tiếp chính là nửa bên phải của bảng đối chiếu ở trên: đổi sang một đoạn dữ liệu chưa từng thấy thì còn đứng vững không. Con đường đó là kiểm định ngoài mẫu, và workspace có tab riêng để làm. Những chiến lược chính thức mang huy hiệu «Đã kiểm định» trong Thư viện chiến lược, thứ mà chúng qua ở tiêu chí 2 chính là kiểm định nói trong bài này — mỗi chiến lược đều kèm backtest thật, con số xem được ngay: Thư viện chiến lược.