---
title: "General FAQ"
description: "Frequently asked questions about wrun: getting started, data sources and context, technical indicators, plotting, troubleshooting, language features…"
order: 116
section: "faq"
---

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

# General FAQ

Frequently asked questions about wrun: getting started, data sources and context, technical indicators, plotting, troubleshooting, language features, performance, and the error messages people search for.

## Getting started

**What is a wrun indicator?** One file in TypeScript syntax. You write it in the chart's editor, **Run** compiles it in your browser and draws it on the chart, and **Publish** puts it on OpenMarket for you, the people you invite, or everyone. Once published it runs in each reader's browser, or on OpenMarket's servers when its code is **Protected**. Every output is a number series: a line, a shape, a box coordinate, and every drawn one is a value an alert can follow. The module has no filesystem, no network, and no order capability. [Your first indicator](../getting-started/primer-first-indicator.md) walks through the first one.

**Do I need to know TypeScript?** The file is AssemblyScript: TypeScript syntax over fixed-width numbers. You need about a page of it: `let x: f64 = NaN` declares a number, `i32(...)` turns a float into a whole number, `function`, `if`, `for`, and `class` work as in TypeScript, and there is no `any`, no closures capturing locals, and no dynamic typing. The **Moving Average** starter (`sma-codefirst`) is a handful of lines with a comment on every statement; if you can read it, you can write one.

**Why does an indicator declare its outputs instead of drawing them?** An indicator declares what it reads and writes at the top of the file and computes numbers once per bar in `onBar()`; the chart draws from the declarations. That is what lets one file compile in your browser, compute the same way in each reader's browser or on OpenMarket's servers, and carry alerts that run in OpenMarket's cloud. [What is wrun](../getting-started/introduction.md) has the full picture.

