---
title: "Limitations"
description: "What an Indicator does not do yet, and where to find the numbers. An Indicator is a sandboxed, declared computation over market data; a few things a kScript…"
order: 73
section: "faq"
---

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

# Limitations

What an Indicator does not do yet, and where to find the numbers. An Indicator is a sandboxed, declared computation over market data; a few things a kScript (legacy) does are deliberately out of scope today, and knowing them up front saves you from designing around a feature that is not there.

## Not supported today

**Numbers only in outputs.** Every output is a 64-bit float and `NaN` is the one "nothing here" value. Text reaches the chart only through string slots and renderers under the second runtime contract; a color, a symbol string, or a free-text setting has no param form (every param is a number). Decisions are numbers too: `1` or `0` in a data-only output, turned into a look by the sheet.

**No handles to drawn shapes.** Boxes and segments are declared once and evaluated on every bar; there is no object to move, extend, or delete later, and no growing collection of them (16 boxes and 16 segments per sheet). A shape that should end is a `when` gate that turns `0`, and the bars it was alive on stay drawn. A kScript that mutates drawings stays on the kScript engine ([Drawing objects](../functions/drawing-objects.md)).

**Tape is live only.** The daemon's `tape` buffer requires `min_size` and serves individual prints. Historical tape and pre-bucketed order-size bands remain unavailable: `history` must be `"0"`, and `trade_volume_by_size` still refuses by name. Side-split aggregate volume remains the scalar `trades` source ([Data sources](../core-concepts/data-sources.md#live-tape)).

**The chart ignores pins.** In the browser every input reads the chart's own market and interval; `symbol`, `exchange`, and `interval` pins are honored on your machine only. A cross-venue or higher-timeframe package is a package for your machine, and a higher timeframe on the chart is a bucket fold inside the module ([Multi-timeframe](../core-concepts/multi-timeframe.md)).

**`range()` is not drawn on the chart.** A declared range validates and installs, and scalar surfaces ignore it as designed, but the chart does not render it yet; shade a band with a box on every bar instead. `fills` exists only in hand-written sheets.

**No alerts from the chart yet.** Alerts armed from the chart on a published Indicator are behind a flag today. The supported path is a watch on the metric id from your machine: `om watch create` with a level or an edge condition on `wrun/@scope/name/<output>` ([Alerts](../functions/alerts.md)).

**Screens and backtests refuse celled packages.** A package with a `volume_profile` or `book` input runs on the chart, in watches, and under `om metric get` / `om metric series`, but `om metric screen` and `om backtest` refuse it by name: their replay and fan-out paths carry no cell blocks yet.

**No history array.** `state()` sees one bar. There is no `close[1]`; the previous value is a variable you kept, and a window is a ring buffer you fill. This is also why an Indicator cannot look ahead by accident ([Execution model](../core-concepts/execution-model.md)).

**No persistence across runs.** Module state lives for one evaluation and is restored by `reset()` for the forming bar. Nothing survives a reload or carries from one run to the next; anything you need next time is recomputed from the loaded history.

**No cross-Indicator communication on the chart.** Two overlays on the same chart do not share state. On your machine a hand-written sheet can compose an installed package's output as an input (a metric source); the chart does not compose.

**No execution from the file.** The module has no filesystem, no network, and no order capability. A watch on the metric can carry an execute action; that authorization lives on the watch and never in the Indicator.

## Named refusals

Each gap that a surface can hit at runtime is a typed refusal, so the message names the way out:

```text
wrun_cells_unavailable          a celled input reads a class this data plane does not serve
wrun_celled_metric_unsupported  a backtest or screen was asked to evaluate a celled package
wrun_cell_block_too_large       a bar's block exceeds the input's max_cells (never truncated)
wrun_preview_displacement_unsupported  chart preview of an output with displacement_bars
wrun_source_set_generated       a sheet edit on a code-first workspace (edit the declaration)
wrun_render_result_too_large    the expanded render selection passed 2 MiB in one run
```

[Common errors](common-errors.md) lists each one with its cause and fix.

## Sandbox limits

Every Indicator runs under fixed ceilings so one module cannot exhaust the chart or the daemon: 16 boxes and 16 segments per sheet, 32 renderers, 64 drawings, 64 polyline points, 64 string slots of at most 4096 bytes each, 64 KiB of strings per row and 8 MiB per run, bar offsets within -500..500, a 4 MiB default memory ceiling, and the `max_cells` contract on every celled input. The full table, with the exact refusal for each, is in the [Limits reference](../reference/limits.md).

## Build and runtime errors

For the messages you hit while writing an Indicator (a coordinate passed as a string instead of a handle, a param option that does not exist, a missing cast, a sheet field out of range, the four-export contract), see [Common errors](common-errors.md). Each one is listed by its exact text with a cause and a fix.
