Sources

Rolling Sources

ValueScroll and PaletteScroll keep a moving window of columns. One new column arrives per bar, and the oldest is overwritten in place.

Updated Publisher Alien_AlgorithmsPine Script v6

When to use a scroll

Use a rolling source when a picture grows by one column each bar: an oscillator map, a volatility strip, a state history. A field would need its whole content shifted left on every bar. A scroll overwrites its oldest column instead and never moves the rest.

Create and push

A scroll and one column per barpine
var pc.ValueScroll history = pc.valueScroll(5, 150)   // rows, capacity

if barstate.isconfirmed
    history.push(array.from(rsi5, rsi8, rsi13, rsi21, rsi34))
  • valueScroll(rows, capacity) and paletteScroll(rows, capacity) take from 2 to 99,999 rows and columns of capacity.
  • push(column) takes exactly rows values, bottom row first, and returns the scroll.
  • A value scroll takes an array<float> in which na is transparent. A palette scroll takes an array<int> in which -1 is transparent.
Push on confirmed bars
Calling push() inside barstate.isconfirmed keeps one column per completed bar. Pushing on every realtime tick would add a column per tick.

The moving window

A scroll shows only the columns it has been given. Until it is full, it is as wide as the number of pushes. Once capacity is reached, each new column overwrites the oldest.

FieldMeaning
rowsCells in every pushed column.
capacityThe most columns the scroll keeps.
writtenColumns pushed so far, stopping at capacity. This is the current width.

Draw a scroll

One draw callpine
if barstate.islast
    heat.drawLookback(history, 0.0, 5.0)   // source, bottom, top
  • A scroll is drawn with drawLookback(scroll, bottom, top, rightOffset = 0). It ends at the current bar, uses one bar per column, and puts the newest column on the right.
  • At least two columns must have been pushed. Before that the call does nothing and leaves any existing drawings as they are.
  • rightOffset shifts the right edge by a number of bars, forward when positive.

A rolling heatmap

Five RSI lengths, one column per confirmed barpine
//@version=6
indicator("PineCanvas - Rolling RSI Heatmap", overlay = false,
  max_polylines_count = 100)
import Alien_Algorithms/PineCanvas/1 as pc
// Make sure to update to the latest library version

// Stateful series calculations must run on every bar.
float rsi5 = ta.rsi(close, 5)
float rsi8 = ta.rsi(close, 8)
float rsi13 = ta.rsi(close, 13)
float rsi21 = ta.rsi(close, 21)
float rsi34 = ta.rsi(close, 34)

var pc.ValueScroll history = pc.valueScroll(5, 150)
var pc.Canvas heat = pc.heatmap(
  pc.gradient(#602060, #305bb4, #31b6ad, #f4d24c, #f07735))
  .colorLevels(32)
  .valueRange(0.0, 100.0)
  .opacity(25, 100)

if barstate.isconfirmed
    history.push(array.from(rsi5, rsi8, rsi13, rsi21, rsi34))

if barstate.islast
    heat.drawLookback(history, 0.0, 5.0)

The fixed valueRange(0, 100) keeps a colour tied to an RSI value, so the map does not re-colour itself as the window moves.

A state strip

Price against three averagespine
//@version=6
indicator("PineCanvas - Trend State Strip", overlay = false, max_polylines_count = 100)
import Alien_Algorithms/PineCanvas/1 as pc

// Stateful series calculations must run on every bar.
float ema20 = ta.ema(close, 20)
float ema50 = ta.ema(close, 50)
float ema200 = ta.ema(close, 200)

var pc.PaletteScroll states = pc.paletteScroll(3, 200)
var pc.Canvas strip = pc.newCanvas(array.from(color.red, color.teal))

if barstate.isconfirmed
    states.push(array.from(close >= ema200 ? 1 : 0, close >= ema50 ? 1 : 0, close >= ema20 ? 1 : 0))

if barstate.islast
    strip.drawLookback(states, 0.0, 3.0)

Each column holds three palette indices: red when price closed below an average, teal when it closed above. The slowest average is the bottom row because the pushed array is read bottom row first.

Scaling a rolling value source

Automatic scaling can look at the whole window, at each column, or at each row. For rows that have different natural ranges, autoScale(pc.ScaleMode.eachRow) lets each one use the full gradient. Canvas & Styling describes the modes.

Automatic scaling follows the window
With autoScale() the range is recalculated from the columns currently held, so colours can shift as old extremes leave the window. Use valueRange() when a colour must keep one meaning.

Next: a scroll is the simplest heatmap source. For a heatmap anchored to price levels, see Heatmaps on Price.

PineCanvas is a graphics library for Pine Script. TradingView drawing, memory, and execution limits still apply. © Alien_Algorithms.