TradingCharts

Type System

Every value in ChartScript has two tags: a type (what shape the value has) and a qualifier (how often it changes). The compiler uses both to decide where a value may be used.

Types

Fundamental types

Type Example literals Notes
int 0, 42, -7, 1_000_000 Underscore separators allowed.
float 3.14, .5, 1e-4, math.pi IEEE-754 double; a bare integer literal auto-promotes.
bool true, false, na na is accepted anywhere a bool is expected and reads as false.
string "text", 'text' Double- and single-quote delimited; same semantics.
color #RRGGBB, #AARRGGBB, color.aqua 24-bit RGB or 32-bit ARGB literals; see Colors.

The special value na (not available) belongs to every type and signals "no value yet" — common on the first bars of a moving average, on days without a dividend, and when a request.* call returns no data for the current bar.

Series and simple values

The series/simple split is the heart of the language. A value is series when it changes bar to bar (close, volume, ta.sma(close, 20), anything derived from a bar). A value is simple when it is fixed over the entire run (a literal, a declared var constant, the result of input.*()).

int   length = 20            // simple int   (input-style constant)
float ma     = ta.sma(close, length)   // series float
bool  up     = close > open  // series bool  (changes every bar)

Series values are historical: close[0] is the current bar's close, close[1] the previous bar's, and so on back to bar 0 of the chart's history. Simple values have no [n] dimension (they never changed, so looking back has no meaning).

User-defined types (UDTs) and enums

Scripts can declare their own structured types with type and enumerated string sets with enum:

type Pivot
    int   bar
    float price
    bool  isHigh

enum Trend
    bull = "Bullish"
    bear = "Bearish"
    flat = "Neutral"

Collection types

Collection Written as See also
array array<float> Arrays
map map<string, int> Maps
matrix matrix<float> Matrices

Collections are mutable; array.push(), map.put(), and matrix.set() modify the collection in place.

Qualifiers

A qualifier records how often a value changes:

Qualifier Changes… Produced by
const never literals, var initializers to literals
input at most once, when the user edits an input input.*() calls
simple never during a run const + input together
series every bar close, volume, time, any arithmetic involving a series

Qualifiers form a widening order: const < input < simple < series. A location that requires const may accept nothing less constant; a location that accepts series accepts everything.

Example — this fails because length is series int (it is read on every bar), but ta.sma's length parameter wants simple int:

length = bar_index                // series int
ma     = ta.sma(close, length)    // compile error: expected simple int

The fix is to make length simple:

length = input.int(20, "Length")  // input int (narrows to simple when used)
ma     = ta.sma(close, length)    // OK

Automatic conversions

The compiler inserts the following conversions silently:

  • int → float (20 where a float is expected).
  • const → wider qualifier when a wider is required.
  • Any type → string when the target position is a format string (str.format placeholders).

No other conversion is implicit. Explicit conversion uses the str.tostring/str.tonumber/int(x)/float(x)/bool(x) family.

na and type-tagged variables

A variable declared with only an initial na has an inferred type, which the compiler locks to the type of the first non-na value you assign:

var pivotPrice = na    // inferred later
if ta.pivothigh(5, 5) != na
    pivotPrice := high[5]      // locks to float

To declare the type up front (useful when the first assignment may be na), use an explicit type keyword:

var float pivotPrice = na

Explicit type keywords: int, float, bool, string, color, plus any UDT or array<…>/map<…>/matrix<…> form.

Checking for na

Use na(x) or nz(x, replacement):

previousClose = na(close[1]) ? close : close[1]       // fallback
smoothed      = nz(ta.sma(close, 20), close)          // 0-replace via nz

Comparison against na with ==/!= is accepted but discouraged — na(x) is clearer and always correct.

See also