21 tháng Chín, 2026 · kỹ thuật

Khởi động lại chiến lược giữa chừng khi backtest. Nó có nhớ mình đang nắm giữ gì không?

Khởi động lại chiến lược giữa chừng khi backtest. Nó có nhớ mình đang nắm giữ gì không?

Một bài kiểm tra backtest hữu ích chẳng liên quan gì đến việc tìm tham số tốt hơn: dừng tiến trình giữa chừng, khôi phục rồi chạy tiếp cùng lượt phát lại. Với đầu vào giống hệt nhau và bộ mô phỏng khớp lệnh được kiểm soát, các quyết định, lệnh và vốn chủ sở hữu phải khớp với một lượt chạy liên tục.

Nếu không khớp, bạn đã tìm ra vấn đề quản lý trạng thái. Chiến lược phụ thuộc vào thứ gì đó mà bạn không lưu hoặc không thể dựng lại. Sự phụ thuộc đó quan trọng mỗi khi lượt nghiên cứu được tiếp tục, worker được thay thế hoặc dịch vụ giao dịch giấy triển khai mã mới.

Tôi thích bài kiểm tra này vì đáp án mong đợi rõ ràng khác thường. Không cần tranh luận xem thị trường có thay đổi không. Cả hai lượt chạy đều nhận cùng một thị trường.

Dưới đây là 3 cách khởi động lại sai. Các con số chỉ để minh họa; mỗi lỗi đều có thể xảy ra trong một hệ thống vốn có tính xác định.

1. Tải lại vài nến rồi cho rằng chỉ báo đã khởi động ổn định

Giả sử chiến lược dùng đường trung bình động hàm mũ chu kỳ 100. Cách cập nhật là:

alpha = 2 / 101
ema_next = alpha * close + (1 - alpha) * ema_previous

Tiến trình chạy liên tục giữ nguyên giá trị EMA đã tích lũy. Tiến trình khởi động lại tải về 100 nến, lấy giá đóng cửa đầu tiên làm giá trị khởi tạo EMA, rồi cho rằng chỉ báo chu kỳ 100 cần 100 quan sát.

Giả định đó nhầm lẫn tham số làm mượt của chỉ báo với một cửa sổ ghi nhớ hữu hạn. EMA vẫn giữ ảnh hưởng giảm dần từ trạng thái ban đầu. Nếu hai phiên bản bắt đầu với chênh lệch EMA là 10 đơn vị giá, các mức giá tiếp theo giống hệt nhau sẽ làm chênh lệch thu hẹp như sau:

Số lần cập nhật kể từ khi khởi tạoChênh lệch còn lạiTỷ lệ sai số ban đầu còn lại
1001.35313.53%
2500.06740.674%
5000.0004540.00454%

Phép tính là 10 * (99 / 101)^k. Tải 100 nến chỉ cho bạn 99 lần cập nhật nếu quan sát đầu tiên được dùng làm giá trị khởi tạo.

Hậu quả thường xuất hiện gần ngưỡng ra quyết định. Một lượt chạy thấy giá cao hơn EMA; lượt kia thấy giá thấp hơn. Một chênh lệch số học nhỏ tạo ra cả một giao dịch phát sinh. Khi chuyện đó xảy ra, thời gian chờ, tiền mặt khả dụng và các quyết định về sau cũng có thể lệch nhau.

Hãy lưu trạng thái chỉ báo đệ quy, trạng thái khởi tạo và sự kiện được xử lý gần nhất. Hoặc phát lại từ một trạng thái ban đầu đã biết. Khởi động với lịch sử dài hơn có thể cho ra một giá trị gần đúng chấp nhận được, nhưng hãy chọn độ dài dựa trên ngưỡng sai số cụ thể và kiểm tra xem sai số đó có thể làm thay đổi quyết định hay không. “Gấp 5 lần chu kỳ” chỉ là quy ước, không phải bằng chứng.

Và lịch sử không chỉ nằm ở các chỉ báo. Phân vị trượt cần cửa sổ dữ liệu của nó. Mô hình trực tuyến có thể cần trạng thái bộ tối ưu. Quy tắc chờ 3 nến sau một khoản lỗ cần ghi nhớ khoản lỗ và bộ đếm.

2. Lưu vị thế nhưng quên các lệnh đang xử lý

Vị thế mục tiêu của bạn là 10 đơn vị. Lệnh mua 10 đơn vị đã khớp 4, còn 6 đang chờ. Bạn lưu checkpoint với vị thế là 4, khởi động lại rồi gửi thêm lệnh mua 6 đơn vị còn thiếu.

Nếu phần còn lại của lệnh ban đầu và lệnh thay thế đều khớp, bạn sẽ nắm giữ 16 đơn vị.

Trong backtest, lỗi này thường bị che giấu vì khởi động lại bộ máy khớp lệnh âm thầm xóa các lệnh đang hoạt động. Khi giao dịch giấy, trình mô phỏng hoặc dịch vụ bên ngoài có thể vẫn giữ chúng. Cùng một mã khôi phục sẽ tạo ra mức độ phơi nhiễm khác nhau tùy thành phần nào còn hoạt động.

Khi khởi động lạiTrạng thái thực tếKhôi phục chỉ dựa trên vị thế ghi nhận
Vị thế mục tiêu1010
Vị thế đã khớp44
Khối lượng mua còn chờ60
Khối lượng cần mua thêm06

Hậu quả là một loạt lệnh bất thường ngay sau khi khôi phục. Đôi khi mức phơi nhiễm tăng gấp đôi. Đôi khi hệ thống đóng một vị thế dù lệnh bảo vệ vẫn đang hoạt động, khiến lệnh đó có thể mở vị thế mới về sau.

