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

Lỗi thường gặp

Mỗi mục dưới ghi đúng chữ FireAnt Terminal báo, vì sao xảy ra và cách sửa. Đoạn mã có dấu ✗ là cách viết sai (để bạn nhận ra), ngay sau là cách viết đúng.

Lỗi hiện ở đâu​

NơiKhi nàoVí dụ
Gạch đỏ trong trình soạnNgay khi gõ — kiểm cú pháp và kiểu theo đặc tả ngôn ngữ. Rê chuột lên chỗ gạch để đọcKhông có tên 'len' (gõ sai, hay quên khai báo?)
Dải đỏ trên trình soạnKhi chạy (Thêm vào biểu đồ / Chạy lại), kèm số dòng, tô dòng lỗi và nút Sửa giúp tôi (nhờ Copilot sửa — Copilot)Lỗi cú pháp: …, Lỗi: …, Vượt ngân sách: …
Thẻ Nhật kýLỗi khi chạy, kèm số dòng; và dòng bạn ghi bằng ctx.log
Cảnh báo vàngScript chạy nhưng có vấn đềScript không vẽ gì: …

Gặp gạch đỏ thì sửa trước khi chạy: có những lỗi không làm script dừng nhưng cho kết quả sai (mục Dùng >, && với chuỗi).

Dùng >, <, &&, || với chuỗi​

Trình soạn báo: Không dùng toán tử '>' cho kiểu 'Series' và 'number' — với chuỗi dùng .add() / .sub() / .gt()…

Vì sao: chuỗi là cả cột số; toán tử của JavaScript so sánh đối tượng, không so từng nến. Script vẫn chạy nhưng sai: r > 70 luôn là false (dấu không bao giờ hiện), a && b trả về b (bỏ mất điều kiện a).

// ✗ sai — chạy được nhưng dấu không bao giờ hiện
indicator({
name: "RSI trên 70 (sai)",
plot: (d) => {
const r = ta.rsi(d.close, 14);
return { RSI: line(r), "Trên 70": shape(r > 70, { at: "top" }) };
},
});
indicator({
name: "RSI trên 70 (đúng)",
plot: (d) => {
const r = ta.rsi(d.close, 14);
return { RSI: line(r), "Trên 70": shape(r.gt(70), { at: "top" }) };
},
});

Bảng đổi: > → .gt(), >= → .gte(), < → .lt(), <= → .lte(), == → .eq(), != → .neq(), && → .and(), || → .or(), ! → .not(). Trong onBar thì ngược lại: giá trị là số, dùng toán tử bình thường.

A[0]: cần chuỗi hoặc số​

Vì sao: cộng / trừ chuỗi bằng +, - — JavaScript biến chuỗi thành chữ ("[object Object]1"), đầu ra nhận một thứ không phải chuỗi.

// ✗ lỗi: param — dùng + với chuỗi
indicator({
name: "Giá cộng 1 (sai)",
plot: (d) => ({ A: line(d.close + 1) }),
});
indicator({
name: "Giá cộng 1 (đúng)",
plot: (d) => ({ A: line(d.close.add(1)) }),
});

shift(n) với n âm dùng dữ liệu tương lai — không được phép​

Vì sao: shift(-1) đọc nến sau — tín hiệu sẽ "biết trước". Tương tự: ctx.bar: barsAgo phải ≥ 0 (không đọc được nến sau), ctx.prev: barsAgo phải ≥ 0 …, ctx.track(...).at(k): k phải ≥ 0 ….

// ✗ lỗi: lookahead — so với giá ngày mai
indicator({
name: "Ngày mai tăng (sai)",
pane: "price",
plot: (d) => ({ "Tăng": shape(d.close.shift(-1).gt(d.close), { at: "below" }) }),
});

Sửa: chỉ so với quá khứ — "hôm nay tăng so với hôm qua" là d.close.gt(d.close.shift(1)). Muốn biết tín hiệu sau đó giá đi thế nào, dùng bảng Kiểm thử chiến lược — không đưa vào chỉ báo.

Không có tên 'x' (gõ sai, hay quên khai báo?)​

Khi chạy: Lỗi: len is not defined. Vì sao: dùng một tên chưa khai báo — thường là quên p. trước tên tham số, gõ sai chữ hoa / thường, hoặc dùng biến khai báo trong hàm khác.

