@tony01/astroneum 0.4.1-beta.2

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 (59) hide show
  1. package/CHANGELOG.md +237 -0
  2. package/LICENSE +21 -0
  3. package/README.md +198 -0
  4. package/dist/Indicator-BBI3L_lx.d.ts +1181 -0
  5. package/dist/ar-SA-AEPUSRMF.js +2 -0
  6. package/dist/astroneum.css +1 -0
  7. package/dist/chunk-2SN3RH42.js +2 -0
  8. package/dist/chunk-2YYGUSVX.js +3 -0
  9. package/dist/chunk-3GJSZFLM.js +2 -0
  10. package/dist/chunk-4YOLQ5DC.js +2 -0
  11. package/dist/chunk-I4YQBP2M.js +3 -0
  12. package/dist/chunk-OOMZRONH.js +35 -0
  13. package/dist/chunk-PV2GAINM.js +2 -0
  14. package/dist/chunk-SDXH2WAI.js +3 -0
  15. package/dist/chunk-YFPXTHZX.js +2 -0
  16. package/dist/chunk-YW3STIPY.js +653 -0
  17. package/dist/de-DE-4PR3NRQ7.js +2 -0
  18. package/dist/entries/alerts.d.ts +93 -0
  19. package/dist/entries/alerts.js +2 -0
  20. package/dist/entries/datafeeds/crypto.d.ts +65 -0
  21. package/dist/entries/datafeeds/crypto.js +2 -0
  22. package/dist/entries/datafeeds/polygon.d.ts +113 -0
  23. package/dist/entries/datafeeds/polygon.js +2 -0
  24. package/dist/entries/multichart.d.ts +96 -0
  25. package/dist/entries/multichart.js +2 -0
  26. package/dist/entries/portfolio.d.ts +55 -0
  27. package/dist/entries/portfolio.js +2 -0
  28. package/dist/entries/replay.d.ts +141 -0
  29. package/dist/entries/replay.js +2 -0
  30. package/dist/entries/script.d.ts +68 -0
  31. package/dist/entries/script.js +2 -0
  32. package/dist/entries/watchlist.d.ts +43 -0
  33. package/dist/entries/watchlist.js +2 -0
  34. package/dist/es-ES-HNDVPSLW.js +2 -0
  35. package/dist/fr-FR-Y7XWRGF2.js +2 -0
  36. package/dist/hi-IN-KEGIKIMV.js +2 -0
  37. package/dist/id-ID-QXDIUQUZ.js +2 -0
  38. package/dist/index.d.ts +1434 -0
  39. package/dist/index.js +2 -0
  40. package/dist/it-IT-UDTDFSRB.js +2 -0
  41. package/dist/ja-JP-NIODTBW3.js +2 -0
  42. package/dist/ko-KR-DQHPXKBA.js +2 -0
  43. package/dist/nl-NL-BB3ZHCXS.js +2 -0
  44. package/dist/pl-PL-I5MZDLFD.js +2 -0
  45. package/dist/pt-BR-MAMRTOYR.js +2 -0
  46. package/dist/ru-RU-F43D6B7G.js +2 -0
  47. package/dist/th-TH-KTFIUAD6.js +2 -0
  48. package/dist/tr-TR-WFTKJ22Y.js +2 -0
  49. package/dist/vi-VN-CD3WI2FQ.js +2 -0
  50. package/dist/zh-CN-Y2C6RSOI.js +3 -0
  51. package/docs/STRUCTURE.md +231 -0
  52. package/docs/TODO-DESIGN.md +261 -0
  53. package/docs/TODO.md +222 -0
  54. package/docs/api.md +528 -0
  55. package/docs/datafeed-guide.md +311 -0
  56. package/docs/design-astroneum.md +479 -0
  57. package/docs/plugin-development.md +565 -0
  58. package/docs/tv-functions-skill.md +706 -0
  59. package/package.json +147 -0
