Skip to content

matrix ​

How do you hold a table of numbers in a script and do linear algebra on it, such as fitting a line to the last 20 closes? Make a matrix with matrix.new<float>(rows, columns, initial_value), fill it with matrix.set, and combine matrices with matrix.mult, matrix.transpose and matrix.inv. Rows and columns count from 0. Most functions here can also be called as a method, as in m.get(0, 1).

pine
//@version=6
indicator("Slope of the last 20 closes")
int n = 20
X = matrix.new<float>(n, 2, 1.0) // column 0 stays 1: the intercept
y = matrix.new<float>(n, 1)
for i = 0 to n - 1
    X.set(i, 1, i)               // column 1: the bar's place, oldest first
    y.set(i, 0, close[n - 1 - i])
Xt = X.transpose()
beta = Xt.mult(X).inv().mult(Xt).mult(y) // least squares: inv(X'X) X'y
plot(bar_index >= n ? beta.get(1, 0) : na, "Slope per bar")

Shape and indexes ​

A matrix has matrix.rows rows and matrix.columns columns, and every row is as long as the first. It holds at most 100,000 elements, and making or growing one past that stops the script with an error.

An index past an edge reads na here

matrix.get, matrix.row and matrix.col past an edge read na, and matrix.set there does nothing. TradingView stops the script with an error, so a wrong index here goes unnoticed.

References and copies ​

A matrix variable holds a reference, so m2 = m gives one matrix two names. matrix.set, fill, add_row, add_col, remove_row, remove_col, swap_rows, swap_columns, reverse and sort change the matrix itself. Every other function returns a new matrix or array, and changing it leaves the original as it was.

An earlier bar's matrix ​

m[1] keeps the rows the matrix had when the previous bar closed, so a row added since doesn't show in it. The rows themselves are shared with today's matrix, though, so a cell written since shows its new value in m[1]. To compare with the earlier bar's values, keep a matrix.copy of them yourself.

Where this engine parts from TradingView ​

Several functions don't yet do what TradingView's do. Each says so in a warning: matrix.concat, matrix.diff, matrix.reshape, matrix.reverse, matrix.mult with an array, matrix.add_row and matrix.add_col without an array, matrix.remove_row and matrix.remove_col without an index, and the parameter names of matrix.row and matrix.col.

matrix.new ​

pine
matrix.new<type>(rows, columns, initial_value) → matrix<type>

A new matrix of rows by columns, every element set to initial_value.

With no initial value each element is na, a matrix<bool> included. An object given as the initial value is one object shared by every cell.

ParameterDefaultDescription
rows
series int
0How many rows.
columns
series int
0How many columns.
initial_value
<matrix_type>
naThe value of every element.

matrix.get ​

pine
matrix.get(id, row, column) → <matrix_type>

Also a method: id.get(row, column).

The element at row and column, or na past an edge: see shape and indexes.

ParameterDescription
id
any matrix type
The matrix.
row
series int
The row, from 0.
column
series int
The column, from 0.

matrix.set ​

pine
matrix.set(id, row, column, value) → void

Also a method: id.set(row, column, value).

Sets the element at row and column to value. Past an edge it does nothing.

ParameterDescription
id
any matrix type
The matrix.
row
series int
The row, from 0.
column
series int
The column, from 0.
value
series <type of the matrix's elements>
The new value.

matrix.rows ​

pine
matrix.rows(id) → series int

Also a method: id.rows().

How many rows the matrix has.

Parameter
id
any matrix type

matrix.columns ​

pine
matrix.columns(id) → series int

Also a method: id.columns().

How many columns the matrix has, or 0 if it has no rows.

Parameter
id
any matrix type

matrix.elements_count ​

pine
matrix.elements_count(id) → series int

Also a method: id.elements_count().

How many elements the matrix holds: its rows times its columns.

Parameter
id
any matrix type

matrix.row ​

pine
matrix.row(id, index) → array<type>

Also a method: id.row(index).

A new array of the values in row index, or na past the last row.

Pass the row by position

TradingView names this parameter row. Here it is index, so pass it by position. matrix.row(m, row = 1) stops the script with an error.

ParameterDescription
id
any matrix type
The matrix.
index
series int
The row, from 0.

matrix.col ​

pine
matrix.col(id, index) → array<type>

Also a method: id.col(index).

A new array of the values in column index, or na past the last column.

Pass the column by position

TradingView names this parameter column. Here it is index, so pass it by position. matrix.col(m, column = 1) doesn't read the column you name, and on the compiled engine it stops the script with an error.

ParameterDescription
id
any matrix type
The matrix.
index
series int
The column, from 0.

