millionchart
فارسی

Arrays, maps and matrices

A sliding window in an array, counts in two maps and a table of counts in a matrix, each kept in a state from bar to bar.

A collection kept in a state lives from bar to bar, so a script can remember a window of values, a count for each key or a table of counts. The methods are written after the name of the value: window.push(x), totals.at(key), counts.row(0).

Rolling median band#

An array kept in a state as a sliding window: push, shift, size, median and percentile.

Cuprel
// A window of recent closes kept in an array. push adds the newest close at the end, shift drops the oldest once the window is full,
// and median, percentile, min and max read the window. The array is a state, so it lives from bar to bar.
indicator "Rolling median band"
    edition = 1
    display = price

input size: int = 15, name = "Window size", min = 3, max = 200
state window: array<float> = array<float>()
window.push(close)
if window.size() > size
    window.shift()
plot(window.median(), name = "Median", color = color.orange)
plot(window.percentile(90), name = "Upper decile", color = color.green)
plot(window.percentile(10), name = "Lower decile", color = color.red)
plot(window.max() - window.min(), name = "Spread", display = none)

Volume by weekday#

Two maps keyed by the weekday: set, at, keys and size, and a loop over the keys.

Cuprel
// A map keeps a value for each key. The key here is the number of the weekday: the map adds the volume of every bar to its weekday's entry, a second map counts the bars,
// and the keys are walked to find the weekday that has traded the most so far.
indicator "Volume by weekday"
    edition = 1
    display = pane

state totals: map<int, float> = map<int, float>()
state counts: map<int, int> = map<int, int>()
let day = clock.weekday_of(bar.time, zone = "UTC")
totals.set(day, (totals.at(day) ?? 0) + volume)
counts.set(day, (counts.at(day) ?? 0) + 1)
mut busiest = 0
mut most = 0.0
for key in totals.keys()
    if totals.at(key) > most
        most = totals.at(key)
        busiest = key
plot(volume, name = "Volume", style = histogram, color = color.gray)
plot(totals.at(day) / counts.at(day), name = "Average for this weekday", color = color.orange)
plot(busiest, name = "Busiest weekday", display = none)
plot(totals.size(), name = "Weekdays seen", display = none)

Up and down transitions#

A 2 by 2 matrix of counts: set, at, row and trace, and the sum of a row.

Cuprel
// Counting transitions in a matrix. Row 0 stands for "the bar before closed down" and row 1 for "closed up"; the column says the same about the bar after it.
// Each row is divided by its sum, so the first two plots are the share of up bars after an up bar and after a down bar so far; the trace, the sum of the diagonal, gives the share of bars that continued the direction.
indicator "Up and down transitions"
    edition = 1
    display = pane

state counts: matrix<float> = matrix<float>(2, 2, 0.0)
let before = if close[1] > open[1] then 1 else 0
let after = if close > open then 1 else 0
if bar.index > 0
    counts.set(before, after, counts.at(before, after) + 1)
let down_total = counts.row(0).sum()
let up_total = counts.row(1).sum()
plot(counts.at(1, 1) / up_total, name = "Up after up", color = color.green)
plot(counts.at(0, 1) / down_total, name = "Up after down", color = color.red)
plot(counts.trace() / (down_total + up_total), name = "Share that continue", color = color.gray)

Array read with brackets#

Brackets on an array read the history of a series, not an item.

Cuprel · error E3173
// A mistake on purpose: window[1] reads the history of the array, not its second item (window.at(1) does).
indicator "Rolling median band"
    edition = 1
    display = price

input size: int = 15, name = "Window size", min = 3, max = 200
state window: array<float> = array<float>()
window.push(close)
if window.size() > size
    window.shift()
plot(window[1], name = "Second item", color = color.orange)
plot(window.percentile(90), name = "Upper decile", color = color.green)
plot(window.percentile(10), name = "Lower decile", color = color.red)
plot(window.max() - window.min(), name = "Spread", display = none)

Determinant of a matrix that is not square#

A determinant needs a square matrix; this one has two rows and three columns.

Cuprel · error E5614
// A mistake on purpose: a determinant needs a square matrix, and this one has two rows and three columns.
indicator "Up and down transitions"
    edition = 1
    display = pane

state counts: matrix<float> = matrix<float>(2, 3, 0.0)
let before = if close[1] > open[1] then 1 else 0
let after = if close > open then 1 else 0
if bar.index > 0
    counts.set(before, after, counts.at(before, after) + 1)
let down_total = counts.row(0).sum()
let up_total = counts.row(1).sum()
plot(counts.det() / up_total, name = "Up after up", color = color.green)
plot(counts.at(0, 1) / down_total, name = "Up after down", color = color.red)
plot(counts.trace() / (down_total + up_total), name = "Share that continue", color = color.gray)