MMTMMT Docs

Entities

Create persistent chart entities (Line, Box, Label, Marker, Arrow) with mutable handles.

Legacy Scripting v2

These docs remain available while the v2 engine is supported. For new scripts, use Scripting v3.

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?) -> handle

Draws 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
  })
}
OptionTypeRequiredDefaultDescription
x1numberno0Start x coordinate (unix timestamp)
y1numberno0Start y coordinate (price)
x2numberno0End x coordinate (unix timestamp)
y2numberno0End y coordinate (price)
widthnumberno1Line width in pixels
colorcolornocolor.whiteLine color
stylelinestyle.*nolinestyle.solidLine style (solid, dotted, dashed, arrow.right, arrow.left, arrow.both)
labelstringno""Text label displayed on the line
zIndexnumberno0Renderer z-order value
forceOverlayboolnofalsePromote 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.right draws the arrowhead at x2,y2
  • linestyle.arrow.left draws the arrowhead at x1,y1
  • linestyle.arrow.both draws arrowheads at both ends

Handle methods:

  • ln.set(options?) -> handle — update any options, returns the handle for chaining
  • ln.clone(newKey) -> handle — duplicate the entity under a new key
  • ln.delete() -> boolean — remove from chart

Box

Box(key, options?) -> handle

Draws 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
  })
}
OptionTypeRequiredDefaultDescription
x1numberno0Left x coordinate (unix timestamp)
y1numberno0Top y coordinate (price)
x2numberno0Right x coordinate (unix timestamp)
y2numberno0Bottom y coordinate (price)
colorcolornocolor.whiteFill color
roundingnumberno0Corner radius in pixels
borderColorcolornofill colorBorder color
borderWidthnumberno0Border width in pixels
borderStylelinestyle.solid | linestyle.dotted | linestyle.dashednolinestyle.solidBorder style
extendextend.* or extend.*[]noextend.noneExtend the box left/right/up/down
textstringno""Text rendered inside the box
textSizesize.*nosize.autoBox text size
textColorcolornocolor.whiteText color
textHAligntext.align.*notext.align.centerHorizontal text alignment
textVAligntext.align.*notext.align.centerVertical text alignment
textWraptext.wrap.*notext.wrap.autoText wrapping mode
zIndexnumberno0Renderer z-order value
forceOverlayboolnofalsePromote this box to the overlay chart. Sticky per key/handle identity.

Handle methods:

  • box.set(options?) -> handle — update any options, returns the handle for chaining
  • box.clone(newKey) -> handle — duplicate the entity under a new key
  • box.delete() -> boolean — remove from chart

Label

Label(key, options?) -> handle

Places 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
  })
}
OptionTypeRequiredDefaultDescription
xnumberno0X coordinate (unix timestamp)
ynumberno0Y coordinate (price)
textstringno""Label text content
colorcolornocolor.whiteText color
sizenumberno12Font size
textAligntext.align.*notext.align.centerHorizontal text alignment; labels are always vertically centered
zIndexnumberno0Renderer z-order value
forceOverlayboolnofalsePromote this label to the overlay chart. Sticky per key/handle identity.

Handle methods:

  • tag.set(options?) -> handle — update any options, returns the handle for chaining
  • tag.clone(newKey) -> handle — duplicate the entity under a new key
  • tag.delete() -> boolean — remove from chart

Marker

Marker(key, options?) -> handle

Places 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
  })
}
OptionTypeRequiredDefaultDescription
xnumberno0X coordinate (unix timestamp)
ynumberno0Y coordinate (price)
shapeshape.*noshape.circleMarker shape (see Drawing Constants)
sizenumberno5Marker size in pixels
colorcolornocolor.whiteMarker color
zIndexnumberno0Renderer z-order value
forceOverlayboolnofalsePromote 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 chaining
  • m.clone(newKey) -> handle — duplicate the entity under a new key
  • m.delete() -> boolean — remove from chart

Arrow

Arrow(key, options?) -> handle

Draws 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
  })
}
OptionTypeRequiredDefaultDescription
x1numberno0Start x coordinate (unix timestamp)
y1numberno0Start y coordinate (price)
x2numberno0End x coordinate (unix timestamp)
y2numberno0End y coordinate (price)
widthnumberno1.5Arrow shaft width in pixels
colorcolorno#466BE5Arrow color
stylelinestyle.solid | linestyle.dotted | linestyle.dashednolinestyle.solidArrow line style
headLengthPxnumberno8Arrow head length in pixels
headWidthRationumberno0.6Arrow head width relative to head length
zIndexnumberno0Renderer z-order value
forceOverlayboolnofalsePromote this arrow to the overlay chart. Sticky per key/handle identity.

Handle methods:

  • a.set(options?) -> handle — update any options, returns the handle for chaining
  • a.clone(newKey) -> handle — duplicate the entity under a new key
  • a.delete() -> boolean — remove from chart

LineFill

LineFill(key, lineA, lineB, options?) -> handle

Fills 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) })
}
OptionTypeRequiredDefaultDescription
colorcolornocolor.whiteFill 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 color
  • fill.clone(newKey) -> handle — duplicate the entity under a new key
  • fill.delete() -> boolean — remove from chart

Global Delete

You can also delete any entity handle using the global helper:

entity.delete(handle) // -> boolean

Example

//@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)
  }
}

On this page