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

Bài 12 — Lọc cả thị trường và Quant AI Studio

Bạn sẽ học: chạy điều kiện của script trên cả một rổ mã để tìm mã vừa có tín hiệu; viết script dùng dữ liệu ngoài giá (khối ngoại, BCTC) cho việc lọc; đưa chiến lược sang Quant AI Studio để kiểm thử trên cả rổ nhiều năm.

12.1. Viết script để lọc​

⋯ › Lọc bằng script… chạy script trên từng mã của một rổ rồi giữ các mã thoả một điều kiện. Điều kiện chọn được là:

  • mỗi điều kiện trong alerts (Cảnh báo: …);
  • mỗi đầu ra shape, bgcolor, barcolor (Hình: …);
  • với chiến lược: Tín hiệu mua (▲), Tín hiệu bán (▼), Đang giữ (đã mua, chưa bán).

Các đường (line, area, hist, đường bậc thang) của script thành cột của bảng kết quả (tối đa 4). Vì vậy một script để lọc tốt nên có: điều kiện rõ trong alerts hoặc shape, và vài đường đáng đưa vào cột.

indicator({
name: "Vượt đỉnh 52 tuần kèm khối lượng",
pane: "price",
params: {
n: param.int(250, { min: 50, max: 500, label: "Số phiên của đỉnh" }),
vol: param.num(1.5, { min: 1, max: 5, step: 0.1, label: "KL gấp TB 20" }),
},
plot: (d, p) => {
const dinh = d.high.highest(p.n).shift(1);
const klTB = ta.sma(d.volume, 20);
return {
"Đỉnh cũ": line(dinh, { color: "up", dash: "dash", step: true }),
"KL / TB 20": line(d.volume.div(klTB), { pane: "KL", color: "accent" }),
"Vượt đỉnh": shape(d.close.gt(dinh).and(d.volume.gt(klTB.mul(p.vol))), { at: "below", shape: "flag", color: "up" }),
};
},
alerts: (d, p) => ({
"Vượt đỉnh kèm khối lượng": d.close.gt(d.high.highest(p.n).shift(1)).and(d.volume.gt(ta.sma(d.volume, 20).mul(p.vol))),
}),
});

Thêm vào biểu đồ, rồi ⋯ › Lọc bằng script… › Điều kiện = Cảnh báo: Vượt đỉnh kèm khối lượng, Đúng trong = 5 phiên, Rổ mã = Cổ phiếu HOSE, Thanh khoản = ≥ 5 tỷ › Lọc. Kết quả có cột Đỉnh cũ, KL / TB 20 của script cùng giá, % thay đổi, giá trị giao dịch. Chi tiết giao diện: Lọc mã bằng script.

Lọc bằng script trên VN30

RổDữ liệu dùng khi lọc
Watchlist, mã tự nhập ≤ 30 mãNến ngày như biểu đồ (chỉ giá, khối lượng)
Rổ có tên (VN30, HOSE…) hoặc trên 30 mãDữ liệu Quant AI Studio: giá, khối lượng và khối ngoại, tự doanh, BCTC, vĩ mô — theo gói (giới hạn)

Script có onBar chưa lọc được — điều kiện phải viết bằng phép chuỗi.

12.2. Lọc bằng dữ liệu ngoài giá​

Khi lọc trên rổ có tên, script đọc được trường dữ liệu của Quant: khối ngoại, tự doanh, định giá, BCTC theo ngày công bố, vĩ mô (Bài 8). Ví dụ: mã được khối ngoại mua ròng 5 phiên liên tiếp trong xu hướng tăng.

// dữ liệu Quant — dùng khi Lọc bằng script trên rổ có tên; trên biểu đồ đường khối ngoại để trống
indicator({
name: "Khối ngoại mua ròng 5 phiên",
plot: (d) => {
const muaRong = d.foreignNet.gt(0);
const du5 = muaRong.rolling(5).sum().eq(5);
return {
"Khối ngoại ròng (tỷ)": hist(d.foreignNet.div(1e9), { up: "up", down: "down" }),
"Mua ròng 5 phiên": shape(du5.and(d.close.gt(ta.sma(d.close, 50))), { at: "top", shape: "circle", color: "up" }),
};
},
alerts: (d) => ({
"Khối ngoại mua ròng 5 phiên, giá trên MA 50": d.foreignNet.gt(0).rolling(5).sum().eq(5).and(d.close.gt(ta.sma(d.close, 50))),
}),
});
  • d.foreignNet — giá trị mua ròng của khối ngoại (đồng) mỗi phiên.
  • x.rolling(5).sum() — tổng 5 phiên gần nhất; 5 phiên đều mua ròng thì tổng của điều kiện (1 / 0) bằng 5.

