Đi tới nội dung chính
Chuyển tới nội dung chính

Bài 10 — Kiểm thử và đọc kết quả

Bạn sẽ học: chạy kiểm thử chiến lược trên biểu đồ, hiểu từng chỉ số kết quả, đặt vốn / phí / cách khớp lệnh ngay trong mã, và những câu hỏi cần đặt ra trước khi tin một kết quả đẹp.

10.1. Chạy kiểm thử​

  1. Thêm chiến lược vào biểu đồ (ví dụ chiến lược ở Bài 9).
  2. Khung script › thẻ Kiểm thử chiến lược › chọn kỳ (Toàn bộ lịch sử, Từ 2018, 5 năm, 3 năm).
  3. Bấm Chạy kiểm thử. Biểu đồ thêm ngăn Vốn (triệu đồng) và Sụt giảm %, mũi tên tại các lệnh vào / ra.

Kiểm thử chạy trên chính nến của biểu đồ — mã và khung đang xem (phút, giờ, ngày…). Đổi mã / khung / tham số sau khi chạy thì bảng ghi Mã / tham số đã đổi — chạy lại. Giao diện chi tiết: Kiểm thử chiến lược.

Kết quả kiểm thử: chỉ số, đường vốn so với mua và giữ

10.2. Đọc các chỉ số​

Chỉ sốNghĩaĐọc thế nào
Lợi nhuậnLãi / lỗ cả kỳ so với vốn ban đầu, đã trừ phí, thuế, trượt giáSo với Mua và giữ cùng mã cùng kỳ: chiến lược có đáng công không
CAGRLợi nhuận kép mỗi nămSo được giữa các kỳ dài ngắn khác nhau
SharpeLợi nhuận trên mỗi đơn vị biến động (theo năm)Trên 1 là khá; trên 2 trên một mã thường là dấu hiệu quá khớp
Sụt giảm tối đaMức giảm sâu nhất của vốn từ một đỉnhBạn có chịu nổi mức giảm này bằng tiền thật không
Số giao dịchSố lần mua – bán đã đóngDưới 30 là mẫu nhỏ: kết quả có thể chỉ là may
Tỷ lệ thắngPhần trăm giao dịch có lãiKhông tự nói lên gì: thắng 35 % vẫn lãi nếu lãi lớn, lỗ nhỏ
Profit factorTổng lãi / tổng lỗ của các giao dịchTrên 1 là lãi; 1,5–2 là tốt; rất cao với ít giao dịch thì đáng ngờ
Thời gian có vị thếPhần trăm thời gian đang giữ cổ phiếuThấp = vốn nhàn rỗi nhiều, rủi ro thấp hơn mua và giữ

Thẻ Giao dịch liệt kê từng lệnh: Vào, Ra, giá, khối lượng, lãi / lỗ, số phiên giữ, Lý do ra (Tín hiệu bán, Dừng lỗ, Dừng lỗ kéo theo, Chốt lời, Hết thời gian giữ, Đang giữ…), MAE (lỗ tạm lớn nhất trong lúc giữ) và MFE (lãi tạm lớn nhất). MFE lớn mà lãi chốt nhỏ → thoát quá muộn; MAE thường xuyên gần mức dừng lỗ → dừng lỗ quá chặt. Thẻ Theo tháng cho thấy lợi nhuận có đều hay dồn vào vài tháng may mắn.

10.3. Đặt vốn, phí, cách khớp trong mã​

Không khai báo gì thì kiểm thử dùng mặc định của FireAnt Terminal (vốn 1 tỷ đồng, toàn bộ vốn mỗi lệnh, luật cổ phiếu Việt Nam). Khai báo trong mã khi chiến lược cần khác:

strategy({
name: "Bollinger hồi về giữa dải",
signals: (d) => {
const bb = ta.bb(d.close, 20, 2);
return { entry: d.close.crossBelow(bb.lower), exit: d.close.crossAbove(bb.mid) };
},
portfolio: { capital: 200000000, sizing: 0.5 },
costs: { fees: 0.002, sellTax: 0.001, slippage: 0.002 },
execution: { at: "open", delay: 1 },
rules: { maxAdvPct: 0.1 },
risk: { stopLoss: 0.08, maxHoldBars: 20 },
});
MụcÝ nghĩa trong ví dụ
portfolio.capitalVốn ban đầu 200 triệu đồng
portfolio.sizingMỗi lần mua dùng 50 % vốn hiện có (số 0–1); "equal" = mặc định
portfolio.pyramidingSố lần được mua thêm cùng chiều (mặc định 1: không nhồi lệnh)
costs.feesPhí mỗi chiều 0,2 % (mặc định 0,15 %)
costs.sellTaxThuế bán 0,1 %
costs.slippageTrượt giá 0,2 % mỗi lệnh
execution.at, delayKhớp giá mở cửa ("open") hoặc đóng cửa ("close") của nến thứ delay sau tín hiệu
rules.maxAdvPctMỗi lệnh tối đa 10 % khối lượng trung bình 20 phiên (đây cũng là mặc định) — tránh giả định mua được khối lượng lớn ở mã kém thanh khoản

Đủ các mục (rules.limitLock, settlement, lotSize, phái sinh feePerContract, multiplier, flatAt…): Tham chiếu › Chiến lược.

