22 tháng Mười, 2026 · dữ liệu

Chúng tôi dựng lại một backtest sau khi nhà cung cấp dữ liệu thay đổi dữ liệu lịch sử

Chúng tôi dựng lại một backtest sau khi nhà cung cấp dữ liệu thay đổi dữ liệu lịch sử

6 tuần sau khi chạy backtest, chúng tôi chạy lại với cùng mã, cấu hình và khoảng thời gian. Vốn cuối kỳ đã khác. Không khác quá nhiều, nhưng đủ để tỷ lệ Sharpe giảm từ 1.31 xuống 1.08 và làm thay đổi bộ tham số trông có vẻ tốt nhất.

Chiến lược không thay đổi. Dữ liệu lịch sử thì có. Nhà cung cấp đã điều chỉnh giao dịch và nến của một số ngày, còn lần chạy đầu tiên của chúng tôi không lưu lại chính xác bản chụp dữ liệu đầu vào. Chúng tôi mất vài ngày tiếp theo để xác định kết quả mới là do dữ liệu được sửa, lỗi trong pipeline hay một quy trình nghiên cứu không thể tái lập.

Thứ Hai: lần chạy lại cho kết quả khác

Manh mối đầu tiên là một khoảng chênh nhỏ trên một cặp giao dịch giao ngay có thanh khoản cao. Nến ban đầu của chúng tôi ghi nhận mức cao nhất là 62,418. Lần chạy lại ghi nhận 62,431. Chênh lệch đó có vẻ vô hại cho đến khi chúng tôi lần theo điểm vào lệnh của chiến lược: ngưỡng nằm giữa hai mức giá này. Chỉ vài nến thay đổi đã tạo ra tín hiệu khác, dẫn đến các vị thế khác nhau vài ngày sau đó.

Chúng tôi so sánh số lượng giao dịch theo ngày và phát hiện sai khác bắt đầu từ một ngày duy nhất. Sau đó, chúng tôi đối chiếu các hàng dữ liệu thô dùng cho ngày đó. Phản hồi hiện tại của nhà cung cấp có một số giao dịch đã được sửa và một nến tổng hợp đã được điều chỉnh. Phản hồi chúng tôi dùng trước đó không kèm nhật ký thay đổi nào.

Đây là hành vi bình thường của dữ liệu. Sàn giao dịch sửa hồ sơ; nhà cung cấp bổ sung dữ liệu còn thiếu, sửa các giao dịch ghi nhận sai và điều chỉnh logic tổng hợp. Một truy vấn về “dữ liệu tháng 1” có thể trả về kết quả khác vào tháng 3.

Thứ Ba: chúng tôi tìm ra bằng chứng còn thiếu

Chúng tôi đã lưu tên nhà cung cấp, mã giao dịch và khoảng thời gian trong hồ sơ lần chạy. Nhưng chúng tôi chưa lưu phản hồi thực tế hay mã băm nội dung cho từng phân vùng dữ liệu đầu vào. Vì vậy, chúng tôi có thể chứng minh mình đã yêu cầu dữ liệu gì, nhưng không thể biết nhà cung cấp đã trả về những byte nào.

Chúng tôi lấy các tệp cũ nhất còn tìm được trong bộ nhớ đệm và so sánh với phản hồi hiện tại. Khác biệt không phải do điều chỉnh chia tách cổ phiếu hay chuyển đổi múi giờ. Đó là một số bản ghi giao dịch đã sửa, được truyền qua bộ dựng nến. Điều này loại trừ một giả thuyết, nhưng bộ nhớ đệm không đầy đủ nên chúng tôi vẫn không thể dựng lại chính xác mọi nến bị ảnh hưởng.

Thông tin chúng tôi ghi lạiCâu hỏi có thể trả lờiThông tin còn thiếu
Nhà cung cấp, mã giao dịch, khoảng thời gianLần chạy đã gửi yêu cầu nàoNội dung phản hồi
Phiên bản pipelineMã nào đã dựng các nếnCác hàng dữ liệu đầu vào chính xác
Thời điểm chạyCông việc được chạy khi nàoKhi đó có bản sửa đổi nào của nhà cung cấp

