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

Khai báo và tham số

Mỗi script gọi đúng một lần indicator({...}) hoặc strategy({...}). Không gọi lần nào: lỗi Script cần gọi một trong indicator(...), strategy(...), screen(...), research(...); gọi hai lần: Script gọi 2 lần indicator / strategy / screen / research — mỗi script chỉ một.

indicator({...})​

indicator({ name, short?, description?, pane?, scale?, params?, resolution?,
series?, state?, onBar?, plot, alerts?, alertNames?, limits? })
TrườngKiểuNghĩa
namechữ, bắt buộcTên trên chú giải, thư viện, cảnh báo
shortchữTên ngắn trên chú giải
descriptionchữMô tả hiện trong thư viện
pane"price" | "new""price": vẽ chồng lên giá; "new" (mặc định): ngăn riêng
scale{ range?, levels?, format?, digits? }Thang của ngăn riêng: range: [0, 100] cố định thang, levels: [30, 70] vạch mức, format định dạng số (Đầu ra › format), digits số chữ số thập phân
paramsđối tượngTham số — param
resolutionkhungGhim khung tính của cả chỉ báo ("1W"): dữ liệu d là nến khung đó, gióng về biểu đồ — xem Dữ liệu › tf
series(d, p) => ({ tên: chuỗi })Chuỗi đầu vào cho onBar (ctx.v.tên) — onBar
state() => ({ … })Trạng thái ban đầu của onBar (dữ liệu thuần)
onBar(ctx, s, p) => ({ tên: số }) | voidLogic theo từng nến — onBar
plot(d, p, o) => ({ tên: đầu ra }), bắt buộcĐầu ra trên biểu đồ; khoá là tên trên chú giải — Đầu ra. Không vẽ gì: () => ({})
alerts(d, p, o) => ({ tên: điều kiện | { when, message?, barClose? } })Điều kiện cảnh báo, cũng là điều kiện Lọc bằng script — Bài 5
alertNamesmảng chữTên các sự kiện ctx.alert(tên) mà onBar được bắn — onBar › alert
limits{ lines?, boxes?, labels?, polylines?, track? }Số đối tượng vẽ giữ tối đa mỗi loại (mặc định 50, tối đa 500; polylines — đường gấp khúc — tối đa 100); track: số nến ctx.track giữ (mặc định 500, tối đa 5.000)

Các hàm plot, alerts, series, signals… chạy một lần khi dựng script (và mỗi khi tham số / mã / khung đổi) để lắp phép tính; onBar chạy mỗi nến. Đầu ra tối đa 64, điều kiện cảnh báo tối đa 32.

indicator({
name: "Chỉ báo đủ trường",
short: "Đủ trường",
description: "Minh hoạ mọi trường của indicator().",
pane: "new",
scale: { range: [0, 100], levels: [30, 50, 70], format: "number", digits: 1 },
params: { len: param.int(14, { min: 2, max: 50, label: "Chu kỳ" }) },
limits: { labels: 20 },
series: (d, p) => ({ rsi: ta.rsi(d.close, p.len) }),
state: () => ({ lanVuot: 0 }),
onBar: (ctx, s) => {
if (ctx.prev("rsi", 1) <= 70 && ctx.v.rsi > 70) {
s.lanVuot += 1;
ctx.draw.label({ at: { barsAgo: 0, price: ctx.v.rsi }, text: `#${s.lanVuot}`, color: "down", size: "s" });
}
return { lan: s.lanVuot };
},
plot: (d, p, o) => ({
RSI: line(ta.rsi(d.close, p.len), { color: "accent" }),
"Số lần vượt 70": line(o.lan, { color: "textMuted", step: true, hidden: true }),
}),
alerts: (d, p) => ({ "RSI vượt 70": { when: ta.rsi(d.close, p.len).crossAbove(70), message: "RSI vừa vượt 70", barClose: true } }),
});

strategy({...})​

strategy({ name, description?, params?, resolution?,
signals | rank + select | weights | onBar, filter?,
risk?, portfolio?, execution?, costs?, rules?,
universe?, period?, benchmark?, warmup?, rebalance?, optimize?,
series?, state?, plot?, alerts?, alertNames?, limits? })
TrườngNghĩaTrên biểu đồ
name, description, params, resolutionNhư indicator✓
signals(d, p) => điều kiện | { entry, exit?, score?, limit?, stop?, short? } — khi nào mua / bán✓ — Chiến lược › signals
filter(d, p) => điều kiện — chỉ cho vào lệnh khi đúng✓
riskDừng lỗ, chốt lời, dừng lỗ kéo theo, giữ tối đa✓ — risk
portfolio, execution, costs, rulesVốn, cách khớp, phí, luật thị trường✓ — Chiến lược
plot, alertsĐầu ra thêm, cảnh báo (mặc định vẽ chồng lên giá)✓
universe, period, benchmark, warmup, rebalance, optimizeRổ, kỳ, chỉ số so sánh, khởi động, tái cân bằng, tối ưuBỏ qua — dùng khi mở trong Quant AI Studio
rank + select, weightsChiến lược xoay vòng / tỷ trọng theo rổStudio
series, state, onBar (lệnh ctx.buy…)Chiến lược kiểu mệnh lệnh (lệnh giấy)✓ — bảng kiểm thử chạy khi chiến lược đã thêm vào biểu đồ; chưa lọc mã được — Lệnh trong onBar