execution: { at: "close", delay: 0 } là giả định lạc quan

Khớp ngay ở giá đóng cửa của chính nến sinh tín hiệu nghĩa là bạn biết giá đóng cửa trước khi đặt lệnh ATC. Có thể dùng để thử chiến lược kiểu ATC, nhưng kết quả sẽ tốt hơn thực tế; mặc định (mở cửa nến sau) an toàn hơn.

10.4. Tuỳ chọn chạy, Monte Carlo, xuất kết quả​

  • Chiến lược onBar (lệnh giấy ctx.buy / ctx.sell / ctx.order / ctx.exit / ctx.closePosition) chạy được trong bảng kiểm thử như chiến lược signals; nến khởi động (ctx.warmup) không đặt lệnh — Lệnh trong onBar.
  • Khớp trong nến (thanh của bảng): theo thiết lập, đường đi O–H–L–C (ước — lệnh khớp kiểu này có dấu ≈), hoặc kính lúp nến 1 phút: dừng lỗ / chốt lời / lệnh chờ trong nến ngày hay nến giờ khớp theo nến 1 phút thật bên trong, biết lệnh nào chạm trước. Nến cũ hơn dữ liệu 1 phút (khoảng 555 phiên gần nhất) lùi về đường đi.
  • Trễ lệnh 1–3 nến: lệnh thị trường khớp ở nến thứ mấy sau nến đặt lệnh — kiểm xem chiến lược còn chạy khi bạn chậm tay.
  • Thẻ Monte Carlo: xáo thứ tự (hoặc lấy mẫu lại) danh sách giao dịch hàng nghìn lần → dải đường vốn, sụt giảm có thể sâu tới đâu, xác suất lỗ và xác suất sụt giảm chạm ngưỡng. Hạt giống cố định: chạy lại cho cùng số — Monte Carlo.
  • Xuất Chuyên nghiệp: Giao dịch (CSV), Tổng quan (CSV), Báo cáo in được (PDF)…, Tải báo cáo HTML — Xuất kết quả.
  • Trình soạn đang mở script: rãnh trái hiện thời gian theo dòng của lần tính gần nhất (như Pine Profiler) — dòng tốn từ 5 ms tô cam.

10.5. Trước khi tin một kết quả đẹp​

  1. Đủ giao dịch chưa? Dưới 30 giao dịch thì vài lệnh may mắn quyết định cả kết quả.
  2. Hơn mua và giữ không? Một chiến lược thua mua và giữ cả về lợi nhuận lẫn sụt giảm thì không đáng dùng.
  3. Chạy trên mã khác thì sao? Đổi mã trên biểu đồ (cùng ngành, khác ngành) rồi chạy lại. Chiến lược chỉ chạy tốt trên đúng mã bạn đã chọn để viết thường là may. Chạy trên cả rổ bằng Quant AI Studio cho câu trả lời chắc hơn (Bài 12).
  4. Chạy trên kỳ khác thì sao? So 5 năm với 3 năm và Từ 2018: kết quả có giữ được qua các giai đoạn thị trường khác nhau.
  5. Phí và trượt giá thực tế chưa? Tăng slippage lên 0,3 % với mã thanh khoản thấp; chiến lược giao dịch dày rất nhạy với phí.
  6. Tham số có phải "vừa khít" không? Đổi tham số lên xuống một chút: kết quả sụp đổ là dấu hiệu quá khớp — Bài 11.
Không có dữ liệu tương lai trong tín hiệu

Ngôn ngữ chặn đọc nến sau (shift(-1)…) và tín hiệu chỉ khớp từ nến kế tiếp, nên kết quả kiểm thử không bị "biết trước". Phần còn lại — chọn mã, chọn kỳ, chọn tham số sau khi đã nhìn kết quả — là thiên lệch do người kiểm thử, ngôn ngữ không chặn được.

Bài tập​

Lấy chiến lược Giá cắt MA 50 ở Bài 9, thêm risk.stopLoss 5 % rồi kiểm thử trên 3 mã khác nhau (một ngân hàng, một bất động sản, một công nghệ), kỳ 5 năm. Ghi lại lợi nhuận, sụt giảm tối đa, số giao dịch và so với mua và giữ. Chiến lược có tốt đều trên cả ba không?

Mã của bài tập
strategy({
name: "Giá cắt MA 50 + dừng lỗ 5 %",
params: { len: param.int(50, { min: 10, max: 200, label: "Chu kỳ MA" }) },
signals: (d, p) => {
const ma = ta.sma(d.close, p.len);
return { entry: d.close.crossAbove(ma), exit: d.close.crossBelow(ma) };
},
risk: { stopLoss: 0.05 },
plot: (d, p) => ({ [`MA ${p.len}`]: line(ta.sma(d.close, p.len), { color: "ref" }) }),
});

Thường bạn sẽ thấy chiến lược cắt MA chạy tốt ở mã có xu hướng dài, và thua mua và giữ ở mã đi ngang nhiều — đó là đặc tính của chiến lược theo xu hướng, không phải lỗi của mã.

Tiếp theo: Bài 11 — Tối ưu tham số và tránh quá khớp