Trả lời ngắn: Backtest thủ công là việc áp cùng một protocol đã khóa lên các mẫu dữ liệu quá khứ theo thứ tự thời gian, chỉ mở thông tin mà người quan sát được phép biết ở mỗi bước. Mục tiêu là tạo bản ghi có thể kiểm lại, không phải tìm vài đoạn chart đẹp hoặc chứng minh tương lai.

Đọc xong, bạn sẽ hiểu:

  • Cách khóa rule, nguồn và danh sách mẫu trước khi xem diễn biến sau đó.
  • Cách mở từng completed bar, ghi terminal state và giữ cả mẫu thiếu dữ liệu.
  • Vì sao raw count của backtest chưa phải winrate, lợi thế hay bảo đảm kết quả.

Lưu ý giáo dục: Toàn bộ mã, mức giá và sáu cửa sổ trong bài là dữ liệu hư cấu. Bài không đề xuất mua, bán, gửi lệnh hay dùng tiền thật.

1. Backtest thủ công không phải tìm chart đẹp

Hãy tưởng tượng bài kiểm tra có đáp án úp. Làm từng câu rồi mới lật đáp án thì phép kiểm còn ý nghĩa. Xem trước, sửa câu hỏi và chỉ giữ câu đúng sẽ làm hỏng nó.

Ta đã biết lịch sử nên dễ chọn giai đoạn “hợp mắt”. Frozen protocol là rule, nguồn, phạm vi và phiên bản không đổi trong một lượt kiểm. Nó giữ câu hỏi đứng yên khi dữ liệu trả lời.

Backtest thủ công không phải:

  • sưu tầm vài screenshot minh họa cho setup;
  • kéo chart tới đoạn đẹp rồi kể vì sao “đáng lẽ phải thấy”;
  • đổi threshold sau mỗi mẫu;
  • forward test trên dữ liệu mới đang hình thành;
  • bằng chứng rằng tương lai sẽ lặp lại quá khứ.

CFA Institute cho rằng backtest cần hypothesis, mục tiêu, rules và process; đồng thời cảnh báo look-ahead và survivorship bias. CFA Institute — Backtesting & Simulation

Look-ahead là dùng thông tin chưa có tại thời điểm mô phỏng. Đứng ở bar 1 mà đã thấy bar 3 sẽ làm cách đọc nhiễm kết quả tương lai.

Câu chắc chắn sai là: “Sáu mẫu lịch sử đã chứng minh setup hoạt động.” Câu có điều kiện đúng hơn: “Theo protocol v1 và sáu cửa sổ giả đã khóa, ta ghi được sáu raw state có thể đối chiếu.” Suy luận sẽ sai nếu danh sách mẫu được chọn sau khi biết outcome hoặc rule đổi trong lúc chạy.

2. Manual Backtest Packet sáu bước

Hình 1 — Cùng một rule phải đi qua mọi mẫu trước khi raw log được tổng hợp.

Manual Backtest Packet là “phong bì” gồm ba tài liệu:

  • Protocol Card: setup ID, rule version, source, symbol, timeframe, timezone, observation window và missing-data rule;
  • Sample Index: danh sách sample ID và timestamp theo thứ tự đã khóa;
  • Raw State Log: từng bar được mở, phép kiểm và terminal state của từng mẫu.

Batch là một lượt chạy dùng đúng một protocol; batch ID ngăn trộn phiên bản.

a. Freeze rules

Ghi candidate, invalid, valid, expiry, observation unit và event order. Candidate selector thật cũng phải được khóa. Demo nhận sẵn Candidate Index nên không chứng minh cách tìm candidate.

b. Lock samples

Sample Index là danh sách mẫu theo thời gian khóa trước reveal. Ghi start/end, nguồn, cách xử lý mẫu trùng và lý do loại trừ.

c. Reveal one bar

One-bar reveal nghĩa là mỗi bước chỉ mở thêm một completed bar. Người làm ghi giá trị rồi áp rule ngay, thay vì nhìn toàn bộ cửa sổ trước.

d. Apply event order

Kiểm điều kiện theo đúng thứ tự đã khóa. Nếu dữ liệu thiếu thì dừng ở trạng thái dữ liệu; không nhảy qua để tìm valid hoặc invalid ở bar sau.

e. Log terminal state

Ghi terminal event đầu tiên và đóng sample. Bar về sau không được bổ sung vào record cũ. Log thô phải đủ để người khác tính lại.

f. Audit

Audit trail gồm protocol version, sample list, raw values, output và exception. Reconciliation đối chiếu index với record và trạng thái. Sáu sample phải tạo sáu dòng, kể cả unavailable.

Nếu cần sửa rule, dừng batch và lưu v1. Tạo v2 cho một Sample Index chưa mở. Một nghiên cứu CME về backtesting lưu ý rằng sửa strategy sau khi xem out-of-sample rồi chạy lại không còn là một phép kiểm thật sự chưa thấy dữ liệu. CME Group — Backtesting

3. Demo BT-MANUAL-M15-v1

Batch dùng INV-DEMO-M15-v1 từ bài #10, cùng mã giả, source, timezone và completed M15 data. Candidate Index C01–C06 có sẵn; phát hiện candidate nằm ngoài bài tập.

Protocol:

  • quan sát bốn completed M15 bars tiếp theo;
  • close đầu tiên <100INVALID;
  • close đầu tiên >102VALID;
  • tới bar 4 chưa có hai event trên → EXPIRED;
  • mỗi bar kiểm data usable → invalid → valid → expiry;
  • terminal state đầu tiên đóng sample.

a. Replay C02, không nhìn bar kế

C02 mở bar 1 là 101,4: data đủ, không <100 hoặc >102WAITING.

Mở bar 2 là 100,8: vẫn WAITING.

Bar 3 là 99,7 <100INVALID; sample đóng, không xem bar 4.

Hình 2 — Reveal dừng tại terminal event, nên dữ liệu phía sau không rò vào quyết định.

b. Raw State Log sáu mẫu

Sample Revealed closes First terminal event Output
C01 101,4 → 102,2 Bar 2 >102 VALID
C02 101,4 → 100,8 → 99,7 Bar 3 <100 INVALID
C03 101,4 → 101,8 → 101,1 → 101,6 Bar 4, chưa có event EXPIRED
C04 101,2 → 100,4 → 102,1 Bar 3 >102 VALID
C05 101,0 → [missing] Bar 2 thiếu dữ liệu UNAVAILABLE
C06 100,9 → 99,9 Bar 2 <100 INVALID

Hình 3 — Tổng raw state bằng đúng sáu sample; dòng thiếu dữ liệu vẫn nằm trong audit.

Reconciliation:

indexed 6 = recorded 6 = valid 2 + invalid 2 + expired 1 + unavailable 1

Đây chỉ là raw tally, không phải winrate, xác suất, expectancy, profitability hay bằng chứng robust. Card thiếu invalid rule, expiry, observation unit hoặc source trả SKIP; batch không mở.

4. Sai lầm, giới hạn và rủi ro

a. Nhìn tương lai hoặc chọn mẫu bằng outcome

Nhìn cả window trước khi ghi bar 1 tạo look-ahead. Selection bias là chọn khoảng thời gian hoặc sample vì đã biết chúng ủng hộ kết luận. Đổi ngày bắt đầu cho tới khi bảng đẹp là một dạng selection bias.

b. Chỉ giữ đối tượng còn tồn tại

Survivorship bias xuất hiện khi dataset chỉ giữ đối tượng còn tồn tại, bỏ phần đã biến mất. CFA cũng cảnh báo survivorship, look-ahead, overfitting và điểm bắt đầu mẫu. CFA Institute Research Foundation — Investment Model Validation

c. Rule drift

Rule drift là rule đổi âm thầm trong cùng batch. Kéo window từ bốn lên năm bar nhưng vẫn ghi v1 khiến các sample dùng hai thước đo.

d. Xóa missing row

C05 thiếu bar nên UNAVAILABLE, không phải invalid và cũng không phải “không tính cho gọn”. Xóa nó làm reconciliation từ sáu còn năm mà không có lý do. Missingness đôi khi còn phản ánh chất lượng nguồn.

e. Đếm trùng hoặc giải quyết overlap bằng hindsight

Hai candidate window có thể chồng nhau. Cách giữ/bỏ phải được viết trước, chẳng hạn first-candidate-wins. Không xem outcome của cả hai rồi chọn mẫu đẹp hơn.

f. Tin một mẫu nhỏ

Sáu sample chỉ đủ học quy trình. Nó không đại diện cho nhiều chế độ thị trường, biến động hoặc giai đoạn dữ liệu. Quá khứ cũng có thể khác hiện tại; dữ liệu lịch sử có thể được sửa hoặc thiếu.

g. Nhầm state test với execution test

Demo chỉ phân loại setup state. Nó chưa mô hình spread, fee, slippage, liquidity, latency, intrabar path hay kết quả tài chính. Manual replay còn có lỗi nhập liệu và sai dấu so sánh do con người.

TradingView có thể replay dữ liệu lịch sử và export record, nhưng công cụ không xóa bias do protocol sai. TradingView — Learn to trade on historical data Bài #12 sẽ xử lý UI.

5. Checklist chạy một batch

Trước khi reveal

  1. Batch ID và setup version đã ghi chưa?
  2. Candidate selector hoặc Sample Index đã khóa chưa?
  3. Source, symbol, timeframe và timezone có cố định không?
  4. Invalid, valid, expiry, observation unit và event order đã đủ chưa?
  5. Missing, duplicate và overlap rule đã viết chưa?