Checkpoint cần lưu cả danh tính và trạng thái vòng đời của lệnh cùng với vị thế. Trước khi tạo hành động mới, quá trình khôi phục phải đối soát các bản ghi đó với hệ thống khớp lệnh. Lệnh chưa rõ kết quả cần được điều tra; coi “không lưu xác nhận” là “chưa từng gửi” chính là cách lệnh trùng được tạo ra.

Mã định danh lệnh phía client ổn định giúp bạn tra cứu chuyện gì đã xảy ra. Chúng chỉ ngăn lệnh trùng khi hệ thống nhận lệnh thực sự áp dụng các quy tắc duy nhất hoặc tính lặp an toàn cần thiết. Hãy lưu cả mã định danh các lần khớp đã xử lý để việc phát lại một lần khớp không làm vị thế tăng thêm lần nữa.

Tôi có thiện cảm với màn hình trạng thái lệnh đơn điệu ấy. Đến ngày khởi động lại, những dòng nhỏ trên đó bỗng trở thành giao diện thú vị nhất cả văn phòng.

3. Khôi phục vị thế rồi bắt đầu sổ cái P&L mới

Hãy xét ví dụ giao dịch spot không đòn bẩy và không có phí. Bắt đầu với $10,000 tiền mặt, mua 10 đơn vị ở giá $100, rồi lưu checkpoint khi giá đánh dấu lên $110.

Trạng thái chính xác là $9,000 tiền mặt cộng với vị thế trị giá $1,100: vốn chủ sở hữu là $10,100. Nếu khôi phục 10 đơn vị nhưng đặt lại tiền mặt về mức ban đầu $10,000, hệ thống sẽ báo $11,100. Bạn vừa tạo ra $1,000 chỉ bằng cách khởi động lại tiến trình.

Một số biến thể ít rõ rệt hơn. Khôi phục giữ nguyên vốn chủ sở hữu nhưng đặt lại giá vào lệnh thành $110. Tổng vốn chủ sở hữu vẫn có thể chính xác trong khi cách phân bổ lãi/lỗ đã thực hiện và chưa thực hiện thay đổi. Nếu điều kiện dừng lỗ hoặc thoát lệnh dùng giá vào lệnh, lối tắt kế toán này sẽ làm thay đổi hành vi giao dịch.

Hoặc hệ thống quên mức vốn chủ sở hữu cao nhất trước đó. Giả sử vốn chủ sở hữu đạt đỉnh $10,600 trước khi giảm xuống $10,100. Mức sụt giảm là khoảng 4.72%. Đặt lại mức đỉnh khi khôi phục khiến chiến lược đột nhiên cho rằng mức sụt giảm bằng 0. Mọi kiểm soát rủi ro dựa trên mức sụt giảm vừa bị đặt lại trái phép.

Vì vậy, hậu quả có thể là vốn chủ sở hữu bị gián đoạn, mức sụt giảm cải thiện đáng ngờ hoặc quy tắc rủi ro ngừng kích hoạt sau các lần triển khai. Hãy giữ nguyên sổ cái và trạng thái của chiến lược phụ thuộc vào kế toán: biến động tiền mặt, vị thế, giá vốn nếu áp dụng, các khoản phí tích lũy và trạng thái ghi nhớ của bộ kiểm soát rủi ro. Đối soát vốn chủ sở hữu được khôi phục với sổ cái tại cùng thời điểm định giá.

Checkpoint cần có một ranh giới nhất quán. Lưu tiền mặt sau khi khớp lệnh nhưng lưu số lượng vị thế trước lần khớp đó sẽ tạo ra một trạng thái chưa từng tồn tại. Hãy ghi các trạng thái liên quan cùng nhau hoặc lưu một chuỗi sự kiện bền vững để có thể dựng lại trạng thái. Lưu con trỏ sự kiện cùng trạng thái đó để quá trình khôi phục không bỏ qua hoặc áp dụng lần khớp hai lần.

Bài kiểm tra tôi sẽ giữ lại trong bộ công cụ nghiên cứu chạy một lượt phát lại tham chiếu liên tục, rồi khởi động lại lượt thứ hai tại những thời điểm cố tình khó xử: trong lúc khởi tạo chỉ báo, sau khi khớp một phần và khi giới hạn rủi ro đang có hiệu lực. Dùng cùng thứ tự sự kiện và giữ nguyên mọi trạng thái ngẫu nhiên của trình mô phỏng. So sánh quyết định đầu tiên sau khôi phục, các bản ghi lệnh và khớp lệnh, cùng đường đi của vốn chủ sở hữu. Chỉ so số dư cuối cùng có thể che giấu những lỗi triệt tiêu lẫn nhau.

Với sự cố xảy ra sau khi gửi lệnh nhưng trước khi nhận xác nhận, bộ kiểm thử cũng cần giữ riêng trạng thái của dịch vụ khớp lệnh, độc lập với tiến trình chiến lược. Nếu không, nó sẽ xóa mất chính sự bất định mà bạn đang muốn kiểm tra.

Đặc tả của một chiến lược bao gồm những gì nó ghi nhớ. Hãy mô tả bộ nhớ đó đủ rõ để bạn có thể dừng tiến trình giữa chừng khi phát lại và chỉ ra chính xác cách nó tiếp tục hoạt động.

trạng thái chiến lượcbacktestkhôi phục checkpointgiao dịch giấy
← Tất cả bài viết