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

Bài 3 — Tín hiệu, mũi tên, tô màu

Bạn sẽ học: viết điều kiện (lớn hơn, cắt lên, kết hợp "và / hoặc"), đánh dấu bằng mũi tên / hình / ký tự, tô nền vùng thời gian, tô màu nến, và lọc để mỗi tín hiệu chỉ hiện một lần.

3.1. Điều kiện là một chuỗi 1 / 0​

Mọi phép so sánh cho ra một chuỗi điều kiện: 1 ở nến đúng, 0 ở nến sai.

Điều kiệnViết
Giá đóng cửa trên MA 50d.close.gt(ta.sma(d.close, 50))
RSI dưới 30ta.rsi(d.close, 14).lt(30)
RSI nằm trong 40–60ta.rsi(d.close, 14).between(40, 60)
EMA 20 cắt lên EMA 50 (nến trước ≤, nến này >)ta.ema(d.close, 20).crossAbove(ta.ema(d.close, 50))
Giá cắt xuống 100d.close.crossBelow(100)
Nến tăngd.close.gt(d.open)
Khối lượng gấp đôi trung bình 20d.volume.gt(ta.sma(d.volume, 20).mul(2))
Cả hai điều kiệna.and(b)
Một trong haia.or(b)
Không phảia.fillna(0).not()

3.2. Mũi tên và hình​

shape(điều kiện, { … }) vẽ một dấu ở mọi nến điều kiện đúng.

indicator({
name: "Giá cắt MA 50",
pane: "price",
plot: (d) => {
const ma = ta.sma(d.close, 50);
return {
"MA 50": line(ma, { color: "ref" }),
"Cắt lên": shape(d.close.crossAbove(ma), { at: "below", shape: "arrowUp", color: "up", text: "Mua" }),
"Cắt xuống": shape(d.close.crossBelow(ma), { at: "above", shape: "arrowDown", color: "down", text: "Bán" }),
};
},
});
Tuỳ chọnGiá trị
at"above" trên nến (mặc định), "below" dưới nến, "value" tại mức value, "top" / "bottom" mép trên / dưới ngăn
shape"triangleUp", "triangleDown", "arrowUp", "arrowDown", "circle", "square", "diamond", "flag", "label"
charMột ký tự thay hình, ví dụ "★", "B"
textChữ ngắn kèm dấu
color / colorsMàu / luật màu
size"s", "m", "l"
valueMức vẽ khi at: "value" (số hoặc chuỗi)

Đặt dấu ngay tại một mức giá — ví dụ chấm tại đáy nến có bóng dưới dài:

indicator({
name: "Bóng dưới dài",
pane: "price",
plot: (d) => {
const than = d.close.sub(d.open).abs();
const bongDuoi = d.open.min(d.close).sub(d.low);
const dai = bongDuoi.gt(than.mul(2)).and(bongDuoi.gt(d.high.sub(d.low).mul(0.5)));
return {
"Bóng dưới dài": shape(dai, { at: "value", value: d.low, shape: "circle", color: "up", size: "s" }),
};
},
});

a.min(b) là giá trị nhỏ hơn của hai chuỗi ở từng nến — ở đây là cạnh dưới của thân nến.

3.3. Tô nền​

bgcolor(điều kiện, { color, opacity }) tô cả cột nền của nến khi điều kiện đúng — hợp để thấy giai đoạn (xu hướng, vùng quá mua…).

indicator({
name: "Nền theo MA 200",
pane: "price",
plot: (d) => {
const ma = ta.sma(d.close, 200);
return {
"MA 200": line(ma, { color: "textMuted", width: 2 }),
"Trên MA 200": bgcolor(d.close.gt(ma), { color: "up", opacity: 0.06 }),
"Dưới MA 200": bgcolor(d.close.lt(ma), { color: "down", opacity: 0.06 }),
};
},
});

Với chỉ báo ngăn riêng, bgcolor tô nền của ngăn đó; muốn tô ngăn giá thì thêm pane: "price" vào tuỳ chọn của đầu ra.

3.4. Tô màu nến​

barcolor(điều kiện, { color }) tô lại chính nến giá khi điều kiện đúng:

