References & offsets

13 functions

REF(X, N)

The value of X N bars ago. N may be a series.

Where the reference falls outside the data, the previous available value is carried forward.

X(series)
The series to look back into.
N(integer)
How many bars back. 1 is the previous bar. May itself be a series.
// bar-on-bar return
CHG: CLOSE / REF(CLOSE, 1) - 1;

// gap: today's open against yesterday's close
GAP: (OPEN - REF(CLOSE, 1)) / REF(CLOSE, 1) * 100, COLORSTICK;

// N as a series — always look back to the last signal bar
BACK := BARSLAST(CROSS(MA5, MA20));
SIGPRICE: REF(CLOSE, BACK);
REFV(X, N)

Same as REF but returns an invalid value instead of carrying forward.

X(series)
The series to look back into.
N(integer)
How many bars back.
// REF flattens the first 20 bars into a repeated value;
// REFV leaves them empty, which is what you want on a chart
FLAT: REF(CLOSE, 20),  COLORGRAY;
GAPPED: REFV(CLOSE, 20), COLORYELLOW;
REFX(X, N)

The value of X N bars in the future — a forward-looking reference.

Forward references make historical output look better than live trading ever will. Use them for research, not for signals.

X(series)
The series to look forward into.
N(integer)
How many bars ahead.

Also written as REFX1

// research only: what did price do in the 5 bars after a signal?
SIG := CROSS(MA5, MA20);
FWD: IF(SIG, REFX(CLOSE, 5) / CLOSE - 1, DRAWNULL);
// on the last 5 bars there is no future yet, so FWD goes blank there
REFXV(X, N)

Forward reference that returns an invalid value at the right edge.

X(series)
The series to look forward into.
N(integer)
How many bars ahead.
// same as REFX, except the last N bars stay empty
// instead of repeating the final value
FWD: REFXV(CLOSE, 5), COLORYELLOW;
VALUEWHEN(COND, X)

The value X had the last time COND was true, held until the next occurrence.

COND(condition)
When to sample X.
X(series)
The series to sample and hold.
// entry price, held flat until the next crossover
ENTRY: VALUEWHEN(CROSS(MA5, MA20), CLOSE), COLORYELLOW;

// floating P/L against that entry
PNL: (CLOSE - ENTRY) / ENTRY * 100, COLORSTICK;
CONST(X)

The final value of X, broadcast as a constant across every bar.

X(series)
The series whose last value is taken.
// a flat line at the most recent close, across the whole chart
LAST: CONST(CLOSE), COLORGRAY, DOTLINE;

// percentage distance of every bar from that level
DIST: (CLOSE / CONST(CLOSE) - 1) * 100;
ISVALID(X)

1 where X holds a usable number, 0 where it is missing or invalid.

X(series)
The value to test.
// MA60 is invalid until 60 bars have accumulated —
// fall back to price so the line has no hole at the left edge
SAFE: IF(ISVALID(MA(CLOSE, 60)), MA(CLOSE, 60), CLOSE);

// guard a division that can hit zero
RATIO: IF(ISVALID(VOL / MA(VOL, 20)), VOL / MA(VOL, 20), 1);
ALIGNRIGHT(X)

Right-aligns a shorter series against the last bar instead of the first.

X(series)
The shorter series to re-align.
// a series borrowed from elsewhere may be shorter than the chart;
// align it to the right so the newest values line up with today
ALIGNED: ALIGNRIGHT(COVER_C('WEEK')), COLORYELLOW;
TESTSKIP(COND)

Abort evaluation of the rest of the script when COND is false — a fast exit for scans.

COND(condition)
Evaluation continues only where this holds.
// cheap filter first, expensive maths afterwards —
// symbols that fail the filter never reach the heavy lines
TESTSKIP(VOL > MA(VOL, 20) * 2);
SIG: CROSS(MA(CLOSE, 5), MA(CLOSE, 60)) AND CLOSE > MA(CLOSE, 250);
BACKSET(COND, N)

When COND is true, set the current bar and the preceding N−1 bars to 1.

Reaches backwards in time, so anything built on it repaints. Common inside pivot detection.

COND(condition)
The trigger. Where it holds, the fill starts.
N(integer)
How many bars to fill, counting the trigger bar itself.
// shade the 5 bars leading into each new 20-bar high —
// note this only appears once the high is in, so it repaints
LEADIN := BACKSET(HIGH >= HHV(HIGH, 20), 5);
STICKLINE(LEADIN, HIGH, LOW, 8, 1), COLORLIBLUE;
REVERSE(X)

Negates X — equivalent to 0 − X.

X(series)
The series to negate.
// mirror volume below the axis to build a two-sided histogram
UPVOL:   IF(CLOSE > OPEN, VOL, 0), COLORSTICK;
DOWNVOL: IF(CLOSE < OPEN, REVERSE(VOL), 0), COLORSTICK;
COVER_C(PERIOD) · COVER_C(PERIOD, N)

Close of a higher timeframe, resampled onto the current bars. The two-argument form references N of those higher-timeframe bars back.

PERIOD is a name such as 'MIN5', 'MIN15', 'MIN30', 'MIN60', 'DAY', 'WEEK', 'MONTH', 'SEASON', 'HALFYEAR' or 'YEAR'. Conversion only goes from a smaller timeframe to a larger one — asking for 'MIN5' while on a daily chart returns nothing. COVER_O, COVER_H, COVER_L, COVER_V and COVER_A work identically for the other fields.

PERIOD(string)
Timeframe name, e.g. 'MIN60', 'DAY', 'WEEK'. Must be larger than the chart's own timeframe.
N(integer)
Optional. How many bars back in that larger timeframe.

Also written as COVER_O, COVER_H, COVER_L, COVER_V, COVER_A

// weekly moving average, drawn on a daily chart
WEEKMA: MA(COVER_C('WEEK'), 5), COLORYELLOW;

// last week's range, held across this week's bars
PREVHIGH: COVER_H('WEEK', 1), COLORGRAY, DOTLINE;
PREVLOW:  COVER_L('WEEK', 1), COLORGRAY, DOTLINE;
SYSPARAM(N)

Viewport information: 2 first visible bar index, 3 last visible bar index, 4 highest high in view, 5 lowest low in view.

Using it makes the script recompute on every pan and zoom, because its value depends on what is currently on screen.

N(integer)
Which field: 2 first visible bar, 3 last visible bar, 4 highest high in view, 5 lowest low in view.
// pin the visible range to the top-left corner of the pane
DRAWTEXT_FIX(ISLASTBAR, 0.02, 0.05, 0,
             VARCAT('H ', VAR2STR(SYSPARAM(4), 2))), COLORWHITE;
DRAWTEXT_FIX(ISLASTBAR, 0.02, 0.12, 0,
             VARCAT('L ', VAR2STR(SYSPARAM(5), 2))), COLORWHITE;