Trong khi chạy

  1. Chỉ mở một completed bar mỗi bước.
  2. Ghi raw value trước khi đánh state.
  3. Dừng sample tại terminal event đầu tiên.
  4. Gặp missing/source mismatch thì ghi UNAVAILABLE, không backfill.
  5. Phát hiện rule/version/source đổi thì dừng cả batch, không sửa lén.

Sau khi chạy

  1. Số row có bằng Sample Index không?
  2. Tổng từng state có bằng số row không?
  3. Mọi exclusion/missing có reason không?
  4. Rule-change note có tách khỏi raw log không?
  5. Kết luận có dừng ở điều dữ liệu thật sự chứng minh không?

Batch chỉ tiếp tục khi contract đầy đủ. Batch phải dừng khi rule drift, source mismatch hoặc sample conflict chưa có cách xử lý viết trước. Sau audit, giữ nguyên raw log và tạo phiên bản mới nếu cần cải tiến.

6. Bài tập 15 phút

Dùng giấy, Google Sheets hoặc LibreOffice Calc. Không cần broker, tài khoản hay tiền thật.

  1. Ghi BT-MANUAL-M15-v1 và rule lên đầu trang.
  2. Tạo cột sample, bar, close, data usable, invalid, valid, expiry, state.
  3. Che các close phía sau bằng một cột trống hoặc tờ giấy.
  4. Replay C01–C06, mỗi lần mở một close.
  5. Dừng tại terminal state và ghi reason.
  6. Cuối cùng đối chiếu index, record và raw state.

Mẫu đối chiếu đã điền

Check Expected
Indexed samples 6
Recorded rows 6
VALID 2
INVALID 2
EXPIRED 1
UNAVAILABLE 1
Dòng bị xóa âm thầm 0

Nếu tổng state không bằng sáu, quay lại tìm row thiếu hoặc bị đếm hai lần. Kết quả đạt là người khác dùng cùng Packet tạo được cùng sáu output, không phải một tỷ lệ nghe hấp dẫn.

7. Tổng kết: khóa đề trước khi mở đáp án

a. Năm ý chính

  • Backtest thủ công áp một frozen protocol lên dữ liệu lịch sử theo thứ tự.
  • Sample Index phải được khóa trước reveal để giảm lựa chọn theo outcome.
  • One-bar reveal ngăn thông tin tương lai rò vào state hiện tại.
  • Missing sample phải giữ trong Raw State Log và reconciliation.
  • Raw tally không chứng minh tương lai; rule đổi cần batch/version mới.

b. Câu hỏi tự kiểm tra

  • Vì sao vài screenshot đẹp chưa phải backtest?
  • C02 đóng ở bar nào và vì sao?
  • C05 phải được ghi thế nào?
  • Khi muốn đổi expiry từ bốn lên năm bar, cần làm gì?

c. Gợi ý đáp án

Xem gợi ý câu 1

Screenshot được chọn sau khi biết outcome không có frozen sample scope hoặc reconciliation. → Xem mục 1–2.

Xem gợi ý câu 2

C02 đóng `INVALID` tại bar 3 vì close `99,7 <100`; không đọc bar sau. → Xem mục 3.

Xem gợi ý câu 3

Giữ C05 trong log với `UNAVAILABLE` và reason thiếu bar; không xóa khỏi tổng sáu. → Xem mục 3–4.

Xem gợi ý câu 4

Dừng/lưu batch v1, tạo protocol v2 và chạy trên một Sample Index chưa mở. → Xem mục 2 và 5.

d. Thuật ngữ cần nhớ

Thuật ngữ Giải thích ngắn
Backtest thủ công Áp protocol cố định lên dữ liệu quá khứ theo thứ tự.
Frozen protocol Rule, nguồn, phạm vi và version không đổi trong batch.
Sample Index Danh sách mẫu đã khóa trước reveal.
One-bar reveal Mỗi bước chỉ mở một completed bar mới.
Look-ahead bias Dùng thông tin chưa có tại thời điểm mô phỏng.
Selection bias Chọn mẫu vì outcome đã biết.
Survivorship bias Chỉ giữ đối tượng còn tồn tại.
Rule drift Rule đổi âm thầm trong cùng batch.
Audit trail Dấu vết đủ để tái lập phép kiểm.
Reconciliation Đối chiếu index, record và tổng state.

e. Nguồn tham khảo

f. Bài trước và bài tiếp theo

Quay lại Invalid Setup: Khi nào phải bỏ kèo? #10 để ôn terminal state và non-revival. Tiếp tục với Backtest bằng TradingView #12 để đưa Packet này vào Bar Replay mà không nhìn trước tương lai.

Nhắc lại: Nội dung chỉ phục vụ giáo dục. Backtest dùng dữ liệu lịch sử và không bảo đảm kết quả tương lai; sáu sample giả không phải cơ sở để dùng vốn thật.