@tradecanvas/chart 1.19.0 → 1.20.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 (68) hide show
  1. package/README.md +90 -1070
  2. package/dist/Chart.d.ts +16 -5
  3. package/dist/Chart.d.ts.map +1 -1
  4. package/dist/LayoutSession-6FNgfBby.cjs +2 -0
  5. package/dist/LayoutSession-6FNgfBby.cjs.map +1 -0
  6. package/dist/{LayoutSession-Bwz14MjP.js → LayoutSession-DepARyHT.js} +306 -292
  7. package/dist/LayoutSession-DepARyHT.js.map +1 -0
  8. package/dist/i18n-CIHfGH-4.cjs +2 -0
  9. package/dist/i18n-CIHfGH-4.cjs.map +1 -0
  10. package/dist/{i18n-BH0McEvQ.js → i18n-fBzhlejv.js} +7 -1
  11. package/dist/i18n-fBzhlejv.js.map +1 -0
  12. package/dist/index.cjs +1 -1
  13. package/dist/index.d.ts +2 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +49 -49
  16. package/dist/index.js.map +1 -1
  17. package/dist/widget/ChartWidget.d.ts +2 -0
  18. package/dist/widget/ChartWidget.d.ts.map +1 -1
  19. package/dist/widget/WidgetOrderTicket.d.ts +5 -0
  20. package/dist/widget/WidgetOrderTicket.d.ts.map +1 -1
  21. package/dist/widget/index.cjs +14 -14
  22. package/dist/widget/index.cjs.map +1 -1
  23. package/dist/widget/index.js +305 -280
  24. package/dist/widget/index.js.map +1 -1
  25. package/dist/widget/locales/ar.d.ts.map +1 -1
  26. package/dist/widget/locales/cs.d.ts.map +1 -1
  27. package/dist/widget/locales/da.d.ts.map +1 -1
  28. package/dist/widget/locales/de.d.ts.map +1 -1
  29. package/dist/widget/locales/el.d.ts.map +1 -1
  30. package/dist/widget/locales/en.d.ts +3 -0
  31. package/dist/widget/locales/en.d.ts.map +1 -1
  32. package/dist/widget/locales/es.d.ts.map +1 -1
  33. package/dist/widget/locales/et.d.ts.map +1 -1
  34. package/dist/widget/locales/fa.d.ts.map +1 -1
  35. package/dist/widget/locales/fr.d.ts.map +1 -1
  36. package/dist/widget/locales/he.d.ts.map +1 -1
  37. package/dist/widget/locales/hu.d.ts.map +1 -1
  38. package/dist/widget/locales/id.d.ts.map +1 -1
  39. package/dist/widget/locales/index.cjs +1 -1
  40. package/dist/widget/locales/index.cjs.map +1 -1
  41. package/dist/widget/locales/index.js +85 -1
  42. package/dist/widget/locales/index.js.map +1 -1
  43. package/dist/widget/locales/it.d.ts.map +1 -1
  44. package/dist/widget/locales/ja.d.ts.map +1 -1
  45. package/dist/widget/locales/ko.d.ts.map +1 -1
  46. package/dist/widget/locales/ms.d.ts.map +1 -1
  47. package/dist/widget/locales/nb.d.ts.map +1 -1
  48. package/dist/widget/locales/nl.d.ts.map +1 -1
  49. package/dist/widget/locales/pl.d.ts.map +1 -1
  50. package/dist/widget/locales/pt.d.ts.map +1 -1
  51. package/dist/widget/locales/ro.d.ts.map +1 -1
  52. package/dist/widget/locales/ru.d.ts.map +1 -1
  53. package/dist/widget/locales/sk.d.ts.map +1 -1
  54. package/dist/widget/locales/sv.d.ts.map +1 -1
  55. package/dist/widget/locales/th.d.ts.map +1 -1
  56. package/dist/widget/locales/tr.d.ts.map +1 -1
  57. package/dist/widget/locales/vi.d.ts.map +1 -1
  58. package/dist/widget/locales/zh.d.ts.map +1 -1
  59. package/dist/widget/locales/zhHant.d.ts.map +1 -1
  60. package/dist/widget/orderTicket.d.ts +19 -2
  61. package/dist/widget/orderTicket.d.ts.map +1 -1
  62. package/package.json +7 -3
  63. package/dist/LayoutSession-Bwz14MjP.js.map +0 -1
  64. package/dist/LayoutSession-C3NIrkK8.cjs +0 -2
  65. package/dist/LayoutSession-C3NIrkK8.cjs.map +0 -1
  66. package/dist/i18n-BH0McEvQ.js.map +0 -1
  67. package/dist/i18n-D0C88QUR.cjs +0 -2
  68. package/dist/i18n-D0C88QUR.cjs.map +0 -1
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import { S as e, _ as t, a as n, b as r, c as i, d as a, f as o, g as s, h as c, i as l, l as u, m as ee, n as te, o as ne, p as re, r as ie, s as ae, t as oe, u as se, v as ce, x as le, y as ue } from "./LayoutSession-Bwz14MjP.js";
2
- import { CHART_STYLE_KEYS as de, DARK_TERMINAL as fe, DARK_THEME as pe, DARK_THEME as me, DEFAULT_DRAWING_STYLE as he, DEFAULT_RECONNECT as d, DEFAULT_SIGNAL_STYLE as f, DEFAULT_STREAM_CONFIG as p, DEFAULT_TIMEFRAME_FAVORITES as m, DEFAULT_TRADE_ZONE_STYLE as h, DEFAULT_TRADING_CONFIG as g, LIGHT_THEME as _, LIGHT_THEME as v, MARKET_CRYPTO as y, MARKET_HNX as b, MARKET_HOSE as x, MARKET_NYSE as S, MARKET_UPCOM as C, PRICE_SOURCES as w, TC_PALETTE as T, TC_SERIES_COLORS as E, TIMEFRAMES_CRYPTO as D, TIMEFRAMES_FOREX as O, TIMEFRAMES_STOCK as k, VN_COLORS as A, VOLUME_ALPHA as j, barsAreDaily as M, computePriceLimits as N, createVNTheme as P, formatFraction as F, formatNumber as I, formatVND as L, formatVolumeLoc as R, fractionTick as ge, getCurrentSession as _e, getLocale as ve, indicatorSource as ye, isPriceSource as be, isTimeFrame as xe, isValidTimeZone as Se, marketStatus as Ce, normalizeBar as we, normalizeBarTime as Te, offsetAt as Ee, parseIndicatorSource as De, parseTimeframe as Oe, pickBaseTimeframe as ke, priceFormatterFor as Ae, rankSymbols as je, readNews as Me, readQuote as Ne, registerLocale as Pe, resampleBars as Fe, setLocale as Ie, sourcePrice as Le, stepDecimals as Re, t as ze, tickBarCount as Be, timeframeBucketStart as Ve, timeframeToMs as He, volumeColor as Ue, wallToUtc as We, zoneOffsetMinutes as Ge } from "@tradecanvas/commons";
3
- import { AlertManager as Ke, Animator as qe, BarCountdown as Je, BaseFinanceChart as z, BinanceAdapter as Ye, BybitAdapter as Xe, ChartLegend as Ze, ChartStateManager as Qe, CoinbaseAdapter as $e, CompareRenderer as et, CrosshairTooltip as tt, CurrentPriceLine as nt, DEFAULT_LEGEND_CONFIG as rt, DEFAULT_MAX_WEBGL_CHARTS as it, DEFAULT_SESSION_HOURS as at, DataExporter as ot, DrawingBase as st, Easing as ct, FinanceCrosshair as B, IndicatorBase as lt, IndicatorValueMap as ut, KeyboardHandler as dt, KrakenAdapter as ft, MAX_ALERT_BARS as pt, MIN_ALERT_BARS as mt, MockAdapter as ht, PaperExecutionAdapter as gt, PollingAdapter as _t, RANGE_PRESETS as vt, ReplayManager as yt, ResamplingAdapter as bt, Screenshot as xt, SessionBreaks as St, SessionShading as Ct, SignalMarkerManager as wt, StreamManager as Tt, TickAggregator as Et, TickBarAdapter as Dt, TickBarBuilder as Ot, TradeZoneManager as kt, UndoRedoManager as At, VolumeRenderer as jt, Watermark as Mt, WebSocketAdapter as Nt, barIndexToTime as Pt, barIndexToX as Ft, barIndexToX as V, formatTooltipTime as It, isPriceLevelAlert as Lt, layoutSquarifiedTreemap as Rt, layoutUniformGrid as zt, lttbDownsample as Bt, lttbVisibleIndices as Vt, priceToY as Ht, priceToYMapper as Ut, priceToYMapper as Wt, rangePresetStart as Gt, renderDepthChart as Kt, renderEquityCurve as qt, renderGauge as Jt, renderHeatmap as Yt, renderSparkline as Xt, renderWaterfall as Zt, servesTimeframe as Qt, setMaxWebGLCharts as $t, timeToX as en, timestampToBarIndex as tn, timestampToBarIndex as nn, toHeikinAshi as rn, toKagi as an, toLineBreak as on, toPointAndFigure as sn, toRangeBars as cn, toRenko as ln, withResampling as un, withTickBars as dn, xToBarIndex as fn, xToBarIndex as H, xToTime as pn, yToPrice as mn, yToPrice as hn } from "@tradecanvas/core";
1
+ import { S as e, _ as t, a as n, b as r, c as i, d as a, f as o, g as s, h as c, i as l, l as u, m as ee, n as te, o as ne, p as re, r as ie, s as ae, t as oe, u as se, v as ce, x as le, y as ue } from "./LayoutSession-DepARyHT.js";
2
+ import { CHART_STYLE_KEYS as de, DARK_TERMINAL as fe, DARK_THEME as pe, DARK_THEME as me, DEFAULT_DRAWING_STYLE as he, DEFAULT_RECONNECT as d, DEFAULT_SIGNAL_STYLE as f, DEFAULT_STREAM_CONFIG as p, DEFAULT_TIMEFRAME_FAVORITES as m, DEFAULT_TRADE_ZONE_STYLE as h, DEFAULT_TRADING_CONFIG as g, HNX_SESSIONS as _, HOSE_SESSIONS as v, LIGHT_THEME as y, LIGHT_THEME as b, MARKET_CRYPTO as x, MARKET_HNX as S, MARKET_HOSE as C, MARKET_HOSE_ETF as w, MARKET_NYSE as T, MARKET_UPCOM as E, MARKET_VN30F as D, PRICE_SOURCES as O, TC_PALETTE as k, TC_SERIES_COLORS as A, TIMEFRAMES_CRYPTO as j, TIMEFRAMES_FOREX as M, TIMEFRAMES_STOCK as N, UPCOM_SESSIONS as P, VN30F_SESSIONS as F, VN_COLORS as I, VOLUME_ALPHA as L, barsAreDaily as R, computePriceLimits as ge, createVNTheme as _e, formatFraction as ve, formatNumber as ye, formatVND as be, formatVolumeLoc as xe, fractionTick as Se, getCurrentSession as Ce, getLocale as we, indicatorSource as Te, isPriceSource as Ee, isTimeFrame as De, isValidTimeZone as Oe, marketStatus as ke, normalizeBar as Ae, normalizeBarTime as je, offsetAt as Me, parseIndicatorSource as Ne, parseTimeframe as Pe, pickBaseTimeframe as Fe, priceFormatterFor as Ie, priceStepAt as Le, rankSymbols as Re, readNews as ze, readQuote as Be, registerLocale as Ve, resampleBars as He, roundToPriceStep as Ue, scaleMarketPrices as We, setLocale as Ge, sourcePrice as Ke, stepDecimals as qe, t as Je, tickBarCount as Ye, timeframeBucketStart as Xe, timeframeToMs as Ze, vn30fContracts as Qe, vn30fLastTradingDay as $e, volumeColor as et, wallToUtc as tt, zoneOffsetMinutes as nt } from "@tradecanvas/commons";
3
+ import { AlertManager as rt, Animator as it, BarCountdown as at, BaseFinanceChart as z, BinanceAdapter as ot, BybitAdapter as st, ChartLegend as ct, ChartStateManager as lt, CoinbaseAdapter as ut, CompareRenderer as dt, CrosshairTooltip as ft, CurrentPriceLine as pt, DEFAULT_LEGEND_CONFIG as B, DEFAULT_MAX_WEBGL_CHARTS as mt, DEFAULT_SESSION_HOURS as ht, DataExporter as gt, DrawingBase as _t, Easing as vt, FinanceCrosshair as V, IndicatorBase as yt, IndicatorValueMap as bt, KeyboardHandler as xt, KrakenAdapter as St, MAX_ALERT_BARS as Ct, MIN_ALERT_BARS as wt, MockAdapter as Tt, PaperExecutionAdapter as Et, PollingAdapter as Dt, RANGE_PRESETS as Ot, ReplayManager as kt, ResamplingAdapter as At, Screenshot as jt, SessionBreaks as Mt, SessionShading as Nt, SignalMarkerManager as Pt, StreamManager as Ft, TickAggregator as It, TickBarAdapter as Lt, TickBarBuilder as Rt, TradeZoneManager as zt, UndoRedoManager as Bt, VolumeRenderer as Vt, Watermark as Ht, WebSocketAdapter as Ut, barIndexToTime as Wt, barIndexToX as Gt, barIndexToX as H, formatTooltipTime as Kt, isPriceLevelAlert as qt, layoutSquarifiedTreemap as Jt, layoutUniformGrid as Yt, lttbDownsample as Xt, lttbVisibleIndices as Zt, priceToY as Qt, priceToYMapper as $t, priceToYMapper as en, rangePresetStart as tn, renderDepthChart as nn, renderEquityCurve as rn, renderGauge as an, renderHeatmap as on, renderSparkline as sn, renderWaterfall as cn, servesTimeframe as ln, setMaxWebGLCharts as un, timeToX as dn, timestampToBarIndex as fn, timestampToBarIndex as pn, toHeikinAshi as mn, toKagi as hn, toLineBreak as gn, toPointAndFigure as _n, toRangeBars as vn, toRenko as yn, withResampling as bn, withTickBars as xn, xToBarIndex as Sn, xToBarIndex as U, xToTime as Cn, yToPrice as wn, yToPrice as Tn } from "@tradecanvas/core";
4
4
  //#region src/frameworks/syncIndicators.ts
