---
title: Release Notes
description: >-
  kScript release history: features, fixes, and breaking changes, listed
  newest first with anchor links into full entries.
---

All notable changes to **kScript** are recorded here. Releases are sorted with the latest first.

## Latest release

> **v3.0.67**: Foreign-domain panes, perps backtesting, tape sources
>
> **July 2026** · Engine `@orangecharts/kscript` 3.0.67 (rolls up the 3.0.62–3.0.66 interim releases into the current build; each bullet notes the version that introduced it). Scripts can now emit **foreign-domain panes**: `plotMatrix()` (categorical grid), `plotCurve()` (numeric-X function pane), and `plotTiles()` (KPI card dashboard) render whole offchart panes whose X domain is pane-private instead of the shared time axis, including computed text tiles, `valueFormat`, `hideLegendValues`, and caps enforced as named errors. The strategy engine gains **perps mode** (`instrument="perps"`: leveraged sizing on isolated margin, maker/taker fees, funding, a liquidation model with `onLiquidation`, and a set of new stats). Two **array-celled tape sources** (`trades`, `trade_volume_by_size`) bring real order-flow reading to scripts, `plotHistogram()` draws baseline-grown columns, `array.sort()` accepts a comparator, and the malformed-import error finally speaks human.

### Added

- **Foreign-domain panes: `plotMatrix` / `plotCurve` / `plotTiles`** (3.0.67). Three builtins that emit whole offchart PANES exempt from time pan/zoom and the crosshair. Ground rules, enforced at compile time with named errors: the script's `define` must be `position: "offchart"` (`plotMatrix requires define(position="offchart") ...`), a script can emit only one foreign pane (`Only one foreign-domain pane output per script ...`), and the builtin is called once with the finished dataset from an `isLastBar` block (accumulate per-bar state in `static` arrays first).
  - `plotMatrix(data, rowLabels, colLabels, format?, summary?, highlight?, gridHeight?)`: categorical grid of `[rowIdx, colIdx, value]` cells. `format="percent"` renders `0.047` as `+4.7%`; up to 5 pinned `summary` rows sit under the grid (an `na` summary value renders blank); `highlight` emphasizes a row and/or column.
  - `plotCurve(data, series?, style?, color?, fill?, markers?, valueFormat?, gridHeight?)`: numeric-X pane of `[x, v1, ...vn]` rows, up to 6 series. `na` series values are gaps, not zeros; rows must be strictly ascending in `x` (unsorted or duplicate `x` is a validation error). Vertical `markers` accept the literal `x: 'spot'`, which tracks the main series' last close live. **`valueFormat`** (`"number" | "currency" | "percent" | "compact"`) formats the Y axis and the hover card from one formatter, so they can never disagree.
  - `plotTiles(tiles, data, texts?, columns?, gridHeight?)`: KPI cards. Card structure (labels, captions, formats, accents) is settings; card values arrive as `[tileIndex, value]` data rows. **Computed text tiles** (wire v1.2): `texts = [{ tile, text }]` sets a `format: "text"` tile's displayed string at run time, with the static `text` setting as the fallback; a `texts` entry targeting a non-text tile is an error. `accent: "auto"` colors by value sign; an `na` value drops the row and the tile renders as awaiting data.
  - **`hideLegendValues`** (boolean) is accepted by all three builtins. **Caps are validated at the source as named errors, never silent truncation**, for example: `plotMatrix.rowLabels must have at most 64 entries, got 65`, `plotCurve supports at most 6 series, data[0] carries 7`, `plotTiles.tiles must have at most 24 entries, got 25`, `plotMatrix.data has duplicate cell (0, 0)`.