Chiến lược phải có một trong signals, rank, weights, onBar; thiếu cả bốn: strategy cần một trong: signals(d, p), rank(d, p), weights(d, p) hoặc onBar. signals trả sai kiểu: signals(d, p) phải trả về chuỗi hoặc { entry, exit?, score? }.

signals trả thẳng một chuỗi điều kiện thì chuỗi đó là entry:

strategy({
name: "Mua khi giá trên MA 20 (signals rút gọn)",
signals: (d) => d.close.gt(ta.sma(d.close, 20)).and(d.close.shift(1).lte(ta.sma(d.close, 20).shift(1))),
risk: { trailingStop: 0.08 },
});

Các cấu hình risk, portfolio, execution, costs, rules viết được dạng đối tượng hoặc hàm của tham số: risk: (p) => ({ stopLoss: p.sl }).

param.* — tham số​

Khai báo trong params: { tên: param.xxx(…) }; giá trị đọc ở p.tên. Chung cho mọi loại: label (chữ hiện trên cột Tham số). Giá trị người dùng chỉnh lưu cùng biểu đồ, ưu tiên hơn mặc định trong mã (Tham số).

param.int​

param.int(macDinh, { min?, max?, step? = 1, label? }) → số nguyên

Ô số nguyên. Giá trị ngoài [min, max] bị kéo về giới hạn, số lẻ làm tròn. Thẻ Tối ưu quét trong min–max.

param.num​

param.num(macDinh, { min?, max?, step?, label? }) → số

Ô số thực (hệ số ATR 2,5, số độ lệch chuẩn…).

param.pct​

param.pct(macDinh, { min?, max?, step? = 0.005, label? }) → tỷ lệ

Ô phần trăm: hiện 7 %, giá trị trong mã là 0,07. Dùng cho dừng lỗ, ngưỡng thay đổi giá.

param.bool​

param.bool(macDinh, { label? }) → true | false

Hộp đánh dấu. Dùng để bật / tắt một phần đầu ra (...(p.x ? { … } : {})) hoặc một điều kiện lọc.

param.choice​

param.choice(macDinh, [luaChon…], { label? }) → phần tử được chọn

Danh sách chọn; phần tử là chữ hoặc số. Giá trị không có trong danh sách → mặc định. Dùng cho loại đường trung bình, nguồn giá (d.source(p.src)), màu, khung (d.tf(p.khung)).

param.enum​

param.enum(macDinh, { giaTri: "Nhãn", … } | [giaTri…] | [{ value, label }…], { label?, group?, tooltip? }) → giá trị được chọn

Danh sách chọn có nhãn (như input.enum của Pine): bảng chỉnh hiện nhãn, script nhận giá trị (khoá). Mặc định phải là một lựa chọn; lựa chọn trùng hoặc rỗng báo lỗi khi khai báo. param.choice vẫn dùng được khi không cần nhãn.

indicator({
name: "Đường trung bình chọn loại",
pane: "price",
params: {
loai: param.enum("ema", { ema: "Trung bình hàm mũ", sma: "Trung bình đơn giản", wma: "Trung bình có trọng số" }, { label: "Loại" }),
n: param.int(20, { min: 2, max: 200, label: "Chu kỳ" }),
},
plot: (d, p) => ({
MA: line(p.loai === "ema" ? ta.ema(d.close, p.n) : p.loai === "sma" ? ta.sma(d.close, p.n) : ta.wma(d.close, p.n), { color: "accent" }),
}),
});

param.price​

param.price(macDinh | null, { label? }) → giá

Ô giá + nút Chọn trên biểu đồ (bấm nút rồi bấm lên biểu đồ để lấy giá tại con trỏ). null = chờ người dùng chọn; chưa chọn → NaN.

param.time​

param.time(macDinh | null, { label? }) → mốc thời gian (ms UTC)

Ô thời điểm + nút Chọn trên biểu đồ (bấm một nến). Mặc định viết "2025-03-10" hoặc số ms; null = chờ chọn. So với d.time: d.time.gte(p.moc).