5
- function gn(e) {
5
+ function En(e) {
6
6
  let { id: t, params: n = {}, position: r = null } = typeof e == "string" ? { id: e } : e;
7
7
  return JSON.stringify([
8
8
  t,
@@ -10,9 +10,9 @@ function gn(e) {
10
10
  r
11
11
  ]);
12
12
  }
13
- function _n(e, t, n) {
13
+ function Dn(e, t, n) {
14
14
  let r = /* @__PURE__ */ new Map(), i = t.map((e) => {
15
- let t = gn(e), n = r.get(t) ?? 0;
15
+ let t = En(e), n = r.get(t) ?? 0;
16
16
  return r.set(t, n + 1), {
17
17
  spec: e,
18
18
  key: `${t}#${n}`
@@ -27,18 +27,18 @@ function _n(e, t, n) {
27
27
  }
28
28
  //#endregion
29
29
  //#region src/plugins/overlayScale.ts
30
- function vn(e) {
31
- let { viewport: t, data: n } = e, r = Wt(t), i = n.length - 1, a = Math.max(0, Math.floor(t.visibleRange.from)), o = Math.min(i, Math.ceil(t.visibleRange.to)), s = (e) => n.length > 0 ? nn(e, n) : e;
30
+ function On(e) {
31
+ let { viewport: t, data: n } = e, r = en(t), i = n.length - 1, a = Math.max(0, Math.floor(t.visibleRange.from)), o = Math.min(i, Math.ceil(t.visibleRange.to)), s = (e) => n.length > 0 ? pn(e, n) : e;
32
32
  return {
33
- timeToX: (e) => V(s(e), t),
33
+ timeToX: (e) => H(s(e), t),
34
34
  xToTime: (e) => {
35
- let r = H(e, t);
36
- return n.length > 0 ? Pt(r, n) : r;
35
+ let r = U(e, t);
36
+ return n.length > 0 ? Wt(r, n) : r;
37
37
  },
38
- indexToX: (e) => V(e, t),
39
- xToIndex: (e) => H(e, t),
38
+ indexToX: (e) => H(e, t),
39
+ xToIndex: (e) => U(e, t),
40
40
  priceToY: r,
41
- yToPrice: (e) => hn(e, t),
41
+ yToPrice: (e) => Tn(e, t),
42
42
  barWidth: t.barWidth,
43
43
  visible: o < a ? {
44
44
  from: 0,
@@ -51,7 +51,7 @@ function vn(e) {
51
51
  }
52
52
  //#endregion
53
53
  //#region src/grid/ChartGrid.ts
54
- var U = {
54
+ var W = {
55
55
  "1x1": {
56
56
  cols: 1,
57
57
  rows: 1
@@ -84,7 +84,7 @@ var U = {
84
84
  cols: 2,
85
85
  rows: 3
86
86
  }
87
- }, yn = class {
87
+ }, kn = class {
88
88
  root;
89
89
  cells = [];
90
90
  layout;
@@ -95,11 +95,11 @@ var U = {
95
95
  this.options = t, this.layout = t.layout ?? "2x2", this.root = document.createElement("div"), this.root.style.cssText = "display:grid;width:100%;height:100%;overflow:hidden;", e.appendChild(this.root), this.applyLayout(), this.createCells();
96
96
  }
97
97
  applyLayout() {
98
- let { cols: e, rows: t } = U[this.layout], n = this.options.gap ?? 1;
98
+ let { cols: e, rows: t } = W[this.layout], n = this.options.gap ?? 1;
99
99
  this.root.style.gridTemplateColumns = `repeat(${e}, 1fr)`, this.root.style.gridTemplateRows = `repeat(${t}, 1fr)`, this.root.style.gap = `${n}px`;
100
100
  }
101
101
  createCells() {
102
- let { cols: e, rows: t } = U[this.layout], n = e * t;
102
+ let { cols: e, rows: t } = W[this.layout], n = e * t;
103
103
  for (let e = 0; e < n; e++) this.cells.push(this.createCell(e));
104
104
  }
105
105
  createCell(e) {
@@ -144,7 +144,7 @@ var U = {
144
144
  }
145
145
  setLayout(e) {
146
146
  if (e === this.layout) return;
147
- let t = this.cells.length, { cols: n, rows: r } = U[e], i = n * r;
147
+ let t = this.cells.length, { cols: n, rows: r } = W[e], i = n * r;
148
148
  if (i < t) for (let e = t - 1; e >= i; e--) {
149
149
  let t = this.cells[e];
150
150
  t.chart.destroy(), t.container.remove(), this.cells.pop();
@@ -191,13 +191,13 @@ var U = {
191
191
  this.cells = [], this.root.remove();
192
192
  }
193
193
  }
194
- }, bn = class extends z {
194
+ }, An = class extends z {
195
195
  options;
196
196
  constructor(e, t) {
197
197
  super(e, t.theme), this.options = t, this.requestRender();
198
198
  }
199
199
  renderChart(e, t, n, r) {
200
- Xt(e, t, n, this.options, r);
200
+ sn(e, t, n, this.options, r);
201
201
  }
202
202
  update(e) {
203
203
  this.options = {
@@ -211,15 +211,15 @@ var U = {
211
211
  ...e
212
212
  }, this.requestRender();
213
213
  }
214
- }, xn = class extends z {
214
+ }, jn = class extends z {
215
215
  options;
216
216
  crosshair = null;
217
217
  constructor(e, t) {
218
- super(e, t.theme), this.options = t, t.crosshair !== !1 && (this.crosshair = new B(this.canvas, () => this.requestRender())), this.requestRender();
218
+ super(e, t.theme), this.options = t, t.crosshair !== !1 && (this.crosshair = new V(this.canvas, () => this.requestRender())), this.requestRender();
219
219
  }
220
220
  renderChart(e, t, n, r) {
221
221
  let i = this.crosshair?.getPosition() ?? null;
222
- Kt(e, t, n, this.options, r, i);
222
+ nn(e, t, n, this.options, r, i);
223
223
  }
224
224
  update(e) {
225
225
  this.options = {
@@ -236,15 +236,15 @@ var U = {
236
236
  destroy() {
237
237
  this.crosshair?.destroy(), super.destroy();
238
238
  }
239
- }, W = class extends z {
239
+ }, G = class extends z {
240
240
  options;
241
241
  crosshair = null;
242
242
  constructor(e, t) {
243
- super(e, t.theme), this.options = t, t.crosshair !== !1 && (this.crosshair = new B(this.canvas, () => this.requestRender())), this.requestRender();
243
+ super(e, t.theme), this.options = t, t.crosshair !== !1 && (this.crosshair = new V(this.canvas, () => this.requestRender())), this.requestRender();
244
244
  }
245
245
  renderChart(e, t, n, r) {
246
246
  let i = this.crosshair?.getPosition() ?? null;
247
- qt(e, t, n, this.options, r, i);
247
+ rn(e, t, n, this.options, r, i);
248
248
  }
249
249
  update(e, t) {
250
250
  this.options = {
@@ -264,7 +264,7 @@ var U = {
264
264
  destroy() {
265
265
  this.crosshair?.destroy(), super.destroy();
266
266
  }
267
- }, G = class extends z {
267
+ }, K = class extends z {
268
268
  options;
269
269
  crosshair = null;
270
270
  cachedRects = [];
@@ -273,7 +273,7 @@ var U = {
273
273
  lastLayoutHeight = 0;
274
274
  handleClick = null;
275
275
  constructor(e, t) {
276
- super(e, t.theme), this.options = t, this.currentData = t.data ?? [], t.crosshair !== !1 && (this.crosshair = new B(this.canvas, () => this.requestRender())), t.onCellClick && (this.handleClick = (e) => {
276
+ super(e, t.theme), this.options = t, this.currentData = t.data ?? [], t.crosshair !== !1 && (this.crosshair = new V(this.canvas, () => this.requestRender())), t.onCellClick && (this.handleClick = (e) => {
277
277
  let t = this.canvas.getBoundingClientRect(), n = e.clientX - t.left, r = e.clientY - t.top;
278
278
  this.onCanvasClick(n, r);
279
279
  }, this.canvas.addEventListener("click", this.handleClick)), this.recomputeLayout(), this.requestRender();
@@ -290,8 +290,8 @@ var U = {
290
290
  id: e.id,
291
291
  weight: e.weight ?? (Math.abs(e.value) || 1)
292
292
  }));
293
- this.cachedRects = Rt(n, e, t);
294
- } else this.cachedRects = zt(this.currentData.map((e) => ({ id: e.id })), e, t);
293
+ this.cachedRects = Jt(n, e, t);
294
+ } else this.cachedRects = Yt(this.currentData.map((e) => ({ id: e.id })), e, t);
295
295
  }
296
296
  onCanvasClick(e, t) {
297
297
  if (this.options.onCellClick) for (let n of this.cachedRects) {
@@ -306,7 +306,7 @@ var U = {
306
306
  renderChart(e, t, n, r) {
307
307
  (t !== this.lastLayoutWidth || n !== this.lastLayoutHeight) && this.recomputeLayout();
308
308
  let i = this.crosshair?.getPosition() ?? null;
309
- Yt(e, t, n, this.currentData, this.cachedRects, this.options, r, i);
309
+ on(e, t, n, this.currentData, this.cachedRects, this.options, r, i);
310
310
  }
311
311
  update(e) {
312
312
  this.currentData = e, this.options = {
@@ -323,15 +323,15 @@ var U = {
323
323
  destroy() {
324
324
  this.crosshair?.destroy(), this.handleClick && this.canvas.removeEventListener("click", this.handleClick), super.destroy();
325
325
  }
326
- }, K = class extends z {
326
+ }, Mn = class extends z {
327
327
  options;
328
328
  crosshair = null;
329
329
  constructor(e, t) {
330
- super(e, t.theme), this.options = t, t.crosshair !== !1 && (this.crosshair = new B(this.canvas, () => this.requestRender())), this.requestRender();
330
+ super(e, t.theme), this.options = t, t.crosshair !== !1 && (this.crosshair = new V(this.canvas, () => this.requestRender())), this.requestRender();
331
331
  }
332
332
  renderChart(e, t, n, r) {
333
333
  let i = this.crosshair?.getPosition() ?? null;
334
- Zt(e, t, n, this.options, r, i);
334
+ cn(e, t, n, this.options, r, i);
335
335
  }
336
336
  update(e) {
337
337
  this.options = {
@@ -348,12 +348,12 @@ var U = {
348
348
  destroy() {
349
349
  this.crosshair?.destroy(), super.destroy();
350
350
  }
351
- }, Sn = 500;
352
- function Cn(e) {
351
+ }, Nn = 500;
352
+ function Pn(e) {
353
353
  let t = 1 - e;
354
354
  return 1 - t * t * t;
355
355
  }
356
- var wn = class extends z {
356
+ var Fn = class extends z {
357
357
  options;
358
358
  currentValue;
359
359
  targetValue;
@@ -364,7 +364,7 @@ var wn = class extends z {
364
364
  super(e, t.theme), this.options = t, this.currentValue = t.value, this.targetValue = t.value, this.requestRender();
365
365
  }
366
366
  renderChart(e, t, n, r) {
367
- Jt(e, t, n, this.options, r, this.currentValue);
367
+ an(e, t, n, this.options, r, this.currentValue);
368
368
  }
369
369
  setValue(e) {
370
370
  if (this.options.animate === !1) {
@@ -394,7 +394,7 @@ var wn = class extends z {
394
394
  if (this.animationFrameId !== null) return;
395
395
  let e = () => {
396
396
  if (this.animationFrameId = null, this.animationStart === null) return;
397
- let t = this.options.animationDuration ?? Sn, n = performance.now() - this.animationStart, r = Math.min(1, n / Math.max(1, t)), i = Cn(r);
397
+ let t = this.options.animationDuration ?? Nn, n = performance.now() - this.animationStart, r = Math.min(1, n / Math.max(1, t)), i = Pn(r);
398
398
  this.currentValue = this.animationFrom + (this.targetValue - this.animationFrom) * i, this.requestRender(), r < 1 ? this.animationFrameId = requestAnimationFrame(e) : (this.currentValue = this.targetValue, this.animationStart = null);
399
399
  };
400
400
  this.animationFrameId = requestAnimationFrame(e);
@@ -405,7 +405,7 @@ var wn = class extends z {
405
405
  destroy() {
406
406
  this.cancelAnimation(), super.destroy();
407
407
  }
408
- }, Tn = [
408
+ }, In = [
409
409
  "Jan",
410
410
  "Feb",
411
411
  "Mar",
@@ -440,7 +440,7 @@ function Y(e) {
440
440
  if (e.length === 0) return [];
441
441
  let t = [];
442
442
  for (let n of e) {
443
- let e = Ve(n.time, "1M"), r = t[t.length - 1];
443
+ let e = Xe(n.time, "1M"), r = t[t.length - 1];
444
444
  r && r.key === e ? r.close = n.equity : t.push({
445
445
  key: e,
446
446
  close: n.equity
@@ -453,7 +453,7 @@ function Y(e) {
453
453
  let a = new Date(e.key), o = a.getUTCFullYear(), s = a.getUTCMonth();
454
454
  r.push({
455
455
  id: `${o}-${String(s + 1).padStart(2, "0")}`,
456
- label: Tn[s],
456
+ label: In[s],
457
457
  group: String(o),
458
458
  value: i
459
459
  });
@@ -513,9 +513,9 @@ function Q(e) {
513
513
  //#endregion
514
514
  //#region src/finance/PerformanceDashboard.ts
515
515
  function $(e) {
516
- return !e || e === "dark" ? me : e === "light" ? v : e;
516
+ return !e || e === "dark" ? me : e === "light" ? b : e;
517
517
  }
518
- var En = class {
518
+ var Ln = class {
519
519
  options;
520
520
  theme;
521
521
  root;
@@ -558,7 +558,7 @@ var En = class {
558
558
  "gap:14px"
559
559
  ].join(";"), this.root.appendChild(o);
560
560
  let s = this.buildPanel("Equity Curve", i, a);
561
- s.wrap.style.gridColumn = "1 / -1", o.appendChild(s.wrap), this.equityChart = new W(s.body, {
561
+ s.wrap.style.gridColumn = "1 / -1", o.appendChild(s.wrap), this.equityChart = new G(s.body, {
562
562
  data: q(t.equityCurve),
563
563
  theme: e,
564
564
  lineColor: e.candleUp,
@@ -566,7 +566,7 @@ var En = class {
566
566
  crosshair: !0
567
567
  });
568
568
  let c = this.buildPanel("Drawdown", i, a);
569
- o.appendChild(c.wrap), this.drawdownChart = new W(c.body, {
569
+ o.appendChild(c.wrap), this.drawdownChart = new G(c.body, {
570
570
  data: J(t.equityCurve),
571
571
  theme: e,
572
572
  lineColor: e.candleDown,
@@ -575,7 +575,7 @@ var En = class {
575
575
  valueFormat: (e) => `${e.toFixed(1)}%`
576
576
  });
577
577
  let l = Y(t.equityCurve), u = this.buildPanel("Monthly Returns", i, a);
578
- o.appendChild(u.wrap), this.heatmap = new G(u.body, {
578
+ o.appendChild(u.wrap), this.heatmap = new K(u.body, {
579
579
  data: l,
580
580
  theme: e,
581
581
  showValues: !0,
@@ -664,6 +664,6 @@ var En = class {
664
664
  }
665
665
  };
666
666
  //#endregion
667
- export { Ke as AlertManager, qe as Animator, Je as BarCountdown, Ye as BinanceAdapter, Xe as BybitAdapter, de as CHART_STYLE_KEYS, i as Chart, yn as ChartGrid, Ze as ChartLegend, Qe as ChartStateManager, $e as CoinbaseAdapter, et as CompareRenderer, tt as CrosshairTooltip, nt as CurrentPriceLine, fe as DARK_TERMINAL, pe as DARK_THEME, he as DEFAULT_DRAWING_STYLE, r as DEFAULT_HISTORY_PAGE_SIZE, rt as DEFAULT_LEGEND_CONFIG, it as DEFAULT_MAX_WEBGL_CHARTS, d as DEFAULT_RECONNECT, at as DEFAULT_SESSION_HOURS, f as DEFAULT_SIGNAL_STYLE, p as DEFAULT_STREAM_CONFIG, m as DEFAULT_TIMEFRAME_FAVORITES, h as DEFAULT_TRADE_ZONE_STYLE, g as DEFAULT_TRADING_CONFIG, ot as DataExporter, e as DataManager, xn as DepthChart, ne as DragDropImporter, st as DrawingBase, u as EXCHANGE_TIMEZONE, ct as Easing, W as EquityCurveChart, wn as GaugeChart, le as HISTORY_RETRY_MS, G as HeatmapChart, lt as IndicatorBase, ut as IndicatorValueMap, dt as KeyboardHandler, ft as KrakenAdapter, _ as LIGHT_THEME, ce as LayoutManager, oe as LayoutSession, y as MARKET_CRYPTO, b as MARKET_HNX, x as MARKET_HOSE, S as MARKET_NYSE, C as MARKET_UPCOM, pt as MAX_ALERT_BARS, te as MAX_LAYOUT_NAME, mt as MIN_ALERT_BARS, ht as MockAdapter, c as PLUGIN_API_VERSION, w as PRICE_SOURCES, gt as PaperExecutionAdapter, En as PerformanceDashboard, se as PluginManager, _t as PollingAdapter, vt as RANGE_PRESETS, yt as ReplayManager, bt as ResamplingAdapter, xt as Screenshot, St as SessionBreaks, Ct as SessionShading, wt as SignalMarkerManager, bn as SparklineChart, Tt as StreamManager, T as TC_PALETTE, E as TC_SERIES_COLORS, D as TIMEFRAMES_CRYPTO, O as TIMEFRAMES_FOREX, k as TIMEFRAMES_STOCK, ue as ThemeManager, Et as TickAggregator, Dt as TickBarAdapter, Ot as TickBarBuilder, kt as TradeZoneManager, At as UndoRedoManager, A as VN_COLORS, j as VOLUME_ALPHA, jt as VolumeRenderer, K as WaterfallChart, Mt as Watermark, Nt as WebSocketAdapter, Ft as barIndexToX, M as barsAreDaily, ie as cleanLayoutName, a as clearGlobalPlugins, J as computeDrawdownCurve, Y as computeMonthlyReturns, N as computePriceLimits, P as createVNTheme, F as formatFraction, I as formatNumber, It as formatTooltipTime, L as formatVND, R as formatVolumeLoc, ge as fractionTick, _e as getCurrentSession, o as getGlobalPlugins, ve as getLocale, ye as indicatorSource, Lt as isPriceLevelAlert, be as isPriceSource, xe as isTimeFrame, Se as isValidTimeZone, l as localStorageLayouts, Bt as lttbDownsample, Vt as lttbVisibleIndices, Ce as marketStatus, n as memoryLayouts, we as normalizeBar, Te as normalizeBarTime, Ee as offsetAt, vn as overlayScale, s as overlaysForLayer, De as parseIndicatorSource, ae as parseOHLCV, Oe as parseTimeframe, ke as pickBaseTimeframe, t as pluginKey, Ae as priceFormatterFor, Ht as priceToY, Ut as priceToYMapper, Gt as rangePresetStart, je as rankSymbols, Me as readNews, Ne as readQuote, Pe as registerLocale, re as registerPlugin, Fe as resampleBars, Q as selectKeyStats, Qt as servesTimeframe, Ie as setLocale, $t as setMaxWebGLCharts, Le as sourcePrice, Re as stepDecimals, _n as syncIndicators, ze as t, Be as tickBarCount, en as timeToX, He as timeframeToMs, tn as timestampToBarIndex, q as toEquityPoints, rn as toHeikinAshi, an as toKagi, on as toLineBreak, sn as toPointAndFigure, cn as toRangeBars, ln as toRenko, ee as unregisterPlugin, Ue as volumeColor, We as wallToUtc, un as withResampling, dn as withTickBars, fn as xToBarIndex, pn as xToTime, mn as yToPrice, Ge as zoneOffsetMinutes };
667
+ export { rt as AlertManager, it as Animator, at as BarCountdown, ot as BinanceAdapter, st as BybitAdapter, de as CHART_STYLE_KEYS, i as Chart, kn as ChartGrid, ct as ChartLegend, lt as ChartStateManager, ut as CoinbaseAdapter, dt as CompareRenderer, ft as CrosshairTooltip, pt as CurrentPriceLine, fe as DARK_TERMINAL, pe as DARK_THEME, he as DEFAULT_DRAWING_STYLE, r as DEFAULT_HISTORY_PAGE_SIZE, B as DEFAULT_LEGEND_CONFIG, mt as DEFAULT_MAX_WEBGL_CHARTS, d as DEFAULT_RECONNECT, ht as DEFAULT_SESSION_HOURS, f as DEFAULT_SIGNAL_STYLE, p as DEFAULT_STREAM_CONFIG, m as DEFAULT_TIMEFRAME_FAVORITES, h as DEFAULT_TRADE_ZONE_STYLE, g as DEFAULT_TRADING_CONFIG, gt as DataExporter, e as DataManager, jn as DepthChart, ne as DragDropImporter, _t as DrawingBase, u as EXCHANGE_TIMEZONE, vt as Easing, G as EquityCurveChart, Fn as GaugeChart, le as HISTORY_RETRY_MS, _ as HNX_SESSIONS, v as HOSE_SESSIONS, K as HeatmapChart, yt as IndicatorBase, bt as IndicatorValueMap, xt as KeyboardHandler, St as KrakenAdapter, y as LIGHT_THEME, ce as LayoutManager, oe as LayoutSession, x as MARKET_CRYPTO, S as MARKET_HNX, C as MARKET_HOSE, w as MARKET_HOSE_ETF, T as MARKET_NYSE, E as MARKET_UPCOM, D as MARKET_VN30F, Ct as MAX_ALERT_BARS, te as MAX_LAYOUT_NAME, wt as MIN_ALERT_BARS, Tt as MockAdapter, c as PLUGIN_API_VERSION, O as PRICE_SOURCES, Et as PaperExecutionAdapter, Ln as PerformanceDashboard, se as PluginManager, Dt as PollingAdapter, Ot as RANGE_PRESETS, kt as ReplayManager, At as ResamplingAdapter, jt as Screenshot, Mt as SessionBreaks, Nt as SessionShading, Pt as SignalMarkerManager, An as SparklineChart, Ft as StreamManager, k as TC_PALETTE, A as TC_SERIES_COLORS, j as TIMEFRAMES_CRYPTO, M as TIMEFRAMES_FOREX, N as TIMEFRAMES_STOCK, ue as ThemeManager, It as TickAggregator, Lt as TickBarAdapter, Rt as TickBarBuilder, zt as TradeZoneManager, P as UPCOM_SESSIONS, Bt as UndoRedoManager, F as VN30F_SESSIONS, I as VN_COLORS, L as VOLUME_ALPHA, Vt as VolumeRenderer, Mn as WaterfallChart, Ht as Watermark, Ut as WebSocketAdapter, Gt as barIndexToX, R as barsAreDaily, ie as cleanLayoutName, a as clearGlobalPlugins, J as computeDrawdownCurve, Y as computeMonthlyReturns, ge as computePriceLimits, _e as createVNTheme, ve as formatFraction, ye as formatNumber, Kt as formatTooltipTime, be as formatVND, xe as formatVolumeLoc, Se as fractionTick, Ce as getCurrentSession, o as getGlobalPlugins, we as getLocale, Te as indicatorSource, qt as isPriceLevelAlert, Ee as isPriceSource, De as isTimeFrame, Oe as isValidTimeZone, l as localStorageLayouts, Xt as lttbDownsample, Zt as lttbVisibleIndices, ke as marketStatus, n as memoryLayouts, Ae as normalizeBar, je as normalizeBarTime, Me as offsetAt, On as overlayScale, s as overlaysForLayer, Ne as parseIndicatorSource, ae as parseOHLCV, Pe as parseTimeframe, Fe as pickBaseTimeframe, t as pluginKey, Ie as priceFormatterFor, Le as priceStepAt, Qt as priceToY, $t as priceToYMapper, tn as rangePresetStart, Re as rankSymbols, ze as readNews, Be as readQuote, Ve as registerLocale, re as registerPlugin, He as resampleBars, Ue as roundToPriceStep, We as scaleMarketPrices, Q as selectKeyStats, ln as servesTimeframe, Ge as setLocale, un as setMaxWebGLCharts, Ke as sourcePrice, qe as stepDecimals, Dn as syncIndicators, Je as t, Ye as tickBarCount, dn as timeToX, Ze as timeframeToMs, fn as timestampToBarIndex, q as toEquityPoints, mn as toHeikinAshi, hn as toKagi, gn as toLineBreak, _n as toPointAndFigure, vn as toRangeBars, yn as toRenko, ee as unregisterPlugin, Qe as vn30fContracts, $e as vn30fLastTradingDay, et as volumeColor, tt as wallToUtc, bn as withResampling, xn as withTickBars, Sn as xToBarIndex, Cn as xToTime, wn as yToPrice, nt as zoneOffsetMinutes };
668
668
 
669
669
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/frameworks/syncIndicators.ts","../src/plugins/overlayScale.ts","../src/grid/ChartGrid.ts","../src/finance/SparklineChart.ts","../src/finance/DepthChart.ts","../src/finance/EquityCurveChart.ts","../src/finance/HeatmapChart.ts","../src/finance/WaterfallChart.ts","../src/finance/GaugeChart.ts","../src/finance/performanceData.ts","../src/finance/PerformanceDashboard.ts"],"sourcesContent":["import type { PanelPosition } from '@tradecanvas/commons';\n\n/**\n * An indicator a framework component shows: its id (`'rsi'`), or its id with\n * its inputs and, for one in a pane, where the pane goes.\n */\nexport type IndicatorSpec =\n | string\n | { id: string; params?: Record<string, number | string | boolean>; position?: PanelPosition };\n\n/** What the components need of a chart to keep its indicators in step. */\nexport interface IndicatorHost {\n addIndicator(...args: [string, Record<string, number | string | boolean>?, PanelPosition?]): string | null;\n removeIndicator(instanceId: string): void;\n}\n\n/** One spec as text: the same indicator with the same inputs (in any order) and place reads the same. */\nfunction specKey(spec: IndicatorSpec): string {\n const { id, params = {}, position = null } = typeof spec === 'string' ? { id: spec } : spec;\n return JSON.stringify([id, Object.keys(params).sort().map((k) => [k, params[k]]), position]);\n}\n\n/**\n * Brings the chart's indicators to `specs`: those no longer asked for go,\n * new ones come, and one whose inputs or place changed is put back with\n * them. `current` maps each spec (and its count, for two alike) to its\n * instance on the chart, and is kept up to date.\n */\nexport function syncIndicators(chart: IndicatorHost, specs: readonly IndicatorSpec[], current: Map<string, string>): void {\n const seen = new Map<string, number>();\n const wanted = specs.map((spec) => {\n const key = specKey(spec);\n const n = seen.get(key) ?? 0;\n seen.set(key, n + 1);\n return { spec, key: `${key}#${n}` };\n });\n const keys = new Set(wanted.map((w) => w.key));\n for (const [key, instanceId] of [...current]) {\n if (keys.has(key)) continue;\n chart.removeIndicator(instanceId);\n current.delete(key);\n }\n for (const { spec, key } of wanted) {\n if (current.has(key)) continue;\n const instanceId = typeof spec === 'string'\n ? chart.addIndicator(spec)\n : spec.position !== undefined\n ? chart.addIndicator(spec.id, spec.params ?? {}, spec.position)\n : chart.addIndicator(spec.id, spec.params ?? {});\n if (instanceId) current.set(key, instanceId);\n }\n}\n","import type { DataSeries, ViewportState } from '@tradecanvas/commons';\nimport {\n barIndexToTime,\n barIndexToX,\n priceToYMapper,\n timestampToBarIndex,\n xToBarIndex,\n yToPrice,\n} from '@tradecanvas/core';\n\n/**\n * Where things go on screen in one frame, as the chart itself places them:\n * bars by time or index, prices on a log or upside-down scale too. For an\n * overlay plugin's `render`, built from the context it is handed.\n *\n * Bars are those of `context.data`, the series on screen: on a Renko, Kagi,\n * point & figure, line break or range-bar chart they are its bricks or\n * columns, not the feed's bars (`chart.isTimeAligned()` says which). Times\n * between bars and past either end are placed in proportion once there are\n * two bars; with fewer, a time lands on the nearest bar.\n */\nexport interface FrameScale {\n /** x of the middle of the bar at `time` (the data's own unit); between bars and past either end in proportion. */\n timeToX(time: number): number;\n /** The bar time at `x`, extrapolated past either end of the data. */\n xToTime(x: number): number;\n /** x of the middle of bar `index` of the data. */\n indexToX(index: number): number;\n /** The bar index at `x`, rounded to the nearest bar. */\n xToIndex(x: number): number;\n priceToY(price: number): number;\n yToPrice(y: number): number;\n /** A bar's body width in pixels at this zoom. */\n readonly barWidth: number;\n /** The first and last bar indexes on screen, within the data; `to < from` when there is none. */\n readonly visible: { readonly from: number; readonly to: number };\n}\n\n/**\n * The scale of an overlay plugin's frame:\n *\n * ```ts\n * render(ctx, context) {\n * const s = overlayScale(context);\n * for (let i = s.visible.from; i <= s.visible.to; i++) {\n * ctx.fillRect(s.indexToX(i) - s.barWidth / 2, s.priceToY(context.data[i].high), s.barWidth, 2);\n * }\n * }\n * ```\n */\nexport function overlayScale(context: { viewport: ViewportState; data: DataSeries }): FrameScale {\n const { viewport, data } = context;\n const toY = priceToYMapper(viewport);\n const last = data.length - 1;\n const from = Math.max(0, Math.floor(viewport.visibleRange.from));\n const to = Math.min(last, Math.ceil(viewport.visibleRange.to));\n const indexOf = (time: number) => (data.length > 0 ? timestampToBarIndex(time, data) : time);\n return {\n timeToX: (time) => barIndexToX(indexOf(time), viewport),\n xToTime: (x) => {\n const index = xToBarIndex(x, viewport);\n return data.length > 0 ? barIndexToTime(index, data) : index;\n },\n indexToX: (index) => barIndexToX(index, viewport),\n xToIndex: (x) => xToBarIndex(x, viewport),\n priceToY: toY,\n yToPrice: (y) => yToPrice(y, viewport),\n barWidth: viewport.barWidth,\n visible: to < from ? { from: 0, to: -1 } : { from, to },\n };\n}\n","import type { ChartOptions, Theme, TimeFrame, DataSeries, DataAdapter, StreamConfig } from '@tradecanvas/commons';\nimport { Chart } from '../Chart.js';\n\nexport type GridLayout = '1x1' | '1x2' | '2x1' | '2x2' | '1x3' | '3x1' | '2x3' | '3x2';\n\nexport interface GridCellConfig {\n symbol?: string;\n timeframe?: TimeFrame;\n chartOptions?: Partial<ChartOptions>;\n}\n\nexport interface ChartGridOptions {\n layout?: GridLayout;\n theme?: ChartOptions['theme'];\n syncCrosshair?: boolean;\n syncTimeAxis?: boolean;\n gap?: number;\n cells?: GridCellConfig[];\n chartOptions?: Partial<ChartOptions>;\n}\n\ninterface GridCell {\n container: HTMLDivElement;\n chart: Chart;\n symbol: string;\n timeframe: TimeFrame;\n}\n\nconst LAYOUT_MAP: Record<GridLayout, { cols: number; rows: number }> = {\n '1x1': { cols: 1, rows: 1 },\n '1x2': { cols: 2, rows: 1 },\n '2x1': { cols: 1, rows: 2 },\n '2x2': { cols: 2, rows: 2 },\n '1x3': { cols: 3, rows: 1 },\n '3x1': { cols: 1, rows: 3 },\n '2x3': { cols: 3, rows: 2 },\n '3x2': { cols: 2, rows: 3 },\n};\n\nexport class ChartGrid {\n private root: HTMLDivElement;\n private cells: GridCell[] = [];\n private layout: GridLayout;\n private options: ChartGridOptions;\n private destroyed = false;\n private syncing = false;\n\n constructor(container: HTMLElement, options: ChartGridOptions = {}) {\n this.options = options;\n this.layout = options.layout ?? '2x2';\n\n this.root = document.createElement('div');\n this.root.style.cssText = 'display:grid;width:100%;height:100%;overflow:hidden;';\n container.appendChild(this.root);\n\n this.applyLayout();\n this.createCells();\n }\n\n private applyLayout(): void {\n const { cols, rows } = LAYOUT_MAP[this.layout];\n const gap = this.options.gap ?? 1;\n this.root.style.gridTemplateColumns = `repeat(${cols}, 1fr)`;\n this.root.style.gridTemplateRows = `repeat(${rows}, 1fr)`;\n this.root.style.gap = `${gap}px`;\n }\n\n private createCells(): void {\n const { cols, rows } = LAYOUT_MAP[this.layout];\n const count = cols * rows;\n for (let i = 0; i < count; i++) this.cells.push(this.createCell(i));\n }\n\n private createCell(i: number): GridCell {\n const cellConfig = this.options.cells?.[i] ?? {};\n\n const cellEl = document.createElement('div');\n cellEl.style.cssText = 'position:relative;overflow:hidden;min-width:0;min-height:0;';\n this.root.appendChild(cellEl);\n\n const chartOpts: ChartOptions = {\n chartType: 'candlestick',\n autoScale: true,\n features: {\n crosshair: true,\n keyboard: true,\n volume: true,\n legend: true,\n priceAxis: true,\n timeAxis: true,\n grid: true,\n },\n ...this.options.chartOptions,\n ...cellConfig.chartOptions,\n theme: this.options.theme,\n };\n\n const chart = new Chart(cellEl, chartOpts);\n\n const cell: GridCell = {\n container: cellEl,\n chart,\n symbol: cellConfig.symbol ?? `Chart ${i + 1}`,\n timeframe: cellConfig.timeframe ?? '5m',\n };\n\n // Charts can differ in symbol and timeframe, so the crosshair is linked by\n // time: the others show a vertical line on the bar containing that time.\n if (this.options.syncCrosshair !== false) {\n chart.on('crosshairMove', (e) => {\n const time = e.payload.bar?.time;\n if (time === undefined) return;\n for (const other of this.cells) {\n if (other.chart !== chart) other.chart.setCrosshairTime(time);\n }\n });\n chart.on('crosshairLeave', () => {\n for (const other of this.cells) {\n if (other.chart !== chart) other.chart.setCrosshairTime(null);\n }\n });\n }\n\n if (this.options.syncTimeAxis !== false) {\n chart.on('visibleRangeChange', (e) => {\n if (this.syncing) return;\n this.syncing = true;\n const { from, to } = e.payload;\n const srcData = chart.getData();\n if (srcData.length > 0 && from >= 0 && to < srcData.length) {\n const fromTime = srcData[from]?.time;\n const toTime = srcData[to]?.time;\n if (fromTime && toTime) {\n for (const other of this.cells) {\n if (other.chart !== chart) {\n other.chart.setVisibleRange(fromTime, toTime);\n }\n }\n }\n }\n this.syncing = false;\n });\n }\n\n return cell;\n }\n\n setLayout(layout: GridLayout): void {\n if (layout === this.layout) return;\n const oldCount = this.cells.length;\n const { cols, rows } = LAYOUT_MAP[layout];\n const newCount = cols * rows;\n\n if (newCount < oldCount) {\n for (let i = oldCount - 1; i >= newCount; i--) {\n const cell = this.cells[i];\n cell.chart.destroy();\n cell.container.remove();\n this.cells.pop();\n }\n }\n\n this.layout = layout;\n this.applyLayout();\n\n // New cells get the same options and linking as the first ones.\n for (let i = oldCount; i < newCount; i++) this.cells.push(this.createCell(i));\n }\n\n getChart(index: number): Chart | null {\n return this.cells[index]?.chart ?? null;\n }\n\n getCharts(): Chart[] {\n return this.cells.map(c => c.chart);\n }\n\n getCellCount(): number {\n return this.cells.length;\n }\n\n setData(index: number, data: DataSeries): void {\n this.cells[index]?.chart.setData(data);\n }\n\n setAllData(data: DataSeries): void {\n for (const cell of this.cells) {\n cell.chart.setData(data);\n }\n }\n\n async connectCell(index: number, config: StreamConfig): Promise<void> {\n const cell = this.cells[index];\n if (!cell) return;\n cell.symbol = config.symbol;\n cell.timeframe = config.timeframe;\n await cell.chart.connect(config);\n }\n\n /**\n * Connect each chart to a symbol. An adapter keeps one stream, so pass a\n * function that makes one per chart (`() => new BinanceAdapter()`); a single\n * adapter object serves one chart only.\n */\n async connectAll(\n adapter: DataAdapter | ((symbol: string, index: number) => DataAdapter),\n symbols: string[],\n timeframe: TimeFrame,\n historyLimit = 500,\n ): Promise<void> {\n const promises: Promise<void>[] = [];\n for (let i = 0; i < this.cells.length && i < symbols.length; i++) {\n promises.push(this.connectCell(i, {\n adapter: typeof adapter === 'function' ? adapter(symbols[i], i) : adapter,\n symbol: symbols[i],\n timeframe,\n historyLimit,\n }));\n }\n await Promise.all(promises);\n }\n\n setTheme(theme: Theme): void {\n for (const cell of this.cells) {\n cell.chart.setTheme(theme);\n }\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n for (const cell of this.cells) {\n cell.chart.destroy();\n cell.container.remove();\n }\n this.cells = [];\n this.root.remove();\n }\n}\n","import type { SparklineOptions, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, renderSparkline } from '@tradecanvas/core';\n\nexport class SparklineChart extends BaseFinanceChart {\n private options: SparklineOptions;\n\n constructor(container: HTMLElement, options: SparklineOptions) {\n super(container, options.theme);\n this.options = options;\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n renderSparkline(ctx, width, height, this.options, theme);\n }\n\n update(data: number[]): void {\n this.options = { ...this.options, data };\n this.requestRender();\n }\n\n setOptions(opts: Partial<SparklineOptions>): void {\n this.options = { ...this.options, ...opts };\n this.requestRender();\n }\n}\n","import type { DepthChartOptions, DepthData, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, FinanceCrosshair, renderDepthChart } from '@tradecanvas/core';\n\nexport class DepthChart extends BaseFinanceChart {\n private options: DepthChartOptions;\n private crosshair: FinanceCrosshair | null = null;\n\n constructor(container: HTMLElement, options: DepthChartOptions) {\n super(container, options.theme);\n this.options = options;\n\n if (options.crosshair !== false) {\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n }\n\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n const pos = this.crosshair?.getPosition() ?? null;\n renderDepthChart(ctx, width, height, this.options, theme, pos);\n }\n\n update(data: DepthData): void {\n this.options = { ...this.options, data };\n this.requestRender();\n }\n\n setOptions(opts: Partial<DepthChartOptions>): void {\n this.options = { ...this.options, ...opts };\n this.requestRender();\n }\n\n destroy(): void {\n this.crosshair?.destroy();\n super.destroy();\n }\n}\n","import type { EquityCurveOptions, EquityPoint, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, FinanceCrosshair, renderEquityCurve } from '@tradecanvas/core';\n\nexport class EquityCurveChart extends BaseFinanceChart {\n private options: EquityCurveOptions;\n private crosshair: FinanceCrosshair | null = null;\n\n constructor(container: HTMLElement, options: EquityCurveOptions) {\n super(container, options.theme);\n this.options = options;\n\n if (options.crosshair !== false) {\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n }\n\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n const pos = this.crosshair?.getPosition() ?? null;\n renderEquityCurve(ctx, width, height, this.options, theme, pos);\n }\n\n update(data: EquityPoint[], benchmark?: EquityPoint[]): void {\n this.options = { ...this.options, data };\n if (benchmark !== undefined) {\n this.options = { ...this.options, benchmark };\n }\n this.requestRender();\n }\n\n setOptions(opts: Partial<EquityCurveOptions>): void {\n this.options = { ...this.options, ...opts };\n this.requestRender();\n }\n\n destroy(): void {\n this.crosshair?.destroy();\n super.destroy();\n }\n}\n","import type { HeatmapCell, HeatmapOptions, Theme } from '@tradecanvas/commons';\nimport {\n BaseFinanceChart,\n FinanceCrosshair,\n layoutUniformGrid,\n layoutSquarifiedTreemap,\n renderHeatmap,\n} from '@tradecanvas/core';\nimport type { LayoutRect } from '@tradecanvas/core';\n\nexport class HeatmapChart extends BaseFinanceChart {\n private options: HeatmapOptions;\n private crosshair: FinanceCrosshair | null = null;\n private cachedRects: LayoutRect[] = [];\n private currentData: HeatmapCell[] = [];\n private lastLayoutWidth = 0;\n private lastLayoutHeight = 0;\n private handleClick: ((e: MouseEvent) => void) | null = null;\n\n constructor(container: HTMLElement, options: HeatmapOptions) {\n super(container, options.theme);\n this.options = options;\n this.currentData = options.data ?? [];\n\n if (options.crosshair !== false) {\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n }\n\n if (options.onCellClick) {\n this.handleClick = (e: MouseEvent) => {\n const rect = this.canvas.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n this.onCanvasClick(x, y);\n };\n this.canvas.addEventListener('click', this.handleClick);\n }\n\n this.recomputeLayout();\n this.requestRender();\n }\n\n private recomputeLayout(): void {\n const bounds = { x: 0, y: 0, width: this.width, height: this.height };\n const padding = this.options.cellPadding ?? 2;\n this.lastLayoutWidth = this.width;\n this.lastLayoutHeight = this.height;\n\n if (this.options.weighted) {\n const weighted = this.currentData.map(c => ({\n id: c.id,\n weight: c.weight ?? (Math.abs(c.value) || 1),\n }));\n this.cachedRects = layoutSquarifiedTreemap(weighted, bounds, padding);\n } else {\n this.cachedRects = layoutUniformGrid(\n this.currentData.map(c => ({ id: c.id })),\n bounds,\n padding,\n );\n }\n }\n\n private onCanvasClick(x: number, y: number): void {\n if (!this.options.onCellClick) return;\n\n for (const lr of this.cachedRects) {\n const r = lr.rect;\n if (x >= r.x && x <= r.x + r.width && y >= r.y && y <= r.y + r.height) {\n const cell = this.currentData.find(c => c.id === lr.id);\n if (cell) this.options.onCellClick(cell);\n return;\n }\n }\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n if (width !== this.lastLayoutWidth || height !== this.lastLayoutHeight) {\n this.recomputeLayout();\n }\n\n const pos = this.crosshair?.getPosition() ?? null;\n renderHeatmap(ctx, width, height, this.currentData, this.cachedRects, this.options, theme, pos);\n }\n\n update(data: HeatmapCell[]): void {\n this.currentData = data;\n this.options = { ...this.options, data };\n this.recomputeLayout();\n this.requestRender();\n }\n\n setOptions(opts: Partial<HeatmapOptions>): void {\n this.options = { ...this.options, ...opts };\n if (opts.data) {\n this.currentData = opts.data;\n }\n this.recomputeLayout();\n this.requestRender();\n }\n\n destroy(): void {\n this.crosshair?.destroy();\n if (this.handleClick) {\n this.canvas.removeEventListener('click', this.handleClick);\n }\n super.destroy();\n }\n}\n","import type { Theme, WaterfallBar, WaterfallOptions } from '@tradecanvas/commons';\nimport { BaseFinanceChart, FinanceCrosshair, renderWaterfall } from '@tradecanvas/core';\n\nexport class WaterfallChart extends BaseFinanceChart {\n private options: WaterfallOptions;\n private crosshair: FinanceCrosshair | null = null;\n\n constructor(container: HTMLElement, options: WaterfallOptions) {\n super(container, options.theme);\n this.options = options;\n\n if (options.crosshair !== false) {\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n }\n\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n const pos = this.crosshair?.getPosition() ?? null;\n renderWaterfall(ctx, width, height, this.options, theme, pos);\n }\n\n update(data: WaterfallBar[]): void {\n this.options = { ...this.options, data };\n this.requestRender();\n }\n\n setOptions(opts: Partial<WaterfallOptions>): void {\n this.options = { ...this.options, ...opts };\n this.requestRender();\n }\n\n destroy(): void {\n this.crosshair?.destroy();\n super.destroy();\n }\n}\n","import type { GaugeOptions, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, renderGauge } from '@tradecanvas/core';\n\nconst DEFAULT_ANIMATION_MS = 500;\n\nfunction easeOutCubic(t: number): number {\n const inv = 1 - t;\n return 1 - inv * inv * inv;\n}\n\nexport class GaugeChart extends BaseFinanceChart {\n private options: GaugeOptions;\n private currentValue: number;\n private targetValue: number;\n private animationStart: number | null = null;\n private animationFrom = 0;\n private animationFrameId: number | null = null;\n\n constructor(container: HTMLElement, options: GaugeOptions) {\n super(container, options.theme);\n this.options = options;\n this.currentValue = options.value;\n this.targetValue = options.value;\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n renderGauge(ctx, width, height, this.options, theme, this.currentValue);\n }\n\n setValue(value: number): void {\n const animate = this.options.animate !== false;\n if (!animate) {\n this.cancelAnimation();\n this.currentValue = value;\n this.targetValue = value;\n this.options = { ...this.options, value };\n this.requestRender();\n return;\n }\n\n this.targetValue = value;\n this.animationFrom = this.currentValue;\n this.animationStart = performance.now();\n this.options = { ...this.options, value };\n this.startAnimationLoop();\n }\n\n setOptions(opts: Partial<GaugeOptions>): void {\n const next = { ...this.options, ...opts };\n // If `value` is part of the partial, route through animation path\n if (opts.value !== undefined && opts.value !== this.targetValue) {\n this.options = next;\n this.setValue(opts.value);\n return;\n }\n this.options = next;\n this.requestRender();\n }\n\n private startAnimationLoop(): void {\n if (this.animationFrameId !== null) return;\n const step = (): void => {\n this.animationFrameId = null;\n if (this.animationStart === null) return;\n\n const duration = this.options.animationDuration ?? DEFAULT_ANIMATION_MS;\n const elapsed = performance.now() - this.animationStart;\n const t = Math.min(1, elapsed / Math.max(1, duration));\n const eased = easeOutCubic(t);\n this.currentValue = this.animationFrom + (this.targetValue - this.animationFrom) * eased;\n\n this.requestRender();\n\n if (t < 1) {\n this.animationFrameId = requestAnimationFrame(step);\n } else {\n this.currentValue = this.targetValue;\n this.animationStart = null;\n }\n };\n this.animationFrameId = requestAnimationFrame(step);\n }\n\n private cancelAnimation(): void {\n if (this.animationFrameId !== null) {\n cancelAnimationFrame(this.animationFrameId);\n this.animationFrameId = null;\n }\n this.animationStart = null;\n }\n\n destroy(): void {\n this.cancelAnimation();\n super.destroy();\n }\n}\n","import type { EquityPoint, HeatmapCell } from '@tradecanvas/commons';\nimport { timeframeBucketStart } from '@tradecanvas/commons';\n\n/** Minimal equity sample shape — structurally satisfied by analytics' EquityPoint. */\nexport interface EquitySample {\n time: number;\n equity: number;\n}\n\n/** Subset of analytics RiskMetrics needed to render the stats strip. */\nexport interface RiskMetricsLike {\n totalReturnPct: number;\n cagr: number;\n sharpe: number;\n sortino: number;\n maxDrawdownPct: number;\n winRate: number;\n profitFactor: number;\n trades: number;\n}\n\nexport interface DashboardStat {\n label: string;\n value: string;\n tone: 'positive' | 'negative' | 'neutral';\n}\n\nconst MONTH_LABELS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n\n/** Map an analytics equity curve to the finance EquityCurveChart point shape. */\nexport function toEquityPoints(curve: ReadonlyArray<EquitySample>): EquityPoint[] {\n return curve.map((p) => ({ time: p.time, value: p.equity }));\n}\n\n/**\n * Underwater drawdown curve as a percentage (<= 0). Each point is the equity's\n * shortfall from the running peak: `equity / peak - 1`, expressed in percent.\n */\nexport function computeDrawdownCurve(curve: ReadonlyArray<EquitySample>): EquityPoint[] {\n let peak = -Infinity;\n return curve.map((p) => {\n if (p.equity > peak) peak = p.equity;\n const dd = peak > 0 ? (p.equity / peak - 1) * 100 : 0;\n return { time: p.time, value: dd };\n });\n}\n\n/**\n * Calendar-month returns as heatmap cells. Each month's return is chained off\n * the prior month's closing equity (the first month chains off its own opening\n * equity), so the series reads as sequential monthly performance. `group` is\n * the year and `value` is the return in percent.\n */\nexport function computeMonthlyReturns(curve: ReadonlyArray<EquitySample>): HeatmapCell[] {\n if (curve.length === 0) return [];\n\n // Collapse the curve to one closing equity per calendar month, in order.\n const months: { key: number; close: number }[] = [];\n for (const p of curve) {\n const key = timeframeBucketStart(p.time, '1M');\n const last = months[months.length - 1];\n if (last && last.key === key) {\n last.close = p.equity;\n } else {\n months.push({ key, close: p.equity });\n }\n }\n\n let prevClose = curve[0].equity;\n const cells: HeatmapCell[] = [];\n for (const m of months) {\n const base = prevClose === 0 ? 1 : prevClose;\n const returnPct = (m.close / base - 1) * 100;\n prevClose = m.close;\n const d = new Date(m.key);\n const year = d.getUTCFullYear();\n const month = d.getUTCMonth();\n cells.push({\n id: `${year}-${String(month + 1).padStart(2, '0')}`,\n label: MONTH_LABELS[month],\n group: String(year),\n value: returnPct,\n });\n }\n return cells;\n}\n\nfunction pct(value: number): string {\n const sign = value > 0 ? '+' : '';\n return `${sign}${value.toFixed(2)}%`;\n}\n\nfunction tone(value: number): DashboardStat['tone'] {\n if (value > 0) return 'positive';\n if (value < 0) return 'negative';\n return 'neutral';\n}\n\n/** The headline stats rendered as cards above the charts. */\nexport function selectKeyStats(metrics: RiskMetricsLike): DashboardStat[] {\n return [\n { label: 'Total Return', value: pct(metrics.totalReturnPct), tone: tone(metrics.totalReturnPct) },\n { label: 'CAGR', value: pct(metrics.cagr * 100), tone: tone(metrics.cagr) },\n { label: 'Sharpe', value: metrics.sharpe.toFixed(2), tone: tone(metrics.sharpe) },\n { label: 'Sortino', value: metrics.sortino.toFixed(2), tone: tone(metrics.sortino) },\n { label: 'Max Drawdown', value: pct(metrics.maxDrawdownPct), tone: 'negative' },\n { label: 'Win Rate', value: `${(metrics.winRate * 100).toFixed(1)}%`, tone: 'neutral' },\n { label: 'Profit Factor', value: Number.isFinite(metrics.profitFactor) ? metrics.profitFactor.toFixed(2) : '∞', tone: tone(metrics.profitFactor - 1) },\n { label: 'Trades', value: String(metrics.trades), tone: 'neutral' },\n ];\n}\n","import type { Theme, ThemeName } from '@tradecanvas/commons';\nimport { DARK_THEME, LIGHT_THEME } from '@tradecanvas/commons';\nimport { EquityCurveChart } from './EquityCurveChart.js';\nimport { HeatmapChart } from './HeatmapChart.js';\nimport {\n toEquityPoints,\n computeDrawdownCurve,\n computeMonthlyReturns,\n selectKeyStats,\n type EquitySample,\n type RiskMetricsLike,\n type DashboardStat,\n} from './performanceData.js';\n\n/** Structurally satisfied by analytics' `BacktestResult`. */\nexport interface PerformanceResult {\n equityCurve: ReadonlyArray<EquitySample>;\n metrics: RiskMetricsLike;\n}\n\nexport interface PerformanceDashboardOptions {\n result: PerformanceResult;\n theme?: ThemeName | Theme;\n title?: string;\n subtitle?: string;\n}\n\nfunction resolveTheme(theme?: ThemeName | Theme): Theme {\n if (!theme || theme === 'dark') return DARK_THEME;\n if (theme === 'light') return LIGHT_THEME;\n return theme as Theme;\n}\n\n/**\n * A composed strategy-performance dashboard: a headline stats strip, an equity\n * curve, an underwater drawdown panel, and a monthly-returns heatmap. Built\n * entirely from a backtest `result`, reusing the finance chart renderers.\n *\n * ```ts\n * const result = new Backtester(opts).run(bars, strategy);\n * const dash = new PerformanceDashboard(el, { result, theme: 'dark' });\n * ```\n */\nexport class PerformanceDashboard {\n private options: PerformanceDashboardOptions;\n private theme: Theme;\n private root: HTMLDivElement;\n private equityChart: EquityCurveChart | null = null;\n private drawdownChart: EquityCurveChart | null = null;\n private heatmap: HeatmapChart | null = null;\n\n constructor(container: HTMLElement, options: PerformanceDashboardOptions) {\n this.options = options;\n this.theme = resolveTheme(options.theme);\n this.root = document.createElement('div');\n this.build();\n container.appendChild(this.root);\n }\n\n private build(): void {\n const t = this.theme;\n const { result, title, subtitle } = this.options;\n const surface = this.panelBackground();\n const border = t.grid;\n\n this.root.style.cssText = [\n 'display:flex',\n 'flex-direction:column',\n 'gap:14px',\n 'width:100%',\n 'box-sizing:border-box',\n 'padding:16px',\n `background:${t.background}`,\n `color:${t.text}`,\n `font-family:${t.font.family}`,\n ].join(';');\n\n if (title || subtitle) {\n const header = document.createElement('div');\n if (title) {\n const h = document.createElement('div');\n h.textContent = title;\n h.style.cssText = `font-size:${t.font.sizeLarge}px;font-weight:600;letter-spacing:-0.01em;`;\n header.appendChild(h);\n }\n if (subtitle) {\n const s = document.createElement('div');\n s.textContent = subtitle;\n s.style.cssText = `font-size:${t.font.sizeSmall}px;color:${t.textSecondary};margin-top:2px;`;\n header.appendChild(s);\n }\n this.root.appendChild(header);\n }\n\n // Stats strip\n this.root.appendChild(this.buildStatsStrip(selectKeyStats(result.metrics), surface, border));\n\n // Chart grid\n const grid = document.createElement('div');\n grid.style.cssText = [\n 'display:grid',\n 'grid-template-columns:repeat(auto-fit, minmax(280px, 1fr))',\n 'grid-auto-rows:220px',\n 'gap:14px',\n ].join(';');\n this.root.appendChild(grid);\n\n const equityPanel = this.buildPanel('Equity Curve', surface, border);\n equityPanel.wrap.style.gridColumn = '1 / -1';\n grid.appendChild(equityPanel.wrap);\n this.equityChart = new EquityCurveChart(equityPanel.body, {\n data: toEquityPoints(result.equityCurve),\n theme: t,\n lineColor: t.candleUp,\n fillArea: true,\n crosshair: true,\n });\n\n const ddPanel = this.buildPanel('Drawdown', surface, border);\n grid.appendChild(ddPanel.wrap);\n this.drawdownChart = new EquityCurveChart(ddPanel.body, {\n data: computeDrawdownCurve(result.equityCurve),\n theme: t,\n lineColor: t.candleDown,\n fillArea: true,\n crosshair: true,\n valueFormat: (v) => `${v.toFixed(1)}%`,\n });\n\n const monthlyCells = computeMonthlyReturns(result.equityCurve);\n const heatPanel = this.buildPanel('Monthly Returns', surface, border);\n grid.appendChild(heatPanel.wrap);\n this.heatmap = new HeatmapChart(heatPanel.body, {\n data: monthlyCells,\n theme: t,\n showValues: true,\n valueFormat: (v) => `${v >= 0 ? '+' : ''}${v.toFixed(1)}`,\n colorScale: { negative: t.candleDown, zero: surface, positive: t.candleUp },\n });\n }\n\n private buildStatsStrip(stats: DashboardStat[], surface: string, border: string): HTMLDivElement {\n const strip = document.createElement('div');\n strip.style.cssText = [\n 'display:grid',\n 'grid-template-columns:repeat(auto-fit, minmax(120px, 1fr))',\n 'gap:10px',\n ].join(';');\n\n const t = this.theme;\n for (const stat of stats) {\n const card = document.createElement('div');\n card.style.cssText = [\n `background:${surface}`,\n `border:1px solid ${border}`,\n 'border-radius:10px',\n 'padding:10px 12px',\n 'display:flex',\n 'flex-direction:column',\n 'gap:4px',\n ].join(';');\n\n const label = document.createElement('div');\n label.textContent = stat.label;\n label.style.cssText = `font-size:${t.font.sizeSmall}px;color:${t.textSecondary};text-transform:uppercase;letter-spacing:0.04em;`;\n\n const value = document.createElement('div');\n value.textContent = stat.value;\n const color = stat.tone === 'positive' ? t.candleUp : stat.tone === 'negative' ? t.candleDown : t.text;\n value.style.cssText = `font-size:${t.font.sizeLarge}px;font-weight:600;color:${color};font-variant-numeric:tabular-nums;`;\n\n card.appendChild(label);\n card.appendChild(value);\n strip.appendChild(card);\n }\n return strip;\n }\n\n private buildPanel(title: string, surface: string, border: string): { wrap: HTMLDivElement; body: HTMLDivElement } {\n const t = this.theme;\n const wrap = document.createElement('div');\n wrap.style.cssText = [\n `background:${surface}`,\n `border:1px solid ${border}`,\n 'border-radius:10px',\n 'overflow:hidden',\n 'display:flex',\n 'flex-direction:column',\n ].join(';');\n\n const head = document.createElement('div');\n head.textContent = title;\n head.style.cssText = [\n `font-size:${t.font.sizeSmall}px`,\n 'font-weight:600',\n `color:${t.textSecondary}`,\n 'padding:8px 12px',\n `border-bottom:1px solid ${border}`,\n 'text-transform:uppercase',\n 'letter-spacing:0.04em',\n ].join(';');\n\n const body = document.createElement('div');\n body.style.cssText = 'flex:1;min-height:0;position:relative;';\n\n wrap.appendChild(head);\n wrap.appendChild(body);\n return { wrap, body };\n }\n\n /** A subtle surface tint distinct from the page background, per theme. */\n private panelBackground(): string {\n return this.theme.name === 'light' ? 'rgba(0,0,0,0.02)' : 'rgba(255,255,255,0.03)';\n }\n\n /** Replace the displayed result and re-render all panels. */\n update(result: PerformanceResult): void {\n this.options = { ...this.options, result };\n this.destroyCharts();\n this.root.replaceChildren();\n this.build();\n }\n\n setTheme(theme: ThemeName | Theme): void {\n this.theme = resolveTheme(theme);\n this.options = { ...this.options, theme };\n this.destroyCharts();\n this.root.replaceChildren();\n this.build();\n }\n\n private destroyCharts(): void {\n this.equityChart?.destroy();\n this.drawdownChart?.destroy();\n this.heatmap?.destroy();\n this.equityChart = null;\n this.drawdownChart = null;\n this.heatmap = null;\n }\n\n destroy(): void {\n this.destroyCharts();\n this.root.remove();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/frameworks/syncIndicators.ts","../src/plugins/overlayScale.ts","../src/grid/ChartGrid.ts","../src/finance/SparklineChart.ts","../src/finance/DepthChart.ts","../src/finance/EquityCurveChart.ts","../src/finance/HeatmapChart.ts","../src/finance/WaterfallChart.ts","../src/finance/GaugeChart.ts","../src/finance/performanceData.ts","../src/finance/PerformanceDashboard.ts"],"sourcesContent":["import type { PanelPosition } from '@tradecanvas/commons';\n\n/**\n * An indicator a framework component shows: its id (`'rsi'`), or its id with\n * its inputs and, for one in a pane, where the pane goes.\n */\nexport type IndicatorSpec =\n | string\n | { id: string; params?: Record<string, number | string | boolean>; position?: PanelPosition };\n\n/** What the components need of a chart to keep its indicators in step. */\nexport interface IndicatorHost {\n addIndicator(...args: [string, Record<string, number | string | boolean>?, PanelPosition?]): string | null;\n removeIndicator(instanceId: string): void;\n}\n\n/** One spec as text: the same indicator with the same inputs (in any order) and place reads the same. */\nfunction specKey(spec: IndicatorSpec): string {\n const { id, params = {}, position = null } = typeof spec === 'string' ? { id: spec } : spec;\n return JSON.stringify([id, Object.keys(params).sort().map((k) => [k, params[k]]), position]);\n}\n\n/**\n * Brings the chart's indicators to `specs`: those no longer asked for go,\n * new ones come, and one whose inputs or place changed is put back with\n * them. `current` maps each spec (and its count, for two alike) to its\n * instance on the chart, and is kept up to date.\n */\nexport function syncIndicators(chart: IndicatorHost, specs: readonly IndicatorSpec[], current: Map<string, string>): void {\n const seen = new Map<string, number>();\n const wanted = specs.map((spec) => {\n const key = specKey(spec);\n const n = seen.get(key) ?? 0;\n seen.set(key, n + 1);\n return { spec, key: `${key}#${n}` };\n });\n const keys = new Set(wanted.map((w) => w.key));\n for (const [key, instanceId] of [...current]) {\n if (keys.has(key)) continue;\n chart.removeIndicator(instanceId);\n current.delete(key);\n }\n for (const { spec, key } of wanted) {\n if (current.has(key)) continue;\n const instanceId = typeof spec === 'string'\n ? chart.addIndicator(spec)\n : spec.position !== undefined\n ? chart.addIndicator(spec.id, spec.params ?? {}, spec.position)\n : chart.addIndicator(spec.id, spec.params ?? {});\n if (instanceId) current.set(key, instanceId);\n }\n}\n","import type { DataSeries, ViewportState } from '@tradecanvas/commons';\nimport {\n barIndexToTime,\n barIndexToX,\n priceToYMapper,\n timestampToBarIndex,\n xToBarIndex,\n yToPrice,\n} from '@tradecanvas/core';\n\n/**\n * Where things go on screen in one frame, as the chart itself places them:\n * bars by time or index, prices on a log or upside-down scale too. For an\n * overlay plugin's `render`, built from the context it is handed.\n *\n * Bars are those of `context.data`, the series on screen: on a Renko, Kagi,\n * point & figure, line break or range-bar chart they are its bricks or\n * columns, not the feed's bars (`chart.isTimeAligned()` says which). Times\n * between bars and past either end are placed in proportion once there are\n * two bars; with fewer, a time lands on the nearest bar.\n */\nexport interface FrameScale {\n /** x of the middle of the bar at `time` (the data's own unit); between bars and past either end in proportion. */\n timeToX(time: number): number;\n /** The bar time at `x`, extrapolated past either end of the data. */\n xToTime(x: number): number;\n /** x of the middle of bar `index` of the data. */\n indexToX(index: number): number;\n /** The bar index at `x`, rounded to the nearest bar. */\n xToIndex(x: number): number;\n priceToY(price: number): number;\n yToPrice(y: number): number;\n /** A bar's body width in pixels at this zoom. */\n readonly barWidth: number;\n /** The first and last bar indexes on screen, within the data; `to < from` when there is none. */\n readonly visible: { readonly from: number; readonly to: number };\n}\n\n/**\n * The scale of an overlay plugin's frame:\n *\n * ```ts\n * render(ctx, context) {\n * const s = overlayScale(context);\n * for (let i = s.visible.from; i <= s.visible.to; i++) {\n * ctx.fillRect(s.indexToX(i) - s.barWidth / 2, s.priceToY(context.data[i].high), s.barWidth, 2);\n * }\n * }\n * ```\n */\nexport function overlayScale(context: { viewport: ViewportState; data: DataSeries }): FrameScale {\n const { viewport, data } = context;\n const toY = priceToYMapper(viewport);\n const last = data.length - 1;\n const from = Math.max(0, Math.floor(viewport.visibleRange.from));\n const to = Math.min(last, Math.ceil(viewport.visibleRange.to));\n const indexOf = (time: number) => (data.length > 0 ? timestampToBarIndex(time, data) : time);\n return {\n timeToX: (time) => barIndexToX(indexOf(time), viewport),\n xToTime: (x) => {\n const index = xToBarIndex(x, viewport);\n return data.length > 0 ? barIndexToTime(index, data) : index;\n },\n indexToX: (index) => barIndexToX(index, viewport),\n xToIndex: (x) => xToBarIndex(x, viewport),\n priceToY: toY,\n yToPrice: (y) => yToPrice(y, viewport),\n barWidth: viewport.barWidth,\n visible: to < from ? { from: 0, to: -1 } : { from, to },\n };\n}\n","import type { ChartOptions, Theme, TimeFrame, DataSeries, DataAdapter, StreamConfig } from '@tradecanvas/commons';\nimport { Chart } from '../Chart.js';\n\nexport type GridLayout = '1x1' | '1x2' | '2x1' | '2x2' | '1x3' | '3x1' | '2x3' | '3x2';\n\nexport interface GridCellConfig {\n symbol?: string;\n timeframe?: TimeFrame;\n chartOptions?: Partial<ChartOptions>;\n}\n\nexport interface ChartGridOptions {\n layout?: GridLayout;\n theme?: ChartOptions['theme'];\n syncCrosshair?: boolean;\n syncTimeAxis?: boolean;\n gap?: number;\n cells?: GridCellConfig[];\n chartOptions?: Partial<ChartOptions>;\n}\n\ninterface GridCell {\n container: HTMLDivElement;\n chart: Chart;\n symbol: string;\n timeframe: TimeFrame;\n}\n\nconst LAYOUT_MAP: Record<GridLayout, { cols: number; rows: number }> = {\n '1x1': { cols: 1, rows: 1 },\n '1x2': { cols: 2, rows: 1 },\n '2x1': { cols: 1, rows: 2 },\n '2x2': { cols: 2, rows: 2 },\n '1x3': { cols: 3, rows: 1 },\n '3x1': { cols: 1, rows: 3 },\n '2x3': { cols: 3, rows: 2 },\n '3x2': { cols: 2, rows: 3 },\n};\n\nexport class ChartGrid {\n private root: HTMLDivElement;\n private cells: GridCell[] = [];\n private layout: GridLayout;\n private options: ChartGridOptions;\n private destroyed = false;\n private syncing = false;\n\n constructor(container: HTMLElement, options: ChartGridOptions = {}) {\n this.options = options;\n this.layout = options.layout ?? '2x2';\n\n this.root = document.createElement('div');\n this.root.style.cssText = 'display:grid;width:100%;height:100%;overflow:hidden;';\n container.appendChild(this.root);\n\n this.applyLayout();\n this.createCells();\n }\n\n private applyLayout(): void {\n const { cols, rows } = LAYOUT_MAP[this.layout];\n const gap = this.options.gap ?? 1;\n this.root.style.gridTemplateColumns = `repeat(${cols}, 1fr)`;\n this.root.style.gridTemplateRows = `repeat(${rows}, 1fr)`;\n this.root.style.gap = `${gap}px`;\n }\n\n private createCells(): void {\n const { cols, rows } = LAYOUT_MAP[this.layout];\n const count = cols * rows;\n for (let i = 0; i < count; i++) this.cells.push(this.createCell(i));\n }\n\n private createCell(i: number): GridCell {\n const cellConfig = this.options.cells?.[i] ?? {};\n\n const cellEl = document.createElement('div');\n cellEl.style.cssText = 'position:relative;overflow:hidden;min-width:0;min-height:0;';\n this.root.appendChild(cellEl);\n\n const chartOpts: ChartOptions = {\n chartType: 'candlestick',\n autoScale: true,\n features: {\n crosshair: true,\n keyboard: true,\n volume: true,\n legend: true,\n priceAxis: true,\n timeAxis: true,\n grid: true,\n },\n ...this.options.chartOptions,\n ...cellConfig.chartOptions,\n theme: this.options.theme,\n };\n\n const chart = new Chart(cellEl, chartOpts);\n\n const cell: GridCell = {\n container: cellEl,\n chart,\n symbol: cellConfig.symbol ?? `Chart ${i + 1}`,\n timeframe: cellConfig.timeframe ?? '5m',\n };\n\n // Charts can differ in symbol and timeframe, so the crosshair is linked by\n // time: the others show a vertical line on the bar containing that time.\n if (this.options.syncCrosshair !== false) {\n chart.on('crosshairMove', (e) => {\n const time = e.payload.bar?.time;\n if (time === undefined) return;\n for (const other of this.cells) {\n if (other.chart !== chart) other.chart.setCrosshairTime(time);\n }\n });\n chart.on('crosshairLeave', () => {\n for (const other of this.cells) {\n if (other.chart !== chart) other.chart.setCrosshairTime(null);\n }\n });\n }\n\n if (this.options.syncTimeAxis !== false) {\n chart.on('visibleRangeChange', (e) => {\n if (this.syncing) return;\n this.syncing = true;\n const { from, to } = e.payload;\n const srcData = chart.getData();\n if (srcData.length > 0 && from >= 0 && to < srcData.length) {\n const fromTime = srcData[from]?.time;\n const toTime = srcData[to]?.time;\n if (fromTime && toTime) {\n for (const other of this.cells) {\n if (other.chart !== chart) {\n other.chart.setVisibleRange(fromTime, toTime);\n }\n }\n }\n }\n this.syncing = false;\n });\n }\n\n return cell;\n }\n\n setLayout(layout: GridLayout): void {\n if (layout === this.layout) return;\n const oldCount = this.cells.length;\n const { cols, rows } = LAYOUT_MAP[layout];\n const newCount = cols * rows;\n\n if (newCount < oldCount) {\n for (let i = oldCount - 1; i >= newCount; i--) {\n const cell = this.cells[i];\n cell.chart.destroy();\n cell.container.remove();\n this.cells.pop();\n }\n }\n\n this.layout = layout;\n this.applyLayout();\n\n // New cells get the same options and linking as the first ones.\n for (let i = oldCount; i < newCount; i++) this.cells.push(this.createCell(i));\n }\n\n getChart(index: number): Chart | null {\n return this.cells[index]?.chart ?? null;\n }\n\n getCharts(): Chart[] {\n return this.cells.map(c => c.chart);\n }\n\n getCellCount(): number {\n return this.cells.length;\n }\n\n setData(index: number, data: DataSeries): void {\n this.cells[index]?.chart.setData(data);\n }\n\n setAllData(data: DataSeries): void {\n for (const cell of this.cells) {\n cell.chart.setData(data);\n }\n }\n\n async connectCell(index: number, config: StreamConfig): Promise<void> {\n const cell = this.cells[index];\n if (!cell) return;\n cell.symbol = config.symbol;\n cell.timeframe = config.timeframe;\n await cell.chart.connect(config);\n }\n\n /**\n * Connect each chart to a symbol. An adapter keeps one stream, so pass a\n * function that makes one per chart (`() => new BinanceAdapter()`); a single\n * adapter object serves one chart only.\n */\n async connectAll(\n adapter: DataAdapter | ((symbol: string, index: number) => DataAdapter),\n symbols: string[],\n timeframe: TimeFrame,\n historyLimit = 500,\n ): Promise<void> {\n const promises: Promise<void>[] = [];\n for (let i = 0; i < this.cells.length && i < symbols.length; i++) {\n promises.push(this.connectCell(i, {\n adapter: typeof adapter === 'function' ? adapter(symbols[i], i) : adapter,\n symbol: symbols[i],\n timeframe,\n historyLimit,\n }));\n }\n await Promise.all(promises);\n }\n\n setTheme(theme: Theme): void {\n for (const cell of this.cells) {\n cell.chart.setTheme(theme);\n }\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n for (const cell of this.cells) {\n cell.chart.destroy();\n cell.container.remove();\n }\n this.cells = [];\n this.root.remove();\n }\n}\n","import type { SparklineOptions, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, renderSparkline } from '@tradecanvas/core';\n\nexport class SparklineChart extends BaseFinanceChart {\n private options: SparklineOptions;\n\n constructor(container: HTMLElement, options: SparklineOptions) {\n super(container, options.theme);\n this.options = options;\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n renderSparkline(ctx, width, height, this.options, theme);\n }\n\n update(data: number[]): void {\n this.options = { ...this.options, data };\n this.requestRender();\n }\n\n setOptions(opts: Partial<SparklineOptions>): void {\n this.options = { ...this.options, ...opts };\n this.requestRender();\n }\n}\n","import type { DepthChartOptions, DepthData, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, FinanceCrosshair, renderDepthChart } from '@tradecanvas/core';\n\nexport class DepthChart extends BaseFinanceChart {\n private options: DepthChartOptions;\n private crosshair: FinanceCrosshair | null = null;\n\n constructor(container: HTMLElement, options: DepthChartOptions) {\n super(container, options.theme);\n this.options = options;\n\n if (options.crosshair !== false) {\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n }\n\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n const pos = this.crosshair?.getPosition() ?? null;\n renderDepthChart(ctx, width, height, this.options, theme, pos);\n }\n\n update(data: DepthData): void {\n this.options = { ...this.options, data };\n this.requestRender();\n }\n\n setOptions(opts: Partial<DepthChartOptions>): void {\n this.options = { ...this.options, ...opts };\n this.requestRender();\n }\n\n destroy(): void {\n this.crosshair?.destroy();\n super.destroy();\n }\n}\n","import type { EquityCurveOptions, EquityPoint, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, FinanceCrosshair, renderEquityCurve } from '@tradecanvas/core';\n\nexport class EquityCurveChart extends BaseFinanceChart {\n private options: EquityCurveOptions;\n private crosshair: FinanceCrosshair | null = null;\n\n constructor(container: HTMLElement, options: EquityCurveOptions) {\n super(container, options.theme);\n this.options = options;\n\n if (options.crosshair !== false) {\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n }\n\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n const pos = this.crosshair?.getPosition() ?? null;\n renderEquityCurve(ctx, width, height, this.options, theme, pos);\n }\n\n update(data: EquityPoint[], benchmark?: EquityPoint[]): void {\n this.options = { ...this.options, data };\n if (benchmark !== undefined) {\n this.options = { ...this.options, benchmark };\n }\n this.requestRender();\n }\n\n setOptions(opts: Partial<EquityCurveOptions>): void {\n this.options = { ...this.options, ...opts };\n this.requestRender();\n }\n\n destroy(): void {\n this.crosshair?.destroy();\n super.destroy();\n }\n}\n","import type { HeatmapCell, HeatmapOptions, Theme } from '@tradecanvas/commons';\nimport {\n BaseFinanceChart,\n FinanceCrosshair,\n layoutUniformGrid,\n layoutSquarifiedTreemap,\n renderHeatmap,\n} from '@tradecanvas/core';\nimport type { LayoutRect } from '@tradecanvas/core';\n\nexport class HeatmapChart extends BaseFinanceChart {\n private options: HeatmapOptions;\n private crosshair: FinanceCrosshair | null = null;\n private cachedRects: LayoutRect[] = [];\n private currentData: HeatmapCell[] = [];\n private lastLayoutWidth = 0;\n private lastLayoutHeight = 0;\n private handleClick: ((e: MouseEvent) => void) | null = null;\n\n constructor(container: HTMLElement, options: HeatmapOptions) {\n super(container, options.theme);\n this.options = options;\n this.currentData = options.data ?? [];\n\n if (options.crosshair !== false) {\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n }\n\n if (options.onCellClick) {\n this.handleClick = (e: MouseEvent) => {\n const rect = this.canvas.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n this.onCanvasClick(x, y);\n };\n this.canvas.addEventListener('click', this.handleClick);\n }\n\n this.recomputeLayout();\n this.requestRender();\n }\n\n private recomputeLayout(): void {\n const bounds = { x: 0, y: 0, width: this.width, height: this.height };\n const padding = this.options.cellPadding ?? 2;\n this.lastLayoutWidth = this.width;\n this.lastLayoutHeight = this.height;\n\n if (this.options.weighted) {\n const weighted = this.currentData.map(c => ({\n id: c.id,\n weight: c.weight ?? (Math.abs(c.value) || 1),\n }));\n this.cachedRects = layoutSquarifiedTreemap(weighted, bounds, padding);\n } else {\n this.cachedRects = layoutUniformGrid(\n this.currentData.map(c => ({ id: c.id })),\n bounds,\n padding,\n );\n }\n }\n\n private onCanvasClick(x: number, y: number): void {\n if (!this.options.onCellClick) return;\n\n for (const lr of this.cachedRects) {\n const r = lr.rect;\n if (x >= r.x && x <= r.x + r.width && y >= r.y && y <= r.y + r.height) {\n const cell = this.currentData.find(c => c.id === lr.id);\n if (cell) this.options.onCellClick(cell);\n return;\n }\n }\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n if (width !== this.lastLayoutWidth || height !== this.lastLayoutHeight) {\n this.recomputeLayout();\n }\n\n const pos = this.crosshair?.getPosition() ?? null;\n renderHeatmap(ctx, width, height, this.currentData, this.cachedRects, this.options, theme, pos);\n }\n\n update(data: HeatmapCell[]): void {\n this.currentData = data;\n this.options = { ...this.options, data };\n this.recomputeLayout();\n this.requestRender();\n }\n\n setOptions(opts: Partial<HeatmapOptions>): void {\n this.options = { ...this.options, ...opts };\n if (opts.data) {\n this.currentData = opts.data;\n }\n this.recomputeLayout();\n this.requestRender();\n }\n\n destroy(): void {\n this.crosshair?.destroy();\n if (this.handleClick) {\n this.canvas.removeEventListener('click', this.handleClick);\n }\n super.destroy();\n }\n}\n","import type { Theme, WaterfallBar, WaterfallOptions } from '@tradecanvas/commons';\nimport { BaseFinanceChart, FinanceCrosshair, renderWaterfall } from '@tradecanvas/core';\n\nexport class WaterfallChart extends BaseFinanceChart {\n private options: WaterfallOptions;\n private crosshair: FinanceCrosshair | null = null;\n\n constructor(container: HTMLElement, options: WaterfallOptions) {\n super(container, options.theme);\n this.options = options;\n\n if (options.crosshair !== false) {\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n }\n\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n const pos = this.crosshair?.getPosition() ?? null;\n renderWaterfall(ctx, width, height, this.options, theme, pos);\n }\n\n update(data: WaterfallBar[]): void {\n this.options = { ...this.options, data };\n this.requestRender();\n }\n\n setOptions(opts: Partial<WaterfallOptions>): void {\n this.options = { ...this.options, ...opts };\n this.requestRender();\n }\n\n destroy(): void {\n this.crosshair?.destroy();\n super.destroy();\n }\n}\n","import type { GaugeOptions, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, renderGauge } from '@tradecanvas/core';\n\nconst DEFAULT_ANIMATION_MS = 500;\n\nfunction easeOutCubic(t: number): number {\n const inv = 1 - t;\n return 1 - inv * inv * inv;\n}\n\nexport class GaugeChart extends BaseFinanceChart {\n private options: GaugeOptions;\n private currentValue: number;\n private targetValue: number;\n private animationStart: number | null = null;\n private animationFrom = 0;\n private animationFrameId: number | null = null;\n\n constructor(container: HTMLElement, options: GaugeOptions) {\n super(container, options.theme);\n this.options = options;\n this.currentValue = options.value;\n this.targetValue = options.value;\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n renderGauge(ctx, width, height, this.options, theme, this.currentValue);\n }\n\n setValue(value: number): void {\n const animate = this.options.animate !== false;\n if (!animate) {\n this.cancelAnimation();\n this.currentValue = value;\n this.targetValue = value;\n this.options = { ...this.options, value };\n this.requestRender();\n return;\n }\n\n this.targetValue = value;\n this.animationFrom = this.currentValue;\n this.animationStart = performance.now();\n this.options = { ...this.options, value };\n this.startAnimationLoop();\n }\n\n setOptions(opts: Partial<GaugeOptions>): void {\n const next = { ...this.options, ...opts };\n // If `value` is part of the partial, route through animation path\n if (opts.value !== undefined && opts.value !== this.targetValue) {\n this.options = next;\n this.setValue(opts.value);\n return;\n }\n this.options = next;\n this.requestRender();\n }\n\n private startAnimationLoop(): void {\n if (this.animationFrameId !== null) return;\n const step = (): void => {\n this.animationFrameId = null;\n if (this.animationStart === null) return;\n\n const duration = this.options.animationDuration ?? DEFAULT_ANIMATION_MS;\n const elapsed = performance.now() - this.animationStart;\n const t = Math.min(1, elapsed / Math.max(1, duration));\n const eased = easeOutCubic(t);\n this.currentValue = this.animationFrom + (this.targetValue - this.animationFrom) * eased;\n\n this.requestRender();\n\n if (t < 1) {\n this.animationFrameId = requestAnimationFrame(step);\n } else {\n this.currentValue = this.targetValue;\n this.animationStart = null;\n }\n };\n this.animationFrameId = requestAnimationFrame(step);\n }\n\n private cancelAnimation(): void {\n if (this.animationFrameId !== null) {\n cancelAnimationFrame(this.animationFrameId);\n this.animationFrameId = null;\n }\n this.animationStart = null;\n }\n\n destroy(): void {\n this.cancelAnimation();\n super.destroy();\n }\n}\n","import type { EquityPoint, HeatmapCell } from '@tradecanvas/commons';\nimport { timeframeBucketStart } from '@tradecanvas/commons';\n\n/** Minimal equity sample shape — structurally satisfied by analytics' EquityPoint. */\nexport interface EquitySample {\n time: number;\n equity: number;\n}\n\n/** Subset of analytics RiskMetrics needed to render the stats strip. */\nexport interface RiskMetricsLike {\n totalReturnPct: number;\n cagr: number;\n sharpe: number;\n sortino: number;\n maxDrawdownPct: number;\n winRate: number;\n profitFactor: number;\n trades: number;\n}\n\nexport interface DashboardStat {\n label: string;\n value: string;\n tone: 'positive' | 'negative' | 'neutral';\n}\n\nconst MONTH_LABELS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n\n/** Map an analytics equity curve to the finance EquityCurveChart point shape. */\nexport function toEquityPoints(curve: ReadonlyArray<EquitySample>): EquityPoint[] {\n return curve.map((p) => ({ time: p.time, value: p.equity }));\n}\n\n/**\n * Underwater drawdown curve as a percentage (<= 0). Each point is the equity's\n * shortfall from the running peak: `equity / peak - 1`, expressed in percent.\n */\nexport function computeDrawdownCurve(curve: ReadonlyArray<EquitySample>): EquityPoint[] {\n let peak = -Infinity;\n return curve.map((p) => {\n if (p.equity > peak) peak = p.equity;\n const dd = peak > 0 ? (p.equity / peak - 1) * 100 : 0;\n return { time: p.time, value: dd };\n });\n}\n\n/**\n * Calendar-month returns as heatmap cells. Each month's return is chained off\n * the prior month's closing equity (the first month chains off its own opening\n * equity), so the series reads as sequential monthly performance. `group` is\n * the year and `value` is the return in percent.\n */\nexport function computeMonthlyReturns(curve: ReadonlyArray<EquitySample>): HeatmapCell[] {\n if (curve.length === 0) return [];\n\n // Collapse the curve to one closing equity per calendar month, in order.\n const months: { key: number; close: number }[] = [];\n for (const p of curve) {\n const key = timeframeBucketStart(p.time, '1M');\n const last = months[months.length - 1];\n if (last && last.key === key) {\n last.close = p.equity;\n } else {\n months.push({ key, close: p.equity });\n }\n }\n\n let prevClose = curve[0].equity;\n const cells: HeatmapCell[] = [];\n for (const m of months) {\n const base = prevClose === 0 ? 1 : prevClose;\n const returnPct = (m.close / base - 1) * 100;\n prevClose = m.close;\n const d = new Date(m.key);\n const year = d.getUTCFullYear();\n const month = d.getUTCMonth();\n cells.push({\n id: `${year}-${String(month + 1).padStart(2, '0')}`,\n label: MONTH_LABELS[month],\n group: String(year),\n value: returnPct,\n });\n }\n return cells;\n}\n\nfunction pct(value: number): string {\n const sign = value > 0 ? '+' : '';\n return `${sign}${value.toFixed(2)}%`;\n}\n\nfunction tone(value: number): DashboardStat['tone'] {\n if (value > 0) return 'positive';\n if (value < 0) return 'negative';\n return 'neutral';\n}\n\n/** The headline stats rendered as cards above the charts. */\nexport function selectKeyStats(metrics: RiskMetricsLike): DashboardStat[] {\n return [\n { label: 'Total Return', value: pct(metrics.totalReturnPct), tone: tone(metrics.totalReturnPct) },\n { label: 'CAGR', value: pct(metrics.cagr * 100), tone: tone(metrics.cagr) },\n { label: 'Sharpe', value: metrics.sharpe.toFixed(2), tone: tone(metrics.sharpe) },\n { label: 'Sortino', value: metrics.sortino.toFixed(2), tone: tone(metrics.sortino) },\n { label: 'Max Drawdown', value: pct(metrics.maxDrawdownPct), tone: 'negative' },\n { label: 'Win Rate', value: `${(metrics.winRate * 100).toFixed(1)}%`, tone: 'neutral' },\n { label: 'Profit Factor', value: Number.isFinite(metrics.profitFactor) ? metrics.profitFactor.toFixed(2) : '∞', tone: tone(metrics.profitFactor - 1) },\n { label: 'Trades', value: String(metrics.trades), tone: 'neutral' },\n ];\n}\n","import type { Theme, ThemeName } from '@tradecanvas/commons';\nimport { DARK_THEME, LIGHT_THEME } from '@tradecanvas/commons';\nimport { EquityCurveChart } from './EquityCurveChart.js';\nimport { HeatmapChart } from './HeatmapChart.js';\nimport {\n toEquityPoints,\n computeDrawdownCurve,\n computeMonthlyReturns,\n selectKeyStats,\n type EquitySample,\n type RiskMetricsLike,\n type DashboardStat,\n} from './performanceData.js';\n\n/** Structurally satisfied by analytics' `BacktestResult`. */\nexport interface PerformanceResult {\n equityCurve: ReadonlyArray<EquitySample>;\n metrics: RiskMetricsLike;\n}\n\nexport interface PerformanceDashboardOptions {\n result: PerformanceResult;\n theme?: ThemeName | Theme;\n title?: string;\n subtitle?: string;\n}\n\nfunction resolveTheme(theme?: ThemeName | Theme): Theme {\n if (!theme || theme === 'dark') return DARK_THEME;\n if (theme === 'light') return LIGHT_THEME;\n return theme as Theme;\n}\n\n/**\n * A composed strategy-performance dashboard: a headline stats strip, an equity\n * curve, an underwater drawdown panel, and a monthly-returns heatmap. Built\n * entirely from a backtest `result`, reusing the finance chart renderers.\n *\n * ```ts\n * const result = new Backtester(opts).run(bars, strategy);\n * const dash = new PerformanceDashboard(el, { result, theme: 'dark' });\n * ```\n */\nexport class PerformanceDashboard {\n private options: PerformanceDashboardOptions;\n private theme: Theme;\n private root: HTMLDivElement;\n private equityChart: EquityCurveChart | null = null;\n private drawdownChart: EquityCurveChart | null = null;\n private heatmap: HeatmapChart | null = null;\n\n constructor(container: HTMLElement, options: PerformanceDashboardOptions) {\n this.options = options;\n this.theme = resolveTheme(options.theme);\n this.root = document.createElement('div');\n this.build();\n container.appendChild(this.root);\n }\n\n private build(): void {\n const t = this.theme;\n const { result, title, subtitle } = this.options;\n const surface = this.panelBackground();\n const border = t.grid;\n\n this.root.style.cssText = [\n 'display:flex',\n 'flex-direction:column',\n 'gap:14px',\n 'width:100%',\n 'box-sizing:border-box',\n 'padding:16px',\n `background:${t.background}`,\n `color:${t.text}`,\n `font-family:${t.font.family}`,\n ].join(';');\n\n if (title || subtitle) {\n const header = document.createElement('div');\n if (title) {\n const h = document.createElement('div');\n h.textContent = title;\n h.style.cssText = `font-size:${t.font.sizeLarge}px;font-weight:600;letter-spacing:-0.01em;`;\n header.appendChild(h);\n }\n if (subtitle) {\n const s = document.createElement('div');\n s.textContent = subtitle;\n s.style.cssText = `font-size:${t.font.sizeSmall}px;color:${t.textSecondary};margin-top:2px;`;\n header.appendChild(s);\n }\n this.root.appendChild(header);\n }\n\n // Stats strip\n this.root.appendChild(this.buildStatsStrip(selectKeyStats(result.metrics), surface, border));\n\n // Chart grid\n const grid = document.createElement('div');\n grid.style.cssText = [\n 'display:grid',\n 'grid-template-columns:repeat(auto-fit, minmax(280px, 1fr))',\n 'grid-auto-rows:220px',\n 'gap:14px',\n ].join(';');\n this.root.appendChild(grid);\n\n const equityPanel = this.buildPanel('Equity Curve', surface, border);\n equityPanel.wrap.style.gridColumn = '1 / -1';\n grid.appendChild(equityPanel.wrap);\n this.equityChart = new EquityCurveChart(equityPanel.body, {\n data: toEquityPoints(result.equityCurve),\n theme: t,\n lineColor: t.candleUp,\n fillArea: true,\n crosshair: true,\n });\n\n const ddPanel = this.buildPanel('Drawdown', surface, border);\n grid.appendChild(ddPanel.wrap);\n this.drawdownChart = new EquityCurveChart(ddPanel.body, {\n data: computeDrawdownCurve(result.equityCurve),\n theme: t,\n lineColor: t.candleDown,\n fillArea: true,\n crosshair: true,\n valueFormat: (v) => `${v.toFixed(1)}%`,\n });\n\n const monthlyCells = computeMonthlyReturns(result.equityCurve);\n const heatPanel = this.buildPanel('Monthly Returns', surface, border);\n grid.appendChild(heatPanel.wrap);\n this.heatmap = new HeatmapChart(heatPanel.body, {\n data: monthlyCells,\n theme: t,\n showValues: true,\n valueFormat: (v) => `${v >= 0 ? '+' : ''}${v.toFixed(1)}`,\n colorScale: { negative: t.candleDown, zero: surface, positive: t.candleUp },\n });\n }\n\n private buildStatsStrip(stats: DashboardStat[], surface: string, border: string): HTMLDivElement {\n const strip = document.createElement('div');\n strip.style.cssText = [\n 'display:grid',\n 'grid-template-columns:repeat(auto-fit, minmax(120px, 1fr))',\n 'gap:10px',\n ].join(';');\n\n const t = this.theme;\n for (const stat of stats) {\n const card = document.createElement('div');\n card.style.cssText = [\n `background:${surface}`,\n `border:1px solid ${border}`,\n 'border-radius:10px',\n 'padding:10px 12px',\n 'display:flex',\n 'flex-direction:column',\n 'gap:4px',\n ].join(';');\n\n const label = document.createElement('div');\n label.textContent = stat.label;\n label.style.cssText = `font-size:${t.font.sizeSmall}px;color:${t.textSecondary};text-transform:uppercase;letter-spacing:0.04em;`;\n\n const value = document.createElement('div');\n value.textContent = stat.value;\n const color = stat.tone === 'positive' ? t.candleUp : stat.tone === 'negative' ? t.candleDown : t.text;\n value.style.cssText = `font-size:${t.font.sizeLarge}px;font-weight:600;color:${color};font-variant-numeric:tabular-nums;`;\n\n card.appendChild(label);\n card.appendChild(value);\n strip.appendChild(card);\n }\n return strip;\n }\n\n private buildPanel(title: string, surface: string, border: string): { wrap: HTMLDivElement; body: HTMLDivElement } {\n const t = this.theme;\n const wrap = document.createElement('div');\n wrap.style.cssText = [\n `background:${surface}`,\n `border:1px solid ${border}`,\n 'border-radius:10px',\n 'overflow:hidden',\n 'display:flex',\n 'flex-direction:column',\n ].join(';');\n\n const head = document.createElement('div');\n head.textContent = title;\n head.style.cssText = [\n `font-size:${t.font.sizeSmall}px`,\n 'font-weight:600',\n `color:${t.textSecondary}`,\n 'padding:8px 12px',\n `border-bottom:1px solid ${border}`,\n 'text-transform:uppercase',\n 'letter-spacing:0.04em',\n ].join(';');\n\n const body = document.createElement('div');\n body.style.cssText = 'flex:1;min-height:0;position:relative;';\n\n wrap.appendChild(head);\n wrap.appendChild(body);\n return { wrap, body };\n }\n\n /** A subtle surface tint distinct from the page background, per theme. */\n private panelBackground(): string {\n return this.theme.name === 'light' ? 'rgba(0,0,0,0.02)' : 'rgba(255,255,255,0.03)';\n }\n\n /** Replace the displayed result and re-render all panels. */\n update(result: PerformanceResult): void {\n this.options = { ...this.options, result };\n this.destroyCharts();\n this.root.replaceChildren();\n this.build();\n }\n\n setTheme(theme: ThemeName | Theme): void {\n this.theme = resolveTheme(theme);\n this.options = { ...this.options, theme };\n this.destroyCharts();\n this.root.replaceChildren();\n this.build();\n }\n\n private destroyCharts(): void {\n this.equityChart?.destroy();\n this.drawdownChart?.destroy();\n this.heatmap?.destroy();\n this.equityChart = null;\n this.drawdownChart = null;\n this.heatmap = null;\n }\n\n destroy(): void {\n this.destroyCharts();\n this.root.remove();\n }\n}\n"],"mappings":"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"}
@@ -291,6 +291,8 @@ export declare class ChartWidget {
291
291
  toggleAccountPanel(open?: boolean): void;
292
292
  /** The order ticket, at a price from the chart (or the market). */
293
293
  private openOrderTicket;
294
+ /** A market's rules for the order ticket (`setMarket`): its step, the day's limits, its lot. */
295
+ private orderRules;
294
296
  /** Redraw the account panel once a frame at most (ticks, fills and order changes come in bursts). */
295
297
  private refreshAccountSoon;
296
298
  private refreshAccount;