Một ví dụ dùng BCTC — mã có ROE (4 quý gần nhất) trên 15 % và lợi nhuận sau thuế 4 quý tăng so với 4 quý liền trước đó:

// dữ liệu Quant — dùng khi Lọc bằng script trên rổ có tên
indicator({
name: "ROE cao, lợi nhuận tăng",
plot: (d) => {
const roe = d.fin("ROE");
const ln4Quy = d.fin("ProfitAfterTax", { ttm: true });
const ln4QuyTruoc = d.fin("ProfitAfterTax", { ttm: true, ago: 4 });
return {
"ROE (%)": line(roe.mul(100), { color: "accent" }),
"Đạt": shape(roe.gt(0.15).and(ln4Quy.gt(ln4QuyTruoc)), { at: "top", shape: "circle", color: "up" }),
};
},
alerts: (d) => ({
"ROE > 15 % và lợi nhuận tăng": d.fin("ROE").gt(0.15).and(d.fin("ProfitAfterTax", { ttm: true }).gt(d.fin("ProfitAfterTax", { ttm: true, ago: 4 }))),
}),
});

d.fin(chỉTiêu, { ttm, period, ago }) đọc chỉ tiêu BCTC theo ngày công bố (không nhìn trước): ttm: true cộng 4 quý gần nhất (chỉ với chỉ tiêu phát sinh trong quý như doanh thu, lợi nhuận), period: "year" lấy BCTC năm, ago: 4 lấy kỳ cách 4 kỳ. Tỷ lệ như ROE tính dạng số thập phân (0,15 = 15 %). Tên 72 chỉ tiêu và đơn vị: Quant AI Studio › d.fin.

12.3. Mở chiến lược trong Quant AI Studio​

⋯ › Mở trong Quant AI Studio đưa script sang Studio: chiến lược thành chiến lược của Studio (chạy trên cả rổ, danh mục nhiều mã, tối ưu, kiểm định độ vững), chỉ báo thành bộ lọc. Bạn chọn rổ khi mở (VN30, VN100, Cổ phiếu HOSE (GTGD ≥ 5 tỷ)…).

Chiến lược có thể khai báo sẵn rổ và cách phân bổ vốn cho Studio — trên biểu đồ các mục này được bỏ qua (biểu đồ luôn chạy trên mã đang xem):

strategy({
name: "Động lượng có lọc thanh khoản",
universe: universe("HOSE").liquid(5e9),
portfolio: { maxPositions: 10, sizing: "equal" },
params: { n: param.int(60, { min: 20, max: 120, label: "Số phiên đỉnh" }) },
signals: (d, p) => ({
entry: d.close.gte(d.close.highest(p.n)).and(d.close.gt(ta.sma(d.close, 200))),
exit: d.close.lt(ta.sma(d.close, 50)),
score: d.close.pct(p.n),
}),
risk: { stopLoss: 0.1, trailingStop: 0.15 },
});
  • universe("HOSE").liquid(5e9) — cổ phiếu HOSE có giá trị giao dịch trung bình 20 phiên từ 5 tỷ đồng (xét theo từng thời điểm khi kiểm thử).
  • portfolio.maxPositions: 10 — giữ tối đa 10 mã cùng lúc, chia đều vốn.
  • score — khi có nhiều tín hiệu hơn chỗ trống, ưu tiên mã có điểm cao hơn (ở đây: tăng mạnh nhất n phiên).

Ngược lại, ở Studio, thẻ Lệnh › Hiện trên biểu đồ đánh dấu các lệnh của chiến lược lên biểu đồ FireAnt Chart đang mở.

12.4. Những phép chỉ có ở Studio​

Phép so giữa các mã trong cùng một phiên — xếp hạng (rank), chọn top (topN), chuẩn hoá theo rổ (zscore, demean), tổng cả rổ (sumAcross) — chỉ có nghĩa khi có nhiều mã, nên chỉ chạy trong Quant AI Studio. Trên biểu đồ (một mã), script dùng chúng dừng với lỗi:

// ✗ lỗi: universe-only — trên biểu đồ không có rổ để xếp hạng
strategy({
name: "Top 10 động lượng (chỉ chạy trong Studio)",
universe: universe("VN100"),
rank: (d) => d.close.pct(120).rank(),
select: { top: 10 },
rebalance: "month",
});

Lỗi hiện là rank() là phép cắt ngang giữa các mã — chỉ dùng được ở dạng rổ (Studio). Chiến lược xoay vòng kiểu này viết và chạy thẳng trong Studio: Quant AI Studio › Chiến lược.

Tổng kết chuỗi bài học​

Bạn đã đi từ một đường EMA tới chiến lược có quản lý rủi ro, kiểm thử, tối ưu có kiểm soát và lọc cả thị trường. Từ đây: