Entities
Create persistent chart entities (Line, Box, Label, Marker, Arrow) with mutable handles.
Legacy Scripting v2
Entities are persistent chart objects that exist while your script is active. Each constructor returns a handle you can update or delete.
Limits: Max 2000 of each entity type per script.
Keys: In //@version=2, every entity requires a non-empty key string. The key identifies the entity per bar — only one entity of each type with a given key can exist per bar.
Versioning: Arrow() is available only in //@version=2. If a required key is missing, the constructor returns a no-op handle and logs an error.
Handle Lifetime
In //@version=2, keyed entities are matched by (entity type, key, current bar unix).
- Calling
Line("trend", ...)twice on the same bar updates that bar's"trend"line and returns the current live handle. - Calling
Line("trend", ...)again on a later bar creates or upserts that later bar's"trend"line. It does not make an older handle from a previous bar current again. .set(),.clone(), and.delete()only work while the underlying entity still exists.- After
.delete(), the handle is invalidated immediately. - A handle can also become stale if the underlying entity is removed later, such as after entity-limit eviction or a full runtime rebuild/replay (
setCode,updateInputs,updateContext).
Recommended pattern: call the constructor inside onBar on every bar where the entity should exist, then use the handle returned for that bar.
//@version=2
indicator("Safe Entity Handle Pattern", true)
const candles = subscribe(data.OHLCV)
let trend = null
function onBar(index) {
if (barIndex() < 20) return
trend = Line("trend", {
x1: unix(20),
y1: candles.low(20),
x2: unix(0),
y2: candles.high()
})
trend.set({
color: candles.close() >= candles.open() ? color.green : color.red,
width: 2
})
}If you keep a handle in a variable, reassign it from the constructor before calling .set(). Do not assume a handle from an earlier bar is still the current live entity for the same key.
Line
Line(key, options?) -> handleDraws a line between two coordinate points.
//@version=2
indicator("Line Example", true)
const candles = subscribe(data.OHLCV)
function onBar(index) {
if (barIndex() < 20) return
Line("trend", {
x1: unix(20),
y1: candles.low(20),
x2: unix(0),
y2: candles.high(),
width: 2,
color: color.green,
style: linestyle.dashed,
label: "Trend",
zIndex: 2
})
}| Option | Type | Required | Default | Description |
|---|---|---|---|---|
x1 | number | no | 0 | Start x coordinate (unix timestamp) |
y1 | number | no | 0 | Start y coordinate (price) |
x2 | number | no | 0 | End x coordinate (unix timestamp) |
y2 | number | no | 0 | End y coordinate (price) |
width | number | no | 1 | Line width in pixels |
color | color | no | color.white | Line color |
style | linestyle.* | no | linestyle.solid | Line style (solid, dotted, dashed, arrow.right, arrow.left, arrow.both) |
label | string | no | "" | Text label displayed on the line |
zIndex | number | no | 0 | Renderer z-order value |
forceOverlay | bool | no | false | Promote this line to the overlay chart. Sticky per key/handle identity. |
linestyle.arrow.* adds arrowheads to Line(...) without changing the separate Arrow() entity API:
linestyle.arrow.rightdraws the arrowhead atx2,y2linestyle.arrow.leftdraws the arrowhead atx1,y1linestyle.arrow.bothdraws arrowheads at both ends
Handle methods:
ln.set(options?) -> handle— update any options, returns the handle for chainingln.clone(newKey) -> handle— duplicate the entity under a new keyln.delete() -> boolean— remove from chart
Box
Box(key, options?) -> handleDraws a filled rectangle between two corner points.
//@version=2
indicator("Box Example", true)
const candles = subscribe(data.OHLCV)
function onBar(index) {
if (barIndex() < 10) return
Box("zone", {
x1: unix(10),
y1: candles.high(10),
x2: unix(0),
y2: candles.low(),
color: color.transp(color.blue, 75),
rounding: 4,
borderColor: color.white,
borderWidth: 2,
borderStyle: linestyle.dashed,
extend: [extend.left, extend.up],
text: "Zone",
textSize: size.md,
textColor: color.white,
textHAlign: text.align.left,
textVAlign: text.align.top,
textWrap: text.wrap.none,
zIndex: 3
})
}| Option | Type | Required | Default | Description |
|---|---|---|---|---|
x1 | number | no | 0 | Left x coordinate (unix timestamp) |
y1 | number | no | 0 | Top y coordinate (price) |
x2 | number | no | 0 | Right x coordinate (unix timestamp) |
y2 | number | no | 0 | Bottom y coordinate (price) |
color | color | no | color.white | Fill color |
rounding | number | no | 0 | Corner radius in pixels |
borderColor | color | no | fill color | Border color |
borderWidth | number | no | 0 | Border width in pixels |
borderStyle | linestyle.solid | linestyle.dotted | linestyle.dashed | no | linestyle.solid | Border style |
extend | extend.* or extend.*[] | no | extend.none | Extend the box left/right/up/down |
text | string | no | "" | Text rendered inside the box |
textSize | size.* | no | size.auto | Box text size |
textColor | color | no | color.white | Text color |
textHAlign | text.align.* | no | text.align.center | Horizontal text alignment |
textVAlign | text.align.* | no | text.align.center | Vertical text alignment |
textWrap | text.wrap.* | no | text.wrap.auto | Text wrapping mode |
zIndex | number | no | 0 | Renderer z-order value |
forceOverlay | bool | no | false | Promote this box to the overlay chart. Sticky per key/handle identity. |
Handle methods:
box.set(options?) -> handle— update any options, returns the handle for chainingbox.clone(newKey) -> handle— duplicate the entity under a new keybox.delete() -> boolean— remove from chart
Label
Label(key, options?) -> handlePlaces a text label at a position on the chart.
//@version=2
indicator("Label Example", true)
const candles = subscribe(data.OHLCV)
function onBar(index) {
Label("breakout", {
x: unix(0),
y: candles.high(),
text: "Breakout",
color: color.white,
size: 12,
textAlign: text.align.right,
zIndex: 4
})
}| Option | Type | Required | Default | Description |
|---|---|---|---|---|
x | number | no | 0 | X coordinate (unix timestamp) |
y | number | no | 0 | Y coordinate (price) |
text | string | no | "" | Label text content |
color | color | no | color.white | Text color |
size | number | no | 12 | Font size |
textAlign | text.align.* | no | text.align.center | Horizontal text alignment; labels are always vertically centered |
zIndex | number | no | 0 | Renderer z-order value |
forceOverlay | bool | no | false | Promote this label to the overlay chart. Sticky per key/handle identity. |
Handle methods:
tag.set(options?) -> handle— update any options, returns the handle for chainingtag.clone(newKey) -> handle— duplicate the entity under a new keytag.delete() -> boolean— remove from chart
Marker
Marker(key, options?) -> handlePlaces a shape marker at a position on the chart.
//@version=2
indicator("Marker Example", true)
const candles = subscribe(data.OHLCV)
function onBar(index) {
Marker("signal", {
x: unix(0),
y: candles.high(),
shape: shape.diamond,
size: 6,
color: color.yellow,
zIndex: 5
})
}| Option | Type | Required | Default | Description |
|---|---|---|---|---|
x | number | no | 0 | X coordinate (unix timestamp) |
y | number | no | 0 | Y coordinate (price) |
shape | shape.* | no | shape.circle | Marker shape (see Drawing Constants) |
size | number | no | 5 | Marker size in pixels |
color | color | no | color.white | Marker color |
zIndex | number | no | 0 | Renderer z-order value |
forceOverlay | bool | no | false | Promote this marker to the overlay chart. Sticky per key/handle identity. |
When updating via .set(), use marker instead of shape for the shape key:
m.set({ marker: shape.up, color: color.green })Handle methods:
m.set(options?) -> handle— update any options, returns the handle for chainingm.clone(newKey) -> handle— duplicate the entity under a new keym.delete() -> boolean— remove from chart
Arrow
Arrow(key, options?) -> handleDraws an arrow between two coordinate points.
//@version=2
indicator("Arrow Example", true)
const candles = subscribe(data.OHLCV)
function onBar(index) {
if (barIndex() < 10) return
Arrow("projection", {
x1: unix(10),
y1: candles.low(10),
x2: unix(0),
y2: candles.high(),
width: 2,
color: color.green,
style: linestyle.dashed,
headLengthPx: 10,
headWidthRatio: 0.75,
zIndex: 6
})
}| Option | Type | Required | Default | Description |
|---|---|---|---|---|
x1 | number | no | 0 | Start x coordinate (unix timestamp) |
y1 | number | no | 0 | Start y coordinate (price) |
x2 | number | no | 0 | End x coordinate (unix timestamp) |
y2 | number | no | 0 | End y coordinate (price) |
width | number | no | 1.5 | Arrow shaft width in pixels |
color | color | no | #466BE5 | Arrow color |
style | linestyle.solid | linestyle.dotted | linestyle.dashed | no | linestyle.solid | Arrow line style |
headLengthPx | number | no | 8 | Arrow head length in pixels |
headWidthRatio | number | no | 0.6 | Arrow head width relative to head length |
zIndex | number | no | 0 | Renderer z-order value |
forceOverlay | bool | no | false | Promote this arrow to the overlay chart. Sticky per key/handle identity. |
Handle methods:
a.set(options?) -> handle— update any options, returns the handle for chaininga.clone(newKey) -> handle— duplicate the entity under a new keya.delete() -> boolean— remove from chart
LineFill
LineFill(key, lineA, lineB, options?) -> handleFills the area between two live Line handles.
//@version=2
indicator("LineFill Example", true)
const candles = subscribe(data.OHLCV)
function onBar(index) {
if (barIndex() < 10) return
const top = Line("top", { x1: unix(10), y1: candles.high(10), x2: unix(0), y2: candles.high() })
const bottom = Line("bottom", { x1: unix(10), y1: candles.low(10), x2: unix(0), y2: candles.low() })
LineFill("band", top, bottom, { color: color.transp(color.blue, 85) })
}| Option | Type | Required | Default | Description |
|---|---|---|---|---|
color | color | no | color.white | Fill color |
LineFill() does not take forceOverlay. Both source lines must already use the same sticky forceOverlay value.
Invalid LineFill() mismatch:
//@version=2
indicator("Invalid LineFill Overlay Mix", false)
const candles = subscribe(data.OHLCV)
function onBar(index) {
const top = Line("top", { x1: unix(10), y1: candles.high(10), x2: unix(0), y2: candles.high(), forceOverlay: true })
const bottom = Line("bottom", { x1: unix(10), y1: candles.low(10), x2: unix(0), y2: candles.low() })
LineFill("band", top, bottom, { color: color.transp(color.blue, 85) }) // throws
}Handle methods:
fill.set(options?) -> handle— update source lines and colorfill.clone(newKey) -> handle— duplicate the entity under a new keyfill.delete() -> boolean— remove from chart
Global Delete
You can also delete any entity handle using the global helper:
entity.delete(handle) // -> booleanExample
//@version=2
indicator("Entity Handle Example", true)
const candles = subscribe(data.OHLCV)
function onBar(index) {
if (barIndex() < 10) return
const ln = Line("main", { x1: unix(10), y1: candles.low(10), x2: unix(0), y2: candles.high() })
// Update the handle returned for this bar.
ln.set({ x2: unix(0), y2: candles.high(), color: color.red })
// After delete(), do not call ln.set()/ln.clone()/ln.delete() again.
if (context.isRealtime) {
entity.delete(ln)
}
}