- **Perps strategy mode** (3.0.63). `strategy(...)` accepts `instrument="spot" | "perps"` plus `leverage` (> 0), `maintenanceMarginPercent`, `makerFeePercent`, `takerFeePercent`, `funding="data" | "off"`, and `onLiquidation="continue" | "halt"`; all are echoed in `output.strategy.declared`. With `instrument="perps"`: every accepted entry commits isolated margin (`notional / leverage`), fees route maker/taker per fill, `funding="data"` consumes host-supplied settlement events (bars where a position is open but no funding data is available are counted in `stats.fundingUnavailableCount` instead of silently zeroed; `funding="off"` is an exact no-op), and an implicit liquidation exit closes the position when adverse movement erodes the committed margin (trade `exitReason: "liquidation"`). `onLiquidation="halt"` latches after the first liquidation and rejects every later entry. New stats: `makerFeesPaid`, `takerFeesPaid`, `fundingPaid`, `fundingEventsApplied`, `fundingUnavailableCount`, `liquidationCount`, `liquidationHalted`, `bankruptcyDeficit`, plus two perps-only bar-aligned series in `output.strategy`: `committedMarginSeries` and `fundingPaidSeries`. Invalid declarations fail loudly (`strategy(): 'leverage' must be a number literal > 0`). See [Strategies](/kscript/strategies/overview).
- **Tape sources: `trade_volume_by_size` and `trades`** (3.0.66). Two array-celled source types for tape reading. `trade_volume_by_size(symbol, exchange)` delivers cells `[bucketId, buyVolUsd, sellVolUsd, buyCount, sellCount]` over fixed USD order-size bands (bucket ids 1..7), so whale CVD comes from real order sizes instead of candle-geometry proxies. `trades(symbol, exchange, minSize?)` delivers each chart bar's individual trades as cells `[offsetMs, price, size, side]` with `side` `+1` (buy) or `-1` (sell); it is engine-complete but platform serving of wide raw-tape windows on liquid markets is still being rolled out, so the documented path today is the bucket source. Rows are dense: a quiet bar simply has zero cells. Both types count as 2 sources against the per-script source budget (the budget error spells it out: `trades sources count as 2 each`), and unknown params are rejected (`Unknown argument 'minSize' for 'trade_volume_by_size'`). See [Data Sources](/kscript/core-concepts/data-sources).
- **`buy_sell_volume` gains a `currency` param** (3.0.66). `source("buy_sell_volume", symbol, exchange, currency="USD")` returns quote-notional (USD) volume; omitting `currency` keeps the base-coin default, so CVD scripts can match production magnitude without in-script `* close` pricing. See [Data Sources](/kscript/core-concepts/data-sources).
- **`plotHistogram(value, base?, colors?, colorIndex?, width?)`** (3.0.66). Single-value columns grown from a `base` baseline (default 0), with the standard dynamic styling (`colors` + per-bar `colorIndex`, `width`) for MACD-style delta and pressure histograms. Arrays are rejected (`plotHistogram takes a single value series; use plotBar for [low, high] ranges`) and it cannot be batched (`plotBatches: 'plotHistogram' is not supported inside a plotBatches callback yet`). See [Plotting](/kscript/functions/plotting).
- **`array.sort()` comparator** (3.0.67). `sort((a, b) => ...)` is accepted alongside the argless numeric sort (`.sort((a, b) => b - a)` sorts descending). The comparator must return a finite number: a comparator that statically returns a non-number is a compile error (`Array method 'sort' comparator must return a number, got string`), and one that returns `na` at run time is a named runtime error (`Array method 'sort' comparator must return a finite number`), never a silent no-op. See [Collections](/kscript/core-concepts/collections).

### Changed

- **Human import-name diagnostic** (3.0.64). A malformed library name in `import` no longer prints raw regexes. It now reads: `Invalid library name in import. Names are lowercase letters, digits, and underscores, starting with a letter, with an optional @x.y.z version pin. Examples: import "my_lib", import "@owner/my_lib", import "@owner/my_lib@1.2.0"`. A well-formed name that simply is not registered still fails as `Unknown library 'my_lib'`. See [Libraries](/kscript/functions/libraries).
- **Version-header verdict.** `//@version=2` and `//@version=3` are interchangeable: the engine routes both to the same modern dialect, and every v3 feature runs under either line. `//@version=3` is the canonical header for new scripts; there is no downgrade. A missing marker or `//@version=1` routes to the deprecated legacy v1 engine. See [Migration (v2 vs v3)](/kscript/migrations/v2-vs-v3).

## Previous releases

> **v3.0.61** — Strategy backtesting framework
>
> **July 2026** · Engine `@orangecharts/kscript` 3.0.61 ships the strategy backtesting framework: `strategy(...)` script headers, `strategy.*` order methods against a deterministic lookahead-free broker emulator (market/limit/stop entries, bracket exits with trailing stops and OCA, sizing modes, commission and slippage), and `output.strategy` on the wire with trades, equity, drawdown, and locked performance stats. Results render in the Strategy Tester panel. See [Strategies](/kscript/strategies/overview) for the full guide.