indicator({
name: "Nến khối lượng đột biến",
pane: "price",
params: { mult: param.num(2, { min: 1.2, max: 10, step: 0.1, label: "Gấp mấy lần TB 20" }) },
plot: (d, p) => {
const dotBien = d.volume.gt(ta.sma(d.volume, 20).mul(p.mult));
return {
"Đột biến tăng": barcolor(dotBien.and(d.close.gt(d.open)), { color: "ai" }),
"Đột biến giảm": barcolor(dotBien.and(d.close.lt(d.open)), { color: "ref" }),
};
},
});

Nền theo MA 200 và nến khối lượng đột biến tô màu

3.5. Mỗi tín hiệu chỉ một lần​

Điều kiện kiểu "RSI dưới 30" đúng nhiều nến liền, nên dấu dày đặc. Ba cách lọc:

MuốnViết
Chỉ nến đầu tiên điều kiện đúngcond.and(cond.shift(1).fillna(0).not()) — hoặc dùng crossAbove / crossBelow nếu là vượt mức
Không báo lại trong N nếncond.and(cond.shift(1).hold(N).fillna(0).not())
Đã bao lâu từ lần đúng gần nhấtcond.barsSince() (số nến; chưa từng đúng → NaN)
indicator({
name: "Vào vùng quá bán (lần đầu)",
pane: "new",
scale: { range: [0, 100] },
plot: (d) => {
const r = ta.rsi(d.close, 14);
const quaBan = r.lt(30);
const lanDau = quaBan.and(quaBan.shift(1).fillna(0).not());
return {
RSI: line(r, { color: "accent" }),
"30": hline(30, { color: "up" }),
"Vào quá bán": shape(lanDau, { at: "bottom", shape: "triangleUp", color: "up" }),
};
},
});

x.hold(n) giữ trạng thái đúng thêm n nến sau mỗi lần đúng; vì thế cond.shift(1).hold(N) đúng nếu cond đã đúng trong N + 1 nến trước — đảo lại là "không báo lại trong khoảng đó".

3.6. Tự định nghĩa mẫu nến​

Mẫu nến nhấn chìm tăng: nến trước giảm, nến này tăng và thân nến này bao trùm thân nến trước.

indicator({
name: "Nhấn chìm tăng / giảm",
pane: "price",
plot: (d) => {
const o1 = d.open.shift(1), c1 = d.close.shift(1);
const tang = c1.lt(o1).and(d.close.gt(d.open)).and(d.close.gte(o1)).and(d.open.lte(c1));
const giam = c1.gt(o1).and(d.close.lt(d.open)).and(d.close.lte(o1)).and(d.open.gte(c1));
return {
"Nhấn chìm tăng": shape(tang, { at: "below", shape: "triangleUp", color: "up" }),
"Nhấn chìm giảm": shape(giam, { at: "above", shape: "triangleDown", color: "down" }),
};
},
});

Thư viện dựng sẵn hơn 30 mẫu nến (búa, sao mai, ba chàng lính…): ta.run("candle-patterns", {}) trả bull, bear, neutral — xem Thư viện mẫu › Mẫu nến.

Bài tập​

  1. Đánh dấu ★ trên nến khi giá đóng cửa cao nhất 52 phiên (đỉnh mới 52 tuần trên nến ngày).
  2. Tô nền vàng nhạt khi dải Bollinger 20 hẹp nhất 100 nến.
Lời giải 1
indicator({
name: "Đỉnh mới 52 tuần",
pane: "price",
plot: (d) => ({
"Đỉnh mới": shape(d.close.gte(d.close.highest(250)), { at: "above", char: "★", color: "ref" }),
}),
});

x.highest(n) là giá trị lớn nhất của n nến gần nhất kể cả nến này — nên "bằng cao nhất" nghĩa là nến này lập đỉnh.

Lời giải 2
indicator({
name: "Bollinger hẹp nhất",
pane: "price",
plot: (d) => {
const w = ta.bb(d.close, 20, 2).width;
return { "Nén": bgcolor(w.lte(w.lowest(100)), { color: "ref", opacity: 0.12 }) };
},
});

Tiếp theo: Bài 4 — Tham số chỉnh được