Drawing Objects#

In addition to plot functions, Pine Script provides drawing objects that can be precisely positioned: label (text labels), line (line segments), and box (rectangles). These objects can be drawn at any position and time on the chart, making them ideal for marking specific bars or drawing pattern structures.

label — Text Label#

label.new() creates a label with text at a specified position:

label.new(x, y, text, style, color, textcolor, size)
ParameterDescription
xHorizontal position (typically bar_index)
yVertical position (price)
textText to display
styleLabel shape
colorLabel background color
textcolorText color
sizeText size
//@version=6
indicator("label Demo", overlay=true)

// Show a marker above every bullish bar
if close > open
    label.new(bar_index, high,
              text="▲",
              style=label.style_label_down,
              color=color.new(color.green, 20),
              textcolor=color.white,
              size=size.small)

label Styles#

Commonly used style options:

ConstantDescription
label.style_label_upUpward label (arrow at bottom)
label.style_label_downDownward label (arrow at top)
label.style_label_leftLeft-pointing label
label.style_label_rightRight-pointing label
label.style_label_centerBox without arrow
label.style_circleCircle
label.style_diamondDiamond
label.style_noneText only, no background

Object Count Limit#

Pine Script retains at most 500 objects of each type by default (label, line, and box are counted independently). When the limit is exceeded, the oldest object is automatically deleted.

If you only need to display the most recent few objects, manage them manually:

//@version=6
indicator("Limit Label Count", overlay=true)

var labelQueue = array.new<label>()

// Create a new label on every bar
lbl = label.new(bar_index, high, str.tostring(math.round(close, 2)),
                style=label.style_label_down, size=size.tiny)
array.push(labelQueue, lbl)

// Keep only the most recent 10 labels
if array.size(labelQueue) > 10
    label.delete(array.shift(labelQueue))

line — Line Segment#

line.new() draws a line segment connecting two points:

line.new(x1, y1, x2, y2, color, width, style, extend)
//@version=6
indicator("Trend Line Demo", overlay=true)

// Draw a line connecting recent pivot highs on the last bar
if barstate.islast
    // Find the two most recent pivot highs
    ph1 = ta.pivothigh(high, 5, 5)
    ph2 = ta.pivothigh(high, 10, 10)

    if not na(ph1) and not na(ph2)
        line.new(bar_index - 5,  ph1,
                 bar_index - 10, ph2,
                 color=color.red, width=2,
                 extend=extend.right)  // Extend to the right

Extend Direction#

The extend parameter controls whether the line extends beyond its endpoints:

ConstantDescription
extend.noneNo extension (default)
extend.rightExtend to the right edge of the chart
extend.leftExtend to the left edge of the chart
extend.bothExtend in both directions

Line Styles#

ConstantDescription
line.style_solidSolid line
line.style_dashedDashed line
line.style_dottedDotted line
line.style_arrow_rightWith right arrow

box — Rectangle#

box.new() draws a rectangle, commonly used to mark patterns or supply/demand zones:

box.new(left, top, right, bottom, border_color, border_width, bgcolor)
//@version=6
indicator("Box Demo", overlay=true)

// Draw a box around the previous bar's candle body
prevOpen  = open[1]
prevClose = close[1]

// Only draw for the most recent bars to avoid too many objects
if bar_index > last_bar_index - 20
    box.new(left=bar_index - 1, top=math.max(prevOpen, prevClose),
            right=bar_index,    bottom=math.min(prevOpen, prevClose),
            border_color=prevClose > prevOpen ? color.green : color.red,
            bgcolor=color.new(prevClose > prevOpen ? color.green : color.red, 70))

Practical Example: Marking Breakout Points#

Using close breaking above the N-bar high as an example, combining label and line:

//@version=6
indicator("Breakout Markers", overlay=true)

lookback = input.int(20, "Breakout Period")

highestHigh = ta.highest(high, lookback)[1]  // Previous bar's lookback high
breakout    = close > highestHigh

if breakout
    // Mark the breakout bar
    label.new(bar_index, low,
              "Breakout " + str.tostring(lookback) + "-bar high\n" +
              str.tostring(math.round(close, 2)),
              style=label.style_label_up,
              color=color.new(color.green, 10),
              textcolor=color.white,
              size=size.normal)

    // Draw the horizontal line that was broken
    line.new(bar_index - lookback, highestHigh,
             bar_index, highestHigh,
             color=color.new(color.red, 30),
             style=line.style_dashed)

Practical Example: Statistics Label on the Last Bar#

//@version=6
indicator("Bar Statistics Label", overlay=true)

var int bullCount = 0
var int bearCount = 0

if close > open
    bullCount := bullCount + 1
else
    bearCount := bearCount + 1

// Only display on the last bar
if barstate.islast
    total   = bullCount + bearCount
    bullPct = total > 0 ? bullCount / total * 100 : 0.0

    label.new(bar_index + 5, high,
              "Bullish: " + str.tostring(bullCount) + " (" +
              str.tostring(math.round(bullPct, 1)) + "%)\n" +
              "Bearish: " + str.tostring(bearCount),
              style=label.style_label_left,
              color=color.new(color.navy, 10),
              textcolor=color.white,
              size=size.normal)

Reference#