// ✗ lỗi: runtime — quên p. trước tham số
indicator({
name: "Quên p. (sai)",
params: { len: param.int(14) },
plot: (d, p) => ({ RSI: line(ta.rsi(d.close, len)) }),
});
indicator({
name: "Có p. (đúng)",
params: { len: param.int(14) },
plot: (d, p) => ({ RSI: line(ta.rsi(d.close, p.len)) }),
});

ta.rsii is not a function — Kiểu '…' không có thuộc tính '…'​

Vì sao: gõ sai tên hàm / thuộc tính. Trình soạn gợi ý: Kiểu 'typeof ta' không có thuộc tính 'rsii' — có phải 'rsi'?. Gõ ta. rồi chờ danh sách gợi ý để chọn đúng tên; tra cứu ở Tham chiếu.

// ✗ lỗi: runtime — gõ sai tên hàm
indicator({ name: "Sai tên hàm", plot: (d) => ({ RSI: line(ta.rsii(d.close, 14)) }) });

Lỗi cú pháp: Unexpected token …​

Vì sao: thiếu / thừa dấu ngoặc, dấu phẩy, dấu nháy. Dải đỏ chỉ đúng dòng, cột. Hay gặp:

  • quên dấu phẩy giữa hai mục của { … };
  • plot: (d) => { A: line(…) } — hàm trả đối tượng phải bọc ngoặc tròn: (d) => ({ A: line(…) });
  • thừa dấu chấm (d.close.), ngoặc không đóng.
// ✗ lỗi: syntax — thừa dấu chấm
indicator({ name: "Thừa dấu chấm", plot: (d) => ({ A: line(d.close.) }) });

Script cần gọi một trong indicator(...), strategy(...), screen(...), research(...)​

Vì sao: script không gọi indicator({ … }) hay strategy({ … }) — có thể đang chỉ có vài dòng tính toán, hoặc gõ sai tên (Indicator).

// ✗ lỗi: no-declaration
const r = 1;

Script gọi 2 lần indicator / strategy / screen / research — mỗi script chỉ một: mỗi script đúng một khai báo. Muốn hai chỉ báo, viết hai script (một biểu đồ gắn được 5 script) hoặc gộp đầu ra vào một plot.

// ✗ lỗi: multiple-declarations
indicator({ name: "Một", plot: (d) => ({ A: line(d.close) }) });
indicator({ name: "Hai", plot: (d) => ({ B: line(d.open) }) });

plot: "A" phải là line(…), hist(…), band(…)…​

Vì sao: giá trị trong plot là một chuỗi chứ không phải đầu ra. Bọc bằng line(…), hist(…)…

// ✗ lỗi: runtime
indicator({ name: "Thiếu line", plot: (d) => ({ A: ta.sma(d.close, 20) }) });

Script không vẽ gì​

Cảnh báo: Script không vẽ gì: giá trị onBar trả về chỉ hiện khi plot dùng tham số thứ ba o, vd onBar trả { "Tên": v } thì plot: (d, p, o) => ({ "Tên": line(o["Tên"]) }).

Vì sao: onBar trả giá trị nhưng plot không dùng chúng.

// ✗ sai — onBar tính nhưng không vẽ
indicator({
name: "Quên vẽ (sai)",
state: () => ({ n: 0 }),
onBar: (ctx, s) => {
s.n = ctx.close > ctx.open ? s.n + 1 : 0;
return { n: s.n };
},
plot: () => ({}),
});
indicator({
name: "Có vẽ (đúng)",
state: () => ({ n: 0 }),
onBar: (ctx, s) => {
s.n = ctx.close > ctx.open ? s.n + 1 : 0;
return { n: s.n };
},
plot: (d, p, o) => ({ "Nến tăng liên tiếp": hist(o.n) }),
});

Biểu đồ trống còn có thể vì: điều kiện không bao giờ đúng (kiểm bằng cột Tại nến), chu kỳ quá dài so với số nến đang có (SMA 500 trên biểu đồ có 300 nến), hoặc dùng dữ liệu chưa có trên biểu đồ (d.fin, khối ngoại… — Bài 8).

o.x: script không có onBar​

Vì sao: dùng đối số o trong plot / alerts khi script không có onBar — o chỉ chứa đầu ra của onBar.

// ✗ lỗi: runtime
indicator({ name: "o không có onBar", plot: (d, p, o) => ({ A: line(o.x) }) });

ctx.ta: lần gọi thứ … trước là …, nến này là …​

Thông báo đầy đủ: ctx.ta: lần gọi thứ 0 trước là sma:5, nến này là ema:10 — gọi ctx.ta ở mọi nến theo cùng thứ tự, hoặc truyền key khi gọi trong nhánh.

