MODEL SELECTION TRONG QUANT: CHỌN MODEL NÀO ĐỂ KHÔNG TỰ LỪA MÌNH?
MODEL SELECTION TRONG QUANT
Trong Machine Learning, Model Selection thường được hiểu khá đơn giản: thử nhiều model, so sánh kết quả rồi chọn model tốt nhất. Chẳng hạn cùng một bộ dữ liệu, ta có thể thử Logistic Regression, Random Forest, Gradient Boosting hoặc Neural Network và chọn phương án có kết quả validation cao nhất. Nhưng trong tài chính, cách làm này dễ gây hiểu nhầm hơn rất nhiều. Một model thắng trên dữ liệu quá khứ chưa chắc là model có khả năng kiếm tiền tốt nhất trong tương lai, bởi dữ liệu tài chính thay đổi theo thời gian, các giai đoạn thị trường khác nhau rất rõ và một quan hệ từng đúng trong quá khứ có thể biến mất hoàn toàn khi market regime thay đổi.
Vì vậy, Model Selection trong Quant không nên được hiểu là cuộc thi xem model nào có điểm cao nhất. Điều quan trọng hơn là tìm ra model nào vẫn hoạt động tương đối ổn khi thay đổi thời gian kiểm tra, thay đổi điều kiện thị trường và đưa vào những dữ liệu mà model chưa từng được nhìn thấy. Một model có performance rất cao trong một giai đoạn nhưng thất bại hoàn toàn ở những giai đoạn còn lại thường đáng lo hơn một model có kết quả thấp hơn một chút nhưng ổn định qua nhiều chu kỳ.
PHẦN 1. MODEL ĐẸP NHẤT TRÊN BACKTEST CHƯA CHẮC LÀ MODEL TỐT NHẤT
Giả sử mình muốn xây một model để xếp hạng cổ phiếu VN100. Mỗi tuần, model sẽ dự báo những cổ phiếu nào có khả năng outperform trong vài tuần tiếp theo. Input có thể bao gồm Momentum ngắn hạn và dài hạn, volatility, volume, khoảng cách với đường trung bình, valuation và một số biến cơ bản của doanh nghiệp. Với cùng một bộ feature như vậy, mình có thể thử một linear model đơn giản, một Random Forest và một Gradient Boosting model phức tạp hơn.
Nếu chỉ nhìn vào backtest, model phức tạp thường có lợi thế. Nó có thể học được nhiều mối quan hệ phi tuyến và interaction giữa các biến mà model đơn giản khó nhận ra. Ví dụ Momentum có thể chỉ hiệu quả khi volatility thấp, hoặc valuation chỉ có tác dụng khi thanh khoản đủ cao. Một model tree-based có thể tự tìm những quan hệ như vậy và tạo ra kết quả rất đẹp trên dữ liệu lịch sử.
Nhưng điều này chỉ có ý nghĩa nếu cách kiểm tra model được thiết kế đúng. Một lỗi rất phổ biến là lấy toàn bộ dữ liệu từ năm 2015 đến 2026 rồi chia ngẫu nhiên 80% làm train và 20% làm test. Đây là cách chia dữ liệu rất bình thường trong nhiều bài toán Machine Learning, nhưng với tài chính, nó có thể làm kết quả đẹp hơn thực tế rất nhiều. Dữ liệu tháng 3/2021 có thể nằm trong training set trong khi tháng 4/2021 lại nằm trong test set. Hai giai đoạn này thuộc gần như cùng một môi trường thị trường, cùng volatility, cùng nhóm cổ phiếu dẫn dắt và có cấu trúc dữ liệu rất giống nhau.
Khi đó, model không thực sự đang dự báo một tương lai hoàn toàn mới. Nó đang được kiểm tra trên dữ liệu khá giống những gì nó vừa học. Điều này đặc biệt nguy hiểm nếu target là lợi nhuận trong 5, 10 hoặc 20 phiên tiếp theo, vì các quan sát nằm gần nhau có thể còn sử dụng những khoảng thời gian tương lai bị chồng lấn. Kết quả validation khi đó có thể cao nhưng không phản ánh đúng khó khăn mà model sẽ gặp khi chạy live.
Với dữ liệu tài chính, cách tự nhiên hơn là luôn để model học từ quá khứ rồi kiểm tra trên tương lai. Ví dụ model có thể học từ 2015–2018 và test trên 2019. Sau đó mở rộng training tới 2019 rồi test trên 2020. Tiếp tục như vậy qua nhiều năm. Khi làm như thế, model buộc phải đối diện với những điều kiện thị trường mới thay vì được kiểm tra trên dữ liệu trộn lẫn với quá khứ.
Một nguồn sai lệch khác còn khó nhận ra hơn nằm ở bước xử lý dữ liệu. Giả sử mình chuẩn hóa toàn bộ dataset trước, sau đó mới chia train và test. Hoặc mình chạy PCA trên cả dữ liệu 2015–2026 rồi mới chia dữ liệu. Hoặc mình dùng toàn bộ lịch sử để chọn ra 30 feature tốt nhất trước khi Cross Validation. Trong những trường hợp đó, model có thể chưa nhìn trực tiếp vào target của tương lai, nhưng quá trình preprocessing đã sử dụng thông tin của tương lai để quyết định cách xử lý dữ liệu.
Đây chính là data leakage. Model tưởng như chỉ học quá khứ nhưng một phần cấu trúc của tương lai đã lọt vào pipeline từ trước. Vì vậy, trong một quy trình Quant nghiêm túc, scaling, PCA, feature selection và model fitting đều phải được thực hiện riêng trong từng training period. Dữ liệu validation chỉ được xử lý bằng những gì đã học từ training data. Nếu làm sai bước này, một model rất bình thường cũng có thể trở thành một model “xuất sắc” trên backtest.
Điều này dẫn tới một nguyên tắc quan trọng: một model không thể được đánh giá tách rời khỏi quy trình đã tạo ra nó. Một XGBoost rất mạnh được xây trên pipeline có leakage có thể kém đáng tin hơn một Linear Regression đơn giản nhưng được kiểm tra đúng cách. Trong Quant, việc xây đúng bài kiểm tra nhiều khi quan trọng hơn việc chọn thuật toán mạnh nhất.
PHẦN 2. MODEL SELECTION THỰC TẾ TRÊN VN100 NÊN LÀM NHƯ THẾ NÀO?
Nếu mình có dữ liệu VN100 từ khoảng năm 2014 đến nay, việc đầu tiên mình làm không phải là thử hàng trăm model. Mình sẽ khóa một phần dữ liệu cuối cùng lại và coi như nó chưa tồn tại. Chẳng hạn giai đoạn 2025–2026 có thể được giữ làm final test. Trong quá trình research ban đầu, mình không nhìn vào performance của giai đoạn này, không chọn feature dựa trên nó và cũng không sửa model chỉ vì thấy kết quả ở đó không đẹp.
Phần dữ liệu còn lại, ví dụ 2014–2024, mới được sử dụng để phát triển model. Nhưng ngay cả trong vùng này, mình cũng không muốn chỉ có một lần train và một lần validation. Mình muốn nhìn thấy model qua nhiều thời kỳ. Model có thể được học trên 2014–2017 rồi kiểm tra trên 2018, sau đó học tới 2018 và test trên 2019, rồi tiếp tục dịch dần về phía trước.
Cách làm này tạo ra nhiều bài kiểm tra nhỏ trên những giai đoạn khác nhau. Đây là điều rất quan trọng với thị trường Việt Nam vì mỗi giai đoạn có đặc điểm rất khác. Có giai đoạn thị trường tăng mạnh, có giai đoạn giảm sâu, có lúc ngân hàng dẫn dắt, có lúc chứng khoán và bất động sản bùng nổ, cũng có thời điểm thanh khoản giảm mạnh và gần như mọi strategy đều khó kiếm tiền.
Nếu một model chỉ hoạt động tốt trong đúng một giai đoạn bull market nhưng gần như không có signal ở những thời điểm khác, kết quả trung bình đẹp có thể đánh lừa mình. Ngược lại, một model không bao giờ tạo ra performance quá nổi bật nhưng phần lớn các giai đoạn đều duy trì kết quả dương lại có thể đáng tin hơn. Với tiền thật, mình thường quan tâm đến sự ổn định như vậy hơn là một con số cực cao đến từ một năm đặc biệt.
Chẳng hạn Model A có kết quả rất tốt trong năm 2021 nhưng kém trong 2018, 2020 và 2022. Model B không có năm nào quá nổi bật nhưng performance tương đối đồng đều qua hầu hết giai đoạn. Nếu chỉ nhìn average score, Model A có thể thắng. Nhưng nếu mục tiêu là triển khai trong vài năm tới, Model B có thể là lựa chọn hợp lý hơn vì nó ít phụ thuộc vào một market regime duy nhất.
Sau khi xác định được cách validation hợp lý, lúc đó mới nên tối ưu hyperparameter. Với Random Forest có thể điều chỉnh depth của tree, số tree hoặc số lượng feature được sử dụng. Với boosting model có thể thử learning rate, độ sâu của tree hay số vòng boosting. Nhưng tất cả quá trình này chỉ được thực hiện trong vùng research. Final test không được tham gia vào việc lựa chọn.
Một lỗi rất dễ mắc là gọi một giai đoạn là “out-of-sample”, sau đó nhìn kết quả thấy chưa tốt rồi tiếp tục chỉnh model. Ví dụ model đầu tiên có Sharpe 0,6 trên giai đoạn test. Mình thêm Momentum 120 ngày và Sharpe lên 0,8. Sau đó thêm volatility filter và Sharpe lên 1,0. Tiếp tục đổi tần suất rebalance và Sharpe lên 1,2. Sau hai mươi lần sửa, strategy trông rất đẹp.
Nhưng lúc này giai đoạn được gọi là out-of-sample thực tế không còn độc lập nữa. Mỗi lần mình nhìn vào kết quả rồi điều chỉnh strategy, mình đang gián tiếp sử dụng thông tin của giai đoạn đó để train model. Không cần model trực tiếp đọc dữ liệu test; chính con người đang tạo ra leakage thông qua quá trình research.
Đây là lý do final holdout cần được bảo vệ rất nghiêm. Nó chỉ nên được mở sau khi toàn bộ feature, model, hyperparameter và cách xây portfolio đã được quyết định. Nếu kết quả cuối cùng không tốt, tốt nhất là chấp nhận rằng hypothesis chưa đủ mạnh thay vì tiếp tục chỉnh cho đến khi final test cũng trở nên đẹp.
PHẦN 3. MODEL TỐT NHẤT KHÔNG PHẢI LÚC NÀO CŨNG LÀ MODEL CÓ SCORE CAO NHẤT
Sau khi đã kiểm soát được cách chia dữ liệu, vẫn còn một câu hỏi khó: nếu có nhiều model đều hoạt động khá tốt thì nên chọn cái nào? Trong Quant, mình không nghĩ chỉ cần sắp xếp theo Sharpe, Rank IC hay một metric duy nhất rồi chọn dòng đầu tiên là đủ.
Giả sử Model A có Rank IC trung bình 0,055 còn Model B chỉ đạt 0,045. Nhìn qua, A rõ ràng tốt hơn. Nhưng khi xem chi tiết, A có hai năm performance âm khá mạnh, turnover cao và phần lớn alpha đến từ một số ít cổ phiếu. Model B có IC thấp hơn nhưng ổn định hơn qua các năm, turnover thấp hơn và signal phân bổ rộng hơn trong universe.
Khi chưa tính phí, A có thể thắng rõ. Nhưng sau transaction cost, chênh lệch có thể giảm mạnh. Nếu tiếp tục thêm slippage, Model B thậm chí có thể tốt hơn. Khi đó, việc chọn model chỉ dựa vào predictive metric đã bỏ qua một phần rất quan trọng của bài toán đầu tư.
Một model Quant tốt cần tạo ra signal có ý nghĩa kinh tế. Nếu model dự báo rất chính xác nhưng mỗi ngày phải thay gần hết danh mục, chi phí giao dịch có thể ăn hết lợi nhuận. Nếu model luôn đẩy portfolio vào những cổ phiếu thanh khoản thấp, backtest có thể đẹp nhưng capacity rất nhỏ. Nếu performance chủ yếu đến từ một nhóm ngành, model có thể đang học sector exposure chứ không phải alpha riêng.
Vì vậy, Model Selection nên xem cả độ ổn định của signal. Nếu một model chỉ hoạt động khi lookback đúng 63 ngày nhưng chuyển thành 60 hoặc 65 ngày là performance biến mất, mình sẽ khá nghi ngờ. Một relationship thực sự có ý nghĩa thường không phụ thuộc quá cực đoan vào một con số duy nhất. Performance có thể giảm nhưng không nên sụp hoàn toàn chỉ vì thay đổi rất nhỏ.
Một test rất hữu ích là cố tình làm điều kiện khó hơn. Tăng transaction cost một chút, thay ngày rebalance, thay cửa sổ tính feature, bỏ một số cổ phiếu có đóng góp lợi nhuận lớn nhất hoặc thay đổi universe. Nếu model vẫn cho kết quả tương đối chấp nhận được, đó là tín hiệu tốt. Nếu chỉ cần một thay đổi nhỏ là performance biến mất, model có thể đã được tối ưu quá sát với dữ liệu lịch sử.
Đây là lý do mình thích phân biệt giữa “winner” và “survivor”. Winner là model có điểm cao nhất trong một cuộc thi trên historical data. Survivor là model không nhất thiết đứng đầu ở mọi lần test nhưng vẫn nằm trong nhóm tốt khi điều kiện thay đổi. Trong trading, survivor thường có giá trị hơn.
Model đơn giản cũng không nên bị xem nhẹ. Nếu Linear Regression và XGBoost cho performance gần giống nhau, mình sẽ cần lý do rất rõ để chọn XGBoost. Model đơn giản dễ hiểu hơn, dễ theo dõi hơn và thường ít có khả năng tận dụng những pattern rất nhỏ trong dữ liệu để overfit. Model phức tạp chỉ thực sự đáng dùng nếu phần cải thiện của nó đủ lớn, đủ ổn định và còn tồn tại sau chi phí.
Một nguyên tắc khác là luôn so model phức tạp với baseline đơn giản. Nếu xây model Machine Learning để chọn cổ phiếu VN100, có thể so nó với Momentum đơn giản, Equal Weight hoặc một linear factor model. Nếu một Neural Network phức tạp không cải thiện đáng kể so với Momentum sau transaction cost, việc thêm hàng loạt layer và feature chưa chắc tạo ra giá trị thực tế.
Cuối cùng, model đã chọn chỉ được chạy một lần trên final holdout. Đây mới là thời điểm quan trọng. Nếu performance giảm nhẹ so với validation thì khá bình thường vì dữ liệu mới luôn khó hơn. Nếu performance giảm mạnh hoặc biến mất hoàn toàn, có khả năng quá trình selection trước đó đã overfit nhiều hơn mình tưởng.
Ngay cả khi final test tốt, hành trình cũng chưa kết thúc. Model vẫn cần paper trading, theo dõi live và kiểm tra liên tục xem cấu trúc thị trường có thay đổi hay không. Trong tài chính, một model không được triển khai vào một môi trường cố định. Nó được triển khai vào một hệ thống mà chính những mối quan hệ model học được có thể thay đổi theo thời gian.
Vì vậy, cách hiểu mình thấy thực tế nhất về Model Selection trong Quant không phải là tìm model thông minh nhất, cũng không phải tìm model có Sharpe cao nhất.
Mục tiêu thực sự là loại dần những model chỉ đẹp vì chúng ta đã nhìn quá kỹ vào quá khứ, để giữ lại những model có khả năng tiếp tục hoạt động khi bước sang dữ liệu mà chúng chưa từng thấy.
Và rất nhiều lần, model đáng dùng nhất không phải model thắng lớn nhất trong backtest.
Nó là model khó chết nhất khi mình cố tình làm mọi thứ khó hơn.
