Chuyển từ Pine Script
- 🇻🇳 Tiếng Việt
- 🇬🇧 English
- 🇰🇷 한국어
- 🇨🇳 中文
Bạn đã quen viết chỉ báo bằng Pine Script trên TradingView? Trang này đối chiếu các khái niệm để bạn tự viết lại bằng FireAnt Script. FireAnt Terminal không chạy mã Pine; bạn viết lại theo bảng dưới, hoặc mô tả ý tưởng để Copilot viết giúp.
Khác biệt cốt lõi
| Pine Script | FireAnt Script | |
|---|---|---|
| Ngôn ngữ | Ngôn ngữ riêng | JavaScript + bộ hàm (ta, param, đầu ra) |
| Mô hình chạy | Cả script chạy lại ở mỗi nến | plot / signals chạy một lần, lắp phép trên cả chuỗi; logic theo nến viết riêng trong onBar |
| Phép trên chuỗi | Toán tử: close > open, a and b | Phương thức: d.close.gt(d.open), a.and(b) |
Lịch sử x[1] | Cú pháp [ ] | x.shift(1); trong onBar: ctx.bar(1).close, ctx.prev("x", 1), ctx.track("x").at(1) |
Biến var | Giữ qua các nến | state: () => ({ … }) + onBar |
na | Giá trị đặc biệt | NaN; điều kiện có 3 trạng thái (đúng / sai / chưa biết) |
| Nhìn trước | request.security(…, lookahead_on) có thể nhìn trước | Không có cách nào đọc nến sau; khung lớn chỉ lấy nến đã đóng |
Bảng đối chiếu nhanh
| Pine | FireAnt Script |
|---|---|
indicator("Tên", overlay = true) | indicator({ name: "Tên", pane: "price", plot: … }) |
strategy("Tên") | strategy({ name: "Tên", signals: … }) |
input.int(14, "Chu kỳ", minval = 2) | params: { len: param.int(14, { min: 2, label: "Chu kỳ" }) } → p.len |
input.float, input.bool, input.string(options = …) | param.num, param.bool, param.choice |
input.source(close) | param.choice("close", ["close", "open", "high", "low", "hl2", "hlc3", "ohlc4"]) + d.source(p.src) |
input.price, input.time | param.price(null), param.time(null) (chọn trên biểu đồ) |
close, open, high, low, volume, hl2, hlc3, ohlc4 | d.close, d.open, … |
bar_index, time | d.index, d.time (ctx.i, ctx.time trong onBar) |
a + b, a - b, a * b, a / b | a.add(b), a.sub(b), a.mul(b), a.div(b) |
a > b, a >= b, a == b | a.gt(b), a.gte(b), a.eq(b) |
a and b, a or b, not a | a.and(b), a.or(b), a.fillna(0).not() |
c ? x : y | x.where(c, y); hằng: d.const(5).where(c) |
nz(x, 0), na(x), fixnan(x) | x.fillna(0), x.isNaN(), x.ffill() |
ta.sma, ta.ema, ta.wma, ta.hma, ta.rma, ta.rsi | cùng tên: ta.sma(d.close, 20) |
ta.macd(close, 12, 26, 9) → [m, s, h] | ta.macd(d.close, 12, 26, 9) → { macd, signal, hist } |
ta.bb(close, 20, 2) | ta.bb(d.close, 20, 2) → { upper, mid, lower, pctB, width } |
ta.atr(14), ta.supertrend(3, 10) | ta.atr(d, 14), ta.supertrend(d, 10, 3) (thứ tự tham số khác; dir dương = tăng) |
ta.stoch(close, high, low, 14) | ta.stoch(d, 14, 3, 3).k |
ta.highest(high, 20), ta.lowest(low, 20) | d.high.highest(20), d.low.lowest(20) |
ta.change(x, n), ta.roc(x, n) | x.diff(n), ta.roc(x, n) |
ta.crossover(a, b), ta.crossunder(a, b), ta.cross | a.crossAbove(b), a.crossBelow(b), a.cross(b) |
ta.barssince(c), ta.valuewhen(c, x, 0) | c.barsSince(), x.valueWhen(c, 0) |
ta.stdev(x, n), math.sum(x, n), ta.cum(x) | x.rolling(n).std(), x.rolling(n).sum(), x.cumsum() |
ta.vwma, ta.alma, ta.linreg, ta.cmo, ta.tsi… | ta.run("vwma", …), ta.run("alma", …) — danh mục |
plot(x, "Tên", color.blue, 2) | "Tên": line(x, { color: "accent", width: 2 }) |
plot(…, style = plot.style_histogram / _columns / _area / _stepline / _circles) | hist, columns, area, line(…, { step: true }), line(…, { points: "circles" }) |
plot(…, color = c ? color.green : color.red) | line(x, { color: "down", colors: [{ when: c, color: "up" }] }) |
color.new(color.red, 70) | "#F6465D4D" (hai số cuối là độ đục) hoặc opacity: 0.3 |
plotshape(c, style = shape.triangleup, location = location.belowbar) | shape(c, { shape: "triangleUp", at: "below" }) |
plotchar(c, char = "★") | shape(c, { char: "★" }) |
hline(70), fill(p1, p2) | hline(70), fill("Tên 1", "Tên 2") |
bgcolor(c ? color.green : na), barcolor(…) | bgcolor(c, { color: "up" }), barcolor(c, { color: … }) |
plotcandle(o, h, l, c) | candles({ open, high, low, close }) |
request.security(syminfo.tickerid, "W", close) | d.tf("1W").close |
alertcondition(c, "Tên", "Lời nhắn") | alerts: (d, p) => ({ "Tên": { when: c, message: "Lời nhắn" } }) |
var x = 0 + x := x + 1 | state: () => ({ x: 0 }) + onBar: (ctx, s) => { s.x += 1; … } |
label.new, line.new, box.new, table.new | ctx.draw.label, ctx.draw.line, ctx.draw.box, ctx.table (trong onBar) |
log.info(…) | ctx.log(…) |
barstate.isconfirmed, barstate.isrealtime | ctx.closed, ctx.realtime |
strategy.entry("L", strategy.long, when = c) / strategy.close("L", when = x) | signals: (d) => ({ entry: c, exit: x }) |
strategy.exit(stop = …, limit = …, trail_percent = …) | risk: { stopLoss, takeProfit, trailingStop } (tỷ lệ) |
strategy(initial_capital, commission_value, pyramiding) | portfolio: { capital, pyramiding }, costs: { fees } |
Ví dụ 1 — đường trung bình và RSI
- Pine Script
- FireAnt Script
//@version=5
indicator("RSI có mức", overlay = false)
len = input.int(14, "Chu kỳ", minval = 2)
r = ta.rsi(close, len)
plot(r, "RSI", color = r > 70 ? color.red : color.blue)
hline(70)
hline(30)
indicator({
name: "RSI có mức",
pane: "new",
params: { len: param.int(14, { min: 2, label: "Chu kỳ" }) },
plot: (d, p) => {
const r = ta.rsi(d.close, p.len);
return {
RSI: line(r, { color: "accent", colors: [{ when: r.gt(70), color: "down" }] }),
"70": hline(70),
"30": hline(30),
};
},
});
Ví dụ 2 — tín hiệu cắt nhau và cảnh báo
- Pine Script
- FireAnt Script
//@version=5
indicator("EMA cắt", overlay = true)
f = ta.ema(close, 20)
s = ta.ema(close, 50)
plot(f)
plot(s)
up = ta.crossover(f, s)
plotshape(up, style = shape.triangleup, location = location.belowbar, color = color.green)
alertcondition(up, "EMA cắt lên", "EMA 20 cắt lên EMA 50")
indicator({
name: "EMA cắt",
pane: "price",
plot: (d) => {
const f = ta.ema(d.close, 20);
const s = ta.ema(d.close, 50);
return {
"EMA 20": line(f),
"EMA 50": line(s),
"Cắt lên": shape(f.crossAbove(s), { shape: "triangleUp", at: "below", color: "up" }),
};
},
alerts: (d) => ({
"EMA cắt lên": { when: ta.ema(d.close, 20).crossAbove(ta.ema(d.close, 50)), message: "EMA 20 cắt lên EMA 50" },
}),
});
Ví dụ 3 — biến var và đếm
- Pine Script
- FireAnt Script
//@version=5
indicator("Đếm nến tăng")
var int dem = 0
dem := close > open ? dem + 1 : 0
plot(dem, style = plot.style_columns)
indicator({
name: "Đếm nến tăng",
state: () => ({ dem: 0 }),
onBar: (ctx, s) => {
s.dem = ctx.close > ctx.open ? s.dem + 1 : 0;
return { dem: s.dem };
},
plot: (d, p, o) => ({ "Đếm": columns(o.dem) }),
});
Riêng ví dụ này còn viết được không cần onBar: d.close.gt(d.open).fillna(0).not().barsSince() là số nến kể từ nến không tăng gần nhất.
Ví dụ 4 — dữ liệu khung tuần
- Pine Script
- FireAnt Script
//@version=5
indicator("EMA tuần", overlay = true)
w = request.security(syminfo.tickerid, "W", ta.ema(close, 20))
plot(w)
indicator({
name: "EMA tuần",
pane: "price",
plot: (d) => ({ "EMA 20 tuần": line(ta.ema(d.tf("1W").close, 20), { step: true }) }),
});
d.tf("1W") chỉ lấy nến tuần đã đóng (như request.security tắt nhìn trước); trong tuần đang chạy, giá trị là của tuần trước. Muốn cả nến tuần đang chạy: d.tf("1W", { forming: true }).
Ví dụ 5 — chiến lược có dừng lỗ
- Pine Script
- FireAnt Script
//@version=5
strategy("RSI 2", overlay = true, initial_capital = 100000000)
r = ta.rsi(close, 2)
if r < 10 and close > ta.sma(close, 200)
strategy.entry("L", strategy.long)
if r > 70
strategy.close("L")
strategy.exit("SL", "L", stop = strategy.position_avg_price * 0.92)
strategy({
name: "RSI 2",
signals: (d) => {
const r = ta.rsi(d.close, 2);
return { entry: r.lt(10).and(d.close.gt(ta.sma(d.close, 200))), exit: r.gt(70) };
},
risk: { stopLoss: 0.08 },
portfolio: { capital: 100000000 },
});
Kết quả kiểm thử sẽ khác TradingView vì FireAnt áp luật thị trường Việt Nam (T+2, lô 100, biên độ, trần / sàn, phí và thuế bán) và khớp lệnh ở giá mở cửa nến sau.
Những điểm hay vấp
- Quên đổi toán tử:
close > openphải thànhd.close.gt(d.open)— xem Lỗi thường gặp. - Mọi thứ không phải
onBar: trong Pine dòng nào cũng chạy mỗi nến; trong FireAnt Script, code trongplotchạy một lần.iftrongplotrẽ nhánh khi dựng (theo tham số), không theo từng nến — điều kiện theo nến viết bằng.where()hoặc trongonBar. - Thứ tự tham số khác:
ta.supertrend(d, chuKy, heSo)(Pine: hệ số trước),ta.atr(d, n)nhậnd. - Thang của một số chỉ báo khác: TSI của thư viện nhân 100; chiều Supertrend ngược dấu với Pine.
- Mảng, kiểu tự định nghĩa, thư viện (
import) không có — dùng mảng JavaScript trongstate, hàm JavaScript.
Used to writing indicators in Pine Script on TradingView? This page maps the concepts so you can rewrite them in FireAnt Script yourself. FireAnt Terminal does not run Pine code; rewrite it using the tables below, or describe your idea and let Copilot write it for you.
Core differences
| Pine Script | FireAnt Script | |
|---|---|---|
| Language | Its own language | JavaScript + a function set (ta, param, outputs) |
| Execution model | The whole script reruns on every bar | plot / signals run once, assembling operations on whole series; per-bar logic is written separately in onBar |
| Series operations | Operators: close > open, a and b | Methods: d.close.gt(d.open), a.and(b) |
History x[1] | [ ] syntax | x.shift(1); in onBar: ctx.bar(1).close, ctx.prev("x", 1), ctx.track("x").at(1) |
var variables | Persist across bars | state: () => ({ … }) + onBar |
na | A special value | NaN; conditions have 3 states (true / false / unknown) |
| Look-ahead | request.security(…, lookahead_on) can look ahead | There is no way to read later bars; higher timeframes only take closed bars |
Quick mapping table
| Pine | FireAnt Script |
|---|---|
indicator("Tên", overlay = true) | indicator({ name: "Tên", pane: "price", plot: … }) |
strategy("Tên") | strategy({ name: "Tên", signals: … }) |
input.int(14, "Chu kỳ", minval = 2) | params: { len: param.int(14, { min: 2, label: "Chu kỳ" }) } → p.len |
input.float, input.bool, input.string(options = …) | param.num, param.bool, param.choice |
input.source(close) | param.choice("close", ["close", "open", "high", "low", "hl2", "hlc3", "ohlc4"]) + d.source(p.src) |
input.price, input.time | param.price(null), param.time(null) (picked on the chart) |
close, open, high, low, volume, hl2, hlc3, ohlc4 | d.close, d.open, … |
bar_index, time | d.index, d.time (ctx.i, ctx.time in onBar) |
a + b, a - b, a * b, a / b | a.add(b), a.sub(b), a.mul(b), a.div(b) |
a > b, a >= b, a == b | a.gt(b), a.gte(b), a.eq(b) |
a and b, a or b, not a | a.and(b), a.or(b), a.fillna(0).not() |
c ? x : y | x.where(c, y); constant: d.const(5).where(c) |
nz(x, 0), na(x), fixnan(x) | x.fillna(0), x.isNaN(), x.ffill() |
ta.sma, ta.ema, ta.wma, ta.hma, ta.rma, ta.rsi | same names: ta.sma(d.close, 20) |
ta.macd(close, 12, 26, 9) → [m, s, h] | ta.macd(d.close, 12, 26, 9) → { macd, signal, hist } |
ta.bb(close, 20, 2) | ta.bb(d.close, 20, 2) → { upper, mid, lower, pctB, width } |
ta.atr(14), ta.supertrend(3, 10) | ta.atr(d, 14), ta.supertrend(d, 10, 3) (different parameter order; positive dir = up) |
ta.stoch(close, high, low, 14) | ta.stoch(d, 14, 3, 3).k |
ta.highest(high, 20), ta.lowest(low, 20) | d.high.highest(20), d.low.lowest(20) |
ta.change(x, n), ta.roc(x, n) | x.diff(n), ta.roc(x, n) |
ta.crossover(a, b), ta.crossunder(a, b), ta.cross | a.crossAbove(b), a.crossBelow(b), a.cross(b) |
ta.barssince(c), ta.valuewhen(c, x, 0) | c.barsSince(), x.valueWhen(c, 0) |
ta.stdev(x, n), math.sum(x, n), ta.cum(x) | x.rolling(n).std(), x.rolling(n).sum(), x.cumsum() |
ta.vwma, ta.alma, ta.linreg, ta.cmo, ta.tsi… | ta.run("vwma", …), ta.run("alma", …) — catalog |
plot(x, "Tên", color.blue, 2) | "Tên": line(x, { color: "accent", width: 2 }) |
plot(…, style = plot.style_histogram / _columns / _area / _stepline / _circles) | hist, columns, area, line(…, { step: true }), line(…, { points: "circles" }) |
plot(…, color = c ? color.green : color.red) | line(x, { color: "down", colors: [{ when: c, color: "up" }] }) |
color.new(color.red, 70) | "#F6465D4D" (the last two digits are opacity) or opacity: 0.3 |
plotshape(c, style = shape.triangleup, location = location.belowbar) | shape(c, { shape: "triangleUp", at: "below" }) |
plotchar(c, char = "★") | shape(c, { char: "★" }) |
hline(70), fill(p1, p2) | hline(70), fill("Tên 1", "Tên 2") |
bgcolor(c ? color.green : na), barcolor(…) | bgcolor(c, { color: "up" }), barcolor(c, { color: … }) |
plotcandle(o, h, l, c) | candles({ open, high, low, close }) |
request.security(syminfo.tickerid, "W", close) | d.tf("1W").close |
alertcondition(c, "Tên", "Lời nhắn") | alerts: (d, p) => ({ "Tên": { when: c, message: "Lời nhắn" } }) |
var x = 0 + x := x + 1 | state: () => ({ x: 0 }) + onBar: (ctx, s) => { s.x += 1; … } |
label.new, line.new, box.new, table.new | ctx.draw.label, ctx.draw.line, ctx.draw.box, ctx.table (in onBar) |
log.info(…) | ctx.log(…) |
barstate.isconfirmed, barstate.isrealtime | ctx.closed, ctx.realtime |
strategy.entry("L", strategy.long, when = c) / strategy.close("L", when = x) | signals: (d) => ({ entry: c, exit: x }) |
strategy.exit(stop = …, limit = …, trail_percent = …) | risk: { stopLoss, takeProfit, trailingStop } (ratios) |
strategy(initial_capital, commission_value, pyramiding) | portfolio: { capital, pyramiding }, costs: { fees } |
Example 1 — moving average and RSI
- Pine Script
- FireAnt Script
//@version=5
indicator("RSI có mức", overlay = false)
len = input.int(14, "Chu kỳ", minval = 2)
r = ta.rsi(close, len)
plot(r, "RSI", color = r > 70 ? color.red : color.blue)
hline(70)
hline(30)
indicator({
name: "RSI có mức",
pane: "new",
params: { len: param.int(14, { min: 2, label: "Chu kỳ" }) },
plot: (d, p) => {
const r = ta.rsi(d.close, p.len);
return {
RSI: line(r, { color: "accent", colors: [{ when: r.gt(70), color: "down" }] }),
"70": hline(70),
"30": hline(30),
};
},
});
Example 2 — crossover signals and alerts
- Pine Script
- FireAnt Script
//@version=5
indicator("EMA cắt", overlay = true)
f = ta.ema(close, 20)
s = ta.ema(close, 50)
plot(f)
plot(s)
up = ta.crossover(f, s)
plotshape(up, style = shape.triangleup, location = location.belowbar, color = color.green)
alertcondition(up, "EMA cắt lên", "EMA 20 cắt lên EMA 50")
indicator({
name: "EMA cắt",
pane: "price",
plot: (d) => {
const f = ta.ema(d.close, 20);
const s = ta.ema(d.close, 50);
return {
"EMA 20": line(f),
"EMA 50": line(s),
"Cắt lên": shape(f.crossAbove(s), { shape: "triangleUp", at: "below", color: "up" }),
};
},
alerts: (d) => ({
"EMA cắt lên": { when: ta.ema(d.close, 20).crossAbove(ta.ema(d.close, 50)), message: "EMA 20 cắt lên EMA 50" },
}),
});
Example 3 — var variables and counting
- Pine Script
- FireAnt Script
//@version=5
indicator("Đếm nến tăng")
var int dem = 0
dem := close > open ? dem + 1 : 0
plot(dem, style = plot.style_columns)
indicator({
name: "Đếm nến tăng",
state: () => ({ dem: 0 }),
onBar: (ctx, s) => {
s.dem = ctx.close > ctx.open ? s.dem + 1 : 0;
return { dem: s.dem };
},
plot: (d, p, o) => ({ "Đếm": columns(o.dem) }),
});
This particular example can also be written without onBar: d.close.gt(d.open).fillna(0).not().barsSince() is the number of bars since the most recent non-up bar.
Example 4 — weekly timeframe data
- Pine Script
- FireAnt Script
//@version=5
indicator("EMA tuần", overlay = true)
w = request.security(syminfo.tickerid, "W", ta.ema(close, 20))
plot(w)
indicator({
name: "EMA tuần",
pane: "price",
plot: (d) => ({ "EMA 20 tuần": line(ta.ema(d.tf("1W").close, 20), { step: true }) }),
});
d.tf("1W") only takes closed weekly bars (like request.security with look-ahead off); during the current week, the value is last week's. To include the forming weekly bar: d.tf("1W", { forming: true }).
Example 5 — strategy with a stop loss
- Pine Script
- FireAnt Script
//@version=5
strategy("RSI 2", overlay = true, initial_capital = 100000000)
r = ta.rsi(close, 2)
if r < 10 and close > ta.sma(close, 200)
strategy.entry("L", strategy.long)
if r > 70
strategy.close("L")
strategy.exit("SL", "L", stop = strategy.position_avg_price * 0.92)
strategy({
name: "RSI 2",
signals: (d) => {
const r = ta.rsi(d.close, 2);
return { entry: r.lt(10).and(d.close.gt(ta.sma(d.close, 200))), exit: r.gt(70) };
},
risk: { stopLoss: 0.08 },
portfolio: { capital: 100000000 },
});
Test results will differ from TradingView because FireAnt applies Vietnamese market rules (T+2, 100-share lots, price limits, ceiling / floor, fees and sales tax) and fills orders at the next bar's open.
Common pitfalls
- Forgetting to convert operators:
close > openmust becomed.close.gt(d.open)— see Common errors. - Everything outside
onBar: in Pine every line runs on every bar; in FireAnt Script, code inplotruns once. Anifinplotbranches at build time (based on parameters), not per bar — per-bar conditions are written with.where()or insideonBar. - Different parameter order:
ta.supertrend(d, chuKy, heSo)(Pine: multiplier first), andta.atr(d, n)takesd. - Some indicators use a different scale: the library's TSI is multiplied by 100; Supertrend direction has the opposite sign from Pine.
- Arrays, user-defined types and libraries (
import) are not available — use JavaScript arrays instateand JavaScript functions.
TradingView에서 Pine Script로 지표를 작성하는 데 익숙하신가요? 이 페이지는 개념을 대조해 FireAnt Script로 직접 다시 작성할 수 있도록 돕습니다. FireAnt Terminal은 Pine 코드를 실행하지 않습니다. 아래 표를 보고 다시 작성하거나, 아이디어를 설명해 Copilot이 대신 작성하도록 하세요.
핵심 차이
| Pine Script | FireAnt Script | |
|---|---|---|
| 언어 | 자체 언어 | JavaScript + 함수 모음(ta, param, 출력) |
| 실행 모델 | 스크립트 전체가 봉마다 다시 실행 | plot / signals는 한 번 실행되어 시리즈 전체에 대한 연산을 조립합니다. 봉 단위 로직은 onBar에 따로 작성 |
| 시리즈 연산 | 연산자: close > open, a and b | 메서드: d.close.gt(d.open), a.and(b) |
과거 값 x[1] | [ ] 문법 | x.shift(1); onBar 안에서는 ctx.bar(1).close, ctx.prev("x", 1), ctx.track("x").at(1) |
var 변수 | 봉을 넘어 유지 | state: () => ({ … }) + onBar |
na | 특수 값 | NaN; 조건은 3가지 상태(참 / 거짓 / 미정) |
| 미래 참조 | request.security(…, lookahead_on)로 미래를 볼 수 있음 | 다음 봉을 읽을 방법이 없음. 큰 주기는 마감된 봉만 가져옴 |
빠른 대조표
| Pine | FireAnt Script |
|---|---|
indicator("Tên", overlay = true) | indicator({ name: "Tên", pane: "price", plot: … }) |
strategy("Tên") | strategy({ name: "Tên", signals: … }) |
input.int(14, "Chu kỳ", minval = 2) | params: { len: param.int(14, { min: 2, label: "Chu kỳ" }) } → p.len |
input.float, input.bool, input.string(options = …) | param.num, param.bool, param.choice |
input.source(close) | param.choice("close", ["close", "open", "high", "low", "hl2", "hlc3", "ohlc4"]) + d.source(p.src) |
input.price, input.time | param.price(null), param.time(null)(차트에서 선택) |
close, open, high, low, volume, hl2, hlc3, ohlc4 | d.close, d.open, … |
bar_index, time | d.index, d.time(onBar 안에서는 ctx.i, ctx.time) |
a + b, a - b, a * b, a / b | a.add(b), a.sub(b), a.mul(b), a.div(b) |
a > b, a >= b, a == b | a.gt(b), a.gte(b), a.eq(b) |
a and b, a or b, not a | a.and(b), a.or(b), a.fillna(0).not() |
c ? x : y | x.where(c, y); 상수: d.const(5).where(c) |
nz(x, 0), na(x), fixnan(x) | x.fillna(0), x.isNaN(), x.ffill() |
ta.sma, ta.ema, ta.wma, ta.hma, ta.rma, ta.rsi | 같은 이름: ta.sma(d.close, 20) |
ta.macd(close, 12, 26, 9) → [m, s, h] | ta.macd(d.close, 12, 26, 9) → { macd, signal, hist } |
ta.bb(close, 20, 2) | ta.bb(d.close, 20, 2) → { upper, mid, lower, pctB, width } |
ta.atr(14), ta.supertrend(3, 10) | ta.atr(d, 14), ta.supertrend(d, 10, 3)(파라미터 순서가 다름; dir 양수 = 상승) |
ta.stoch(close, high, low, 14) | ta.stoch(d, 14, 3, 3).k |
ta.highest(high, 20), ta.lowest(low, 20) | d.high.highest(20), d.low.lowest(20) |
ta.change(x, n), ta.roc(x, n) | x.diff(n), ta.roc(x, n) |
ta.crossover(a, b), ta.crossunder(a, b), ta.cross | a.crossAbove(b), a.crossBelow(b), a.cross(b) |
ta.barssince(c), ta.valuewhen(c, x, 0) | c.barsSince(), x.valueWhen(c, 0) |
ta.stdev(x, n), math.sum(x, n), ta.cum(x) | x.rolling(n).std(), x.rolling(n).sum(), x.cumsum() |
ta.vwma, ta.alma, ta.linreg, ta.cmo, ta.tsi… | ta.run("vwma", …), ta.run("alma", …) — 목록 |
plot(x, "Tên", color.blue, 2) | "Tên": line(x, { color: "accent", width: 2 }) |
plot(…, style = plot.style_histogram / _columns / _area / _stepline / _circles) | hist, columns, area, line(…, { step: true }), line(…, { points: "circles" }) |
plot(…, color = c ? color.green : color.red) | line(x, { color: "down", colors: [{ when: c, color: "up" }] }) |
color.new(color.red, 70) | "#F6465D4D"(마지막 두 자리가 불투명도) 또는 opacity: 0.3 |
plotshape(c, style = shape.triangleup, location = location.belowbar) | shape(c, { shape: "triangleUp", at: "below" }) |
plotchar(c, char = "★") | shape(c, { char: "★" }) |
hline(70), fill(p1, p2) | hline(70), fill("Tên 1", "Tên 2") |
bgcolor(c ? color.green : na), barcolor(…) | bgcolor(c, { color: "up" }), barcolor(c, { color: … }) |
plotcandle(o, h, l, c) | candles({ open, high, low, close }) |
request.security(syminfo.tickerid, "W", close) | d.tf("1W").close |
alertcondition(c, "Tên", "Lời nhắn") | alerts: (d, p) => ({ "Tên": { when: c, message: "Lời nhắn" } }) |
var x = 0 + x := x + 1 | state: () => ({ x: 0 }) + onBar: (ctx, s) => { s.x += 1; … } |
label.new, line.new, box.new, table.new | ctx.draw.label, ctx.draw.line, ctx.draw.box, ctx.table(onBar 안에서) |
log.info(…) | ctx.log(…) |
barstate.isconfirmed, barstate.isrealtime | ctx.closed, ctx.realtime |
strategy.entry("L", strategy.long, when = c) / strategy.close("L", when = x) | signals: (d) => ({ entry: c, exit: x }) |
strategy.exit(stop = …, limit = …, trail_percent = …) | risk: { stopLoss, takeProfit, trailingStop }(비율) |
strategy(initial_capital, commission_value, pyramiding) | portfolio: { capital, pyramiding }, costs: { fees } |
예제 1 — 이동평균과 RSI
- Pine Script
- FireAnt Script
//@version=5
indicator("RSI có mức", overlay = false)
len = input.int(14, "Chu kỳ", minval = 2)
r = ta.rsi(close, len)
plot(r, "RSI", color = r > 70 ? color.red : color.blue)
hline(70)
hline(30)
indicator({
name: "RSI có mức",
pane: "new",
params: { len: param.int(14, { min: 2, label: "Chu kỳ" }) },
plot: (d, p) => {
const r = ta.rsi(d.close, p.len);
return {
RSI: line(r, { color: "accent", colors: [{ when: r.gt(70), color: "down" }] }),
"70": hline(70),
"30": hline(30),
};
},
});
예제 2 — 교차 신호와 알림
- Pine Script
- FireAnt Script
//@version=5
indicator("EMA cắt", overlay = true)
f = ta.ema(close, 20)
s = ta.ema(close, 50)
plot(f)
plot(s)
up = ta.crossover(f, s)
plotshape(up, style = shape.triangleup, location = location.belowbar, color = color.green)
alertcondition(up, "EMA cắt lên", "EMA 20 cắt lên EMA 50")
indicator({
name: "EMA cắt",
pane: "price",
plot: (d) => {
const f = ta.ema(d.close, 20);
const s = ta.ema(d.close, 50);
return {
"EMA 20": line(f),
"EMA 50": line(s),
"Cắt lên": shape(f.crossAbove(s), { shape: "triangleUp", at: "below", color: "up" }),
};
},
alerts: (d) => ({
"EMA cắt lên": { when: ta.ema(d.close, 20).crossAbove(ta.ema(d.close, 50)), message: "EMA 20 cắt lên EMA 50" },
}),
});
예제 3 — var 변수와 카운트
- Pine Script
- FireAnt Script
//@version=5
indicator("Đếm nến tăng")
var int dem = 0
dem := close > open ? dem + 1 : 0
plot(dem, style = plot.style_columns)
indicator({
name: "Đếm nến tăng",
state: () => ({ dem: 0 }),
onBar: (ctx, s) => {
s.dem = ctx.close > ctx.open ? s.dem + 1 : 0;
return { dem: s.dem };
},
plot: (d, p, o) => ({ "Đếm": columns(o.dem) }),
});
이 예제는 onBar 없이도 작성할 수 있습니다: d.close.gt(d.open).fillna(0).not().barsSince()는 가장 최근의 비상승 봉 이후 봉 수입니다.
예제 4 — 주간 주기 데이터
- Pine Script
- FireAnt Script
//@version=5
indicator("EMA tuần", overlay = true)
w = request.security(syminfo.tickerid, "W", ta.ema(close, 20))
plot(w)
indicator({
name: "EMA tuần",
pane: "price",
plot: (d) => ({ "EMA 20 tuần": line(ta.ema(d.tf("1W").close, 20), { step: true }) }),
});
d.tf("1W")는 마감된 주봉만 가져옵니다(미래 참조를 끈 request.security와 같음). 진행 중인 주에는 지난주 값이 표시됩니다. 진행 중인 주봉까지 원하면: d.tf("1W", { forming: true }).
예제 5 — 손절이 있는 전략
- Pine Script
- FireAnt Script
//@version=5
strategy("RSI 2", overlay = true, initial_capital = 100000000)
r = ta.rsi(close, 2)
if r < 10 and close > ta.sma(close, 200)
strategy.entry("L", strategy.long)
if r > 70
strategy.close("L")
strategy.exit("SL", "L", stop = strategy.position_avg_price * 0.92)
strategy({
name: "RSI 2",
signals: (d) => {
const r = ta.rsi(d.close, 2);
return { entry: r.lt(10).and(d.close.gt(ta.sma(d.close, 200))), exit: r.gt(70) };
},
risk: { stopLoss: 0.08 },
portfolio: { capital: 100000000 },
});
FireAnt는 베트남 시장 규칙(T+2, 100주 단위, 가격 제한폭, 상한가 / 하한가, 수수료와 매도세)을 적용하고 다음 봉의 시가에 체결하므로 테스트 결과가 TradingView와 다릅니다.
자주 걸려 넘어지는 부분
- 연산자 변환을 잊음:
close > open은d.close.gt(d.open)이 되어야 합니다 — 자주 발생하는 오류를 참고하세요. onBar가 아닌 모든 코드: Pine에서는 모든 줄이 봉마다 실행되지만, FireAnt Script에서plot안의 코드는 한 번 실행됩니다.plot안의if는 봉마다가 아니라 구성 시점에(파라미터에 따라) 분기합니다. 봉 단위 조건은.where()로 작성하거나onBar안에 작성하세요.- 파라미터 순서가 다름:
ta.supertrend(d, chuKy, heSo)(Pine은 계수가 먼저),ta.atr(d, n)은d를 받습니다. - 일부 지표의 척도가 다름: 라이브러리의 TSI는 100을 곱합니다. 슈퍼트렌드의 방향 부호는 Pine과 반대입니다.
- 배열, 사용자 정의 타입, 라이브러리(
import) 는 없습니다 —state안의 JavaScript 배열과 JavaScript 함수를 사용하세요.
您已习惯在 TradingView 上用 Pine Script 编写指标?本页对照各项概念,帮助您用 FireAnt Script 自行改写。FireAnt Terminal 不运行 Pine 代码;请按下表改写,或描述您的想法让 Copilot 帮您编写。
核心差异
| Pine Script | FireAnt Script | |
|---|---|---|
| 语言 | 专用语言 | JavaScript + 函数集(ta、param、输出) |
| 运行模型 | 整个脚本在每根 K 线上重新运行 | plot / signals 只运行一次,在整条序列上组装运算;逐根 K 线的逻辑单独写在 onBar 中 |
| 序列运算 | 运算符:close > open、a and b | 方法:d.close.gt(d.open)、a.and(b) |
历史 x[1] | [ ] 语法 | x.shift(1);在 onBar 中:ctx.bar(1).close、ctx.prev("x", 1)、ctx.track("x").at(1) |
var 变量 | 跨 K 线保留 | state: () => ({ … }) + onBar |
na | 特殊值 | NaN;条件有 3 种状态(真 / 假 / 未知) |
| 预知未来 | request.security(…, lookahead_on) 可以预知未来 | 没有任何方法读取之后的 K 线;大周期只取已收盘的 K 线 |
快速对照表
| Pine | FireAnt Script |
|---|---|
indicator("Tên", overlay = true) | indicator({ name: "Tên", pane: "price", plot: … }) |
strategy("Tên") | strategy({ name: "Tên", signals: … }) |
input.int(14, "Chu kỳ", minval = 2) | params: { len: param.int(14, { min: 2, label: "Chu kỳ" }) } → p.len |
input.float、input.bool、input.string(options = …) | param.num、param.bool、param.choice |
input.source(close) | param.choice("close", ["close", "open", "high", "low", "hl2", "hlc3", "ohlc4"]) + d.source(p.src) |
input.price、input.time | param.price(null)、param.time(null)(在图表上选取) |
close、open、high、low、volume、hl2、hlc3、ohlc4 | d.close、d.open、… |
bar_index、time | d.index、d.time(在 onBar 中为 ctx.i、ctx.time) |
a + b、a - b、a * b、a / b | a.add(b)、a.sub(b)、a.mul(b)、a.div(b) |
a > b、a >= b、a == b | a.gt(b)、a.gte(b)、a.eq(b) |
a and b、a or b、not a | a.and(b)、a.or(b)、a.fillna(0).not() |
c ? x : y | x.where(c, y);常量:d.const(5).where(c) |
nz(x, 0)、na(x)、fixnan(x) | x.fillna(0)、x.isNaN()、x.ffill() |
ta.sma、ta.ema、ta.wma、ta.hma、ta.rma、ta.rsi | 同名:ta.sma(d.close, 20) |
ta.macd(close, 12, 26, 9) → [m, s, h] | ta.macd(d.close, 12, 26, 9) → { macd, signal, hist } |
ta.bb(close, 20, 2) | ta.bb(d.close, 20, 2) → { upper, mid, lower, pctB, width } |
ta.atr(14)、ta.supertrend(3, 10) | ta.atr(d, 14)、ta.supertrend(d, 10, 3)(参数顺序不同;dir 为正 = 上涨) |
ta.stoch(close, high, low, 14) | ta.stoch(d, 14, 3, 3).k |
ta.highest(high, 20)、ta.lowest(low, 20) | d.high.highest(20)、d.low.lowest(20) |
ta.change(x, n)、ta.roc(x, n) | x.diff(n)、ta.roc(x, n) |
ta.crossover(a, b)、ta.crossunder(a, b)、ta.cross | a.crossAbove(b)、a.crossBelow(b)、a.cross(b) |
ta.barssince(c)、ta.valuewhen(c, x, 0) | c.barsSince()、x.valueWhen(c, 0) |
ta.stdev(x, n)、math.sum(x, n)、ta.cum(x) | x.rolling(n).std()、x.rolling(n).sum()、x.cumsum() |
ta.vwma、ta.alma、ta.linreg、ta.cmo、ta.tsi… | ta.run("vwma", …)、ta.run("alma", …)——目录 |
plot(x, "Tên", color.blue, 2) | "Tên": line(x, { color: "accent", width: 2 }) |
plot(…, style = plot.style_histogram / _columns / _area / _stepline / _circles) | hist、columns、area、line(…, { step: true })、line(…, { points: "circles" }) |
plot(…, color = c ? color.green : color.red) | line(x, { color: "down", colors: [{ when: c, color: "up" }] }) |
color.new(color.red, 70) | "#F6465D4D"(最后两位是不透明度)或 opacity: 0.3 |
plotshape(c, style = shape.triangleup, location = location.belowbar) | shape(c, { shape: "triangleUp", at: "below" }) |
plotchar(c, char = "★") | shape(c, { char: "★" }) |
hline(70)、fill(p1, p2) | hline(70)、fill("Tên 1", "Tên 2") |
bgcolor(c ? color.green : na)、barcolor(…) | bgcolor(c, { color: "up" })、barcolor(c, { color: … }) |
plotcandle(o, h, l, c) | candles({ open, high, low, close }) |
request.security(syminfo.tickerid, "W", close) | d.tf("1W").close |
alertcondition(c, "Tên", "Lời nhắn") | alerts: (d, p) => ({ "Tên": { when: c, message: "Lời nhắn" } }) |
var x = 0 + x := x + 1 | state: () => ({ x: 0 }) + onBar: (ctx, s) => { s.x += 1; … } |
label.new、line.new、box.new、table.new | ctx.draw.label、ctx.draw.line、ctx.draw.box、ctx.table(在 onBar 中) |
log.info(…) | ctx.log(…) |
barstate.isconfirmed、barstate.isrealtime | ctx.closed、ctx.realtime |
strategy.entry("L", strategy.long, when = c) / strategy.close("L", when = x) | signals: (d) => ({ entry: c, exit: x }) |
strategy.exit(stop = …, limit = …, trail_percent = …) | risk: { stopLoss, takeProfit, trailingStop }(比例) |
strategy(initial_capital, commission_value, pyramiding) | portfolio: { capital, pyramiding }、costs: { fees } |
示例 1——均线与 RSI
- Pine Script
- FireAnt Script
//@version=5
indicator("RSI có mức", overlay = false)
len = input.int(14, "Chu kỳ", minval = 2)
r = ta.rsi(close, len)
plot(r, "RSI", color = r > 70 ? color.red : color.blue)
hline(70)
hline(30)
indicator({
name: "RSI có mức",
pane: "new",
params: { len: param.int(14, { min: 2, label: "Chu kỳ" }) },
plot: (d, p) => {
const r = ta.rsi(d.close, p.len);
return {
RSI: line(r, { color: "accent", colors: [{ when: r.gt(70), color: "down" }] }),
"70": hline(70),
"30": hline(30),
};
},
});
示例 2——交叉信号与提醒
- Pine Script
- FireAnt Script
//@version=5
indicator("EMA cắt", overlay = true)
f = ta.ema(close, 20)
s = ta.ema(close, 50)
plot(f)
plot(s)
up = ta.crossover(f, s)
plotshape(up, style = shape.triangleup, location = location.belowbar, color = color.green)
alertcondition(up, "EMA cắt lên", "EMA 20 cắt lên EMA 50")
indicator({
name: "EMA cắt",
pane: "price",
plot: (d) => {
const f = ta.ema(d.close, 20);
const s = ta.ema(d.close, 50);
return {
"EMA 20": line(f),
"EMA 50": line(s),
"Cắt lên": shape(f.crossAbove(s), { shape: "triangleUp", at: "below", color: "up" }),
};
},
alerts: (d) => ({
"EMA cắt lên": { when: ta.ema(d.close, 20).crossAbove(ta.ema(d.close, 50)), message: "EMA 20 cắt lên EMA 50" },
}),
});
示例 3——var 变量与计数
- Pine Script
- FireAnt Script
//@version=5
indicator("Đếm nến tăng")
var int dem = 0
dem := close > open ? dem + 1 : 0
plot(dem, style = plot.style_columns)
indicator({
name: "Đếm nến tăng",
state: () => ({ dem: 0 }),
onBar: (ctx, s) => {
s.dem = ctx.close > ctx.open ? s.dem + 1 : 0;
return { dem: s.dem };
},
plot: (d, p, o) => ({ "Đếm": columns(o.dem) }),
});
这个示例也可以不用 onBar 来写:d.close.gt(d.open).fillna(0).not().barsSince() 就是自最近一根非上涨 K 线以来的 K 线数。
示例 4—— 周线周期数据
- Pine Script
- FireAnt Script
//@version=5
indicator("EMA tuần", overlay = true)
w = request.security(syminfo.tickerid, "W", ta.ema(close, 20))
plot(w)
indicator({
name: "EMA tuần",
pane: "price",
plot: (d) => ({ "EMA 20 tuần": line(ta.ema(d.tf("1W").close, 20), { step: true }) }),
});
d.tf("1W") 只取已收盘的周 K 线(相当于关闭预知未来的 request.security);在进行中的这一周,取值为上一周的值。如果想包含正在形成的周 K 线:d.tf("1W", { forming: true })。
示例 5——带止损的策略
- Pine Script
- FireAnt Script
//@version=5
strategy("RSI 2", overlay = true, initial_capital = 100000000)
r = ta.rsi(close, 2)
if r < 10 and close > ta.sma(close, 200)
strategy.entry("L", strategy.long)
if r > 70
strategy.close("L")
strategy.exit("SL", "L", stop = strategy.position_avg_price * 0.92)
strategy({
name: "RSI 2",
signals: (d) => {
const r = ta.rsi(d.close, 2);
return { entry: r.lt(10).and(d.close.gt(ta.sma(d.close, 200))), exit: r.gt(70) };
},
risk: { stopLoss: 0.08 },
portfolio: { capital: 100000000 },
});
测试结果会与 TradingView 不同,因为 FireAnt 采用越南市场规则(T+2、100 股一手、涨跌幅限制、涨停价 / 跌停价、卖出手续费和税费),并以下一根 K 线的开盘价成交。
常见绊脚点
- 忘记替换运算符:
close > open必须改为d.close.gt(d.open)——参见 常见错误。 - 凡不在
onBar中的代码:在 Pine 中每一行都在每根 K 线上运行;在 FireAnt Script 中,plot里的代码只运行一次。plot中的if是在构建时(按参数)分支,而不是逐根 K 线分支——逐根 K 线的条件请用.where()或写在onBar中。 - 参数顺序不同:
ta.supertrend(d, chuKy, heSo)(Pine:系数在前),ta.atr(d, n)接收d。 - 部分指标的刻度不同:库中的 TSI 乘以 100;Supertrend 的方向与 Pine 符号相反。
- 没有数组、自定义类型、库(
import)——请在state中使 用 JavaScript 数组,使用 JavaScript 函数。