Vì sao: gọi ctx.ta.* trong if / else nên thứ tự gọi khác nhau giữa các nến.

// ✗ lỗi: ta-order
indicator({
name: "ctx.ta trong nhánh (sai)",
onBar: (ctx) => {
const v = ctx.close > ctx.open ? ctx.ta.ema(ctx.close, 10) : ctx.ta.sma(ctx.close, 5);
return { v };
},
plot: (d, p, o) => ({ V: line(o.v) }),
});
indicator({
name: "ctx.ta ngoài nhánh (đúng)",
onBar: (ctx) => {
const ema = ctx.ta.ema(ctx.close, 10);
const sma = ctx.ta.sma(ctx.close, 5);
return { v: ctx.close > ctx.open ? ema : sma };
},
plot: (d, p, o) => ({ V: line(o.v) }),
});

Hoặc giữ trong nhánh nhưng truyền khoá riêng: ctx.ta.ema(ctx.close, 10, "nhanh-tang").

state.f: trạng thái onBar chỉ chứa dữ liệu … không chứa hàm​

Vì sao: state() trả đối tượng có hàm, Date, hay lớp tự viết. Trạng thái phải là dữ liệu thuần (số, chữ, mảng, đối tượng thường) — vì nó được sao chép mỗi lần giá mới. Đặt hàm ở ngoài state.

// ✗ lỗi: state-not-json
indicator({
name: "Hàm trong state (sai)",
state: () => ({ tinh: (x) => x * 2 }),
onBar: (ctx, s) => ({ v: ctx.close }),
plot: (d, p, o) => ({ V: line(o.v) }),
});

d.tf("60") nhỏ hơn khung đang tính 1D — chưa hỗ trợ​

Vì sao: d.tf chỉ nhận khung lớn hơn khung của biểu đồ. Hay gặp khi script viết cho biểu đồ phút (dùng d.tf("60")) được mở trên biểu đồ ngày. Sửa: đổi khung biểu đồ, dùng khung lớn hơn, hoặc — nếu thật sự cần nến nhỏ bên trong mỗi nến — dùng d.ltf("60") (Khung nhỏ hơn).

// ✗ lỗi: tf-lower — biểu đồ ngày không có nến 60 phút
indicator({ name: "Khung nhỏ hơn", plot: (d) => ({ A: line(d.tf("60").close) }) });

rank() là phép cắt ngang giữa các mã — chỉ dùng được ở dạng rổ (Studio)​

Vì sao: rank, topN, zscore, sumAcross… so giữa nhiều mã; biểu đồ chỉ có một mã. Viết trong Quant AI Studio, hoặc dùng bản theo thời gian trên một mã: x.rolling(n).rank(), x.rolling(n).zscore().

// ✗ lỗi: universe-only
indicator({ name: "Xếp hạng giữa các mã", plot: (d) => ({ A: line(d.close.pct(20).rank()) }) });
indicator({ name: "Hạng theo thời gian (đúng)", plot: (d) => ({ "Hạng 250 phiên": line(d.close.pct(20).rolling(250).rank()) }) });

data: đọc giá trị lúc dựng chỉ có ở dạng rổ (Studio) — ở biểu đồ dùng onBar(ctx, state)​

Vì sao: đọc giá trị của chuỗi ngay trong plot (.data, .last(), .get()) — trên biểu đồ giá trị chỉ có khi tính từng nến. Muốn xử lý từng giá trị: onBar (đọc ctx.v.x) hoặc x.map((v) => …).

// ✗ lỗi: eager-in-stream
indicator({
name: "Đọc giá trị lúc dựng (sai)",
plot: (d) => {
const cuoi = d.close.last();
return { A: line(d.close) };
},
});

fillna(value) cần một số — hline(value) cần một số​

Vì sao: truyền chữ hoặc chuỗi vào chỗ cần số. hline chỉ nhận số cố định — mức thay đổi theo nến dùng line(…).

// ✗ lỗi: param
indicator({ name: "hline nhận chữ", plot: (d) => ({ A: hline("70") }) });
indicator({ name: "Mức động dùng line", plot: (d) => ({ "MA 20": line(ta.sma(d.close, 20)), "Đỉnh 20": line(d.high.highest(20)) }) });

Các lỗi tham số khác: d.source: nguồn "…" không có (open, high, low, close, volume, hl2, hlc3, ohlc4), param.session("9-11"): khung giờ dạng "0900-1130", d.macro cần mã chuỗi vĩ mô, ví dụ d.macro("cpi_yoy"), ctx.ta.ema: n cần số nguyên ≥ 1.

