OptiNod Academy
Backtest và giao dịch thực tế — năm điểm khiến đường cong lợi nhuận tách xa
Lý do lợi nhuận backtest không thể xem là lợi nhuận kỳ vọng trong giao dịch thực tế bắt đầu từ giả định lệnh được khớp tại giá đóng cửa của nến. Bài viết phân tích độ trễ giữa tín hiệu và khớp lệnh qua năm điểm cần kiểm tra.
> Điểm khởi đầu khiến đường cong backtest và đường cong giao dịch thực tế tách xa nhau là giả định lệnh được khớp tại giá đóng cửa của nến. Bài viết này xem xét năm điểm nơi độ trễ một nhịp giữa tín hiệu và khớp lệnh biến thành chi phí.
Backtest là quá trình chạy nguyên tắc chiến lược trên dữ liệu quá khứ để tạo ra một đường cong lợi nhuận giả định. Nếu quy tắc rõ ràng và dữ liệu sạch, bất kỳ ai cũng có thể tái tạo cùng một đường cong. Chính khả năng tái tạo đó khiến backtest trở thành công cụ đầu tiên để kiểm chứng chiến lược.
Vấn đề nằm ở chỗ phần lớn mọi người đọc đường cong này như lợi nhuận kỳ vọng trong giao dịch thực tế. Nếu backtest cho ra lợi suất năm 80%, họ kỳ vọng giao dịch thật cũng đạt mức tương tự; khi khoảng cách xuất hiện, họ kết luận chiến lược sai. Nhưng trong đa số trường hợp, quy tắc chiến lược không đổi, chỉ có đường cong bị tách ra. Nguyên nhân nằm ở các giả định mà quy tắc dựa vào.
Giả định lớn nhất là lệnh được khớp tại giá đóng cửa của nến. Công cụ backtest ghi nhận giá đóng cửa của cây nến phát tín hiệu làm giá vào lệnh. Nhưng trong giao dịch thực tế, tín hiệu chỉ được xác nhận sau khi nến đóng, còn lệnh được khớp ở cây nến tiếp theo. Trong khoảng đó, giá đã di chuyển. Độ trễ một nhịp này kết hợp với trượt giá, phí, độ phân giải dữ liệu và thiên lệch sống sót, khiến hai đường cong ngày càng cách xa nhau theo trục thời gian. Bài viết này sẽ đi lần lượt qua năm điểm đó.

Tín hiệu xuất hiện khi nến đóng, nhưng lệnh được khớp ở nến tiếp theo
Giả định đầu tiên của backtest là khi tín hiệu xuất hiện, lệnh được khớp ngay tại giá đóng cửa của chính cây nến đó. Hầu hết các chiến lược dùng giá đóng cửa làm điều kiện kích hoạt, như phá vỡ theo giá đóng cửa hoặc giao cắt đường trung bình theo giá đóng cửa, đều dựa trên giả định này. Nhưng giá đóng cửa là giá trị chỉ được xác nhận tại thời điểm nến kết thúc. Chỉ sau thời điểm đó tín hiệu mới xuất hiện, và lệnh thực tế sẽ được khớp ở cây nến tiếp theo. Giá đóng cửa mà backtest ghi làm giá vào lệnh là mức giá không thể khớp trong giao dịch thực tế.
Ở những giai đoạn yên ả, độ trễ này nhỏ. Nếu giá gần như không di chuyển giữa hai cây nến, giá đóng cửa và giá mở cửa của nến kế tiếp sẽ gần nhau. Nơi độ trễ biến thành chi phí là các cây nến có biến động lớn.
Nến ngày BTC ngày 5 tháng 8 năm 2024 cho thấy khác biệt này rất rõ. Giá đóng cửa ngày 4 tháng 8 là 58.161 USD. Nếu tín hiệu vào lệnh theo giá đóng cửa xuất hiện tại đây, backtest sẽ ghi giá vào lệnh là 58.161 USD. Nhưng trong giao dịch thực tế, tín hiệu đó chỉ được xác nhận sau khi nến ngày 4 tháng 8 đóng, và lệnh sẽ được khớp trong nến ngày 5 tháng 8. Nến ngày 5 tháng 8 mở ở 58.161 USD rồi giảm xuống 49.000 USD trong cùng ngày. Từ giá mở cửa đến đáy là mức giảm khoảng 15,7%. Backtest ghi nhận đây là giao dịch vào ở 58.161 USD và kết thúc tại giá đóng cửa 54.019 USD, nhưng lệnh mua thực tế, ngay sau khi khớp ở giá mở cửa của nến kế tiếp, đã đi thẳng vào vùng lỗ sâu.
Lỗ hổng của giả định khớp tại giá đóng cửa đặc biệt lớn trong các chiến lược theo xu hướng. Chiến lược theo xu hướng thường phát tín hiệu tại giá đóng cửa của một cây nến đã di chuyển mạnh, nên xác suất giá đã đi rất xa trong khoảng giữa tín hiệu và khớp lệnh là cao. Bản thân việc giá đã di chuyển nhiều trong nến tín hiệu cũng làm tăng khả năng nến tiếp theo tiếp tục biến động. Đây chính là nơi backtest giả định khớp tại giá đóng cửa dễ bị thổi phồng lạc quan nhất đối với các điểm vào theo xu hướng.