matrix.add_row ​

pine
matrix.add_row(id, row, array_id) → void

Also a method: id.add_row(row, array_id).

Inserts a row holding the elements of array_id at row, moving the rows from there down one.

A row of another length is kept

Give an array as long as the matrix is wide. Without an array, the new row is empty, and with an array of another length, the row keeps that length. Either way the rows no longer match, where TradingView fills a missing row with na.

ParameterDescription
id
any matrix type
The matrix.
row
series int
Where the new row goes, from 0. Left out, after the last row.
array_id
any array type
The new row's values.

matrix.add_col ​

pine
matrix.add_col(id, column, array_id) → void

Also a method: id.add_col(column, array_id).

Inserts a column holding the elements of array_id at column, moving the columns from there right one.

Missing cells hold 0 here

Without an array the new column holds 0, and an array shorter than the matrix is tall leaves 0 in the rest. TradingView fills them with na.

ParameterDescription
id
any matrix type
The matrix.
column
series int
Where the new column goes, from 0. Left out, after the last column.
array_id
any array type
The new column's values.

matrix.remove_row ​

pine
matrix.remove_row(id, row) → array<type>

Also a method: id.remove_row(row).

Removes row row and returns its values as an array.

The default row differs by engine

Always pass the row. Left out, the TS engine removes nothing and the Rust engine removes the last row.

ParameterDescription
id
any matrix type
The matrix.
row
series int
The row to remove, from 0.

matrix.remove_col ​

pine
matrix.remove_col(id, column) → array<type>

Also a method: id.remove_col(column).

Removes column column and returns its values as an array.

The default column differs by engine

Always pass the column. Left out, the TS engine removes nothing and the Rust engine removes the last column.

ParameterDescription
id
any matrix type
The matrix.
column
series int
The column to remove, from 0.

matrix.swap_rows ​

pine
matrix.swap_rows(id, row1, row2) → void

Also a method: id.swap_rows(row1, row2).

Swaps rows row1 and row2.

Parameter
id
any matrix type
row1
series int
row2
series int

matrix.swap_columns ​

pine
matrix.swap_columns(id, column1, column2) → void

Also a method: id.swap_columns(column1, column2).

Swaps columns column1 and column2.

Parameter
id
any matrix type
column1
series int
column2
series int

matrix.fill ​

pine
matrix.fill(id, value, from_row, to_row, from_column, to_column) → void

Also a method: id.fill(value, from_row, to_row, from_column, to_column).

Sets every element in a block of rows and columns to value. Each range runs from its first index up to, but not including, its last.

ParameterDefaultDescription
id
any matrix type
The matrix.
value
series <type of the matrix's elements>
The value to set.
from_row
series int
0The first row to fill.
to_row
series int
The row to stop before. Left out, the fill runs to the last row.
from_column
series int
0The first column to fill.
to_column
series int
The column to stop before. Left out, the fill runs to the last column.

matrix.reverse ​

pine
matrix.reverse(id) → void

Also a method: id.reverse().

Reverses the order of the rows, in place.

Each row keeps its order here

TradingView's reverses the columns too, so its first element becomes the last. Here each row keeps its order: [[1, 2], [3, 4]] becomes [[3, 4], [1, 2]], where TradingView gives [[4, 3], [2, 1]].

Parameter
id
any matrix type

matrix.sort ​

pine
matrix.sort(id, column, order, sort_field) → void

Also a method: id.sort(column, order, sort_field).

Reorders the rows by the values in one column, in place.

A na sorts last in ascending order.

ParameterDefaultDescription
id
any matrix type
The matrix.
column
series int
0The column whose values set the order.
order
simple sort_order
order.ascendingorder.ascending or order.descending.
sort_field
series string/int
In a matrix of objects, the field to sort by: its name, or its place counting from 0. Left out, the first field.

matrix.copy ​

pine
matrix.copy(id) → matrix<type>

Also a method: id.copy().

A new matrix holding the same values. An object in a cell is the same object in both.

Parameter
id
any matrix type

matrix.submatrix ​

pine
matrix.submatrix(id, from_row, to_row, from_column, to_column) → matrix<type>

Also a method: id.submatrix(from_row, to_row, from_column, to_column).

A new matrix of the rows from from_row and the columns from from_column, each up to, but not including, the last index given.

ParameterDefaultDescription
id
any matrix type
The matrix.
from_row
series int
0The first row to take.
to_row
series int
The row to stop before. Left out, the last row is included.
from_column
series int
0The first column to take.
to_column
series int
The column to stop before. Left out, the last column is included.

matrix.transpose ​

pine
matrix.transpose(id) → matrix<type>