use("…"): chưa nạp thư viện này — kiểm tra id và phiên bản trong Script của tôi​

Vì sao: dòng use("<id>@<phiên bản>") trỏ tới thư viện (hoặc phiên bản) không có trong Script của tôi — gõ tay sai id, thư viện đã xoá, hoặc script được chép từ máy / người khác. Mở Thư viện › Của tôi, chọn thư viện, bấm Chép dòng use (bản …) rồi dán lại. Các lỗi cùng loại (mã import): use(…) cần chuỗi "<id>@<phiên bản>" (khoá phải là chuỗi viết sẵn, không dùng biến), Thư viện dùng vòng tròn: …, Thư viện … gọi indicator(…) — thư viện chỉ khai báo library({ name, exports }) — Thư viện.

Tối đa 4 mã khác mỗi script​

Mỗi script đọc tối đa 4 mã khác qua d.symbol (không tính VNINDEX của d.bench). Ngoài ra: plot có … đầu ra — tối đa 64, alerts có … điều kiện — tối đa 32, Trạng thái onBar vượt 256 KB — Giới hạn.

Script chạy quá 2 giây … — đã dừng​

Thông báo: Vượt ngân sách: 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. (khi cập nhật giá: … quá 50 ms mỗi lần cập nhật theo tick …).

Vì sao và cách sửa: vòng lặp lồng nhau trong onBar (mỗi nến lặp lại cả trăm nến trước), mảng trong state dài mãi không cắt, while không dừng. Thay vòng lặp bằng phép chuỗi (highest, rolling), cắt mảng (shift() khi quá dài) — xem Hỏi đáp › Hiệu năng.

Kiểm thử dành cho chiến lược​

Kiểm thử dành cho chiến lược — tạo bằng Mới ▸ Chiến lược mới hoặc chọn mẫu chiến lược ở Thư viện.: script đang là indicator. Đổi thành strategy({ … }) với signals (hoặc lệnh giấy trong onBar) — Bài 9.

Chiến lược kiểm thử trên biểu đồ cần signals(d, p) hoặc onBar (lệnh giấy): strategy thiếu cả hai. Chiến lược onBar chạy trong bảng kiểm thử khi đã Thêm vào biểu đồ (Lệnh trong onBar).

Kiểm thử chạy xong nhưng không có giao dịch nào​

  • Điều kiện entry không bao giờ đúng: thêm tạm plot vẽ shape(entry…) để thấy, hoặc xem số ▲ trên biểu đồ.
  • Tối ưu / Walk-forward ghi Bỏ khỏi lưới vì không đủ nến khởi động: … hoặc báo Biểu đồ có … nến, không đủ cho đoạn khởi động của mọi giá trị "…" trong lưới: max của tham số quá lớn — mọi tổ hợp chấm sau đoạn khởi động của tổ hợp dài nhất (EMA 300 cần khoảng 6.300 nến), giá trị không chừa đủ nến để chấm bị bỏ. Hạ max — Bài 11.
  • Kiểm thử bắt đầu sau đoạn khởi động: chỉ báo đệ quy cần khoảng 20 × chu kỳ nến (EMA 200 cần ~4.000 nến; MACD của nến tuần cần hơn 500 tuần). Biểu đồ ít lịch sử (mã mới niêm yết, khung phút) có thể hết nến trước khi kiểm thử bắt đầu — dùng chu kỳ ngắn hơn, SMA thay EMA, hoặc xem khung lớn hơn.
  • Kỳ quá ngắn (3 năm) cho chiến lược dài hạn: chọn Toàn bộ lịch sử.

Đường dùng d.fin, khối ngoại, d.flow… trống​

  • d.fin, d.macro, khối ngoại, tự doanh, định giá (trường Quant): biểu đồ FireAnt Chart chưa đưa các dữ liệu này vào script — không phải lỗi của bạn. Dùng chúng khi Lọc bằng script trên rổ có tên hoặc trong Quant AI Studio — Bài 12.
  • d.flow, d.footprint (dòng tiền chủ động): cần gói Chuyên nghiệp; khung giây không có.
  • d.symbol, d.bench, d.ltf: biểu đồ tự nạp nến; đường trống một lúc rồi hiện khi nạp xong. Mã gõ sai (không có nến) thì trống mãi; nến cũ hơn dữ liệu 1 phút thì phép gộp của d.ltf ra NaN.