> **v3.0.54** — Statistics rows, sparse source alignment, and canonical registry release
>
> **July 2026** · Engine `@orangecharts/kscript` 3.0.54 is the canonical public build for the post-mini-chart engine line. It includes **per-bar statistics rows** through `plotStatRow()`, aligns sparse flow sources onto the candle timeline so missing buckets read as zero after coverage begins, and publishes the merged 3.0.52/3.0.53 work under one registry version for frontend, backend, alerts, and docs to consume.

### Added

- **`plotStatRow(value, title?, format?, polarity?, priority?, colors?)`**: adds a compact row to the per-bar statistics strip under the price pane. Use it for volume, delta, funding, liquidation totals, range, or custom scores without drawing a new series or owning a pane. [Docs](/kscript/functions/plotting#plotstatrow)

### Fixed

- **Sparse flow-source alignment**: sources that declare missing buckets as zero now align to the chart timeline before scripts read them. Missing post-coverage buckets become `0`; bars before the source's first real row stay `na`.
- **`plotMiniChartGrid()` signature lockstep**: editor metadata and runtime signatures agree on the same tooltip-capable argument set.

> **v3.0.49** — Viewport mini-charts, pinned request anchors & panel styling
>
> **July 2026** · Engine `@orangecharts/kscript` 3.0.49 (rolls up the unpublished 3.0.27–3.0.48 internal releases into one npm version). Scripts can now render **viewport-pinned mini-chart dashboards**: `plotMiniChartGrid()` draws a grid of small OHLC panels that stays at a fixed screen position while the chart pans, fed by `requestBars(..., { bars, anchor: "latest" })` so every panel tracks the **newest** market bars — historical panning never changes them, and they update live as bars form and close. Panels take five looks (`candleStyle`: candles, hollow, OHLC bars, line, area), an optional per-panel **% change badge** (`showChange`) and a **volume strip** (`showVolume`), plus fast/slow MAs and full color control. `requestBars` also gains composed intervals (`"2h"`, `"3h"`, `"12h"`, `"2d"` — aggregated from the largest natively-served divisor) and the explicit `anchor: "window"` default. See [Mini-chart grids](/kscript/functions/plotting#plotminichartgrid) and [Multi-source](/kscript/core-concepts/multi-source).

### Added

- **`plotMiniChartGrid(panels, ...)`**: viewport-anchored grid (up to 12 panels × 100 bars) with layout (`position`, `columns`, `panelWidth`/`panelHeight`/`gap`), colors, MA overlays, `candleStyle`, `showChange`, `showVolume`. Render-only — costs no source budget. [Docs](/kscript/functions/plotting#plotminichartgrid)
- **`requestBars(..., { anchor: "latest" | "window" })`**: `"latest"` pins the returned rows to the newest native bars regardless of pan position or execution window; `"window"` spells the default. The literal must be static; an anchored and a window-relative request of the same symbol/timeframe are two distinct sources. [Docs](/kscript/core-concepts/multi-source)
- **Composed intervals in `requestBars`**: `"2h"`, `"3h"`, `"12h"`, `"2d"`, `"45m"` and similar now return true bars at the requested timeframe, UTC-bucket-aggregated from the largest natively-served divisor (previously these silently fell back to chart-interval rows).

> **v3.0.26** — Calendar timeframes & per-source deep HTF
>
> **June 2026** · Engine `@orangecharts/kscript` 3.0.26. Higher-timeframe `htf()` and `request()` gain **calendar-period tokens** `1D`/`1W`/`1M`/`1Q`/`1Y` (uppercase, UTC-anchored: `1W` = Monday week, `1M`/`1Q`/`1Y` = calendar month/quarter/year), distinct from rolling `Nm`/`Nh`/`Nd` epoch-floor buckets, and case-significant (`1m` minute vs `1M` month). Multi-count calendar tokens (`2W`) are rejected. An `opts` object `{ mode?, offset?, bars? }` adds `mode: "developing"` (current forming period), `offset: N` (N completed periods back, confirmed-only), and request-only `bars: N` (exact fetch depth); a bare opts object in the type/exchange slot is coerced to opts. **Correction:** a coarser-timeframe `request()` now fetches its **own deep history** scaled by the requested interval (daily/weekly/monthly/yearly levels resolve on a 1m chart), superseding the earlier "bounded by the chart's loaded window" behavior. Day/week/month aggregate from a deep daily backing source; quarter/year from a weekly one (quarter/year open/close can be off by up to ~1 week). See [Multi-Timeframe](/kscript/core-concepts/multi-timeframe).

### Added

- **`requestBars(symbol, timeframe, type?, exchange?, { bars })`**: returns the last N **native** bars of a symbol at a coarse interval as a plain `[time, open, high, low, close, volume]` array (oldest first), draw-only and independent of `maxBarsBack`. The drawing counterpart to `request()`: iterate the rows and draw (last N daily highs/lows, weekly ranges) instead of feeding a chart-aligned, TA-chainable series. [Docs](/kscript/core-concepts/multi-source)

> **v3.0.15** — Deep-history anchoring & plot-label rules
>
> **June 2026** · Engine `@orangecharts/kscript` 3.0.15. `define(..., maxBarsBack=N)` opt-in deep-history declaration: the host preloads up to `N` bars (capped at 20000, and per viewer tier on the chart) so cumulative and anchored VWAPs stay fixed as the chart pans instead of re-anchoring to the newest loaded bar. Plot labels are now **required and unique** at publish, while `desc` is **optional and no longer validated**. A coarser-timeframe `request()` fetches that interval natively. (At 3.0.15 a higher-timeframe `request()` was still bounded by the chart's loaded window; engine 3.0.26 changed this so each higher-timeframe request fetches its own deep history. See the 3.0.26 entry above.)

## Older releases

> **v3.2.0** — Ergonomics & precision
>
> **June 2026** · Named streams on multi-output indicators (`bands.upper`, `macd.signal[1]`), calendar-anchored VWAP (`vwap(anchor="day")` — stable under history loading, honest `na` for partial sessions), and methods on user-defined types (`func` in `type` blocks with `this`, instances stay clone-safe plain data).
>
> [Full notes →](#v3.2.0-june-2026)

> **v3.0.7** — v2 compatibility hardening
>
> **June 2026** · Engine patch release (`@orangecharts/kscript` 3.0.7). No new features: v2 conveniences restored (`plotText` alignment synonyms, `plotShape` shape aliases incl. `star`, bare `NaN` as an alias of `na`) and two runtime sandbox ceilings raised to installed-base reality (data sources 8 → 20, output objects 20,000 → 50,000).
>
> [Full notes →](#v3.0.7-june-2026)

> **v3.1.0** — Multi-source & data policy
>
> **June 2026** · Multi-symbol and multi-venue scripts get first-class tooling: `request()` (one-call other-symbol/HTF data), `ltf()` (lower-timeframe bars as cells on your chart's bars), a per-script source budget, machine-readable source catalog, and aggregation patterns (cross-exchange CVD, weighted OI) documented end to end.
>
> [Full notes →](#v3.1.0-june-2026)

> **v3.0.0** — The flexibility release
>
> **June 2026** · Collections + lambdas, user-defined types, real `na`, stateful drawing objects with handles, multi-timeframe `htf()` (no-repaint by default), a reference-validated TA library (~40 indicators), value-driven styling, typed inputs (incl. `source` re-targeting), and importable libraries with versioning and hot reload.
>
> [Full notes →](#v3.0.0-june-2026)

## All releases

| Version                                                              | Date     | Highlights                                                                                                                                | Breaking changes                                                 |
| -------------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| **v3.0.67**                                                          | Jul 2026 | Foreign-domain panes (`plotMatrix`/`plotCurve`/`plotTiles` incl. computed text tiles, `valueFormat`, `hideLegendValues`, source-validated caps), perps strategy mode (isolated margin, maker/taker fees, funding, liquidation + new stats), tape sources (`trades`, `trade_volume_by_size`, `buy_sell_volume` `currency`), `plotHistogram`, `array.sort` comparator, human import diagnostic (rolls up 3.0.62–3.0.66) | None (additive) |
| **v3.0.61**                                                          | Jul 2026 | Strategy backtesting framework: `strategy(...)` headers, `strategy.*` orders, deterministic lookahead-free broker emulator, `output.strategy` trades/equity/stats | None (additive) |
| **v3.0.54**                                                          | Jul 2026 | `plotStatRow` per-bar statistics strip rows, sparse flow-source zero alignment, canonical registry release for the 3.0.52/3.0.53 work | None |
| **v3.0.49**                                                          | Jul 2026 | Viewport mini-chart grids (`plotMiniChartGrid` with `candleStyle`/`showChange`/`showVolume`), `requestBars` `anchor: "latest"`/`"window"`, composed intervals (`2h`, `3h`, `12h`, `2d`) | None (additive; omitted options render identically) |
| [**v3.0.7**](/kscript/releases/changelog#v3.0.7-june-2026)          | Jun 2026 | v2 compatibility hardening: `plotText`/`plotShape` enum synonyms restored (case-insensitive, `star` maps to `diamond`), bare `NaN` accepted as an alias of `na`, runtime source budget raised 8 → 20, output-object ceiling raised 20,000 → 50,000 | None (strictly widening) |
| [**v3.2.0**](/kscript/releases/changelog#v3.2.0-june-2026)          | Jun 2026 | Named streams on multi-output TA (`.upper`/`.signal`/`.k`/`.line` + history indexing), `vwap(anchor)` calendar sessions, struct methods (`func` + `this` in `type` blocks), `fillBetween` works end to end on named streams | None (additive; unanchored `vwap()` and positional access unchanged) |
| [**v3.1.0**](/kscript/releases/changelog#v3.1.0-june-2026)          | Jun 2026 | `request()` sugar, `ltf()` lower-timeframe cells, per-script runtime source budget (8 at release, 20 since v3.0.7), source catalog, multi-venue aggregation docs (cross-exchange CVD, weighted OI), feed eviction hardening | None (additive; `ltf()` requires a platform data-service update) |
| [**v3.0.0**](/kscript/releases/changelog#v3.0.0-june-2026)          | Jun 2026 | Collections + lambdas/reducers, `type` structs, `na`/`isna`/`nz`, `color` type, drawing objects (`line.new`...`table.new` + handles), `htf()` MTF, ~40 reference-validated TA builtins, `switch`/`persist`/defaults/`format`, typed inputs, `library()`/`import`, sandbox limits manifest | Two corrections: 8 TA builtins to textbook formulas + strict `sma` warmup (early-bar values change; see [Migration (v2 vs v3)](/kscript/migrations/v2-vs-v3)) |
| [**v2.2.0**](/kscript/releases/changelog#v2.2.0-june-2026)          | Jun 2026 | `plotPie` per-bar pie chart (auto-normalized slices, `display` text mode, batchable with per-element radius/colors); documented `volume_profile` row structure + raw bucket access | None (additive within v2) |
| [**v2.1.0**](/kscript/releases/changelog#v2.1.0-may-2026)            | May 2026 | `plotPriceLabel` builtin, `glow` halo on chart-shape plots, `lineStyle` (solid/dashed/dotted), `opacity` on plotShape/plotText | None (additive within v2) |
| [**v2.0.0**](/kscript/releases/changelog#v2.0.0-september-2025) | Sep 2025 | Per-bar execution model, kwargs, stronger compiler, dedicated data subscriptions, scalars from indicators, `func` + loops, extended plots | Yes (relative to **v1**; see [Migration (v1 vs v2)](/kscript/migrations/v1-vs-v2)) |

---

## v3.0.7 — June 2026

Engine patch release (`@orangecharts/kscript` 3.0.7), focused on v2 compatibility hardening after the v3 rollout. Nothing here is a new feature: call forms that were legal on v2 are accepted again, and two sandbox ceilings move up to match how scripts are actually used.

### Restored

- **`plotText` alignment synonyms** — `yAlign` accepts `CENTER`/`ABOVE`/`BELOW` again, case-insensitively, normalized to `middle`/`top`/`bottom`.
- **`plotShape` shape aliases** — shape names are case-insensitive and the v2 aliases are accepted, including `star` (maps to `diamond`).
- **Bare `NaN`** — accepted again as an alias of `na`.

### Raised

- **Source budget** — runtime `MAX_SOURCES_PER_SCRIPT` moved 8 → **20** distinct data sources per script. Engine `3.0.11` unified the editor and runtime budgets at 20, so a 6-20 source aggregation script now passes both.
- **Output objects** — 20,000 → **50,000** per run (`MAX_OUTPUT_OBJECTS`).

### Compatibility

- None breaking; every change strictly widens what is accepted. Scripts written against the stricter v3.0.0 surface run unchanged.

---

## v3.2.0 — June 2026

Three quality-of-life walls came down: multi-output indicators grew names, VWAP grew anchors, and types grew methods.

### Added

- **Named streams.** `bb`/`keltner` expose `.basis`/`.upper`/`.lower`, `macd` exposes `.macd`/`.signal`/`.histogram` (alias `.hist`), `stoch` exposes `.k`/`.d`, `supertrend` exposes `.line`/`.direction`. Streams support history indexing (`macd.signal[1] > macd.signal[2]`) and feed `fillBetween(bands.upper, bands.lower, ...)` directly. Unknown stream names are compile errors listing the valid ones.
- **Anchored VWAP.** `vwap(anchor="day"|"week"|"month")` (or raw milliseconds) resets at UTC calendar boundaries. Anchored values are stable when older history lazy-loads (each session is self-contained); a leading partial session emits `na` instead of a wrong line. `vwap()` with no anchor keeps the cumulative behavior unchanged.
- **Struct methods.** `func` declarations inside `type` blocks, dispatched from the type with `this` bound to the receiver (`this.field = x` mutates the struct). Instances remain plain clone-safe data; methods never collide with globals; library-exported types carry their methods.

### Compatibility

- Fully additive: positional stream access, unanchored `vwap()`, and field-only types behave byte-identically to v3.1.

---

## v3.1.0 — June 2026

The data layer opened up: one script can now combine symbols, venues, and data types with proper guard rails, and the docs gained a dedicated [Multi-Source & Aggregation](/kscript/core-concepts/multi-source) guide.

### Added

- **`request(symbol, timeframe?, type?, exchange?)`** — one call for the most common multi-symbol need; sugar over `source()` + `htf()` with the same no-repaint guarantee. [Docs](/kscript/core-concepts/multi-source)
- **`ltf(interval, ...)`** — lower-timeframe bars delivered as **cells on the chart's own bars** (`ltf("15m").cells` on a 1h chart = each bar's four 15m bars), composing with reducers and structs like any order-flow source. Requires the matching platform data-service update; intervals are literal strings, strictly finer than the chart.
- **Source budget** — at most **8 distinct data sources per script** at release (identical calls dedupe; `htf()`/derived series free), joining the sandbox manifest with the usual loud line:column error and tier override. Raised to **20** in [v3.0.7](#v3.0.7-june-2026).
- **Source catalog** — the platform now serves a machine-readable catalog of which source types and venues exist, and unavailable requests fail with the list of what does.
- **Aggregation patterns documented** — cross-exchange CVD, venue-weighted open interest, dominance ratios, and HTF views of aggregates, all on the new multi-source page.

### Changed

- Live feeds for **non-OHLCV secondary sources** (funding, open interest, ratios) now merge ticks by their real data shape on the backend; secondary series on live charts become correct where they were previously merged as candles.
- Idle feed eviction hardened platform-side (streams with zero registered consumers unsubscribe within one scan; failures keep streams alive rather than dropping them).

### Compatibility

- Fully additive language-side. `ltf()` errors clearly until the platform data services ship the matching update.

---

## v3.0.0 — June 2026

The largest upgrade kScript has had: the language grows from "indicator scripting" to a full charting language with data structures, your own types, stateful drawings, multi-timeframe access, and shareable libraries. Existing v2 scripts run unchanged (two narrow numeric corrections aside; see below). Full guides for everything here are linked throughout the docs; the migration page has the [adoption path](/kscript/migrations/v2-vs-v3).

### Added

- **Collections** — first-class arrays and maps with method-call syntax (`book.push(x)`, `levels.get("poc")`), negative tail indexing, insertion-ordered maps, and compile-time element-type checking. [Docs](/kscript/core-concepts/collections)
- **Lambdas & reducers** — `(x) => ...` with closures; `map`/`filter`/`reduce`/`forEach`/`find`/`some`/`every` replace most loops. [Docs](/kscript/core-concepts/lambdas-and-reducers)
- **User-defined types** — `type Zone { top: number, bottom: number }`, `Zone.new(top=...)`, defaults, nesting, collections of structs, all field access compile-checked. [Docs](/kscript/core-concepts/user-defined-types)
- **Real `na`** — falsy, propagating, structurally equal; `isna()`/`nz()`; a compiler warning on direct na-comparison; events never fire on `na`. [Docs](/kscript/core-concepts/na-and-scalar-types)
- **`color` type** — validated `color.rgb(r, g, b, a?)`; strings remain valid everywhere.
- **Multi-timeframe** — `htf(source, "4h")` base-aligned views with a **no-repaint default** (provably causal), `developing` mode, `offset`, scalar and footprint resampling. [Docs](/kscript/core-concepts/multi-timeframe)
- **Stateful drawing objects** — `line.new`, `box.new`, `label.new`, `polyline.new`, `linefill.new`, `table.new` return mutable handles: move, restyle, `delete()`; store handles in collections and structs. [Docs](/kscript/functions/drawing-objects)
- **Drawing primitives** — 10 `plotShape` shapes with `location` placement and `char` markers; `barcolor()`; `fillBetween()`; per-cell styled tables. [Docs](/kscript/functions/drawing-primitives)
- **Styling** — size tiers, tooltips on every output, unified alignment, `zOrder`, `palette()`, and value-driven per-element gradients/opacity/glow. [Docs](/kscript/functions/styling)
- **Control flow & ergonomics** — `switch` (no fallthrough), compound assignment, `persist` (the clearer spelling of `static`), default parameters, `format()`/`tostring()`/`tonumber()`. [Docs](/kscript/functions/control-flow)
- **TA library** — ~40 indicators each validated bar-for-bar against independent textbook references (1e-6), including multi-output `bb`, `keltner`, `stoch`, `supertrend`, `macd`; uniform warmup and forward-fill conventions; everything composes (including over order-flow series). [Docs](/kscript/functions/ta-library)
- **Typed inputs** — `int`, `float`, `source`, `timeframe`, `session`, `symbol`; constraints enforced (never silently clamped); `group`/`tooltip`/`inline`; settings changes apply with zero refetches; `source` inputs can point an indicator at microstructure data. [Docs](/kscript/functions/typed-inputs)
- **Libraries** — `library("name", "1.0.0")` + `import "name" as ta`, version pinning, script-wins precedence with warnings, hot reload in the playground. [Docs](/kscript/functions/libraries)
- **Sandbox limits manifest** — every ceiling named and documented with exact numbers; all failures report line:column; runaway scripts are interrupted mid-loop. [Docs](/kscript/faq/limitations)

### Changed

- **Eight TA builtins corrected to textbook formulas** (`ema`, `rsi`, `macd`, `psar`, `adx`, `highest`, `lowest`, plus strict `sma` warmup): early-bar/warmup values change versus v2 (honest `na` warmup instead of fabricated early values; convergent thereafter). `stddev` and `rma` keep their legacy semantics, documented as such. Details and reasoning: [Migration (v2 vs v3)](/kscript/migrations/v2-vs-v3).

### Compatibility

- No new reserved words (`type`, `switch`, `persist`, `import` are contextual).
- Script-defined functions always beat same-named new builtins.
- Legacy call forms (positional inputs, scalar table cells, `static`, string colors, uppercase alignment) all keep working.

---

## v2.2.0 — June 2026

Pie plots and clearer volume-profile access: a new proportional pie builtin, plus first-class documentation of the `volume_profile` row structure and raw price-level bucket access.

### Added

- **`plotPie(value, price, radius?, colors?, opacity?, display?)`** — per-bar pie chart drawn as a proportional circle anchored to a price.
  - `value` is an array of slice magnitudes, **normalized automatically** (`[60, 40]` → 60% / 40%; `[3, 1]` → 75% / 25%).
  - `price` sets the vertical anchor; `radius` (px), `colors` (per slice), and `opacity` (0–1) control appearance.
  - `display` — per-slice text mode: `"percent"` (default), `"value"`, or `"none"`. This is a single mode string, **not** the `label=[...]`/`desc=[...]` series-label arrays the other plots take.
  - **Batchable** — works inside `plotBatches`, so you can draw one pie per price level (e.g. buy/sell split at every `volume_profile` bucket). Each batched pie carries its **own** `radius`, `colors`, and `opacity`.

### Documented

- **`volume_profile` data structure** — each bar is a row shaped `[timestamp, [priceLow, priceHigh, buyVol, sellVol], …]`: slot `0` is the timestamp and every later slot is one price-level bucket. The bucket count varies per bar.
- **Raw bucket access** — alongside the scalar `vp*` accessors, you can iterate buckets directly: `vpa[0]` is the current row and `vpa[0][i + 1]` is the i-th bucket. Pairs naturally with `vpBucketCount` + `plotBatches` (e.g. a pie per bucket).
- **Accessor functions** — `vpBuy`, `vpSell`, `vpDelta`, `vpTotal`, `vpPoc`, `vpPocVolume`, `vpBucketCount`, `vpPriceHigh`, `vpPriceLow` documented with parameter tables and examples.

### Reference

- [Plotting](/kscript/functions/plotting) — `plotPie` parameter table and examples.
- [Volume Profile Functions](/kscript/functions/volume-profile) — data structure, raw bucket access, and the full `vp*` accessor reference.
- Backward-compatible within v2; no migration required.

---

## v2.1.0 — May 2026

Plotting refresh: a new per-bar label builtin and richer styling kwargs across the existing chart-shape plots.

### Added

- **`plotPriceLabel(price, text?, type?, position?, ...)`** — per-bar decorative label anchored at a price level. Three visual modes:
  - `"callout"` (default): text box with a leader line and dot
  - `"simple"`: centered text box
  - `"icon-only"`: SVG path or image URL, with `iconSize`, `anchorX`, `anchorY` controls
  - Text styling kwargs: `color`, `backgroundColor`, `fontFamily`, `fontWeight` (clamped 100–800), `size` (clamped 1–30), `opacity` (clamped 0–1)
  - `tooltip` for hover text (supports `\n` for line breaks)
  - `icon-only` URLs support animated GIFs and WebP, so labels can render looping or animated icons
- **`glow` kwarg** on `plotLine`, `plotBar`, `plotCandle`, `plotShape`, and `plot` — soft halo around the stroke. `true` enables a default blur in the series color; a number sets the blur radius in pixels (clamped 0–30, 0 disables).
- **`lineStyle` kwarg** on `plotLine` and `plot` — `"solid"` (default), `"dashed"`, or `"dotted"`. No effect on bar / candle / point types.
- **`opacity` kwarg** on `plotShape` — overall element opacity (0–1, clamped).
- **`fontWeight` and `opacity` kwargs** on `plotText` — text weight 100–800 (clamped, rounded to nearest 100) and overall opacity 0–1 (clamped).

### Changed

- **`plotShape` shape catalog clarified** — `"circle"`, `"triangle"`, `"cross"`, and `"diamond"` are all supported. The reference previously documented circle-only.

### Reference

- [Plotting](/kscript/functions/plotting) — full parameter tables, including the new entries.
- This release is backward-compatible within v2; no migration required.

---

## v2.0.0 — September 2025

Major release of **kScript v3** on the OpenMarket platform: new execution model, language features, and standard library—with intentional breaking differences from **v1** for long-term ergonomics and performance.

### Added

- **Per-bar execution** with clear phases for initialization, calculation, and plotting—see [Execution model](/kscript/core-concepts/execution-model).
- **Keyword arguments** on builtins for clearer, order-independent calls ([Keyword arguments](/kscript/core-concepts/keyword-arguments)).
- **`func` user-defined functions** and **`for` / `while` loops** (with the documented `var` restrictions) ([User functions](/kscript/core-concepts/user-functions)).
- **Dedicated data subscriptions**: `ohlcv(...)`, `trades(...)`, `orderbook(...)` replacing the generic v1-only `source(...)` pattern in v2 docs.
- **Reverse index access** on time series (`ts[0]` = latest bar) as described in the v1→v2 transition material.
- **Extended plotting**: `plotCandle`, `plotShape`, and richer styling kwargs alongside existing line/bar plots ([Plotting](/kscript/functions/plotting)).

### Changed

- **Technical indicator helpers** now resolve to **scalar values per bar** instead of returning full composite series that required manual alignment in typical v1 usage.
- **Compiler** performs stronger **static analysis** (syntax, scope, types) so more issues surface at edit time rather than at runtime.
- **OHLCV field access** standardized via accessors such as `ohlcvTs.close`, `ohlcvTs.volume`, etc.

### Fixed

- Class of issues where v1 scripts could **run without obvious errors** yet mis-align series or misuse full-series returns; v2’s model and compile checks reduce this failure mode.

### Breaking changes

- Scripts written for **kScript v1** are **not** source-compatible with **v2** without migration (execution model, subscriptions, indicator return shapes, and keyword-only ergonomics). Use the [v1 vs v2 migration guide](/kscript/migrations/v1-vs-v2) together with this entry when porting.
- Removal of reliance on **`buildTimeseries` / `mergeTimeseries` / `matchTimestamp`-style manual alignment** in favor of engine-driven per-bar evaluation for typical indicators.