Also a method: id.transpose().

A new matrix with the rows and columns swapped, so row i becomes column i.

Parameter
id
any matrix type

matrix.reshape ​

pine
matrix.reshape(id, rows, columns) → void

Also a method: id.reshape(rows, columns).

A new matrix of rows by columns, filled with the elements read row by row. It reads na unless the counts match.

It returns a new matrix here

TradingView's reshapes id itself and returns nothing. Here id stays as it was, so assign the result: m2 = matrix.reshape(m, 3, 2).

ParameterDescription
id
any matrix type
The matrix.
rows
series int
The new number of rows.
columns
series int
The new number of columns.

matrix.concat ​

pine
matrix.concat(id1, id2) → matrix<type>

Also a method: id1.concat(id2).

A new matrix with the columns of id2 after those of id1. It reads na unless the two have as many rows.

It returns a new matrix, joined side by side

TradingView's appends id2 to id1 itself and returns id1. Here id1 stays as it was, and the result is joined side by side.

ParameterDescription
id1
any matrix type
The matrix on the left.
id2
any matrix type
The matrix added on its right.

matrix.sum ​

pine
matrix.sum(id1, id2) → matrix<float>/matrix<int>
matrix.sum(id1) → series float  // AmenoScript only

Also a method: id1.sum(id2).

A new matrix of id1 plus id2, element by element, or of id1 with a number added to every element.

Two matrices of different shapes give na. With id2 left out, the call gives the sum of every element of id1 as a number, and na if any is na. TradingView has no such one-argument form.

ParameterDescription
id1
matrix<int>/matrix<float>
The matrix.
id2
matrix<int>/matrix<float>/series float
A matrix of the same shape, or a number.

matrix.diff ​

pine
matrix.diff(id1, id2) → matrix<float>/matrix<int>

Also a method: id1.diff(id2).

A new matrix of the differences between each row of id1 and the row before it.

The second matrix is ignored here

TradingView's returns id1 minus id2, a matrix or a number. Here id2 is ignored, so matrix.diff(a, b) gives the wrong result. Subtract with matrix.sum(a, matrix.mult(b, -1)) instead.

ParameterDescription
id1
matrix<int>/matrix<float>
The matrix.
id2
matrix<int>/matrix<float>
Read nowhere.

matrix.mult ​

pine
matrix.mult(id1, id2) → matrix<float>

Also a method: id1.mult(id2).

A new matrix: the matrix product of id1 and id2, or id1 with every element multiplied by a number.

For a product, id1 needs as many columns as id2 has rows, and the result has id1's rows and id2's columns. Other shapes give na.

A matrix times an array reads na here

TradingView also multiplies a matrix by an array, giving an array. Here that reads na, so turn the array into a one-column matrix first.

ParameterDescription
id1
matrix<int>/matrix<float>
The matrix on the left.
id2
matrix<int>/matrix<float>/series float
The matrix on the right, or a number.

matrix.kron ​

pine
matrix.kron(id1, id2) → matrix<float>/matrix<int>

Also a method: id1.kron(id2).

A new matrix: the Kronecker product of id1 and id2, in which each element of id1 multiplies a whole copy of id2.

Parameter
id1
matrix<int>/matrix<float>
id2
matrix<int>/matrix<float>

matrix.pow ​

pine
matrix.pow(id, power) → matrix<float>/matrix<int>

Also a method: id.pow(power).

A new matrix: a square matrix multiplied by itself power times.

A power of 0 gives the identity matrix. A negative power gives the inverse of the matrix raised to that power, or na if there is none. A matrix that isn't square gives na.

ParameterDescription
id
matrix<int>/matrix<float>
The square matrix.
power
series int
How many times to multiply it.

matrix.det ​

pine
matrix.det(id) → series float/int

Also a method: id.det().

The determinant of a square matrix: 0 for a singular one, and na for one that isn't square.

Parameter
id
matrix<int>/matrix<float>

matrix.inv ​

pine
matrix.inv(id) → matrix<float>/matrix<int>

Also a method: id.inv().

A new matrix, the inverse of a square matrix, or na when it is singular or not square.

Parameter
id
matrix<int>/matrix<float>

matrix.pinv ​

pine
matrix.pinv(id) → matrix<float>/matrix<int>

Also a method: id.pinv().

A new matrix, the pseudoinverse of id.

Only a full-rank matrix inverts here

Here it works only when the rows or the columns are independent (full rank), and reads na otherwise. TradingView's gives a pseudoinverse for any matrix.

Parameter
id
matrix<int>/matrix<float>

matrix.rank ​

pine
matrix.rank(id) → series int

Also a method: id.rank().

