Pine Script v6 collections

Pine Script matrices: shapes, operations and errors

A Pine Script matrix stores a rectangular collection of one element type. Use matrix.new<float>(rows, columns, initialValue), then get or set a cell with row and column indices. For multiplication, A.columns() must equal B.rows(); a 2 × 3 matrix times a 3 × 2 matrix produces a 2 × 2 result. Check dimensions and missing values before calculating, then compare the result with a small hand-worked example.

Draft matrix code with Pineify

Choose a matrix, an array or a table

For a calculation with three inputs per observation, a rectangular matrix gives every row the same contract. A single series or array is simpler for one value per bar. A TradingView table displays text and values; it does not supply matrix arithmetic. Name what each axis means before writing an indexing loop.

  • Pine collections cannot directly contain another collection type. A literal array<array<float>> is not the route to nested storage; use UDT fields for that design.
  • For this page, rows and columns are mathematical positions. Neither axis automatically represents chart bars, timestamps or symbols.
RepresentationExample taskConstraint
matrix<float>Two observations, three numeric features eachEvery row has three cells
array<float>One ordered list of six valuesYou define any row/column mapping yourself
Array of UDT row objectsRows containing different numbers of eventsEach UDT can hold an array; validate each row separately
tableShow the final calculation on a chartDisplay object, not a numeric matrix

Work a 2 × 3 by 3 × 2 multiplication by hand

Let A have rows [1, 2, 3] and [4, 5, 6]. Let B have rows [7, 8], [9, 10] and [11, 12]. To obtain C[row, column], multiply corresponding entries in that row of A and that column of B, then add them. The shared length is three. These are illustrative constants, so every expected result is independent of chart prices.

  • A + A has rows [2, 4, 6] and [8, 10, 12]. Addition works cell by cell, unlike the dot products above.
  • A + B is invalid because their shapes differ. A × A is also invalid: its inner dimensions would be 3 and 2.
  • B × A is valid here but has shape 3 × 3. Its first cell is 7 × 1 + 8 × 4 = 39, so swapping operands changes the calculation.
Output cellRow of A · column of BExpected value
C[0, 0]1 × 7 + 2 × 9 + 3 × 1158
C[0, 1]1 × 8 + 2 × 10 + 3 × 1264
C[1, 0]4 × 7 + 5 × 9 + 6 × 11139
C[1, 1]4 × 8 + 5 × 10 + 6 × 12154

Run the multiplication and inspect all four outputs

Paste this complete indicator into Pine Editor. It creates the inputs once with var, populates them on the first bar, and asserts all four product cells. The separate pane plots 58, 64, 139 and 154. It also checks that changing a numeric row copy leaves A unchanged. These are expected chart results; the source has passed syntax validation, which does not execute the chart assertions.

  • After a.set(0, 0, 10.0), the stored product is still the earlier result. Recomputing with the changed A would make C[0, 0] equal 121.
  • A numeric row() or col() result is a separate array. For matrices of labels or UDT objects, the copied elements can still reference the same objects.
  • The first-bar initialization is appropriate for constants. If inputs change each bar, schedule both updates and calculations according to that data model.
Complete Pine v6 example: fixed matrices with output assertionspinescript
//@version=6
indicator("Matrix multiplication checks")

checkValue(float actual, float expected, string cell) =>
    if na(actual) or math.abs(actual - expected) > 0.000001
        runtime.error("Unexpected value at " + cell)
    actual

var matrix<float> a = matrix.new<float>()
var matrix<float> b = matrix.new<float>()
var matrix<float> product = na

if barstate.isfirst
    a.add_row(0, array.from(1.0, 2.0, 3.0))
    a.add_row(1, array.from(4.0, 5.0, 6.0))
    b.add_row(0, array.from(7.0, 8.0))
    b.add_row(1, array.from(9.0, 10.0))
    b.add_row(2, array.from(11.0, 12.0))
    if a.columns() != b.rows()
        runtime.error("Left columns must equal right rows")
    product := matrix.mult(a, b)
    checkValue(product.get(0, 0), 58.0, "C[0,0]")
    checkValue(product.get(0, 1), 64.0, "C[0,1]")
    checkValue(product.get(1, 0), 139.0, "C[1,0]")
    checkValue(product.get(1, 1), 154.0, "C[1,1]")
    array<float> rowCopy = a.row(0)
    array.set(rowCopy, 0, 99.0)
    checkValue(a.get(0, 0), 1.0, "A remains unchanged")
    array<float> secondColumn = a.col(1)
    checkValue(array.get(secondColumn, 1), 5.0, "A column 1")
    a.set(0, 0, 10.0)
    checkValue(a.get(0, 0), 10.0, "Explicit matrix update")
    checkValue(product.get(0, 0), 58.0, "Product is not recalculated")

