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

Bài 4 — Tham số chỉnh được

Bạn sẽ học: đưa các con số trong mã thành tham số hiện ở cột Tham số; dùng đủ loại tham số (số, phần trăm, bật / tắt, danh sách chọn, mức giá và thời điểm chọn bằng cách bấm lên biểu đồ).

4.1. Khai báo và dùng​

indicator({
name: "Dải Bollinger tuỳ chỉnh",
pane: "price",
params: {
len: param.int(20, { min: 5, max: 100, label: "Chu kỳ" }),
k: param.num(2, { min: 1, max: 4, step: 0.25, label: "Số độ lệch chuẩn" }),
},
plot: (d, p) => {
const bb = ta.bb(d.close, p.len, p.k);
return {
"Dải": band(bb.upper, bb.lower, { color: "accent", opacity: 0.1 }),
"Giữa": line(bb.mid, { color: "accent", dash: "dash" }),
};
},
});
  • params là một đối tượng: tên tham số → khai báo. Tên chỉ dùng trong mã (p.len), chữ hiện cho người dùng là label.
  • Mọi hàm của khai báo (plot, alerts, signals, onBar…) nhận giá trị tham số ở đối số p.
  • Giá trị trong mã (20, 2) là mặc định. Người dùng đổi trong cột Tham số thì giá trị đó lưu riêng cho biểu đồ — xem Tham số: mặc định trong mã và giá trị của bạn.
  • Giá trị ngoài [min, max] bị kéo về giới hạn; param.int làm tròn thành số nguyên.
Đặt min / max hợp lý

Thẻ Tối ưu của bảng kiểm thử quét các tham số số trong khoảng min–max của chúng. Khoảng quá rộng (1–1000) làm lưới thưa, bỏ sót vùng tốt; khoảng hẹp vừa đủ cho kết quả tối ưu có nghĩa hơn (Bài 11).

4.2. Các loại tham số​

Khai báoÔ trên cột Tham sốGiá trị p.x
param.int(14, { min, max, step, label })Ô số nguyênsố nguyên
param.num(2.5, { min, max, step, label })Ô số thựcsố
param.pct(0.07, { min, max, step, label })Ô phần trăm (hiện 7 %)tỷ lệ: 0,07
param.bool(true, { label })Hộp đánh dấutrue / false
param.choice("EMA", ["SMA", "EMA", "WMA"], { label })Danh sách chọnphần tử được chọn (chữ hoặc số)
param.price(null, { label })Ô giá + nút Chọn trên biểu đồgiá; chưa chọn → NaN
param.time(null, { label })Ô thời điểm + nút Chọn trên biểu đồmốc thời gian (ms); chưa chọn → NaN
param.symbol("VNINDEX", { label })Ô mã (tự viết hoa)mã chữ hoa

Viết gọn bằng giá trị trần cũng được: params: { len: 14, k: 2.5, show: true } (số nguyên → int, số thực → num, đúng / sai → bool) — nhưng không có nhãn tiếng Việt và giới hạn.

Nguồn giá, màu, khung: dùng param.choice

Ngôn ngữ còn có param.source, param.color, param.resolution, param.text, param.session (để tương thích với script chuyển từ nơi khác), nhưng cột Tham số của FireAnt Terminal hiện chỉ hiện chúng thành một ô chữ. Để người dùng chọn được trong danh sách, khai báo bằng param.choice như ví dụ dưới.

4.3. Chọn loại đường trung bình​

p.loai là một chữ bình thường, nên rẽ nhánh bằng JavaScript ngay trong plot:

indicator({
name: "Đường trung bình chọn loại",
pane: "price",
params: {
loai: param.choice("EMA", ["SMA", "EMA", "WMA", "HMA"], { label: "Loại" }),
len: param.int(20, { min: 2, max: 300, label: "Chu kỳ" }),
src: param.choice("close", ["close", "open", "high", "low", "hl2", "hlc3", "ohlc4"], { label: "Nguồn" }),
mau: param.choice("accent", ["accent", "up", "down", "ref", "ceil", "ai"], { label: "Màu" }),
},
plot: (d, p) => {
const x = d.source(p.src);
const ma = p.loai === "SMA" ? ta.sma(x, p.len) : p.loai === "WMA" ? ta.wma(x, p.len) : p.loai === "HMA" ? ta.hma(x, p.len) : ta.ema(x, p.len);
return { [`${p.loai} ${p.len}`]: line(ma, { color: p.mau, width: 2 }) };
},
});
  • d.source(p.src) lấy chuỗi theo tên nguồn người dùng chọn ("close" → d.close, "hl2" → d.hl2…).
  • Màu là chữ nên truyền thẳng p.mau vào color.
  • a ? b : c đọc là "nếu a thì b, không thì c"; nối nhiều lần để chọn trong nhiều loại.