param.symbol​

param.symbol(macDinh, { label? }) → mã chữ hoa

Ô mã (cổ phiếu, chỉ số, ETF). Mã sai định dạng → mặc định. Dùng với d.symbol(p.ma) — nến của mã người dùng chọn (Mã khác).

param.source, param.color, param.resolution, param.text, param.session​

Khai báoGiá trị
param.source("close")Tên nguồn: open, high, low, close, volume, hl2, hlc3, ohlc4
param.color("up")Tên màu / mã màu
param.resolution("1W")Khung; null = khung của biểu đồ
param.text("…", { maxLength })Chữ tự do
param.session("0900-1130")Khung giờ HHMM-HHMM (nhiều đoạn cách dấu phẩy); sai định dạng báo lỗi khi khai báo

Khai báo và dùng được trong mã, nhưng cột Tham số của Terminal hiện chỉ hiện chúng thành ô chữ — muốn người dùng chọn trong danh sách, dùng param.choice.

Thư viện: library và use​

Hàm dùng chung cho nhiều script (như library / import của Pine): một script khai báo library({ name, exports }) — hàm, số, chữ, mảng / đối tượng thường — rồi Lưu (mỗi lần lưu là một phiên bản trong Script của tôi). Script khác dùng bằng use("<id>@<phiên bản>"): phiên bản ghim, sửa thư viện không đổi script đang dùng tới khi bạn đổi số phiên bản. Thư viện › chọn thư viện › Chép dòng use để có đúng dòng cần dán.

// Thư viện "Xu hướng" (Mới ▸ Thư viện mới, rồi Lưu)
library({
name: "Xu hướng",
exports: {
trendUp: (d, n = 50) => d.close.gt(ta.ema(d.close, n)),
LEVELS: [30, 70],
},
});

// Script dùng thư viện (id + phiên bản lấy từ nút Chép dòng use)
const xu = use("s1abc2def@3");
indicator({
name: "Dùng thư viện",
plot: (d) => ({ "Xu hướng tăng": bgcolor(xu.trendUp(d, 100), { color: "up", opacity: 0.08 }), "Mức": hline(xu.LEVELS[1]) }),
});
  • Khoá trong use(…) phải là chuỗi viết sẵn (không dùng biến): Terminal tìm thư viện trước khi chạy vì sandbox không có mạng.
  • Thư viện không chạy riêng, không gọi indicator / strategy; không xuất được chuỗi (Series) — xuất hàm dựng chuỗi.
  • Thư viện dùng thư viện khác được; dùng vòng tròn, thiếu thư viện / phiên bản, quá 16 thư viện hoặc quá 200.000 ký tự mỗi thư viện báo lỗi import đúng dòng use(…). Lỗi trong hàm của thư viện ghi kèm tên thư viện và dòng trong thư viện.

Khai báo gọn​

params: { len: 14, k: 2.5, show: true, loai: "EMA" } — số nguyên → int, số thực → num, true / false → bool, chữ → choice một lựa chọn. Không có nhãn, không có giới hạn.

Ví dụ đủ loại tham số​

indicator({
name: "Đủ loại tham số",
pane: "price",
params: {
len: param.int(20, { min: 2, max: 200, label: "Chu kỳ" }),
k: param.num(2, { min: 0.5, max: 5, step: 0.5, label: "Hệ số" }),
gap: param.pct(0.03, { min: 0.01, max: 0.2, label: "Khoảng cách" }),
show: param.bool(true, { label: "Hiện dải" }),
loai: param.choice("EMA", ["SMA", "EMA"], { label: "Loại" }),
muc: param.price(null, { label: "Mức giá" }),
tu: param.time(null, { label: "Từ ngày" }),
ma: param.symbol("VNINDEX", { label: "Mã so sánh" }),
gon: 10,
},
plot: (d, p) => {
const ma = p.loai === "SMA" ? ta.sma(d.close, p.len) : ta.ema(d.close, p.len);
return {
[`${p.loai} ${p.len}`]: line(ma, { color: "accent" }),
...(p.show ? { "Dải": band(ma.mul(1 + p.gap * p.k), ma.mul(1 - p.gap * p.k), { color: "accent", opacity: 0.08 }) } : {}),
"Mức giá": line(d.const(p.muc), { color: "ref", dash: "dash" }),
"Từ ngày": bgcolor(d.time.gte(p.tu), { color: "ai", opacity: 0.04 }),
[`Cao nhất ${p.gon} nến`]: line(d.high.highest(p.gon), { color: "up", dash: "dot", hidden: true }),
};
},
});

p.ma không dùng ở ví dụ này — tham số không dùng tới vẫn hiện trên cột Tham số.