plot(product.get(0, 0), "C00 = 58", color=color.blue)
plot(product.get(0, 1), "C01 = 64", color=color.orange)
plot(product.get(1, 0), "C10 = 139", color=color.teal)
plot(product.get(1, 1), "C11 = 154", color=color.purple)

Reject missing cells before doing the arithmetic

This example defines a strict policy: only a nonempty float matrix with every cell present is ready. It leaves one cell missing until you enable the input. The default ready flag is 0 and the sum is unavailable; enabling the input fills the last cell with 4, making ready equal 1 and the manual sum equal 10. Replacing a missing observation with zero would change the dataset, so this policy does not do that.

  • na(m) tests the object reference. It does not inspect the numeric cells in an existing matrix.
  • The helper checks dimensions before entering loops. No cell is read from the empty matrix.
  • This is a chosen validation policy, not a claim that every matrix function handles na identically. Validate source data before selecting an aggregation or linear algebra operation.
Complete Pine v6 example: missing ID, empty matrix and missing cell checkspinescript
//@version=6
indicator("Matrix readiness checks")

isReady(matrix<float> m) =>
    bool ready = false
    if not na(m)
        int rows = m.rows()
        int columns = m.columns()
        if rows > 0 and columns > 0
            ready := true
            for row = 0 to rows - 1
                for column = 0 to columns - 1
                    if na(m.get(row, column))
                        ready := false
    ready

bool complete = input.bool(false, "Supply the fourth value")
matrix<float> missingId = na
matrix<float> empty = matrix.new<float>()
matrix<float> sample = matrix.new<float>(2, 2, na)
sample.set(0, 0, 1.0)
sample.set(0, 1, 2.0)
sample.set(1, 0, 3.0)
if complete
    sample.set(1, 1, 4.0)

bool ready = isReady(sample)
float total = na
if ready
    total := 0.0
    for row = 0 to sample.rows() - 1
        for column = 0 to sample.columns() - 1
            total += sample.get(row, column)
if isReady(missingId) or isReady(empty) or ready != complete
    runtime.error("Readiness assertion failed")
if complete and (na(total) or total != 10.0)
    runtime.error("Expected sum 10")

plot(ready ? 1 : 0, "Ready: 0 or 1", color=color.blue)
plot(total, "Sum: na or 10", color=color.orange)

Diagnose a shape error from the operation

Record both input shapes alongside the operation. For A above, row 2 is out of range even though column 2 exists. Inserting a row requires three values; inserting a column requires two. Guard the actual operation rather than checking only whether the matrix contains some elements.

  • For the singular example, 1 × 4 − 2 × 2 = 0. A square shape alone does not establish invertibility.
  • A pseudoinverse is a different operation. Substituting it for an inverse changes the mathematical problem and requires checking the residual.
  • Matching dimensions cannot detect reversed feature order. If one input uses [price, volume] and another assumes [volume, price], the calculation can run with the wrong meaning.
Operation or failureCheckExample diagnosis
get / set0 ≤ row < rows; 0 ≤ column < columnsA.get(2, 0) exceeds the two-row shape
sum / diff with two matricesBoth shapes match2 × 3 plus 3 × 2 is invalid
mult with two matricesLeft columns = right rows2 × 3 times 3 × 2 yields 2 × 2
transposeRows and columns swapA becomes rows [1, 4], [2, 5], [3, 6] before the example update
Matrix growthTotal cells ≤ 100,000500 × 200 reaches the limit; one more row exceeds it
InverseSquare shape and invertible data[[1, 2], [2, 4]] has determinant 0 and no ordinary inverse
Where Pineify fits

Pine Script AI Coding Agent

Provide the intended row and column meanings, expected shapes and a small input/output example. Ask the Pine Script AI Coding Agent to draft or revise the calculation and add guards. Request a syntax check, then run the assertions in TradingView; generated code does not establish numerical correctness or trading performance.

Draft matrix code with Pineify

Frequently asked questions

Educational programming examples, not investment advice. The constants and expected outputs are arithmetic test cases, not trading results. Syntax checks do not verify chart runtime behavior, model assumptions or profitability.

Sources and verification

Published by Pineify. Pineify is an independent product and is not affiliated with TradingView. Sources support the technical explanations; examples do not establish trading performance.