Trượt giá tăng phi tuyến trong các giai đoạn biến động
Trượt giá (Slippage) là chênh lệch giữa giá đặt lệnh và giá khớp thực tế. Lệnh thị trường được khớp bằng cách ăn qua nhiều tầng trong sổ lệnh, nên giá khớp bình quân bất lợi hơn giá chào ngay trước khi đặt lệnh. Trong khi backtest giả định toàn bộ khối lượng được khớp tại một mức giá duy nhất, lệnh thực tế được khớp dần qua nhiều mức giá trong sổ lệnh.
Với BTC spot có thanh khoản dồi dào, trượt giá của một lệnh thị trường nhỏ thường chỉ vài bp (basis point, 1bp là 0,01%). Ở mức này, khác biệt giữa backtest và giao dịch thực tế gần như không đáng kể. Trượt giá bắt đầu tăng phi tuyến ở các giai đoạn biến động bùng nổ và khi xuất hiện gap.
Nhìn lại BTC ngày 5 tháng 8 theo khung giờ, khác biệt này hiện rõ hơn. Nến 06:00 ngày 5 tháng 8 mở ở 52.718 USD, trong vòng một giờ rơi xuống 49.000 USD rồi đóng ở 51.588 USD. Biên độ cao thấp trong một giờ là khoảng 4.000 USD. Nếu đặt lệnh stop-loss bằng lệnh thị trường trong giai đoạn như vậy, sổ lệnh có thể bị rút cạn rất nhanh và lệnh được khớp thấp hơn nhiều so với mức giá dự định. Trong khi backtest ghi nhận stop-loss được khớp tại đúng một điểm 52.000 USD, giá khớp thực tế có thể bị đẩy xuống quanh 50.000 USD. Biến động càng lớn thì sổ lệnh càng mỏng; sổ lệnh càng mỏng thì trượt giá càng tăng, khiến chi phí lan rộng.
Backtest đặt trượt giá bằng 0 đã xóa bỏ hoàn toàn tính phi tuyến này. Nếu phần lớn giao dịch diễn ra trong giai đoạn yên ả, giả định trượt giá 0 có thể không tạo sai số lớn. Nhưng nếu lợi nhuận của chiến lược đến từ vài giao dịch lớn trong giai đoạn biến động mạnh, backtest với trượt giá 0 sẽ lệch xa giao dịch thực tế nhất. Trượt giá nên được xem là một chi phí thay đổi theo biến động. Nếu chỉ dùng một giá trị trung bình, bạn sẽ bỏ sót toàn bộ khoản chi phí lớn thực sự phải trả trong các giai đoạn biến động.
Phí giao dịch và funding tích lũy theo tần suất giao dịch
Nếu nhìn từng giao dịch riêng lẻ, phí có vẻ nhỏ. Phí taker trên sàn thường nằm trong khoảng 0,04% đến 0,1% giá trị giao dịch. Vào lệnh một lần và thoát lệnh một lần tương đương phí hai chiều khoảng 0,08% đến 0,2%. Với một giao dịch đơn lẻ, con số này trông có vẻ có thể bỏ qua. Vấn đề nằm ở tích lũy.
Giả sử một chiến lược lướt sóng giao dịch năm lần mỗi ngày. Nếu phí hai chiều là 0,1%, năm giao dịch mỗi ngày lấy đi 0,5%; trong 20 ngày giao dịch mỗi tháng, khoảng 10% bị mất vào phí. Trong một năm, con số này vượt 100%. Nếu backtest đặt phí bằng 0, toàn bộ 100% đó được ghi thành lợi nhuận, nhưng trong giao dịch thực tế nó bị trừ trực tiếp khỏi tài khoản. Chiến lược càng có tần suất giao dịch cao, đường cong backtest với phí 0 càng tách xa đường cong giao dịch thực tế nhanh hơn.
Với vị thế futures, còn có funding. Hợp đồng vĩnh cửu trao đổi funding mỗi 8 giờ; trong thị trường long áp đảo, vị thế long trả funding cho vị thế short. Đầu tháng 8 năm 2024, funding của BTC perpetual futures vào khoảng 0,01% mỗi 8 giờ. Ba lần mỗi ngày là khoảng 0,03%, một tháng là khoảng 0,9%. Nếu chiến lược theo xu hướng nắm giữ vị thế lâu không đưa funding vào backtest, thời gian nắm giữ càng dài thì đường cong giao dịch thực tế càng bị kéo xuống.
Phí và funding là chi phí khó thấy trong một giao dịch, nhưng sẽ hiện rõ khi giao dịch tích lũy. Dù lợi suất năm trong backtest cao, nếu tần suất giao dịch cao thì lợi nhuận ròng thực tế có thể giảm mạnh. Giảm tần suất giao dịch sẽ làm số tín hiệu ít đi và độ tin cậy thống kê thấp hơn, nên cần xem xét đồng thời tần suất và kỳ vọng lợi nhuận trên mỗi giao dịch. Chỉ khi kỳ vọng lợi nhuận còn dương sau khi trừ phí, chiến lược mới có ý nghĩa trong giao dịch thực tế.

Backtest bằng giá đóng cửa của nến không thấy diễn biến bên trong nến
Backtest chạy trên dữ liệu OHLC ngày chỉ biết mỗi cây nến qua bốn điểm: mở cửa, cao nhất, thấp nhất và đóng cửa. Dữ liệu không cho biết giá đã di chuyển theo thứ tự nào bên trong cây nến. Giới hạn độ phân giải dữ liệu này tạo ra sai số quyết định với các chiến lược đặt đồng thời stop-loss và take-profit.
Giả sử giá cao nhất của một cây nến chạm mức take-profit, còn giá thấp nhất chạm mức stop-loss. Nếu cả hai mức giá đều được chạm trong cùng một cây nến, kết quả giao dịch thực tế phụ thuộc vào mức nào được chạm trước. Nếu take-profit chạm trước, vị thế đóng có lãi; nếu stop-loss chạm trước, vị thế đóng lỗ. Nhưng dữ liệu ngày không chứa thứ tự chạm của giá cao nhất và giá thấp nhất. Trong trường hợp này, công cụ backtest phải tuân theo một giả định cố định; nhiều công cụ dùng mặc định bảo thủ là giả định stop-loss xảy ra trước. Dù giả định theo hướng nào, nó vẫn có thể khác với thứ tự thực tế.
Nến ngày BTC ngày 5 tháng 8 cho thấy đúng vấn đề này. Nến mở ở 58.161 USD, đạt đỉnh 58.306 USD, đáy 49.000 USD và đóng ở 54.019 USD. Khi chia nhỏ theo khung giờ, giá chạm đỉnh 58.306 USD ngay sau khi phiên bắt đầu, rồi sau đó liên tục giảm đến 06:00 và rơi xuống 49.000 USD. Nếu có một vị thế long vào ở giá mở cửa 58.161 USD, đặt take-profit tại 58.300 USD và stop-loss tại 50.000 USD, cả take-profit lẫn stop-loss đều được chạm trong cùng cây nến này. Backtest giả định stop-loss xảy ra trước sẽ xử lý giao dịch này là lỗ. Nhưng diễn biến thực tế cho thấy giá chạm 58.306 USD ngay sau khi mở cửa, nên take-profit 58.300 USD được chạm trước và vị thế đóng có lãi. Cùng một cây nến, cùng hai mức giá, nhưng backtest ghi lỗ còn giao dịch thực tế có lãi. Vì không biết thứ tự chạm, backtest đã ghi ngược dấu của giao dịch.
Để giảm sai số này, độ phân giải dữ liệu backtest cần nhỏ hơn khung nến vào lệnh một bậc. Ngay cả với chiến lược khung ngày, việc xử lý stop-loss và take-profit bằng dữ liệu khung giờ hoặc khung phút để kiểm tra diễn biến bên trong nến sẽ gần thực tế hơn. Backtest không biết diễn biến bên trong nến sẽ sai nhiều nhất ở các giao dịch mà stop-loss và take-profit cùng xuất hiện trong một cây nến.

Thiên lệch sống sót và look-ahead đẩy đường cong lên cao
Nếu bốn điểm trước là các chi phí kéo đường cong giao dịch thực tế xuống, thì thiên lệch sống sót (Survivorship Bias) và look-ahead bias là những méo mó thổi phồng đường cong backtest lên. Các chi phí trước chỉ lộ ra trong giao dịch thực tế, còn hai dạng méo mó này đã nằm sẵn trong giai đoạn backtest nên khó phát hiện hơn.
Thiên lệch sống sót xuất hiện khi bạn chỉ kiểm chứng trên những tài sản còn tồn tại đến hiện tại. Nếu nói là kiểm chứng chiến lược theo xu hướng trên altcoin nhưng chỉ dùng dữ liệu của 100 đồng coin hàng đầu đang được giao dịch ở thời điểm hiện tại, thì 100 đồng đó vốn đã là các tài sản sống sót. Hàng trăm đồng coin bị hủy niêm yết hoặc mất giá trị trong cùng giai đoạn đã bị loại khỏi dữ liệu. Backtest chỉ học được đà tăng của các tài sản sống sót, nhưng không học được thua lỗ từ các tài sản đã biến mất. Nếu chỉ chọn các altcoin từng tăng tốt trong quá khứ để kiểm chứng, gần như chiến lược nào cũng vẽ ra đường cong đẹp. Trong giao dịch thực tế, bạn không thể biết trước đồng coin nào sẽ sống sót, nên backtest có thiên lệch sống sót ngay từ đầu đã nhìn vào một tập mẫu khác thực tế.
Look-ahead xảy ra khi dữ liệu tương lai rò rỉ vào quyết định tại một thời điểm trong quá khứ. Ví dụ phổ biến là dùng giá đóng cửa trước khi nến đóng. Nếu tính tín hiệu bằng giá đóng cửa chưa được xác nhận của một cây nến đang chạy, backtest đang dùng trước một giá trị mà giao dịch thực tế không thể biết. Việc đưa nến tương lai vào tính chỉ báo, hoặc chuẩn hóa dữ liệu bằng thống kê của toàn bộ giai đoạn, cũng là cùng một kiểu rò rỉ. Backtest có look-ahead ra quyết định sau khi đã nhìn thấy một phần tương lai, nên thường tạo ra đường cong mượt một cách phi thực tế.
Hai dạng méo mó này nguy hiểm hơn vì, khác với việc bỏ sót chi phí, chúng làm đường cong trông tốt hơn. Backtest bỏ qua trượt giá hoặc phí sẽ nhanh chóng dẫn đến thất vọng trong giao dịch thực tế, nhưng backtest có thiên lệch sống sót và look-ahead lại cho kết quả đẹp ngay từ giai đoạn kiểm chứng, khiến nhà giao dịch tự tin hơn. Chỉ sau khi đưa vốn thật vào, đường cong mới bắt đầu tách rời. Trước khi tin vào backtest, cần nghi ngờ trước hết về tập dữ liệu và cách xử lý thời điểm.

