@pond-ts/react 0.51.0 → 0.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/CHANGELOG.md +75 -1
  2. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -8,7 +8,8 @@ The `@pond-ts` packages — `pond-ts`, `@pond-ts/react`, `@pond-ts/charts`,
8
8
  tag, so this file covers them all. Pre-1.0: minor bumps may include new features
9
9
  and type-level changes; patch bumps are strictly additive.
10
10
 
11
- [Unreleased]: https://github.com/pond-ts/pond/compare/v0.51.0...HEAD
11
+ [Unreleased]: https://github.com/pond-ts/pond/compare/v0.52.0...HEAD
12
+ [0.52.0]: https://github.com/pond-ts/pond/compare/v0.51.0...v0.52.0
12
13
  [0.51.0]: https://github.com/pond-ts/pond/compare/v0.50.0...v0.51.0
13
14
  [0.50.0]: https://github.com/pond-ts/pond/compare/v0.49.0...v0.50.0
14
15
  [0.49.0]: https://github.com/pond-ts/pond/compare/v0.48.1...v0.49.0
@@ -51,6 +52,79 @@ and type-level changes; patch bumps are strictly additive.
51
52
 
52
53
  ## [Unreleased]
53
54
 
55
+ ## [0.52.0] — 2026-07-23
56
+
57
+ ### Changed
58
+
59
+ - **core / financial:** **Market-scale studies are now typed-array fast**
60
+ (the "SMA/EMA at 1M bars costs hundreds of ms" report). Three cuts along
61
+ the same path, all behaviour-preserving (identical values, warm-ups,
62
+ missing-cell semantics, and rejection errors; every fast path falls back
63
+ to the original sweep when it doesn't apply):
64
+ - **`smooth('ema')` columnar fast path** — on a packed numeric source
65
+ column the EMA recurrence runs straight off the typed buffer into a
66
+ typed result column via trusted construction (key + untouched columns
67
+ pass through zero-copy), replacing the per-row Event/tuple rebuild +
68
+ full-series intake re-pack. 1M rows: **530 ms → 4.4 ms (~120×)**.
69
+ - **`rolling({ count })` numeric fast path** — an all-built-in numeric
70
+ mapping over packed sources feeds the shared incremental reducer states
71
+ directly from the typed buffers and writes snapshots into typed columns
72
+ (no per-row snapshot arrays, no boxed accumulators, no post-pass
73
+ assert/re-pack). 1M rows, `avg`: **135 ms → 32 ms (~4×)**.
74
+ - **financial kernel reads columns, not events** — `rollingColumns` /
75
+ `columnValues` now read study inputs/outputs off the public column API
76
+ instead of materializing `series.events` (an Event + data object per
77
+ row, ~400 ms of pure overhead at 1M rows).
78
+ - End-to-end at 1M bars: `ema()` **603 ms → 2.5 ms (~240×)**, `sma()`
79
+ **569 ms → 56 ms (~10×)**, `bollinger()` **748 ms → 162 ms (~4.6×)**.
80
+ Durable benchmarks: `packages/core/scripts/perf-smooth-ema.mjs`,
81
+ `packages/financial/scripts/perf-studies.mjs`.
82
+
83
+ ### Added
84
+
85
+ - **core:** **`TimeSeries.fromArrow(table, options?)` — ingest a decoded Apache
86
+ Arrow `Table`.** pond stays zero-dependency: bring your own Arrow
87
+ (`tableFromIPC(...)`) and hand the `Table` in; the input is duck-typed against
88
+ a small structural surface (`ArrowTableLike` / `ArrowVectorLike` / …, all
89
+ exported). Ingest is the zero-copy path — every `Float64` column's backing
90
+ `Float64Array` is adopted as-is (`Float32`/int columns convert; int64 value
91
+ columns recombine BigInt-free), and the schema is derived from the Arrow
92
+ fields. The time key is converted **BigInt-free**: Arrow's idiomatic int64
93
+ timestamps are recombined from their two int32 halves rather than
94
+ `Number(bigint)` per row — measured **~11× faster** on the time column (0.6ms
95
+ vs 6.8ms at 500k rows; `scripts/perf-from-arrow.mjs`). Options: `time` (key
96
+ column, default the `'time'` field), `timeUnit` (default read from the Arrow
97
+ Arrow type family — a `Timestamp`'s raw-unit int64 is scaled by its
98
+ `TimeUnit`; `Date32`/`Date64` arrive already normalized to epoch-ms and pass
99
+ through; overridable), `columns` (subset, in order), `name`, `sort`. Numeric
100
+ **and string** columns are supported — string columns (Arrow
101
+ `Utf8`) become dict-encoded `StringColumn`s; any other Arrow type
102
+ (list/struct) throws, naming it. A null time key throws; numeric nulls map to
103
+ `NaN` and string nulls to missing.
104
+ - **core:** **`TimeSeries.fromColumns` / `ValueSeries.fromColumns` now accept
105
+ `string` value columns** (previously numeric-only), packed to dict-encoded
106
+ `StringColumn`s (`null`/`undefined` → missing) — the shared columnar-ingress
107
+ engine now dispatches on the schema kind. Other value kinds (`boolean`,
108
+ arrays) still throw.
109
+ - **charts:** **`<ScatterChart decimate>` — dense scatter plots now decimate**
110
+ (PND-MARKDEC scatter half — the last un-decimated mark type). **Default
111
+ `true`.** When the marks are **uniform** (fixed size + colour, no data-driven
112
+ `radius`/`color`), **opaque**, and denser than the pixel grid, overlapping
113
+ marks collapse to one representative per **mark-radius cell** via a 2D
114
+ pixel-**occupancy** sweep. Scatter has no fill, so a line/bar's per-column
115
+ `[min, max]` envelope would erase interior points — the occupancy grid keeps
116
+ one mark per occupied cell instead, which is **visually lossless** for uniform
117
+ opaque marks at that density (same-cell marks overlap). Interaction (hover /
118
+ click / tracker) still reads **every source point**; the per-point selection
119
+ ring + labels are suppressed only on the decimated (dense) path. A
120
+ **translucent** fill (density-encoded — overlap _should_ build up) or a
121
+ data-driven size/colour keeps the full draw. `decimate={false}` draws every
122
+ mark; `{ threshold }` tunes the trigger. The occupancy sweep uses the affine
123
+ fast path for the per-point pixel mapping. Measured (SciChart-suite
124
+ point-update, real browser): **100k 18 → 73 fps (4×)**, and the ladder now
125
+ runs to **10M** points (previously dead by 1M). `drawScatter` now returns
126
+ `LayerDrawStats` (visible via `onDrawStats`).
127
+
54
128
  ## [0.51.0] — 2026-07-22
55
129
 
56
130
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pond-ts/react",
3
- "version": "0.51.0",
3
+ "version": "0.52.0",
4
4
  "description": "React hooks for pond-ts live time series",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -33,7 +33,7 @@
33
33
  "test:runtime": "vitest run"
34
34
  },
35
35
  "peerDependencies": {
36
- "pond-ts": "^0.51.0",
36
+ "pond-ts": "^0.52.0",
37
37
  "react": "^18.0.0 || ^19.0.0"
38
38
  },
39
39
  "devDependencies": {