Tiện ích và giới hạn
combine([x1, x2, …], (giaTri, i) => so) → chuỗi
- 🇻🇳 Tiếng Việt
- 🇬🇧 English
- 🇰🇷 한국어
- 🇨🇳 中文
combine
combine([x1, x2, …], (giaTri, i) => so) → chuỗi
Ghép nhiều chuỗi bằng một hàm JavaScript chạy ở từng nến: giaTri là mảng giá trị của các chuỗi ở nến đó, i là chỉ số nến. Hàm phải thuần (không nhớ gì giữa các nến). Hai chuỗi thì dùng gọn hơn a.zip(b, (x, y) => …); một chuỗi a.map((x, i) => …).
indicator({
name: "Vị trí giá trong nến (combine)",
plot: (d) => ({
"Vị trí đóng cửa": columns(
combine([d.open, d.high, d.low, d.close], ([o, h, l, c]) => (h > l ? (c - l) / (h - l) : 0.5)),
{ color: "accent" }
),
"Giữa": hline(0.5),
}),
});
Script có combine, map, zip chạy hơi chậm hơn script chỉ dùng phép có sẵn.
stats: thống kê trên mảng
Tính ngay trên một mảng số (không phải chuỗi) — dùng trong onBar với mảng tự giữ trong trạng thái, hoặc trong Quant AI Studio. NaN bị bỏ qua.
| Hàm | Kết quả |
|---|---|
stats.mean(a) | Trung bình |
stats.std(a) | Độ lệch chuẩn mẫu |
stats.variance(a) | Phương sai mẫu |
stats.median(a) | Trung vị |
stats.quantile(a, q) | Phân vị q (0–1) |
stats.corr(a, b) | Hệ số tương quan (cần ≥ 3 cặp) |
stats.linreg(x, y) | { slope, intercept, r2 } |
stats.tstat(a) | Thống kê t của trung bình |
stats.sharpe(loiNhuan, soKyMoiNam = 250) | Sharpe quy năm |
stats.maxDrawdown(giaTri) | Sụt giảm sâu nhất (số âm) |
stats.drawdown(giaTri) | Mảng sụt giảm từ đỉnh tại từng điểm |
stats.forward(giaTri, h) | Lợi nhuận h kỳ sau — chỉ để nghiên cứu, không dùng làm tín hiệu |
dates: ngày
Ngày biểu diễn bằng số ngày kể từ 01/01/1970. Từ mốc thời gian (ms) của nến: Math.floor(ctx.time / 86400000).
| Hàm | Kết quả |
|---|---|
dates.parse("2025-03-10") | Số ngày (nhận cả "2025" = 01/01/2025) |
dates.format(ngay) | "10/03/2025" |
dates.iso(ngay) | "2025-03-10" |
dates.year(ngay), dates.month(ngay), dates.day(ngay) | Năm, tháng (1–12), ngày |
dates.weekday(ngay) | 0 = Chủ nhật … 6 = thứ Bảy |
indicator({
name: "Thống kê trượt và ngày",
pane: "price",
state: () => ({ loiNhuan: [] }),
onBar: (ctx, s) => {
const truoc = ctx.bar(1).close;
if (truoc > 0) s.loiNhuan.push(ctx.close / truoc - 1);
if (s.loiNhuan.length > 60) s.loiNhuan.shift();
const ngay = Math.floor(ctx.time / 86400000);
if (dates.month(ngay) === 1 && dates.day(ngay) <= 7 && dates.weekday(ngay) === 1) {
ctx.draw.label({ id: `nam-${dates.year(ngay)}`, at: { barsAgo: 0, price: ctx.high }, text: `${dates.year(ngay)}`, size: "s", color: "textMuted" });
}
if (s.loiNhuan.length < 60) return;
return {
sharpe: stats.sharpe(s.loiNhuan, 250),
trungVi: stats.median(s.loiNhuan) * 100,
p90: stats.quantile(s.loiNhuan, 0.9) * 100,
lech: stats.std(s.loiNhuan) * 100,
};
},
plot: (d, p, o) => ({
"Sharpe 60 phiên": line(o.sharpe, { pane: "Sharpe", color: "accent" }),
"Trung vị LN ngày %": line(o.trungVi, { pane: "Phân phối", color: "ref" }),
"Phân vị 90 % LN ngày %": line(o.p90, { pane: "Phân phối", color: "up" }),
"Độ lệch chuẩn %": line(o.lech, { pane: "Phân phối", color: "down" }),
}),
});
log
log(...) (và console.log) ghi khi script dựng — hiện ở Nhật ký chạy của Quant AI Studio. Trên biểu đồ, thẻ Nhật ký hiện lỗi, những gì ghi bằng ctx.log(...) trong onBar (gắn với nến — onBar › ctx.log) và dòng console.log(...); log(...) không hiện ở đây.
JavaScript chuẩn
Dùng được: Math (Math.max, Math.min, Math.abs, Math.round, Math.floor, Math.sqrt, Math.log, Math.pow…), Number (Number.isNaN, Number.isFinite), mảng (push, shift, slice, map, filter, reduce, sort…), Object, JSON, chuỗi chữ, template …${x}…, for, while, if, switch, hàm, const / let.
Không có: import, mạng (fetch), lưu trữ trình duyệt, DOM, hẹn giờ (setTimeout), async trong indicator / strategy. Trong onBar và hàm tự viết, Math.random() cho cùng dãy số ở mọi lần chạy và Date.now() / new Date() là mốc của nến đang tính — để script luôn cho cùng kết quả.
Giới hạn
| Giới hạn | Mức |
|---|---|
| Khai báo mỗi script | 1 (indicator hoặc strategy) |
| Script gắn trên một biểu đồ | 5 |
Đầu ra (plot) | 64 |
Điều kiện cảnh báo (alerts) | 32 |
Mã khác (d.symbol) | 4 |
| Nút tính của đồ thị | 5.000 |
| Đối tượng vẽ mỗi loại | mặc định 50, tối đa 500 (limits) |
| Bảng | 9 vị trí, 100 ô mỗi bảng |
| Nhật ký | 1.000 dòng gần nhất |
ctx.track | 500 nến mỗi khoá, tối đa 5.000 (limits.track) |
Trạng thái onBar | 256 KB |
| Thời gian tính toàn bộ lịch sử | 2 giây |
| Thời gian mỗi lần cập nhật giá | 50 ms (vượt nhiều lần liên tiếp: script tạm dừng, chỉ chạy lại khi có nến mới) |
| Thời gian biên dịch | 3 giây |
Vượt thời gian: Script chạy quá 2 giây khi tính toàn bộ lịch sử — đã dừng. Có thể do vòng lặp quá nặng hoặc vô hạn. — xem Hỏi đáp › hiệu năng.
Mã lỗi
Mỗi lỗi có một mã (hiện ở Nhật ký, Copilot đọc được). Lỗi thường gặp kèm cách sửa: Lỗi thường gặp.
| Mã | Khi nào |
|---|---|
syntax | Mã viết sai cú pháp JavaScript (thiếu ngoặc, dấu phẩy…) |
runtime | Lỗi khi chạy: gọi tên không có, sai kiểu, lỗi trong onBar… |
no-declaration, multiple-declarations | Không gọi / gọi nhiều lần indicator / strategy |
lookahead | Đọc nến sau: shift(-1), ctx.bar(-1), ctx.prev(…, -1), ctx.track(…).at(-1) |
universe-only | Phép chỉ có trong Studio (rank, topN…, d.meta) |
eager-in-stream | Đọc giá trị ngay lúc dựng (.data, .last()…) |
tf-lower, tf-misaligned | d.tf khung nhỏ hơn / không là bội số khung đang tính |
ta-order | ctx.ta.* gọi khác thứ tự giữa các nến |
state-not-json | Trạng thái chứa hàm / đối tượng không thuần |
param | Đối số / tham số sai (fillna("0"), hline("70"), d.source("abc"), param.session("9-11")…) |
import | Thư viện use(…): thiếu thư viện / phiên bản, khoá sai dạng, dùng vòng tròn, vượt 16 thư viện / 200.000 ký tự |
limit | Vượt giới hạn (đầu ra, cảnh báo, mã khác, trạng thái) |
budget-history, budget-tick | Vượt thời gian tính |
combine
combine([x1, x2, …], (giaTri, i) => so) → chuỗi
Combines several series with a JavaScript function that runs on each bar: giaTri is the array of the series' values on that bar, i is the bar index. The function must be pure (it remembers nothing between bars). For two series, a.zip(b, (x, y) => …) is shorter; for one series, a.map((x, i) => …).
indicator({
name: "Vị trí giá trong nến (combine)",
plot: (d) => ({
"Vị trí đóng cửa": columns(
combine([d.open, d.high, d.low, d.close], ([o, h, l, c]) => (h > l ? (c - l) / (h - l) : 0.5)),
{ color: "accent" }
),
"Giữa": hline(0.5),
}),
});
Scripts that use combine, map or zip run slightly slower than scripts that only use built-in operations.
stats: statistics on arrays
Computes immediately on an array of numbers (not a series) — use it in onBar with an array you keep in state, or in Quant AI Studio. NaN values are skipped.
| Function | Result |
|---|---|
stats.mean(a) | Mean |
stats.std(a) | Sample standard deviation |
stats.variance(a) | Sample variance |
stats.median(a) | Median |
stats.quantile(a, q) | Quantile q (0–1) |
stats.corr(a, b) | Correlation coefficient (needs ≥ 3 pairs) |
stats.linreg(x, y) | { slope, intercept, r2 } |
stats.tstat(a) | t-statistic of the mean |
stats.sharpe(loiNhuan, soKyMoiNam = 250) | Annualized Sharpe |
stats.maxDrawdown(giaTri) | Maximum drawdown (a negative number) |
stats.drawdown(giaTri) | Array of drawdowns from the peak at each point |
stats.forward(giaTri, h) | Return h periods ahead — for research only, do not use as a signal |
dates: dates
A date is represented as the number of days since 01 Jan 1970. From a bar's timestamp (ms): Math.floor(ctx.time / 86400000).
| Function | Result |
|---|---|
dates.parse("2025-03-10") | Number of days (also accepts "2025" = 01 Jan 2025) |
dates.format(ngay) | "10/03/2025" |
dates.iso(ngay) | "2025-03-10" |
dates.year(ngay), dates.month(ngay), dates.day(ngay) | Year, month (1–12), day |
dates.weekday(ngay) | 0 = Sunday … 6 = Saturday |
indicator({
name: "Thống kê trượt và ngày",
pane: "price",
state: () => ({ loiNhuan: [] }),
onBar: (ctx, s) => {
const truoc = ctx.bar(1).close;
if (truoc > 0) s.loiNhuan.push(ctx.close / truoc - 1);
if (s.loiNhuan.length > 60) s.loiNhuan.shift();
const ngay = Math.floor(ctx.time / 86400000);
if (dates.month(ngay) === 1 && dates.day(ngay) <= 7 && dates.weekday(ngay) === 1) {
ctx.draw.label({ id: `nam-${dates.year(ngay)}`, at: { barsAgo: 0, price: ctx.high }, text: `${dates.year(ngay)}`, size: "s", color: "textMuted" });
}
if (s.loiNhuan.length < 60) return;
return {
sharpe: stats.sharpe(s.loiNhuan, 250),
trungVi: stats.median(s.loiNhuan) * 100,
p90: stats.quantile(s.loiNhuan, 0.9) * 100,
lech: stats.std(s.loiNhuan) * 100,
};
},
plot: (d, p, o) => ({
"Sharpe 60 phiên": line(o.sharpe, { pane: "Sharpe", color: "accent" }),
"Trung vị LN ngày %": line(o.trungVi, { pane: "Phân phối", color: "ref" }),
"Phân vị 90 % LN ngày %": line(o.p90, { pane: "Phân phối", color: "up" }),
"Độ lệch chuẩn %": line(o.lech, { pane: "Phân phối", color: "down" }),
}),
});
log
log(...) (and console.log) writes while the script is being built — shown in the Nhật ký chạy (Run log) of Quant AI Studio. On the chart, the Nhật ký (Log) tab shows errors, whatever you write with ctx.log(...) in onBar (tied to a bar — onBar › ctx.log) and console.log(...) lines; log(...) does not appear there.
Standard JavaScript
Available: Math (Math.max, Math.min, Math.abs, Math.round, Math.floor, Math.sqrt, Math.log, Math.pow…), Number (Number.isNaN, Number.isFinite), arrays (push, shift, slice, map, filter, reduce, sort…), Object, JSON, string literals, template …${x}…, for, while, if, switch, functions, const / let.
Not available: import, network (fetch), browser storage, DOM, timers (setTimeout), async in indicator / strategy. In onBar and your own functions, Math.random() returns the same sequence on every run and Date.now() / new Date() is the timestamp of the bar being computed — so the script always gives the same result.
Limits
| Limit | Value |
|---|---|
| Declarations per script | 1 (indicator or strategy) |
| Scripts attached to one chart | 5 |
Outputs (plot) | 64 |
Alert conditions (alerts) | 32 |
Other tickers (d.symbol) | 4 |
| Computation nodes in the graph | 5,000 |
| Drawing objects per type | 50 by default, up to 500 (limits) |
| Tables | 9 positions, 100 cells per table |
| Log | last 1,000 lines |
ctx.track | 500 bars per key, up to 5,000 (limits.track) |
onBar state | 256 KB |
| Time to compute the full history | 2 seconds |
| Time per price update | 50 ms (exceeded several times in a row: the script pauses and only runs again on a new bar) |
| Compile time | 3 seconds |
When time runs out: Script chạy quá 2 giây khi tính toàn bộ lịch sử — đã dừng. Có thể do vòng lặp quá nặng hoặc vô hạn. (The script ran for more than 2 seconds computing the full history and was stopped. A loop may be too heavy or infinite.) — see FAQ › performance.
Error codes
Each error has a code (shown in the Log, readable by Copilot). Common errors and how to fix them: Common errors.
| Code | When |
|---|---|
syntax | Invalid JavaScript syntax (missing bracket, comma…) |
runtime | Error while running: calling a name that does not exist, wrong type, an error in onBar… |
no-declaration, multiple-declarations | indicator / strategy not called / called more than once |
lookahead | Reading a future bar: shift(-1), ctx.bar(-1), ctx.prev(…, -1), ctx.track(…).at(-1) |
universe-only | An operation available only in Studio (rank, topN…, d.meta) |
eager-in-stream | Reading a value at build time (.data, .last()…) |
tf-lower, tf-misaligned | d.tf with a smaller timeframe / not a multiple of the current timeframe |
ta-order | ctx.ta.* called in a different order between bars |
state-not-json | State contains a function / an impure object |
param | Wrong argument / parameter (fillna("0"), hline("70"), d.source("abc"), param.session("9-11")…) |
import | use(…) libraries: missing library / version, malformed key, circular use, more than 16 libraries / 200,000 characters |
limit | Limit exceeded (outputs, alerts, other tickers, state) |
budget-history, budget-tick | Computation time exceeded |