Chúng tôi đã xem “cùng truy vấn” là “cùng dữ liệu”. Giả định đó khiến thử nghiệm có vẻ dễ tái lập hơn thực tế.

Thứ Tư: dữ liệu sửa đổi làm thay đổi kết luận

Chúng tôi chạy lại các ngày bị ảnh hưởng bằng cả hai phiên bản dữ liệu hiện có. Các nến đã sửa bỏ đi 2 điểm vào lệnh và dời 1 điểm thoát lệnh lên trước 1 nến. 3 giao dịch này giải thích phần lớn thay đổi của Sharpe. Chiến lược nhạy với một vài quan sát gần ngưỡng kích hoạt, dù chuỗi giá tổng thể trên biểu đồ trông gần như giống hệt.

Điều đó không có nghĩa kết quả ban đầu là gian lận hay kết quả đã sửa đương nhiên tốt hơn. Điều đó có nghĩa là cần xác định phạm vi của nhận định: lần chạy cũ mô tả bản chụp dữ liệu chúng tôi có vào thời điểm đó, còn lần chạy lại mô tả dữ liệu lịch sử hiện tại của nhà cung cấp. Chúng tôi không thể thành thật gọi kết quả này là bản tái lập của kết quả kia.

Thứ Năm: chúng tôi cập nhật hồ sơ nghiên cứu

Chúng tôi bổ sung bản chụp dữ liệu đầu vào bất biến cho các lần chạy nghiên cứu mới. Mỗi phân vùng có một mã băm nội dung; bản kê lần chạy ghi lại nguồn, thời điểm truy xuất, phiên bản lược đồ, chính sách điều chỉnh và phiên bản mã chuyển đổi. Với bộ dữ liệu lớn, chúng tôi lưu tệp thực tế trong kho lưu trữ định địa chỉ theo nội dung, nhờ vậy có thể dùng chung các phân vùng giống nhau mà không ghi đè phiên bản trước.

Khi quy định lưu trữ hoặc cấp phép không cho phép giữ lại dữ liệu thô, chúng tôi lưu bằng chứng đầy đủ nhất mà điều khoản cho phép: mã băm, tham số yêu cầu, mã nhận diện phiên bản nguồn và một mẫu nhỏ các hàng đã phân tích để chẩn đoán. Mã băm không thể khôi phục dữ liệu, nhưng cho chúng tôi biết hai lần chạy có dùng những byte giống hệt nhau hay không.

Muốn backtest có thể tái lập, cần định danh đầu vào chứ không chỉ có URL dữ liệu. Hãy ghi lại dữ liệu đã nhận, thời điểm nhận và cách dữ liệu được chuyển thành các hàng mà chiến lược sử dụng.

Thứ Sáu: điều chúng tôi sẽ bỏ qua lần tới

Chúng tôi sẽ không chỉ so sánh các chỉ số tổng quan. Sharpe thay đổi cho biết có điều gì đó đã biến động, nhưng không chỉ ra nguyên nhân. Hãy bắt đầu bằng số hàng và mã băm phân vùng, sau đó tìm ngày đầu tiên có dữ liệu đầu vào khác biệt. Từ đó, lần lượt so sánh các hàng đã chuyển đổi, tín hiệu, lệnh và khớp lệnh.

Chúng tôi cũng sẽ không âm thầm thay dữ liệu cũ bằng dữ liệu lịch sử đã sửa. Các lần sửa rất hữu ích, nhưng những lần chạy cũ cần tiếp tục gắn với dữ liệu đầu vào ban đầu. Bộ dữ liệu mới nên tạo ra một lần chạy mới, có liên kết rõ ràng với lần chạy cũ.

Quy tắc thực tế của chúng tôi giờ rất đơn giản: nếu chạy lại để tái lập một thử nghiệm, hãy cố định bản chụp dữ liệu. Nếu chạy lại để tận dụng dữ liệu lịch sử đã sửa, hãy ghi nhãn đó là một thử nghiệm mới. Chúng tôi mất vài ngày mới rút ra được điều này; giờ nó chỉ chiếm một dòng trong bản kê lần chạy.

dữ liệu thị trườngbacktestkỹ thuật dữ liệukhả năng tái lập
← Tất cả bài viết