---
title: "Data types"
description: "The types a wrun indicator is built from. The file is AssemblyScript, TypeScript syntax over fixed-width numbers, so every value has a declared width and the…"
order: 14
section: "core-concepts"
---

<!-- source: docs/indicators/core-concepts/data-types.md; generated by packages/cli/scripts/gen-indicator-docs.ts, do not edit -->

# Data types

The types a wrun indicator is built from. The file is AssemblyScript, TypeScript
syntax over fixed-width numbers, so every value has a declared width and
the compiler names a mismatch before anything runs. An indicator has two
numeric widths, a boolean, module-internal strings, fixed-size arrays,
and classes, and a missing value is simply `NaN`.

## Primitive types

### `f64`

A 64-bit float: every param, input, and output crosses the host boundary
as one. Prices, volumes, scores, ratios, and decisions (`0.0` or `1.0`)
are all `f64`. A literal with a decimal point is an `f64`; a whole-number
literal is not, so annotate or write the point.

```text
let price: f64 = 45000.5;
let volume: f64 = 1000.0;   // 1000 alone would be an i32
let value: f64 = NaN;       // "no value yet"
```

### `i32`

A 32-bit integer: a period, a ring-buffer cursor, a loop counter, and
what `Cross.update()` answers. Params arrive as
`f64`, so a period becomes an integer with an explicit cast:
`new Sma(i32(p_period()))`. Integer division truncates: `7 / 2` on two
`i32` values is `3`.

```text
let period: i32 = 20;
let cursor: i32 = 0;
const bars = i32(p_period());   // f64 to i32, explicitly
```

### `bool`

`true` or `false`, from comparisons (`<`, `>`, `==`, `!=`) and logical
operators (`&&`, `||`, `!`). A `bool` never leaves the module on its own: a
decision becomes an output by turning it into a number, usually with a
ternary.

```text
const isUptrend: bool = fast > slow;
out_is_uptrend(isUptrend ? 1.0 : 0.0);
```

### `string`

Text lives inside the module: labels you build for a text renderer, keys in
a `Map`, comparisons of two literals. Strings never become params, inputs,
or outputs; the only way out is a declared string slot written in
`onBar()` (`presentation/plotting.md`). Building a string allocates, and
the module never frees memory, so per-bar text goes through the
allocation-free line builder (`sb_text`, `sb_f64`) rather than `+`.
Concatenating a number needs `.toString()`: `"close " + close` is refused
with `Type 'f64' is not assignable to type 'String'`.

### `NaN` is the missing value

There is no missing-value type. A missing `f64` is `NaN`: every TA class
returns it until its window is warm, and writing it to an output draws a
gap. Test it with `isNaN(x)`; `x == NaN` is always false. Arithmetic with
`NaN` stays `NaN` (`na-and-scalar-types.md`).

```text
out_filtered(condition ? value : NaN);   // a gap where the condition fails
```

## Core wrun types

### The per-bar value

There is no series type with a whole history behind it. An input is a
reader function that returns this bar's value, and the host calls
`onBar()` once per bar, oldest first. History is whatever you keep:

- a **remembered value** (`prevClose`) for the previous bar;
- a **TA class** (`Sma`, `Ema`, `Rsi`, ...) for anything windowed, since
  each one keeps its own window;