Checklist kiểm tra thiết lập backtest thực tế hơn
Nếu đưa năm điểm trên vào thiết lập backtest, khoảng cách với đường cong giao dịch thực tế có thể được thu hẹp. Hãy kiểm tra các mục sau trước khi chạy backtest.
- [ ] Thời điểm khớp lệnh: Xử lý vào lệnh và thoát lệnh tại giá mở cửa của nến tiếp theo. Không dùng giá đóng cửa của nến tín hiệu làm giá vào lệnh. Với chiến lược kích hoạt theo giá đóng cửa, đặt mặc định là khớp tại giá mở cửa nến kế tiếp.
- [ ] Trượt giá: Đưa vào chi phí tối thiểu 5bp cho mỗi giao dịch, và áp dụng trượt giá cao hơn cho các giao dịch trong giai đoạn biến động mạnh. Không dùng thiết lập trượt giá 0.
- [ ] Phí và funding: Đưa phí hai chiều theo mức taker của sàn, thường 0,08%~0,2%. Nếu giao dịch futures, trừ funding mỗi 8 giờ, ví dụ khoảng 0,01%, theo tỷ lệ thời gian nắm giữ.
- [ ] Độ phân giải dữ liệu: Với chiến lược đặt cả stop-loss và take-profit, dùng dữ liệu nhỏ hơn khung vào lệnh một bậc, ví dụ chiến lược ngày thì kiểm tra bằng khung giờ hoặc thấp hơn, để xử lý thứ tự chạm bên trong nến.
- [ ] Tập mẫu: Kiểm chứng trên tập tài sản đúng như tại thời điểm đó, bao gồm cả tài sản bị hủy niêm yết hoặc biến mất. Không chỉ kiểm chứng trên những tài sản còn sống sót đến hiện tại.
- [ ] Xử lý thời điểm: Kiểm tra rằng mọi tính toán tín hiệu chỉ dùng giá trị đã xác nhận của các nến đã đóng, và không có nến tương lai hoặc thống kê toàn giai đoạn bị rò rỉ vào dữ liệu.
Backtest phản ánh đầy đủ sáu mục này sẽ cho lợi suất thấp hơn đường cong chạy với chi phí 0. Chính đường cong thấp hơn đó lại gần hơn với lợi nhuận kỳ vọng trong giao dịch thực tế.
Theo dõi song song backtest và giao dịch thực tế giúp thu hẹp nguyên nhân tách rời
Ngay cả khi đã chạy backtest với thiết lập thực tế hơn, kết quả vẫn không thể trùng khớp hoàn toàn với giao dịch thực tế. Để thu hẹp nguyên nhân của phần chênh lệch còn lại, sau khi bắt đầu giao dịch thật, hãy so sánh song song đường cong backtest và đường cong giao dịch thực tế trong cùng giai đoạn. Khi xem từng giao dịch nơi hai đường cong tách ra, bạn sẽ thấy giả định nào đã bị phá vỡ.
Nếu chênh lệch giá vào lệnh lớn, vấn đề nằm ở thời điểm khớp lệnh hoặc trượt giá. Nếu kết quả bị đảo chiều ở giao dịch có stop-loss và take-profit, vấn đề nằm ở diễn biến bên trong nến. Nếu chi phí tích lũy lớn hơn dự kiến, bạn đã ước tính phí hoặc funding quá thấp. Theo dõi sự tách rời ở cấp độ từng giao dịch giúp xác định điểm nào trong năm điểm trên có tác động lớn nhất, rồi đưa điểm đó trở lại thiết lập backtest để điều chỉnh đường cong gần hơn với thực tế.
Backtest là công cụ kiểm chứng hướng đi của chiến lược. Nó không phải công cụ báo trước lợi nhuận giao dịch thực tế. Bắt đầu bằng việc nghi ngờ giả định khớp lệnh tại giá đóng cửa, rồi kiểm tra trượt giá, phí, độ phân giải dữ liệu, thiên lệch sống sót và look-ahead, đường cong backtest sẽ chuyển từ một bức tranh chỉ tạo cảm giác tự tin thành một công cụ giúp ước lượng kết quả thực tế. Chỉ khi giải thích được vì sao hai đường cong tách rời, bạn mới có thể dùng các con số trong backtest cho quyết định giao dịch thật.