How many independent rows the matrix has, counting pivots larger than 1e-10.

Parameter
id
any matrix type

matrix.trace ​

pine
matrix.trace(id) → series float/int

Also a method: id.trace().

The sum of the main diagonal of a square matrix, or na for one that isn't square.

Parameter
id
matrix<int>/matrix<float>

matrix.eigenvalues ​

pine
matrix.eigenvalues(id) → array<float>/array<int>

Also a method: id.eigenvalues().

An array of the eigenvalues of a square matrix, or na if it isn't square.

A 2 by 2 matrix gives the larger first. A larger matrix gives them in order of size, ignoring sign, so -5 comes before 3.

A complex eigenvalue reads as its real part

An eigenvalue that is a complex number comes back as its real part alone, so a rotation's ±i read 0.

Parameter
id
matrix<int>/matrix<float>

matrix.eigenvectors ​

pine
matrix.eigenvectors(id) → matrix<float>/matrix<int>

Also a method: id.eigenvectors().

A new matrix whose column j is the eigenvector, scaled to length 1, for element j of matrix.eigenvalues.

It reads na if the matrix isn't square, or if a vector can't be found.

Parameter
id
matrix<int>/matrix<float>

matrix.avg ​

pine
matrix.avg(id) → series float/int

Also a method: id.avg().

The mean of the elements, skipping na.

Parameter
id
matrix<int>/matrix<float>

matrix.min ​

pine
matrix.min(id) → series float/int

Also a method: id.min().

The smallest element, skipping na.

Parameter
id
matrix<int>/matrix<float>

matrix.max ​

pine
matrix.max(id) → series float/int

Also a method: id.max().

The largest element, skipping na.

Parameter
id
matrix<int>/matrix<float>

matrix.median ​

pine
matrix.median(id) → series float/int

Also a method: id.median().

The middle element once sorted, skipping na. With an even count it is the mean of the middle two.

Parameter
id
matrix<int>/matrix<float>

matrix.mode ​

pine
matrix.mode(id) → series float/int

Also a method: id.mode().

The element that occurs most often, skipping na. On a tie it gives the smallest of them.

Parameter
id
matrix<int>/matrix<float>

matrix.is_square ​

pine
matrix.is_square(id) → series bool

Also a method: id.is_square().

Whether the matrix has as many rows as columns, and at least one.

Parameter
id
any matrix type

matrix.is_zero ​

pine
matrix.is_zero(id) → series bool

Also a method: id.is_zero().

Whether every element is 0. A matrix with no elements reads true, and a na element reads false.

Parameter
id
matrix<float>

matrix.is_binary ​

pine
matrix.is_binary(id) → series bool

Also a method: id.is_binary().

Whether every element is 0 or 1. A na element reads false.

Parameter
id
matrix<float>

matrix.is_diagonal ​

pine
matrix.is_diagonal(id) → series bool

Also a method: id.is_diagonal().

Whether every element off the main diagonal is 0. A matrix that isn't square reads false.

Parameter
id
matrix<float>

matrix.is_antidiagonal ​

pine
matrix.is_antidiagonal(id) → series bool

Also a method: id.is_antidiagonal().

Whether every element off the diagonal from top right to bottom left is 0. A matrix that isn't square reads false.

Parameter
id
matrix<float>

matrix.is_identity ​

pine
matrix.is_identity(id) → series bool

Also a method: id.is_identity().

Whether the matrix has 1 down its main diagonal and 0 everywhere else. A matrix that isn't square reads false.

Parameter
id
matrix<float>

matrix.is_symmetric ​

pine
matrix.is_symmetric(id) → series bool

Also a method: id.is_symmetric().

Whether the matrix equals its transpose. A matrix that isn't square reads false.

Parameter
id
matrix<float>

matrix.is_antisymmetric ​

pine
matrix.is_antisymmetric(id) → series bool

Also a method: id.is_antisymmetric().

Whether the matrix equals its transpose with every sign flipped, so that its diagonal is 0. A matrix that isn't square reads false.

Parameter
id
matrix<float>

matrix.is_triangular ​

pine
matrix.is_triangular(id) → series bool

Also a method: id.is_triangular().

Whether every element above the main diagonal, or every element below it, is 0. A matrix that isn't square reads false.

Parameter
id
matrix<float>

matrix.is_stochastic ​

pine
matrix.is_stochastic(id) → series bool

Also a method: id.is_stochastic().

Whether every row sums to 1, to within 1e-9, with no negative element.

Parameter
id
matrix<float>

AmenoScript is compatible with Pine Script v6. Pine Script is a trademark of TradingView, Inc., which has no part in AmenoScript.