**I have a file written with `init`, `state`, `finalize` and `reset`. Does it still work?** Yes, unchanged: a file that exports those four functions builds and runs exactly as it did, next to files written with `onBar()`. [Execution model](../core-concepts/execution-model.md#the-four-function-form) describes that form.

## Data sources and context

**How does an indicator know which market the chart shows?** Nothing you write. `bar.close()`, or an `input("close", ohlcv.close)` with no pin, follows the chart's own market and interval, and the module never sees a market name. A fixed market is a pinned secondary input, `input("btc", ohlcv.close, { symbol: "BTCUSDT", exchange: "BINANCE_FUTURES" })`: the chart fetches that market's candles and joins them to yours bar by bar ([Data sources](../core-concepts/data-sources.md)).

**Why is the start of my line empty?** The TA classes return `NaN` until their window fills, and a `NaN` output draws nothing on that bar. That is warm-up, not a bug: a 200-bar average has no value on bar 50. Load more history if the line never appears, and read [Execution model](../core-concepts/execution-model.md) for how warm-up works.

**Can I read the previous bar?** Yes, with `History` from `./sdk/stats`: `push()` the value once per bar in `onBar()`, then `ago(1)` is the previous bar's value, and `max()`, `min()`, `mean()` and `sum()` read the whole window ([Stats, history and lists](../functions/stats-history-lists.md#history-xn-from-pine)). There is no `close[1]` index, and `onBar()` sees exactly one bar. By hand it is the same idea: keep the value in a module-level variable when you see it, and a window is a `StaticArray<f64>` you fill as a ring buffer, sized from the param's `max` so it is allocated once:

```typescript sample=faq-previous-bar
param("bars", 5, { min: 2, max: 50, description: "Bars in the trailing window" });
output("change", line, lower, { description: "Close minus the previous bar's close" });
output("window_high", line, overlay, { description: "Highest high of the trailing window" });

const MAX_BARS = 50;
const highs = new StaticArray<f64>(MAX_BARS);
let n: i32 = 5;
let cursor: i32 = 0;
let count: i32 = 0;
let prevClose: f64 = NaN;

function onStart(): void {
  n = i32(p_bars());
}

function onBar(): void {
  const close = bar.close();
  // The previous close is whatever we kept from the previous call: there is no close[1] to read.
  const change = isNaN(prevClose) ? NaN : close - prevClose;
  prevClose = close;
  highs[cursor] = bar.high();
  cursor = (cursor + 1) % n;
  if (count < n) count += 1;
  if (count < n || isNaN(change)) return;
  let h = -Infinity;
  for (let i = 0; i < n; i++) if (highs[i] > h) h = highs[i];
  out_change(change);
  out_window_high(h);
}
```

**Can I analyze multiple markets in one indicator?** Yes: one pinned `ohlcv` input per market, `symbol` and `exchange` always together. The first input stays unpinned and defines the grid; the chart fetches each pinned market's candles at the chart's interval and joins them by timestamp under the input's `missing` policy, live from that market's own feed. Other sources (trades, funding, open interest, liquidations) always read the chart's own market. Stocks, ETFs, forex, gold and silver pin the same way ([Stocks, forex and gold](../core-concepts/multi-source.md#stocks-forex-and-gold)), and an alert reads the pinned markets too ([Alerts](../functions/alerts.md)):

```typescript sample=faq-multi-market
// The first input is the grid: it follows the chart's own market.
input("close", ohlcv.close);
// Pinned inputs read fixed markets; symbol and exchange always pin together.
input("btc_close", ohlcv.close, { symbol: "BTCUSDT", exchange: "BINANCE_FUTURES" });
input("eth_close", ohlcv.close, { symbol: "ETHUSDT", exchange: "BINANCE_FUTURES" });
output("eth_btc", line, lower, { description: "ETH priced in BTC" });
output("vs_btc", line, lower, { unit: "%", description: "This market's close as a percent of BTC's" });

function onBar(): void {
  const btc = in_btc_close();
  if (isNaN(btc) || btc <= 0.0) return;
  out_eth_btc(in_eth_close() / btc);
  out_vs_btc((bar.close() / btc) * 100.0);
}
```

**Can I write an indicator without a data source?** Not without the chart's own candles. A file with `onBar()` and no `input(...)` line runs on them: the chart's close is the bar grid the module walks, whether or not the code reads `bar.close()`. It still needs an output, and **Run** refuses a file without one by name (`a file with onBar() needs at least one output(...) statement: declare what the Indicator draws, e.g. output("value", line, overlay), and write it in onBar() with out_value(...)`). A constant you want to draw is an output written to the same value on every bar.

**Can I declare inputs inside `if`, a loop, or a function?** No. Declarations are read from the text before anything runs, so they are top-level statements of the entry file only; one inside a function is refused with `input(...) declarations must be top-level statements, not inside a function, class, or expression`. Every input is fetched before the first bar, so there is no such thing as a conditional subscription.

**How do I read the order book?** Declare a celled input over the `book` class behind the first input line, `input("close", ohlcv.close)` then `input("book", book.cells, { max_cells: 1000, block_size: 10 })`, and scan its `[price, size, side]` tuples in `onBar()` through the generated `in_book_cells()` count and `in_book_view()` buffer. The chart serves the book it loads for its own market, up to 500 price levels a side, so a full book is up to 1,000 tuples and a smaller `max_cells` refuses the run; `block_size` is required by the declaration, but the chart does not read it. [Order flow](../functions/order-flow-kit.md#depth-window-scans-by-hand) has the bid and ask sums as worked scans.

**How does an indicator handle data gaps?** With a declared policy per input rather than interpolation. A secondary input carries its last value forward by default (`missing: "carry"`), delivers `NaN` on bars without an observation under `missing: "nan"`, or `0` under `missing: "zero"`. Line plots do not interpolate across `NaN`; a gap is a gap. When you want your own fill, do it in `onBar()`:

```typescript sample=faq-forward-fill
input("close", ohlcv.close);
// A sparse feed: bars with no liquidation deliver NaN instead of repeating the last value.
input("liqs", liquidations.liquidations, { missing: "nan" });
output("liq", line, lower, { description: "Liquidation volume this bar, 0 on quiet bars" });
output("last_liq", line, lower, { description: "The most recent liquidation volume, carried forward" });

let lastLiq: f64 = NaN;

function onBar(): void {
  const x = in_liqs();
  let liq: f64;
  if (isNaN(x)) {
    liq = 0.0; // your own zero policy
  } else {
    liq = x;
    lastLiq = x; // your own forward fill
  }
  out_liq(liq);
  out_last_liq(lastLiq);
}
```

On the primary input, `"nan"` and `"zero"` do more: they densify the grid, so a naturally sparse feed becomes one row per bar ([Data sources](../core-concepts/data-sources.md)).

## Technical indicators

**Why am I getting NaN in my calculations?** Three usual causes: a TA class that has not warmed up yet, a division by zero, or an input under `missing: "nan"` on a bar with no observation. Check with `isNaN(x)` (there is no `isnum`; `!isNaN(x)` is the same test), and decide per value: return from `onBar()` before any write (nothing is drawn for that bar), write `NaN` to that one output, or substitute. A two-line `nz` helper covers the substitution case ([Best practices](best-practices.md)).

**Which TA classes exist?** 52 stateful classes in `./sdk/ta` (`Sma`, `Ema`, `Rsi`, `Atr`, `Bb`, `Macd`, `Stoch`, `Adx`, `Supertrend`, an anchored `Vwap`, and the rest). The [TA library](../functions/ta-library.md) lists every class with its constructor, `update()` arguments, and fields. `./sdk/ta-plus` adds 30 more of the same shape (`Dema`, `Tema`, `Trix`, `Kama`, `Aroon`, `Vortex`, the volume lines, Pine's two-length `Dmi`, `SourceStoch` and `SourceVwap` over any source, `HeikinAshi`, and the rest) on [Extra indicators](../functions/extra-indicators.md). The kit pages beside it cover what sits around the math: [Strings and text](../functions/text-formatting.md), the [Clock and sessions kit](../functions/time-and-sessions-kit.md), the [Colors](../functions/colors-kit.md), the [Order flow](../functions/order-flow-kit.md), the [Levels kit](../functions/levels-kit.md) and the [Market structure kit](../functions/market-structure-kit.md).

**How do I use a param as a period?** Read it in `onStart()` and cast it: `sma = new Sma(i32(p_period()))`. Params are `f64`; a period is `i32`; the cast is explicit and the compiler refuses to guess.

## Plotting and visualization

**How do I draw several lines on the same chart?** One `output(...)` per line. `overlay` puts it on the price pane, `lower` in its own pane; `color`, `width`, `opacity`, and `description` are per output ([Plotting](../presentation/plotting.md)).

**Can I plot conditional signals?** Yes: a `shape` output draws a mark at its value only on bars where a second, data-only output named in `shape_where` is nonzero. The decision is a number:

```typescript sample=faq-conditional-mark
param("len", 14, { min: 2, max: 200 });
param("level", 30, { min: 5, max: 50, description: "RSI at or below this counts as oversold" });
output("rsi", line, lower, { color: "#a78bfa" });
// The mark sits at the output's value (this bar's low) and draws only on bars where the gate is 1.
output("buy", shape, overlay, { color: "#22c55e", shape_where: "oversold" });
output("oversold", none);

let rsi = new Rsi(14);
let level: f64 = 30.0;

function onStart(): void {
  rsi = new Rsi(i32(p_len()));
  level = p_level();
}

function onBar(): void {
  const value = rsi.update(bar.close());
  if (isNaN(value)) return;
  out_rsi(value);
  out_buy(bar.low());
  out_oversold(value <= level ? 1.0 : 0.0);
}
```

**How do I change plot colors dynamically?** With a palette and a decision: `color_by` names a data-only output, and each bar's value indexes `colors` (floored; a missing or out-of-range value falls back to entry 0):

```typescript sample=faq-dynamic-color
param("fast", 10, { min: 1, max: 200 });
param("slow", 30, { min: 2, max: 400 });
// Each bar's trend value (0 or 1) indexes the palette: red below the slow average, green above.
output("price", line, overlay, { width: 2, color_by: "trend", colors: ["#ef4444", "#22c55e"] });
output("trend", none);

let fast = new Sma(10);
let slow = new Sma(30);

function onStart(): void {
  fast = new Sma(i32(p_fast()));
  slow = new Sma(i32(p_slow()));
}

function onBar(): void {
  const close = bar.close();
  const f = fast.update(close);
  const s = slow.update(close);
  if (isNaN(s)) return;
  out_price(close);
  out_trend(f > s ? 1.0 : 0.0);
}
```

**Can I write an output inside a conditional or a loop?** The writers are ordinary calls in `onBar()`, so `if (...) out_x(a); else out_x(b);` is fine, and so is computing a value in a loop and writing it once. Each output holds one value per bar: the last write wins, so writing the same output in a loop is a longer way of writing it once. To draw nothing for one output on a bar, write `NaN` to it, or leave it unwritten.

**What is the difference between `line`, `area`, `histogram`, and `scatter`?** They are the plot kinds an output can declare, and they change the look, not the value: `line` joins the points, `area` fills under them, `histogram` and `bar` draw a column per bar, `scatter` draws a point per bar, `candle` draws four outputs as a candle, `shape` draws a gated mark, and `none` computes without drawing. [Plotting](../presentation/plotting.md) lists the options each one takes.

**How does positioning work for shapes and text?** A `shape` output draws at (this bar, its value); there is no separate `location` argument, so put the mark at the bar's low or high by writing that price. Text comes from string slots: `render.text` draws one mark per bar at (bar, a named output), `render.label` draws ONE label at (`x`, `y`) where `x` is an output in epoch seconds (the `time` source), and boxes and segments place themselves by bar offsets from the current bar ([Drawing objects](../presentation/drawing-objects.md)).

**My line hugs the bottom of the price chart.** It is a small-magnitude series drawn on the price axis. Declare it `lower`.

**My box draws with no fill.** Its `opacity` is `0`; the default is 0.2. (A named color never gets that far: the sheet check refuses it and asks for hex, `rgb()`, or `hsl()`.)

**My mark draws on every bar.** A `shape` output without `shape_where` draws wherever it has a value. Add a data-only gate output and name it in `shape_where`; write `0` to the gate on quiet bars.

## Common issues and troubleshooting

**My indicator isn't displaying anything. What's wrong?** Check, in this order: the editor's Console (a build that stopped at any stage draws nothing, and after a **Run** of a draft it says when an output was `NaN` on every bar); whether `onBar()` ever reaches its writes (a TA class that needs more bars than the chart loaded returns `NaN` on every bar); whether the output you expect is declared `none`; whether the chart's market serves the source the input reads (the chart says so by name, and the overlay's legend shows **Could not load**); and whether a pin was refused, or reads nothing on this market. [Debugging](debugging.md) is the full workflow.

**Undefined identifier errors.** `Cannot find name 'out_sma'` means the accessor does not exist: you renamed or removed the declaration, or misspelled the name. Accessors are generated from the declarations, one per name, lowercased with every run of characters outside `[a-z0-9_]` collapsed to `_`: `param("fast.len", ...)` is `p_fast_len()`, `input("BTC-Close", ...)` is `in_btc_close()`. Capitals are fine either way: the accessor also answers to the spelling your file uses, so `param("fastLen", ...)` is read by `p_fastLen()` as well as `p_fastlen()`. Update the call; the compiler's hint names the declaration an `out_`, `p_`, or `in_` name comes from. A plain variable you forgot to declare is the same message from the compiler.

**How do I debug my indicator?** Three ways, all in the editor. Log text with the debug log: `string("debug", { max_bytes: 256 })` and `str_debug(text)` in `onBar()` print each bar's line in the Console. Read numbers at the Console prompt: after a **Run**, type an output's name, `last 20` and an output's name, or an expression. Or declare the suspect value as an output: a `lower` line to see its shape, a `none` output to read it at the prompt without drawing it. [Debugging](debugging.md) has the workflow and the usual suspects.

**Why isn't my indicator updating in real time?** It is, at the chart's pace: the forming bar re-evaluates as live updates arrive, at most about once a second per indicator (updates in between are coalesced, and the last one is never dropped). Each time, the chart restores the module's state as it stood after the last closed bar and runs the forming bar again, so a live value never double-counts. The order book, trades, funding, liquidations, and the volume profile arrive as they happen; open interest, implied volatility, skew, the options chain, and ETF flows are polled, so they move when their poll lands. A draft's overlay stops with its session: **Run** it again after a reload.

**Can I use `null` instead of `NaN` for missing data?** No. Outputs are `f64`, and `f64` has no `null`: `NaN` is the one value that means "nothing here", and the chart draws a gap for it. Writing `0` draws a zero. `isNaN(x)` is the test, and there is no `null` to compare against.

**The chart refuses my symbol or interval pin.** The chart serves pins with restrictions: a market pin only on a secondary `ohlcv` input, one market per pin and never a CME Group venue (`CME`, `CBOT`, `NYMEX`, `COMEX`, `GLOBEX`), an interval pin only coarser than the chart and a whole multiple of it (on `ohlcv`, `odds`, `funding`, and `oi`) and never `3d` on a stock, forex or gold market, and no market or interval pin on the first input. Anything else, an exchange id outside the [list](../reference/symbol-format.md) included, is refused by name in the Console before anything is fetched ([Limitations](../reference/limitations.md), [Multi-timeframe](../core-concepts/multi-timeframe.md)).

## Language features and syntax

**Does it support `switch` statements?** Yes, over integers, with the same fallthrough rules as TypeScript (write `break`). Bucket a float into a small integer first, then branch:

```typescript sample=faq-switch
param("len", 14, { min: 2, max: 200 });
output("score", line, lower, { description: "-1 oversold, 0 neutral, 1 overbought" });

let rsi = new Rsi(14);

// A switch runs over integers: bucket the value first, then branch. Each case breaks.
function zone(value: f64): i32 {
  if (value <= 30.0) return 0;
  if (value >= 70.0) return 2;
  return 1;
}

function onStart(): void {
  rsi = new Rsi(i32(p_len()));
}

function onBar(): void {
  const value = rsi.update(bar.close());
  if (isNaN(value)) return;
  let score: f64 = 0.0;
  switch (zone(value)) {
    case 0:
      score = -1.0;
      break;
    case 2:
      score = 1.0;
      break;
    default:
      score = 0.0;
      break;
  }
  out_score(score);
}
```

**Are objects and arrays supported?** Yes, with static types. `StaticArray<f64>` is the fixed-size buffer for windows, `Array<f64>` grows, `Map` exists, and a `class` with typed fields and methods is the struct. Arrays are homogeneous, `any` does not exist, and allocation belongs in `onStart()` or at module start, never in `onBar()` ([Collections](../core-concepts/collections.md), [User-defined types](../core-concepts/user-defined-types.md)).

**Can an indicator read another indicator's values?** No. Each overlay runs its own module, and no declaration reads another indicator's output. Combine the logic into one file.

**Can I use inputs and TA classes inside my own functions?** Yes. `bar.close()` and the `in_<name>()` readers work in `onBar()` and in any function it calls, and a value passes on as an `f64` argument; a TA class is an ordinary object you can hold in a module-level variable or pass to a function. What a function cannot do is capture a local from an enclosing function (AssemblyScript closures cannot), so shared state is module-level ([User functions](../core-concepts/user-functions.md)).

**Does it support alerts?** Yes, from the chart. Publish the indicator, add it to a chart, and open the alert dialog from its bell in the legend, the right-click menu, or **Alert on** > **Indicators** in the sidebar's alert menu; pick a drawn output and a condition (crossing, greater or less than, a channel, moving up or down). The file can also name a ready-made signal with `alert(name, { when, message })` over a data-only gate. The alert runs in OpenMarket's cloud on the chart's own market, with the overlay's settings ([Alerts](../functions/alerts.md)).

**Can trades be executed from an indicator?** No. The module is sandboxed: no filesystem, no network, no order capability. A strategy (`strategy({...})` in the file) places orders only in the Strategy Tester's simulation, filled against the chart's own candles ([Strategies overview](../strategies/overview.md)).

**Can I show text?** Through a string slot and a renderer (`render.label` for one tag, `render.text` per bar, `render.table` for a grid), which switches the file to the second runtime contract; outputs and params stay numbers ([Drawing objects](../presentation/drawing-objects.md)).

**Can I move or delete a shape after drawing it?** Yes, with a drawing handle: a line, box, label, or polyline the module creates, updates, and deletes across bars by an id. Boxes and segments declared at the top of the file work differently: each bar decides what they draw, and one that should end is a `when` gate that turns `0` ([Drawing objects](../presentation/drawing-objects.md)).

**How many shapes can I have?** 16 declared boxes and 16 segments, each drawn once per bar; 64 renderers, 64 declared drawings, and 64 string slots; drawing handles up to 500 live per kind and 1,500 in all; and at most 2,000 drawings on the chart per run. [Limits](../reference/limits.md) has every cap.

## Performance and optimization

**My indicator is running slowly. How can I optimize it?** The module runs once per loaded bar, and again on the forming bar as live updates arrive, so the cost that matters is per-bar work. Allocate every buffer once, in `onStart()` or at module start, sized from a param's `max`; never `new` anything inside `onBar()` (memory that grows once the bars start stops the run). Keep loops bounded by a param with a declared `max`. Compute a value once and keep it in a variable instead of recomputing it for every output that needs it. The compiled module is a few kilobytes and a 20-bar average over 5,000 bars is instant; an array that grows on every call is the one pattern that makes a long history slow.

**Should I use `const` for constants?** Yes: a module-level `const MAX_BARS = 500` is a compile-time constant, the right size for a `StaticArray`, and it costs nothing per bar. A value that depends on a param is a module-level `let` assigned once in `onStart()`.

## Common error messages

**What does "Conversion from type 'f64' to 'i32' requires an explicit cast" mean?** You handed a float to something that wants a whole number: a class period, a loop bound, an array index, or a counter declared without a type (`let count = 0` is an integer). Write `i32(p_period())`, and declare float variables as `f64` (`let value: f64 = 0.0`). The full list of messages, each with its fix, is in [Common errors](common-errors.md).

## Still have questions?

[Common errors](common-errors.md) lists every message with its fix, [Debugging](debugging.md) is the workflow for an indicator that runs but draws the wrong thing, and [Limitations](../reference/limitations.md) says what is deliberately out of scope today. For everything else, join the discussion on [Discord](https://discord.gg/hjQRzQtbNu) or read the [Quick reference](../reference/quick-reference.md).