package/docs/api.md ADDED
@@ -0,0 +1,528 @@
1
+ # API Reference
2
+
3
+ ## Constructor
4
+
5
+ ```typescript
6
+ <AstroneumChart ref={ref} {...options} />
7
+ ```
8
+
9
+ ### `AstroneumOptions`
10
+
11
+ | Property | Type | Required | Default | Description |
12
+ |---|---|---|---|---|
13
+ | `symbol` | `SymbolInfo` | ✓ | — | Symbol to display on load |
14
+ | `period` | `Period` | ✓ | — | Initial timeframe |
15
+ | `datafeed` | `Datafeed` | ✓ | — | Data source implementation |
16
+ | `theme` | `'light' \| 'dark'` | | `getSystemTheme()` | UI theme. Omit to auto-detect OS color scheme. |
17
+ | `locale` | `string` | | `'en-US'` | UI locale key |
18
+ | `timezone` | `string` | | `'Asia/Shanghai'` | IANA timezone identifier for the X-axis |
19
+ | `watermark` | `string \| Node` | | Astroneum logo SVG | Watermark rendered in the chart center |
20
+ | `styles` | `DeepPartial<Styles>` | | `{}` | Deep-partial engine style override |
21
+ | `drawingBarVisible` | `boolean` | | `true` | Whether the left-side drawing toolbar is shown |
22
+ | `periods` | `Period[]` | | `[1m,5m,15m,1H,2H,4H,D,W,M,Y]` | Timeframes available in the period bar |
23
+ | `mainIndicators` | `IndicatorDef[]` | | `[{ name: 'EMA', calcParams: [7,25,99] }]` | Indicators overlaid on the main candle pane |
24
+ | `subIndicators` | `string[]` | | `['VOL']` | Indicator names rendered in sub-panes below the chart |
25
+ | `plugins` | `ChartPlugin[]` | | `[]` | Plugins mounted with chart lifecycle hooks (`onInit` / disposer) |
26
+
27
+ ---
28
+
29
+ ## Instance methods
30
+
31
+ ### `setTheme(theme)`
32
+ ```typescript
33
+ setTheme(theme: 'light' | 'dark'): void
34
+ ```
35
+ Sets the UI theme. Updates both the `data-theme` attribute and the internal chart styles.
36
+
37
+ ### `getTheme()`
38
+ ```typescript
39
+ getTheme(): string
40
+ ```
41
+ Returns the current theme name.
42
+
43
+ ### `setStyles(styles)`
44
+ ```typescript
45
+ setStyles(styles: DeepPartial<Styles>): void
46
+ ```
47
+ Merges the given partial styles into the engine's current style tree.
48
+
49
+ ### `getStyles()`
50
+ ```typescript
51
+ getStyles(): Styles
52
+ ```
53
+ Returns the full resolved engine style object.
54
+
55
+ ### `setLocale(locale)`
56
+ ```typescript
57
+ setLocale(locale: string): void
58
+ ```
59
+ Switches the UI and engine locale. The locale key must have been registered with `loadLocales()` (for UI strings) and the engine's `registerLocale()` (for OHLC/indicator labels).
60
+
61
+ ### `getLocale()`
62
+ ```typescript
63
+ getLocale(): string
64
+ ```
65
+ Returns the current locale key.
66
+
67
+ ### `setTimezone(timezone)`
68
+ ```typescript
69
+ setTimezone(timezone: string): void
70
+ ```
71
+ Changes the IANA timezone used for the X-axis date labels.
72
+
73
+ ### `getTimezone()`
74
+ ```typescript
75
+ getTimezone(): string
76
+ ```
77
+ Returns the current timezone.
78
+
79
+ ### `setSymbol(symbol)`
80
+ ```typescript
81
+ setSymbol(symbol: SymbolInfo): void
82
+ ```
83
+ Loads a new symbol. Triggers a full data reload via the datafeed.
84
+
85
+ ### `getSymbol()`
86
+ ```typescript
87
+ getSymbol(): SymbolInfo
88
+ ```
89
+ Returns the currently active `SymbolInfo`.
90
+
91
+ ### `setPeriod(period)`
92
+ ```typescript
93
+ setPeriod(period: Period): void
94
+ ```
95
+ Switches the active timeframe. Triggers a full data reload.
96
+
97
+ ### `getPeriod()`
98
+ ```typescript
99
+ getPeriod(): Period
100
+ ```
101
+ Returns the currently active `Period`.
102
+
103
+ ### `serializeState()` / `loadState()`
104
+
105
+ ```typescript
106
+ serializeState(): SerializedChartState
107
+ loadState(state: SerializedChartState): void
108
+ ```
109
+
110
+ Capture and restore the chart's user-visible state — theme, locale,
111
+ timezone, symbol, period, styles, indicators, and drawing overlays —
112
+ as a JSON-safe object.
113
+
114
+ ```ts
115
+ // save
116
+ localStorage.setItem('chart-state', JSON.stringify(chartRef.current!.serializeState()))
117
+
118
+ // restore on mount
119
+ const saved = localStorage.getItem('chart-state')
120
+ if (saved) chartRef.current!.loadState(JSON.parse(saved))
121
+ ```
122
+
123
+ `loadState()` is a best-effort restore: missing or unknown indicator /
124
+ overlay names are silently skipped (matching the engine's behaviour for
125
+ unregistered names). The `version` field lets the format evolve without
126
+ breaking older payloads; payloads from a newer format than the current
127
+ library understands are ignored.
128
+
129
+ ---
130
+
131
+ ## Accessibility
132
+
133
+ `<AstroneumChart>` accepts an `accessible` prop (default `false`) that
134
+ opts the canvas into screen-reader and keyboard-focus support without
135
+ changing visuals:
136
+
137
+ - The container gets `tabindex=0`, `role="img"`, and an `aria-label`
138
+ (defaults to `"<ticker> <period text> chart"`; override via the
139
+ `ariaLabel` prop).
140
+ - A visually-hidden `aria-live="polite"` region announces OHLCV on
141
+ crosshair changes, throttled to ~10 updates / second to avoid
142
+ flooding screen-reader queues.
143
+
144
+ ```tsx
145
+ <AstroneumChart
146
+ symbol={{ ticker: 'BTC-USD' }}
147
+ period={{ multiplier: 1, timespan: 'minute', text: '1m' }}
148
+ datafeed={datafeed}
149
+ accessible
150
+ ariaLabel='Bitcoin / USD 1-minute candles'
151
+ />
152
+ ```
153
+
154
+ For users who require a high-contrast UI, set `theme="high-contrast"`
155
+ (or call `setTheme('high-contrast')`). The bundled theme uses a
156
+ black background, white candles/grid, and yellow accents with strong
157
+ focus rings.
158
+
159
+ ---
160
+
161
+ ## Lazy locales
162
+
163
+ Only `en-US` is bundled with the main entry. Load any other built-in
164
+ locale on demand:
165
+
166
+ ```ts
167
+ import { loadLocale, BUILTIN_LOCALES } from '@tony01/astroneum'
168
+
169
+ await loadLocale('ja-JP')
170
+ chartRef.current?.setLocale('ja-JP')
171
+
172
+ console.log(BUILTIN_LOCALES) // ['en-US', 'zh-CN', 'ja-JP', ...]
173
+ ```
174
+
175
+ `loadLocale(key)` resolves with the dictionary on success, or `null`
176
+ when `key` is not a built-in locale. Concurrent calls for the same
177
+ locale are de-duplicated. To register a fully custom locale,
178
+ keep using `loadLocales(key, dictionary)`.
179
+
180
+ ---
181
+
182
+ ## Subpath entry points
183
+
184
+ Optional features are reachable through dedicated subpath imports so a
185
+ consumer can pull in just what they need.
186
+
187
+ | Subpath | Exports |
188
+ | --- | --- |
189
+ | `astroneum/replay` | `BarReplay`, types `BarReplayOptions`, `BarReplayState` |
190
+ | `astroneum/multichart` | `MultiChartLayout`, types `MultiChartCount`, `MultiChartSlot`, `MultiChartLayoutOptions` |
191
+ | `astroneum/watchlist` | `WatchlistManager`, types `Watchlist`, `WatchSymbol` |
192
+ | `astroneum/portfolio` | `PortfolioTracker`, types `Position`, `PositionSide`, `PnLResult` |
193
+ | `astroneum/alerts` | `AlertManager`, full alert type surface |
194
+ | `astroneum/script` | `ScriptEngine`, types `CompiledIndicator`, `StudyOptions`, `PlotOptions`, `InputOptions` |
195
+ | `astroneum/datafeeds/polygon` | `DefaultDatafeed`, `WebSocketDatafeed`, `WebSocketDatafeedOptions` |
196
+ | `astroneum/datafeeds/crypto` | `createStandardCryptoDatafeed`, `StandardCryptoDatafeed`, `STANDARD_CRYPTO_SYMBOLS`, `DATAFEED_ERROR_EVENT`, `BinanceAdapter`, `BitgetAdapter`, `OkxAdapter`, plus types |
197
+
198
+ All listed symbols also re-export from the root `astroneum` entry today,
199
+ but the root re-exports for these modules will be removed in **v1.0**
200
+ (see the [Roadmap](../README.md#v10--stability)). Migrate to the subpath
201
+ import to be forward-compatible.
202
+
203
+ ```ts
204
+ // recommended — forward-compatible with v1.0
205
+ import { BarReplay } from '@tony01/astroneum/replay'
206
+ import { createStandardCryptoDatafeed } from '@tony01/astroneum/datafeeds/crypto'
207
+
208
+ // legacy — works today, will be removed in v1.0
209
+ import { BarReplay, createStandardCryptoDatafeed } from '@tony01/astroneum'
210
+ ```
211
+
212
+ ---
213
+
214
+ ## Exported utilities
215
+
216
+ ### Brand cast helpers
217
+
218
+ ```typescript
219
+ import { asPrice, asVolume, asTimestamp } from '@tony01/astroneum'
220
+
221
+ const p: Price = asPrice(100.50)
222
+ const v: Volume = asVolume(1_250_000)
223
+ const t: Timestamp = asTimestamp(Date.now())
224
+ ```
225
+
226
+ These are type-safe cast functions. They assert that a plain `number` belongs to a specific financial domain without any runtime overhead.
227
+
228
+ ### `rafCoalesce`
229
+
230
+ ```typescript
231
+ import { rafCoalesce } from '@tony01/astroneum'
232
+
233
+ const dispatch = rafCoalesce((tick: CandleData) => chart.updateBar(tick))
234
+ webSocket.onmessage = e => dispatch(parse(e.data)) // safe to call 100×/s
235
+ ```
236
+
237
+ Returns a dispatcher that schedules `fn` on the next `requestAnimationFrame`, coalescing rapid calls so only the **last** value is delivered per frame. Use this when you only care about the latest state (e.g. price display). For financial accuracy across bursts, use `rafMergeTick` instead.
238
+
239
+ ### `rafMergeTick`
240
+
241
+ ```typescript
242
+ import { rafMergeTick } from '@tony01/astroneum'
243
+
244
+ const cancel = rafMergeTick(incomingTick, (merged) => {
245
+ chart.updateBar(merged)
246
+ })
247
+ // Call cancel() to stop
248
+ ```
249
+
250
+ OHLCV-aware frame coalescer for WebSocket burst handling. Merges all ticks arriving within the same `requestAnimationFrame` frame into one financially accurate bar:
251
+ - `open` = first tick
252
+ - `high` = max across ticks
253
+ - `low` = min across ticks
254
+ - `close` = last tick
255
+ - `volume` = sum across ticks
256
+
257
+ ### `EventBus`
258
+
259
+ ```typescript
260
+ import { EventBus } from '@tony01/astroneum'
261
+ import type { ChartEventMap } from '@tony01/astroneum'
262
+
263
+ const bus = new EventBus<ChartEventMap>()
264
+
265
+ bus.on('tick', (candle) => console.log(candle.close))
266
+ bus.emit('tick', bar)
267
+ bus.off('tick', handler)
268
+ ```
269
+
270
+ Zero-dependency, type-safe synchronous event bus.
271
+
272
+ ### `TickAnimator`
273
+
274
+ ```typescript
275
+ import { TickAnimator } from '@tony01/astroneum'
276
+ import type { TickAnimatorOptions } from '@tony01/astroneum'
277
+
278
+ const opts: TickAnimatorOptions = { duration: 120 } // ms
279
+ const animator = new TickAnimator(opts, (frame) => {
280
+ chart.updateLastBar(frame)
281
+ })
282
+
283
+ animator.push(newTick)
284
+ animator.cancel()
285
+ ```
286
+
287
+ Smooth ease-out cubic interpolation of the last bar's `close`/`high`/`low` over `duration` ms (default 120 ms). Zero allocations in the rAF loop.
288
+
289
+ ### `RingBuffer`
290
+
291
+ ```typescript
292
+ import { RingBuffer } from '@tony01/astroneum'
293
+
294
+ const buf = new RingBuffer<CandleData>(1000) // fixed capacity
295
+ buf.push(candle)
296
+ const arr = buf.toArray() // oldest → newest
297
+ ```
298
+
299
+ Fixed-capacity O(1) circular buffer designed for streaming time-series data.
300
+
301
+ ---
302
+
303
+ ## Exported types
304
+
305
+ ```typescript
306
+ import type {
307
+ // Core
308
+ AstroneumOptions,
309
+ AstroneumHandle,
310
+ SerializedChartState,
311
+ Datafeed,
312
+ SymbolInfo,
313
+ Period,
314
+ CandleData,
315
+ DatafeedSubscribeCallback,
316
+
317
+ // Branded primitives
318
+ Price,
319
+ Volume,
320
+ Timestamp,
321
+
322
+ // Indicator
323
+ IndicatorDef,
324
+ IndicatorPlugin,
325
+ ChartPlugin,
326
+ ChartPluginContext,
327
+
328
+ // Events
329
+ ChartEventMap,
330
+
331
+ // Coordinate space
332
+ Viewport,
333
+
334
+ // Engine types
335
+ Styles,
336
+ DeepPartial,
337
+ Coordinate,
338
+ Bounding,
339
+
340
+ // Utility types
341
+ TickAnimatorOptions,
342
+ TimeframeText,
343
+ Timespan,
344
+
345
+ // MultiChartLayout
346
+ MultiChartCount,
347
+ MultiChartSlot,
348
+ MultiChartLayoutOptions,
349
+
350
+ // BarReplay
351
+ BarReplayOptions,
352
+ BarReplayState,
353
+
354
+ // Drawing templates
355
+ OverlayStylePreset,
356
+ DrawingStyleTemplate,
357
+
358
+ // AlertManager
359
+ Alert,
360
+ AlertCondition,
361
+ AlertStatus,
362
+ AlertFrequency,
363
+ AlertCreate,
364
+ AlertCheckInput,
365
+ AlertTriggeredCallback,
366
+
367
+ // Format helpers
368
+ FormatPriceOptions,
369
+ DateFormatStyle,
370
+ TimeFormatStyle,
371
+
372
+ // ScriptEngine
373
+ CompiledIndicator,
374
+ StudyOptions,
375
+ PlotOptions,
376
+ InputOptions,
377
+
378
+ // WatchlistManager
379
+ Watchlist,
380
+ WatchSymbol,
381
+
382
+ // PortfolioTracker
383
+ Position,
384
+ PositionSide,
385
+ PnLResult,
386
+
387
+ // PerformanceMode
388
+ PerformanceBar,
389
+ } from '@tony01/astroneum'
390
+ ```
391
+
392
+ ### `IndicatorDef`
393
+
394
+ ```typescript
395
+ interface IndicatorDef {
396
+ /** Registered indicator name, e.g. 'EMA', 'MA', 'RSI' */
397
+ name: string
398
+ /** Calculation parameters passed to the indicator engine */
399
+ calcParams?: number[]
400
+ }
401
+ ```
402
+
403
+ ### `IndicatorPlugin<TOutput>`
404
+
405
+ ```typescript
406
+ interface IndicatorPlugin<TOutput> {
407
+ name: string
408
+ shortName?: string
409
+ calcParams?: number[]
410
+ calc(data: CandleData[], params: number[]): TOutput[]
411
+ render2D?(ctx: CanvasRenderingContext2D, output: TOutput[], viewport: Viewport): void
412
+ renderGL?(gl: WebGL2RenderingContext, output: TOutput[], viewport: Viewport, vbo: WebGLBuffer): void
413
+ }
414
+ ```
415
+
416
+ Implement this interface to register a custom typed indicator.
417
+ Use `render2D` for lightweight overlays (< 10k points) and `renderGL` for high-density or GPU-accelerated rendering.
418
+ When `renderGL` is present, Astroneum executes it on a dedicated WebGL2 layer and reuses a per-indicator `vbo`.
419
+ If WebGL2 is unavailable, `render2D` is used as fallback when available.
420
+
421
+ ### `registerIndicatorPlugin(plugin)`
422
+
423
+ ```typescript
424
+ registerIndicatorPlugin<TOutput>(plugin: IndicatorPlugin<TOutput>): void
425
+ ```
426
+
427
+ Adapts `IndicatorPlugin` to the engine `IndicatorTemplate` format and registers it.
428
+
429
+ ### `registerIndicatorPlugins(plugins)`
430
+
431
+ ```typescript
432
+ registerIndicatorPlugins(plugins: IndicatorPlugin<unknown>[]): void
433
+ ```
434
+
435
+ Batch helper for registering multiple indicator plugins.
436
+
437
+ ### `createIndicatorTemplateFromPlugin(plugin)`
438
+
439
+ ```typescript
440
+ createIndicatorTemplateFromPlugin<TOutput>(plugin: IndicatorPlugin<TOutput>): IndicatorTemplate
441
+ ```
442
+
443
+ Returns the converted engine template without registering it. Useful when you want manual control over registration.
444
+
445
+ ### `ChartPlugin`
446
+
447
+ ```typescript
448
+ interface ChartPlugin {
449
+ name?: string
450
+ indicators?: IndicatorPlugin<unknown>[]
451
+ onInit?: (context: ChartPluginContext) => void | (() => void)
452
+ }
453
+ ```
454
+
455
+ `indicators` are registered before chart indicator creation begins. `onInit` runs once after chart initialization and may return a disposer called during chart teardown.
456
+
457
+ ### `ChartPluginContext`
458
+
459
+ ```typescript
460
+ interface ChartPluginContext {
461
+ chart: Chart
462
+ registerIndicatorPlugin: (plugin: IndicatorPlugin<unknown>) => void
463
+ registerIndicatorPlugins: (plugins: IndicatorPlugin<unknown>[]) => void
464
+ }
465
+ ```
466
+
467
+ ### `ChartEventMap`
468
+
469
+ ```typescript
470
+ interface ChartEventMap {
471
+ 'symbol-change': SymbolInfo
472
+ 'period-change': Period
473
+ 'crosshair-move': Coordinate | null
474
+ 'zoom': { scale: number; anchor: ZoomAnchor }
475
+ 'data-load': { type: 'init' | 'forward' | 'backward'; count: number }
476
+ 'tick': CandleData
477
+ 'drawing-start': string
478
+ 'drawing-end': string
479
+ 'theme-change': string
480
+ }
481
+ ```
482
+
483
+ ### `Viewport`
484
+
485
+ ```typescript
486
+ interface Viewport {
487
+ priceMin: Price
488
+ priceMax: Price
489
+ timeMin: Timestamp
490
+ timeMax: Timestamp
491
+ resolution: readonly [width: number, height: number]
492
+ }
493
+ ```
494
+
495
+ Represents the currently visible region of the chart canvas. Used for coordinate-space transforms in custom `IndicatorPlugin` renderers.
496
+
497
+ ---
498
+
499
+ ## Additional exports
500
+
501
+ | Export | Description |
502
+ |---|---|
503
+ | `DefaultDatafeed` | Polygon.io REST + WebSocket datafeed |
504
+ | `MultiChartLayout` | Multi-chart layout manager |
505
+ | `BarReplay` | Historical bar replay engine |
506
+ | `DrawingTemplates` | Save/load drawing style templates |
507
+ | `AlertManager` | Price alert creation and monitoring |
508
+ | `ScriptEngine` | Pine-like indicator scripting sandbox (`compile()` auto-registers indicators) |
509
+ | `registerIndicator` | Register a raw engine `IndicatorTemplate` |
510
+ | `getSupportedIndicators` | List all registered indicator names |
511
+ | `registerOverlay` | Register a raw engine `OverlayTemplate` |
512
+ | `getSupportedOverlays` | List all registered overlay names |
513
+ | `registerXAxis` / `registerYAxis` | Register custom axis templates |
514
+ | `registerIndicatorPlugin` | Register a typed `IndicatorPlugin` via adapter |
515
+ | `registerIndicatorPlugins` | Batch register typed indicator plugins |
516
+ | `createIndicatorTemplateFromPlugin` | Convert `IndicatorPlugin` to engine template |
517
+ | `WatchlistManager` | Symbol watchlist with live prices |
518
+ | `PortfolioTracker` | Position tracking and P&L calculation |
519
+ | `PerformanceMode` | Reduced-render performance optimization |
520
+ | `loadLocales` | Register UI locale strings |
521
+ | `formatPrice` | Format a price number using symbol precision |
522
+ | `formatVolume` | Format a volume number |
523
+ | `formatPercent` | Format a percentage value |
524
+ | `formatDate` / `formatTime` / `formatDateTime` | Date/time formatting helpers |
525
+ | `formatDuration` | Format a duration in milliseconds as human-readable text |
526
+ | `formatPeriod` | Format a `Period` as a human-readable string (e.g. `'1H'`) |
527
+ | `detectPricePrecision` | Auto-detect decimal precision from price data |
528
+