Tables#

The table object can display grid-based information at a fixed position on the chart, making it ideal for dashboards, showing current values of multiple indicators, or displaying strategy statistics. Unlike label, a table is anchored to a corner of the screen and does not move with the bars.

Creating a Table#

table.new(position, columns, rows, bgcolor, border_color, border_width, frame_color, frame_width)
ParameterDescription
positionPosition of the table on screen
columnsNumber of columns
rowsNumber of rows
bgcolorTable background color
border_colorCell border color
border_widthBorder width (px)

Position Constants#

ConstantPosition
position.top_leftTop-left corner
position.top_centerTop center
position.top_rightTop-right corner
position.middle_leftMiddle left
position.middle_centerCenter
position.middle_rightMiddle right
position.bottom_leftBottom-left corner
position.bottom_centerBottom center
position.bottom_rightBottom-right corner

Filling Cells#

After creating the table, use table.cell() to fill each cell’s content:

table.cell(table_id, column, row, text, text_color, text_size, bgcolor, text_halign)

Cell indices start at the top-left corner (0, 0), with columns increasing to the right and rows increasing downward.

Basic Example#

//@version=6
indicator("Simple Table", overlay=true)

// Only create the table on the last bar (avoid rebuilding every bar)
if barstate.islast
    t = table.new(position.top_right, 2, 3,
                  bgcolor=color.new(color.navy, 10),
                  border_color=color.new(color.white, 50),
                  border_width=1)

    // Header row
    table.cell(t, 0, 0, "Indicator", text_color=color.white, text_size=size.small)
    table.cell(t, 1, 0, "Value",     text_color=color.white, text_size=size.small)

    // RSI
    rsiVal = ta.rsi(close, 14)
    table.cell(t, 0, 1, "RSI(14)", text_color=color.white, text_size=size.small)
    table.cell(t, 1, 1, str.tostring(math.round(rsiVal, 2)),
               text_color=rsiVal > 70 ? color.red : rsiVal < 30 ? color.green : color.white,
               text_size=size.small)

    // Volume vs Average Volume
    volMA    = ta.sma(volume, 20)
    volRatio = volume / volMA
    table.cell(t, 0, 2, "Vol Ratio", text_color=color.white, text_size=size.small)
    table.cell(t, 1, 2, str.tostring(math.round(volRatio, 2)) + "x",
               text_color=volRatio > 1.5 ? color.yellow : color.white,
               text_size=size.small)

Persisting Tables with var#

Declaring the table with var avoids recreating it on every bar — you only need to update the cell content:

//@version=6
indicator("Persistent Table", overlay=true)

// Create the table only once
var t = table.new(position.top_right, 2, 4,
                  bgcolor=color.new(color.black, 20),
                  border_color=color.gray, border_width=1)

// Update values on every bar (only update the value column, no rebuild)
if barstate.islast or barstate.isrealtime
    ma20 = ta.sma(close, 20)
    rsi  = ta.rsi(close, 14)
    atr  = ta.atr(14)

    // Header row (safe to write every time)
    table.cell(t, 0, 0, "Indicator", bgcolor=color.new(color.blue, 50), text_color=color.white)
    table.cell(t, 1, 0, "Value",     bgcolor=color.new(color.blue, 50), text_color=color.white)

    table.cell(t, 0, 1, "MA20",    text_color=color.white)
    table.cell(t, 1, 1, str.tostring(math.round(ma20, 2)),
               text_color=close > ma20 ? color.green : color.red)

    table.cell(t, 0, 2, "RSI(14)", text_color=color.white)
    table.cell(t, 1, 2, str.tostring(math.round(rsi, 1)),
               text_color=rsi > 70 ? color.red : rsi < 30 ? color.lime : color.white)

    table.cell(t, 0, 3, "ATR(14)", text_color=color.white)
    table.cell(t, 1, 3, str.tostring(math.round(atr, 2)), text_color=color.white)

Merging Cells#

table.merge_cells() merges adjacent cells, commonly used to create title rows:

//@version=6
indicator("Merged Cells", overlay=true)

if barstate.islast
    t = table.new(position.top_left, 3, 3,
                  bgcolor=color.new(color.navy, 20),
                  border_color=color.white, border_width=1)

    // Merge all three cells in the first row as the title
    table.cell(t, 0, 0, "Multiple MA Dashboard",
               text_color=color.white, text_size=size.normal)
    table.merge_cells(t, 0, 0, 2, 0)  // Merge from (0,0) to (2,0)

    // Data rows
    headers = array.from("Period", "MA Value", "Position")
    periods = array.from(5, 20, 60)

    for col = 0 to 2
        table.cell(t, col, 1, array.get(headers, col),
                   text_color=color.gray, text_size=size.small)

    for row = 0 to 2
        period   = array.get(periods, row)
        maVal    = ta.sma(close, period)
        pos      = close > maVal ? "Above ▲" : "Below ▼"
        posColor = close > maVal ? color.green : color.red

        table.cell(t, 0, row + 2, str.tostring(period) + "-bar",
                   text_color=color.white, text_size=size.small)
        table.cell(t, 1, row + 2, str.tostring(math.round(maVal, 2)),
                   text_color=color.white, text_size=size.small)
        table.cell(t, 2, row + 2, pos,
                   text_color=posColor, text_size=size.small)

Reference#