- a **ring buffer** when you need the last N values yourself: `History`
  is one ready-made
  ([Stats, history and lists](../functions/stats-history-lists.md#history-xn-from-pine)), and by hand it is
  a `StaticArray<f64>` plus a cursor.

Inputs are read-only by construction (`bar.close()` or `in_<name>()`
returns a number), and they are read in `onBar()`. The full model is
`core-concepts/execution-model.md`.

### `StaticArray<f64>`

A fixed-size array allocated once, the workhorse for windows. Size it from
a param's declared `max` at module scope or in `onStart()`, never per bar.
`Array<f64>` (growable) and `Map<K, V>` exist too (`collections.md`).

```text
const MAX_BARS = 200;
const window = new StaticArray<f64>(MAX_BARS);
```

### `class`

Your own typed structs with methods (`user-defined-types.md`).

## Input and configuration types

### Params reach the module as numbers or words

Every setting reaches the module through its generated reader, readable
from `onStart()` on, whatever control the dialog draws for it; the kind is
the declaration ([Setting kinds](../settings/kinds.md)). Every kind reads
as an `f64` except text, whose words `pt_<name>()` reads as a `string`:

| Setting you want | wrun form |
| --- | --- |
| a number or a slider | `param.number("mult", 2.0, { min: 0.5, max: 5, step: 0.1 })` or `param.int("period", 20, { min: 1, max: 200 })`, `slider: true` for the slider; plain `param(...)` is the number field |
| a toggle | `param.bool("show_open", true)`, read as a `bool` through `pb_show_open()` |
| a choice among options | `param.choice("kind", ["line", "bar"], "line")`, read as the index (`0` = line, `1` = bar) and switched on in the code |
| a color | `param.color("fast", "#3b82f6")` bound to the output with `color: "@fast"`; the reader hands the code the color packed into one number |
| a symbol | `param.symbol("pair", "BINANCE_FUTURES:ETHUSDT")` bound to an input with `symbol: "@pair"` |
| words | `param.text("label", "Session average")`, read once in `onStart()` with `pt_label()` as a `string` |

### Data sources are members

An indicator names a source as a member of a source namespace, and the
field is part of the reference:

| Identifier | Description |
| --- | --- |
| `ohlcv.close` (and `open`, `high`, `low`, `volume`) | Price and volume; the chart's own candle needs no declaration (`bar.close()` and the other `bar` fields read it) |
| `funding.rate_close` (and `rate_open`, `predicted_close`, ...) | Funding rates |
| `liquidations.liquidations` | Liquidation volume, optionally by `side` |
| `oi.close` | Open interest |
| `trades.volume` with `side: "BUY"` or `"SELL"` | Side-split trade volume |
| `time.bar_open_sec` | The bar's open time in epoch seconds |

The complete catalog, celled classes included, is `data-sources.md`.

### Placement is per output

An indicator places each output: `overlay` (the price pane) or `lower`
(its own pane), as the third argument of `output(...)`.

## Visual and plotting types

### Color

A color is a string literal in a declaration: `#rrggbb`, `#rrggbbaa`,
`rgb()`, `hsl()`, or a named color on an output. It is never a runtime
value; there is no color variable, and a per-bar color is a data-only
output indexing a declared `colors` palette through `color_by`
(`color-constants.md`).

```text
output("fast", line, overlay, { color: "#FF6B35" });
output("mid", line, overlay, { color_by: "regime", colors: ["#ef4444", "#22c55e"] });
```

### Plot and shape kinds

The second argument of `output(...)` is the plot kind: `line`, `bar`,
`area`, `histogram`, `candle`, `shape`, `scatter`, or `none` (data-only).
A `shape` output draws a mark at its value; the mark's kind is the host's
default, and `render.shape` picks one of `circle`, `cross`,
`triangle_up`, `triangle_down`, `diamond`, `arrow_up`, `arrow_down`,
`flag`, `square` (`presentation/plotting.md`).

## Practical examples

### Colors for multi-line plots

An indicator declares each line's color on its output, and the palette
lives in the file's declarations:

```typescript sample=cc-types-multi-ma
output("sma10", line, overlay, { color: "#FF6B35", width: 2, description: "10-period simple moving average" });
output("sma20", line, overlay, { color: "#3B82F6", width: 2, description: "20-period simple moving average" });
output("sma50", line, overlay, { color: "#10B981", width: 2, description: "50-period simple moving average" });

let sma10 = new Sma(10);
let sma20 = new Sma(20);
let sma50 = new Sma(50);

function onBar(): void {
  const close = bar.close();
  // Each line starts when its own window is warm: the shorter averages draw first.
  out_sma10(sma10.update(close));
  out_sma20(sma20.update(close));
  out_sma50(sma50.update(close));
}
```

The three periods are fixed here, so there is no `onStart()`; each line
draws as soon as its own average is warm, the slower two writing `NaN` (a
gap) until their own windows fill.

### Conditional plotting with `NaN`

Combine a condition with `NaN` to draw a value only when the condition
holds:

```typescript sample=cc-types-conditional
param("limit", 50, { min: 0, max: 1000000, description: "Volume a bar must exceed to be drawn" });
output("filtered", line, overlay, { color: "#dc2626", width: 2, description: "Close, only on bars whose volume exceeds the limit" });
output("volume", histogram, lower, { color: "#94a3b8", description: "Volume" });

let limit: f64 = 50.0;

function onStart(): void {
  limit = p_limit();
}

function onBar(): void {
  const close = bar.close();
  const volume = bar.volume();
  // NaN draws nothing: the line breaks wherever the condition fails, and the volume pane still draws.
  out_filtered(volume > limit ? close : NaN);
  out_volume(volume);
}
```

Writing `NaN` to one output leaves the other outputs drawing; returning
early from `onBar()` before any write leaves the whole bar blank. Both are
correct; pick by whether anything on the bar is meaningful.

## Type conversion and indexing

A candle is not one value with indexed columns. An indicator reads the
chart's own candle one field at a time (`bar.open()`, `bar.high()`,
`bar.low()`, `bar.close()`, `bar.volume()`) and the timestamp through
`bar.time()` (seconds, not
milliseconds). There is no `priceIndex` argument anywhere: a class takes
the number you hand it. Casts are explicit (`i32(x)`, `f64(n)`) and
indexing a number is refused (`type-system.md` lists the messages).

## Best practices

- **Name by what it is.** `prevClose`, `windowHigh`, `barsSeen`: a module-
  level variable's name should say what it carries across bars.
- **Annotate module-level state.** `let value: f64 = NaN;` and
  `let cursor: i32 = 0;` read as documentation and stop an integer literal
  from silently making a variable an `i32`.
- **Keep decisions as outputs.** A `bool` you want to draw or alert on is a
  `0.0` / `1.0` output declared `none`; the sheet turns it into a look.
- **Let `NaN` mean missing.** Never write `0` for "not ready"; a zero is
  drawn and alerted on as a real value.