4.4. Bật / tắt một phần của chỉ báo​

Trả đầu ra có điều kiện bằng toán tử ... (trải đối tượng):

indicator({
name: "MACD tuỳ chọn",
params: {
showHist: param.bool(true, { label: "Hiện histogram" }),
showCross: param.bool(false, { label: "Đánh dấu điểm cắt" }),
},
plot: (d, p) => {
const m = ta.macd(d.close, 12, 26, 9);
return {
MACD: line(m.macd, { color: "accent" }),
"Tín hiệu": line(m.signal, { color: "ref" }),
...(p.showHist ? { Histogram: hist(m.hist, { up: "up", down: "down", opacity: 0.5 }) } : {}),
...(p.showCross ? { "Cắt lên": shape(m.macd.crossAbove(m.signal), { at: "bottom", shape: "triangleUp", color: "up" }) } : {}),
};
},
});

4.5. Mức giá và thời điểm chọn trên biểu đồ​

param.price và param.time có nút Chọn trên biểu đồ: bấm nút rồi bấm vào biểu đồ để lấy giá (hoặc nến). Mặc định null nghĩa là chờ người dùng chọn; trước khi chọn, giá trị là NaN và các phép tính với nó ra NaN (không vẽ).

Mức giá của bạn — kẻ mức và đánh dấu khi giá vượt:

indicator({
name: "Mức giá của tôi",
pane: "price",
params: { muc: param.price(null, { label: "Mức giá" }) },
plot: (d, p) => ({
"Mức": line(d.const(p.muc), { color: "ref", dash: "dash" }),
"Vượt lên": shape(d.close.crossAbove(p.muc), { at: "below", shape: "arrowUp", color: "up" }),
"Thủng xuống": shape(d.close.crossBelow(p.muc), { at: "above", shape: "arrowDown", color: "down" }),
}),
alerts: (d, p) => ({ "Giá vượt mức": d.close.crossAbove(p.muc), "Giá thủng mức": d.close.crossBelow(p.muc) }),
});

d.const(x) biến một số thành chuỗi hằng để vẽ bằng line (dùng line thay hline vì hline cần một số có sẵn khi khai báo).

VWAP neo từ thời điểm bạn chọn — giá trung bình theo khối lượng tính từ một nến (đáy quan trọng, ngày công bố tin…):

indicator({
name: "VWAP neo",
pane: "price",
params: { moc: param.time(null, { label: "Neo từ" }) },
plot: (d, p) => {
const tu = d.time.gte(p.moc);
const giaTri = d.hlc3.mul(d.volume).where(tu, 0).cumsum();
const khoiLuong = d.volume.where(tu, 0).cumsum();
return { "VWAP neo": line(giaTri.div(khoiLuong).where(tu), { color: "ai", width: 2 }) };
},
});
  • d.time.gte(p.moc) — đúng từ nến được chọn trở đi.
  • x.where(dieuKien, 0) — giữ x khi điều kiện đúng, thay bằng 0 khi sai; cumsum() cộng dồn từ nến đầu.
  • .where(tu) cuối cùng bỏ phần trước mốc (thành NaN, không vẽ).

Bài tập​

  1. Thêm vào dải Bollinger ở 4.1 một tham số bật / tắt đường giữa.
  2. Viết chỉ báo "khoảng cách tới MA (%)" với tham số loại MA (SMA / EMA) và chu kỳ; vẽ ở ngăn riêng, mức 0.
Lời giải 1
indicator({
name: "Bollinger có tuỳ chọn",
pane: "price",
params: {
len: param.int(20, { min: 5, max: 100, label: "Chu kỳ" }),
k: param.num(2, { min: 1, max: 4, step: 0.25, label: "Số độ lệch chuẩn" }),
mid: param.bool(true, { label: "Hiện đường giữa" }),
},
plot: (d, p) => {
const bb = ta.bb(d.close, p.len, p.k);
return {
"Dải": band(bb.upper, bb.lower, { color: "accent", opacity: 0.1 }),
...(p.mid ? { "Giữa": line(bb.mid, { color: "accent", dash: "dash" }) } : {}),
};
},
});
Lời giải 2
indicator({
name: "Khoảng cách tới MA (%)",
params: {
loai: param.choice("SMA", ["SMA", "EMA"], { label: "Loại" }),
len: param.int(50, { min: 5, max: 300, label: "Chu kỳ" }),
},
plot: (d, p) => {
const ma = p.loai === "EMA" ? ta.ema(d.close, p.len) : ta.sma(d.close, p.len);
const kc = d.close.div(ma).sub(1).mul(100);
return {
"Khoảng cách %": hist(kc, { up: "up", down: "down", format: "number" }),
"0": hline(0),
};
},
});

Tiếp theo: Bài 5 — Cảnh báo