@tradecanvas/chart 1.51.0 → 1.53.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 (119) hide show
  1. package/dist/Chart.d.ts +275 -10
  2. package/dist/Chart.d.ts.map +1 -1
  3. package/dist/DataManager.d.ts +24 -0
  4. package/dist/DataManager.d.ts.map +1 -1
  5. package/dist/HistoryPager.d.ts +12 -2
  6. package/dist/HistoryPager.d.ts.map +1 -1
  7. package/dist/{LayoutSession-Qkx1huV-.js → LayoutSession-D7uQq3jX.js} +1225 -474
  8. package/dist/LayoutSession-D7uQq3jX.js.map +1 -0
  9. package/dist/LayoutSession-nlhT-EH7.cjs +2 -0
  10. package/dist/LayoutSession-nlhT-EH7.cjs.map +1 -0
  11. package/dist/SeriesStore.d.ts +58 -4
  12. package/dist/SeriesStore.d.ts.map +1 -1
  13. package/dist/charts/ChartTypeStrategy.d.ts +32 -5
  14. package/dist/charts/ChartTypeStrategy.d.ts.map +1 -1
  15. package/dist/frameworks/feedBars.d.ts +22 -6
  16. package/dist/frameworks/feedBars.d.ts.map +1 -1
  17. package/dist/{i18n-DFTQ73Cz.js → i18n-CwCzRLKW.js} +39 -1
  18. package/dist/i18n-CwCzRLKW.js.map +1 -0
  19. package/dist/i18n-D7B7uFrN.cjs +2 -0
  20. package/dist/i18n-D7B7uFrN.cjs.map +1 -0
  21. package/dist/index.cjs +1 -1
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.ts +6 -6
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +124 -101
  26. package/dist/index.js.map +1 -1
  27. package/dist/io/resampleOHLCV.d.ts +10 -4
  28. package/dist/io/resampleOHLCV.d.ts.map +1 -1
  29. package/dist/replay/ReplayStepLoader.d.ts +52 -0
  30. package/dist/replay/ReplayStepLoader.d.ts.map +1 -0
  31. package/dist/replay/intrabarPath.d.ts +44 -0
  32. package/dist/replay/intrabarPath.d.ts.map +1 -0
  33. package/dist/replay/replayStep.d.ts +18 -0
  34. package/dist/replay/replayStep.d.ts.map +1 -0
  35. package/dist/widget/ChartWidget.d.ts +329 -13
  36. package/dist/widget/ChartWidget.d.ts.map +1 -1
  37. package/dist/widget/ChartWidgetGrid.d.ts.map +1 -1
  38. package/dist/widget/WidgetDataWindow.d.ts +7 -0
  39. package/dist/widget/WidgetDataWindow.d.ts.map +1 -1
  40. package/dist/widget/WidgetHotkeySheet.d.ts.map +1 -1
  41. package/dist/widget/WidgetIndicatorLegend.d.ts +21 -3
  42. package/dist/widget/WidgetIndicatorLegend.d.ts.map +1 -1
  43. package/dist/widget/WidgetIndicatorSettings.d.ts.map +1 -1
  44. package/dist/widget/WidgetObjectTree.d.ts +7 -1
  45. package/dist/widget/WidgetObjectTree.d.ts.map +1 -1
  46. package/dist/widget/WidgetReplayBar.d.ts +101 -23
  47. package/dist/widget/WidgetReplayBar.d.ts.map +1 -1
  48. package/dist/widget/WidgetSettings.d.ts +11 -3
  49. package/dist/widget/WidgetSettings.d.ts.map +1 -1
  50. package/dist/widget/chartSettingsStore.d.ts +76 -0
  51. package/dist/widget/chartSettingsStore.d.ts.map +1 -0
  52. package/dist/widget/chartTemplates.d.ts.map +1 -1
  53. package/dist/widget/compareLegend.d.ts +20 -0
  54. package/dist/widget/compareLegend.d.ts.map +1 -0
  55. package/dist/widget/index.cjs +382 -166
  56. package/dist/widget/index.cjs.map +1 -1
  57. package/dist/widget/index.d.ts +1 -1
  58. package/dist/widget/index.d.ts.map +1 -1
  59. package/dist/widget/index.js +2947 -2041
  60. package/dist/widget/index.js.map +1 -1
  61. package/dist/widget/indicatorInputWords.d.ts +19 -0
  62. package/dist/widget/indicatorInputWords.d.ts.map +1 -0
  63. package/dist/widget/locales/ar.d.ts.map +1 -1
  64. package/dist/widget/locales/cs.d.ts.map +1 -1
  65. package/dist/widget/locales/da.d.ts.map +1 -1
  66. package/dist/widget/locales/de.d.ts.map +1 -1
  67. package/dist/widget/locales/el.d.ts.map +1 -1
  68. package/dist/widget/locales/en.d.ts +20 -0
  69. package/dist/widget/locales/en.d.ts.map +1 -1
  70. package/dist/widget/locales/es.d.ts.map +1 -1
  71. package/dist/widget/locales/et.d.ts.map +1 -1
  72. package/dist/widget/locales/fa.d.ts.map +1 -1
  73. package/dist/widget/locales/fr.d.ts.map +1 -1
  74. package/dist/widget/locales/he.d.ts.map +1 -1
  75. package/dist/widget/locales/hu.d.ts.map +1 -1
  76. package/dist/widget/locales/id.d.ts.map +1 -1
  77. package/dist/widget/locales/index.cjs +1 -1
  78. package/dist/widget/locales/index.cjs.map +1 -1
  79. package/dist/widget/locales/index.js +533 -1
  80. package/dist/widget/locales/index.js.map +1 -1
  81. package/dist/widget/locales/it.d.ts.map +1 -1
  82. package/dist/widget/locales/ja.d.ts.map +1 -1
  83. package/dist/widget/locales/ko.d.ts.map +1 -1
  84. package/dist/widget/locales/ms.d.ts.map +1 -1
  85. package/dist/widget/locales/nb.d.ts.map +1 -1
  86. package/dist/widget/locales/nl.d.ts.map +1 -1
  87. package/dist/widget/locales/pl.d.ts.map +1 -1
  88. package/dist/widget/locales/pt.d.ts.map +1 -1
  89. package/dist/widget/locales/ro.d.ts.map +1 -1
  90. package/dist/widget/locales/ru.d.ts.map +1 -1
  91. package/dist/widget/locales/sk.d.ts.map +1 -1
  92. package/dist/widget/locales/sv.d.ts.map +1 -1
  93. package/dist/widget/locales/th.d.ts.map +1 -1
  94. package/dist/widget/locales/tr.d.ts.map +1 -1
  95. package/dist/widget/locales/vi.d.ts.map +1 -1
  96. package/dist/widget/locales/zh.d.ts.map +1 -1
  97. package/dist/widget/locales/zhHant.d.ts.map +1 -1
  98. package/dist/widget/settingsRows.d.ts +12 -3
  99. package/dist/widget/settingsRows.d.ts.map +1 -1
  100. package/dist/widget/symbolInfoView.d.ts.map +1 -1
  101. package/dist/widget/types.d.ts +75 -7
  102. package/dist/widget/types.d.ts.map +1 -1
  103. package/dist/widget/widgetCompare.d.ts +18 -0
  104. package/dist/widget/widgetCompare.d.ts.map +1 -1
  105. package/dist/widget/widgetLayout.d.ts +13 -1
  106. package/dist/widget/widgetLayout.d.ts.map +1 -1
  107. package/dist/widget/widgetSettingsLook.d.ts +3 -1
  108. package/dist/widget/widgetSettingsLook.d.ts.map +1 -1
  109. package/dist/widget/widgetShareState.d.ts +8 -0
  110. package/dist/widget/widgetShareState.d.ts.map +1 -1
  111. package/dist/widget/widgetTimezones.d.ts +4 -1
  112. package/dist/widget/widgetTimezones.d.ts.map +1 -1
  113. package/package.json +3 -3
  114. package/dist/LayoutSession-DuV9kpdQ.cjs +0 -2
  115. package/dist/LayoutSession-DuV9kpdQ.cjs.map +0 -1
  116. package/dist/LayoutSession-Qkx1huV-.js.map +0 -1
  117. package/dist/i18n-Bg_UJSNs.cjs +0 -2
  118. package/dist/i18n-Bg_UJSNs.cjs.map +0 -1
  119. package/dist/i18n-DFTQ73Cz.js.map +0 -1
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/frameworks/syncIndicators.ts","../src/frameworks/feedBars.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/InteractiveChart.ts","../src/finance/BarChart.ts","../src/finance/DonutChart.ts","../src/finance/ScatterChart.ts","../src/finance/HistogramChart.ts","../src/finance/CalendarChart.ts","../src/finance/MatrixChart.ts","../src/finance/CounterClockChart.ts","../src/finance/performanceData.ts","../src/finance/PerformanceDashboard.ts"],"sourcesContent":["import type { IndicatorId, IndicatorParamValues, 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 | IndicatorId\n | { id: IndicatorId; params?: IndicatorParamValues; 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 { OHLCBar } from '@tradecanvas/commons';\nimport { isValidBar } from '../DataManager.js';\n\n/** What the components need of a chart to give it their `data`. */\nexport interface BarFeedHost {\n setData(data: OHLCBar[]): void;\n updateLastBar(bar: OHLCBar): void;\n appendBar(bar: OHLCBar): void;\n appendBars(bars: OHLCBar[]): void;\n /** The bars shown: read to tell bars another writer gave the chart. */\n getData(): readonly OHLCBar[];\n isExtendedHoursVisible(): boolean;\n isReplayActive(): boolean;\n}\n\n/** What `feedBars` gave back, for its next call. */\nexport interface FedBars {\n /** The array given, and how many bars it had then. */\n readonly source: readonly OHLCBar[];\n readonly length: number;\n /** Its last bar as it was then (a copy: the array may change in place). */\n readonly last: OHLCBar | null;\n /** The chart's last bar just after, the object itself: another writer's bar is another object. */\n readonly shownBar: OHLCBar | null;\n /** Fed during a replay: the bars went to the live series, out of sight. */\n readonly inReplay: boolean;\n}\n\nconst sameBar = (a: OHLCBar, b: OHLCBar): boolean =>\n a === b || (a.time === b.time && a.open === b.open && a.high === b.high && a.low === b.low && a.close === b.close && a.volume === b.volume);\n/**\n * A plain copy for the chart: a framework's state can be frozen, and its\n * proxies are not for reading in frames.\n */\nconst copy = (b: OHLCBar): OHLCBar => ({ time: b.time, open: b.open, high: b.high, low: b.low, close: b.close, volume: b.volume });\nconst lastOf = (bars: readonly OHLCBar[]): OHLCBar | null => (bars.length > 0 ? bars[bars.length - 1] : null);\n\n/** Whether the first `count` bars of `next` are those of `prev`. */\nfunction samePrefix(prev: readonly OHLCBar[], next: readonly OHLCBar[], count: number): boolean {\n for (let i = 0; i < count; i++) {\n if (!sameBar(prev[i], next[i])) return false;\n }\n return true;\n}\n\n/**\n * Whether the chart still shows what was fed: no stream or other code gave\n * it bars since. During a replay the bars shown are the replay's, and ticks\n * go to the live series beside them; after one, the live series is back,\n * and only its last time can tell. A last bar fed but not shown is fine\n * while extended hours are hidden: the chart keeps it aside.\n */\nfunction chartAsFed(chart: BarFeedHost, prev: FedBars): boolean {\n if (chart.isReplayActive()) return true;\n const shown = lastOf(chart.getData());\n if (prev.inReplay) return shown?.time === prev.last?.time;\n if (shown !== prev.shownBar) return false;\n return shown?.time === prev.last?.time || !chart.isExtendedHoursVisible();\n}\n\n/** The bars after the forming one, if each is valid and later than the one before; else null. */\nfunction addedAfter(next: readonly OHLCBar[], from: number): OHLCBar[] | null {\n const added: OHLCBar[] = [];\n for (let i = from; i < next.length; i++) {\n if (!isValidBar(next[i]) || !(next[i].time > next[i - 1].time)) return null;\n added.push(copy(next[i]));\n }\n return added;\n}\n\n/**\n * Feeds `next` as ticks when it goes on from what was fed: the bars before\n * the last as they were, the last one changed or bars added after it.\n * Returns false, having fed nothing, when it doesn't.\n */\nfunction feedTicks(chart: BarFeedHost, next: readonly OHLCBar[], prev: FedBars): boolean {\n const p = prev.length;\n // A last bar the chart couldn't take was left out: what it shows isn't what was fed.\n if (p === 0 || !prev.last || !isValidBar(prev.last) || next.length < p || !chartAsFed(chart, prev)) return false;\n // The same array, changed in place: only its end can have moved. The one\n // before, changed in place since (cut short, say), can't be compared.\n if (next !== prev.source && (prev.source.length !== p || !samePrefix(prev.source, next, p - 1))) return false;\n const forming = next[p - 1];\n if (forming.time !== prev.last.time || !isValidBar(forming)) return false;\n const added = addedAfter(next, p);\n if (!added) return false;\n if (!sameBar(forming, prev.last)) chart.updateLastBar(copy(forming));\n if (added.length === 1) chart.appendBar(added[0]);\n else if (added.length > 1) chart.appendBars(added);\n return true;\n}\n\n/**\n * Bars into the chart, as the framework components take their `data`. Bars\n * that go on from those fed before (the last one changed, or bars added after\n * it) go in as ticks (`updateLastBar`, `appendBar`, `appendBars`), as a live\n * feed's do: the view isn't reset, and only the end is computed again. That\n * holds for a new array (`[...bars, next]`) and for the same one changed in\n * place. Anything else is a new series (`setData`): other bars, a bar the\n * chart can't take, or bars another writer gave the chart since. `prev` is\n * what the last call gave back (null for the first); the chart gets plain\n * copies.\n */\nexport function feedBars(chart: BarFeedHost, next: readonly OHLCBar[], prev: FedBars | null): FedBars {\n if (!prev || !feedTicks(chart, next, prev)) chart.setData(next.map(copy));\n const last = next.length > 0 ? copy(next[next.length - 1]) : null;\n const inReplay = chart.isReplayActive();\n return { source: next, length: next.length, last, shownBar: inReplay ? null : lastOf(chart.getData()), inReplay };\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 layoutGroupedTreemap,\n renderHeatmap,\n GROUP_HEADER,\n} from '@tradecanvas/core';\nimport type { GroupRect, 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 cachedGroups: GroupRect[] = [];\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.applyLabel();\n this.recomputeLayout();\n this.requestRender();\n }\n\n /** What screen readers hear: `ariaLabel`, else the cells and groups it has. */\n private applyLabel(): void {\n const groups = new Set(this.currentData.map((c) => c.group).filter(Boolean)).size;\n const described = this.options.grouped && groups > 0\n ? `Market map of ${this.currentData.length} cells in ${groups} groups`\n : `Heatmap of ${this.currentData.length} cells`;\n this.setLabel(this.options.ariaLabel ?? described);\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 this.cachedGroups = [];\n if (this.options.grouped) {\n const weighted = this.currentData.map(c => ({\n id: c.id,\n weight: c.weight ?? (Math.abs(c.value) || 1),\n group: c.group,\n value: c.value,\n }));\n const { groups, cells } = layoutGroupedTreemap(weighted, bounds, padding, GROUP_HEADER);\n this.cachedRects = cells;\n this.cachedGroups = groups;\n } else 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, this.cachedGroups);\n }\n\n update(data: HeatmapCell[]): void {\n this.currentData = data;\n this.options = { ...this.options, data };\n this.applyLabel();\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.applyLabel();\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 { BaseFinanceChartOptions, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, FinanceCrosshair, canvasMeasure, type Measure } from '@tradecanvas/core';\n\ntype HoverOptions = BaseFinanceChartOptions & { crosshair?: boolean };\n\n/**\n * A finance chart that follows the pointer and answers clicks: it keeps the\n * layout it last drew, so a click finds what is under it without redrawing.\n */\nexport abstract class InteractiveChart<O extends HoverOptions, L> extends BaseFinanceChart {\n protected options: O;\n protected layout: L | null = null;\n /** What the cached layout was worked out for: a pointer move redraws without laying out again. */\n private layoutFor: { options: O; width: number; height: number; theme: Theme } | null = null;\n private readonly crosshair: FinanceCrosshair;\n private readonly onClick = (e: MouseEvent) => {\n const rect = this.canvas.getBoundingClientRect();\n if (this.layout) this.clickAt(this.layout, e.clientX - rect.left, e.clientY - rect.top);\n };\n private readonly onMove = (e: PointerEvent) => {\n if (!this.layout || !this.clickable()) return;\n const rect = this.canvas.getBoundingClientRect();\n this.canvas.style.cursor = this.hits(this.layout, e.clientX - rect.left, e.clientY - rect.top) ? 'pointer' : '';\n };\n\n constructor(container: HTMLElement, options: O) {\n super(container, options.theme);\n this.options = options;\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n this.canvas.addEventListener('click', this.onClick);\n this.canvas.addEventListener('pointermove', this.onMove);\n // describe() reads only `options`, set above: subclasses keep no state of their own.\n this.applyLabel();\n this.requestRender();\n }\n\n /** Where everything goes, for the chart's size and theme. */\n protected abstract compute(width: number, height: number, theme: Theme, measure: Measure): L;\n /** Draws the chart from its layout. */\n protected abstract draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: L): void;\n /** A sentence for screen readers when the options give none. */\n protected abstract describe(): string;\n /** Whether a click callback is set. */\n protected abstract clickable(): boolean;\n /** Whether something clickable is at (x, y). */\n protected abstract hits(layout: L, x: number, y: number): boolean;\n /** Calls the click callback for what is at (x, y). */\n protected abstract clickAt(layout: L, x: number, y: number): void;\n\n protected renderChart(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme): void {\n const pointer = this.options.crosshair === false ? null : this.crosshair.getPosition();\n const was = this.layoutFor;\n if (!this.layout || !was || was.options !== this.options || was.width !== width || was.height !== height || was.theme !== theme) {\n this.layout = this.compute(width, height, theme, canvasMeasure(ctx, theme));\n this.layoutFor = { options: this.options, width, height, theme };\n }\n this.draw(ctx, width, height, theme, pointer, this.layout);\n }\n\n setOptions(options: Partial<O>): void {\n this.options = { ...this.options, ...options };\n if ('theme' in options) this.setTheme(options.theme ?? 'dark');\n this.applyLabel();\n this.requestRender();\n }\n\n private applyLabel(): void {\n this.setLabel(this.options.ariaLabel ?? this.describe());\n }\n\n destroy(): void {\n this.crosshair.destroy();\n this.canvas.removeEventListener('click', this.onClick);\n this.canvas.removeEventListener('pointermove', this.onMove);\n super.destroy();\n }\n}\n","import type { BarChartOptions, ChartSeries, Theme } from '@tradecanvas/commons';\nimport { computeBarLayout, hitBar, renderBarChart, type BarLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/**\n * Bars by category: series side by side or stacked, up and down from zero,\n * upright or sideways. Net flows, volumes by session, returns by period.\n */\nexport class BarChart extends InteractiveChart<BarChartOptions, BarLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): BarLayout {\n return computeBarLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: BarLayout): void {\n renderBarChart(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const names = this.options.series.map((s) => s.name).join(', ');\n return `Bar chart of ${names}, ${this.options.categories.length} categories`;\n }\n\n protected clickable(): boolean {\n return this.options.onBarClick !== undefined;\n }\n\n protected hits(layout: BarLayout, x: number, y: number): boolean {\n return hitBar(layout, x, y) !== null;\n }\n\n protected clickAt(layout: BarLayout, x: number, y: number): void {\n const bar = hitBar(layout, x, y);\n if (bar) this.options.onBarClick?.({ category: bar.category, series: bar.series, value: bar.value, index: bar.index });\n }\n\n /** New values: the categories and their series. */\n update(categories: string[], series: ChartSeries[]): void {\n this.setOptions({ categories, series });\n }\n}\n","import type { DonutChartOptions, DonutSlice, Theme } from '@tradecanvas/commons';\nimport { computeDonutLayout, hitSlice, renderDonut, type DonutLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** Parts of a whole as a ring (or a pie): allocation, exposure, order flow by side. */\nexport class DonutChart extends InteractiveChart<DonutChartOptions, DonutLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): DonutLayout {\n return computeDonutLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: DonutLayout): void {\n renderDonut(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const parts = this.options.data.filter((s) => Number.isFinite(s.value) && s.value > 0).map((s) => s.label).join(', ');\n return `${(this.options.innerRadius ?? 0.6) > 0 ? 'Donut' : 'Pie'} chart of ${parts}`;\n }\n\n protected clickable(): boolean {\n return this.options.onSliceClick !== undefined;\n }\n\n protected hits(layout: DonutLayout, x: number, y: number): boolean {\n return hitSlice(layout, x, y) !== null;\n }\n\n protected clickAt(layout: DonutLayout, x: number, y: number): void {\n const arc = hitSlice(layout, x, y);\n if (arc) this.options.onSliceClick?.(arc.slice);\n }\n\n update(data: DonutSlice[]): void {\n this.setOptions({ data });\n }\n}\n","import type { ScatterChartOptions, ScatterSeries, Theme } from '@tradecanvas/commons';\nimport { computeScatterLayout, nearestPoint, renderScatter, type ScatterLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** Points on two value axes, bubbles when they have a size: risk against return, value against growth. */\nexport class ScatterChart extends InteractiveChart<ScatterChartOptions, ScatterLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): ScatterLayout {\n return computeScatterLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: ScatterLayout): void {\n renderScatter(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const points = this.options.series.reduce((n, s) => n + s.points.length, 0);\n const axes = this.options.xLabel && this.options.yLabel ? ` of ${this.options.yLabel} against ${this.options.xLabel}` : '';\n return `Scatter chart${axes}, ${points} points`;\n }\n\n protected clickable(): boolean {\n return this.options.onPointClick !== undefined;\n }\n\n protected hits(layout: ScatterLayout, x: number, y: number): boolean {\n return nearestPoint(layout, x, y) !== null;\n }\n\n protected clickAt(layout: ScatterLayout, x: number, y: number): void {\n const p = nearestPoint(layout, x, y);\n if (p) this.options.onPointClick?.(p.point, p.series);\n }\n\n update(series: ScatterSeries[]): void {\n this.setOptions({ series });\n }\n}\n","import type { HistogramOptions, Theme } from '@tradecanvas/commons';\nimport { computeHistogramLayout, renderHistogram, type HistogramLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** How values spread: daily returns, trade results, with lines at the mean or a VaR. */\nexport class HistogramChart extends InteractiveChart<HistogramOptions, HistogramLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): HistogramLayout {\n return computeHistogramLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: HistogramLayout): void {\n renderHistogram(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n return `Histogram of ${this.options.values.length} values`;\n }\n\n protected clickable(): boolean {\n return false;\n }\n\n protected hits(): boolean {\n return false;\n }\n\n protected clickAt(): void {}\n\n update(values: number[]): void {\n this.setOptions({ values });\n }\n}\n","import type { CalendarChartOptions, CalendarDay, Theme } from '@tradecanvas/commons';\nimport { computeCalendarLayout, hitDay, renderCalendar, type CalendarLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** A value a day on a calendar: daily returns, P&L, volume, a trading journal. */\nexport class CalendarChart extends InteractiveChart<CalendarChartOptions, CalendarLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): CalendarLayout {\n return computeCalendarLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: CalendarLayout): void {\n renderCalendar(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const dates = this.options.data.map((d) => d.date).filter((d) => /^\\d{4}-\\d{2}-\\d{2}$/.test(d)).sort();\n const from = this.options.from ?? dates[0];\n const to = this.options.to ?? dates[dates.length - 1];\n return from && to ? `Calendar of daily values from ${from} to ${to}` : 'Calendar of daily values';\n }\n\n protected clickable(): boolean {\n return this.options.onDayClick !== undefined;\n }\n\n protected hits(layout: CalendarLayout, x: number, y: number): boolean {\n return hitDay(layout, x, y)?.day !== undefined;\n }\n\n protected clickAt(layout: CalendarLayout, x: number, y: number): void {\n const day = hitDay(layout, x, y)?.day;\n if (day) this.options.onDayClick?.(day);\n }\n\n update(data: CalendarDay[]): void {\n this.setOptions({ data });\n }\n}\n","import type { MatrixChartOptions, Theme } from '@tradecanvas/commons';\nimport { computeMatrixLayout, hitMatrixCell, renderMatrix, type MatrixLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** Past this many names, the description gives counts instead. */\nconst MAX_NAMED = 12;\n\n/** A value for each row and column pair, coloured: correlations, volume by hour and weekday. */\nexport class MatrixChart extends InteractiveChart<MatrixChartOptions, MatrixLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): MatrixLayout {\n return computeMatrixLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: MatrixLayout): void {\n renderMatrix(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const { rows, columns } = this.options;\n if (!columns) return rows.length <= MAX_NAMED ? `Matrix of ${rows.join(', ')}` : `Matrix of ${rows.length} rows`;\n return rows.length + columns.length <= MAX_NAMED\n ? `Matrix of ${rows.join(', ')} by ${columns.join(', ')}`\n : `Matrix of ${rows.length} rows by ${columns.length} columns`;\n }\n\n protected clickable(): boolean {\n return this.options.onCellClick !== undefined;\n }\n\n protected hits(layout: MatrixLayout, x: number, y: number): boolean {\n return hitMatrixCell(layout, x, y) !== null;\n }\n\n protected clickAt(layout: MatrixLayout, x: number, y: number): void {\n const hit = hitMatrixCell(layout, x, y);\n if (hit) this.options.onCellClick?.(hit.cell);\n }\n\n /** New values for the same rows and columns; `setOptions` changes the names. */\n update(values: number[][]): void {\n this.setOptions({ values });\n }\n}\n","import type { CounterClockOptions, OHLCBar, Theme } from '@tradecanvas/commons';\nimport { computeCounterClockLayout, counterClockPhase, counterClockPoints, nearestCounterClockPoint, renderCounterClock, shownCount, type CounterClockLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/**\n * Counter-clock chart: average price against average volume, bar by bar, with\n * no time axis. A healthy cycle turns counter-clockwise: volume picks up,\n * price follows, volume fades, price follows it down.\n */\nexport class CounterClockChart extends InteractiveChart<CounterClockOptions, CounterClockLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): CounterClockLayout {\n return computeCounterClockLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: CounterClockLayout): void {\n renderCounterClock(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n return `Counter-clock chart of price against volume, ${this.options.period ?? 25}-bar averages`;\n }\n\n protected clickable(): boolean {\n return this.options.onPointClick !== undefined;\n }\n\n protected hits(layout: CounterClockLayout, x: number, y: number): boolean {\n return nearestCounterClockPoint(layout, x, y) !== null;\n }\n\n protected clickAt(layout: CounterClockLayout, x: number, y: number): void {\n const hit = nearestCounterClockPoint(layout, x, y);\n if (hit) this.options.onPointClick?.(hit.point);\n }\n\n /** The phase of the newest move, 1–8 counter-clockwise from volume rising (see `counterClockPhase`), or null. */\n getPhase(): number | null {\n return counterClockPhase(counterClockPoints(this.options.data, this.options.period ?? 25, shownCount(this.options)));\n }\n\n update(data: OHLCBar[]): void {\n this.setOptions({ data });\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/**\n * Subset of analytics RiskMetrics needed to render the stats strip. The\n * percentages are fractions, as @tradecanvas/analytics returns them: a\n * totalReturnPct of 0.12 shows as +12.00%.\n */\nexport interface RiskMetricsLike {\n /** Total return as a fraction: 0.12 is +12%. */\n totalReturnPct: number;\n /** Compound annual growth rate as a fraction. */\n cagr: number;\n sharpe: number;\n sortino: number;\n /**\n * The deepest fall from a running peak, as a fraction: 0.5 is 50%. Either\n * sign reads as a fall, since some callers sign their drawdowns.\n */\n maxDrawdownPct: number;\n /** Share of winning trades as a fraction. */\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\n/** Metrics arrive as fractions (0.12); the cards show percent (12.00%). */\nconst PERCENT = 100;\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/**\n * The headline stats rendered as cards above the charts. The drawdown is a\n * fall, so it reads with a minus sign whichever sign it arrives with, as the\n * Drawdown panel below plots it.\n */\nexport function selectKeyStats(metrics: RiskMetricsLike): DashboardStat[] {\n return [\n { label: 'Total Return', value: pct(metrics.totalReturnPct * PERCENT), tone: tone(metrics.totalReturnPct) },\n { label: 'CAGR', value: pct(metrics.cagr * PERCENT), 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(-Math.abs(metrics.maxDrawdownPct) * PERCENT), tone: 'negative' },\n { label: 'Win Rate', value: `${(metrics.winRate * PERCENT).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/frameworks/feedBars.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/InteractiveChart.ts","../src/finance/BarChart.ts","../src/finance/DonutChart.ts","../src/finance/ScatterChart.ts","../src/finance/HistogramChart.ts","../src/finance/CalendarChart.ts","../src/finance/MatrixChart.ts","../src/finance/CounterClockChart.ts","../src/finance/performanceData.ts","../src/finance/PerformanceDashboard.ts"],"sourcesContent":["import type { IndicatorId, IndicatorParamValues, 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 | IndicatorId\n | { id: IndicatorId; params?: IndicatorParamValues; 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 { OHLCBar } from '@tradecanvas/commons';\nimport { isValidBar, sameBar } from '../DataManager.js';\n\n/**\n * How many bars before the forming one a component's `data` may correct\n * in place (the venue's final for the bar just closed, a late revision):\n * they go in as `updateBar`, the view kept. A change further back is a new\n * series. Vue and Svelte watch these bars, the forming one and the length.\n */\nexport const CORRECTABLE_BARS = 3;\n\n/** What the components need of a chart to give it their `data`. */\nexport interface BarFeedHost {\n setData(data: OHLCBar[]): void;\n updateLastBar(bar: OHLCBar): void;\n appendBar(bar: OHLCBar): void;\n appendBars(bars: OHLCBar[]): void;\n /**\n * A loaded bar corrected (`Chart.updateBar`): false when the chart has no\n * bar at its time. Without it, a correction is fed as a new series.\n */\n updateBar?(bar: OHLCBar): boolean;\n /** The bars shown: read to tell bars another writer gave the chart. */\n getData(): readonly OHLCBar[];\n isExtendedHoursVisible(): boolean;\n isReplayActive(): boolean;\n}\n\n/** What `feedBars` gave back, for its next call. */\nexport interface FedBars {\n /** The array given, and how many bars it had then. */\n readonly source: readonly OHLCBar[];\n readonly length: number;\n /** Its last bar as it was then (a copy: the array may change in place). */\n readonly last: OHLCBar | null;\n /** Up to `CORRECTABLE_BARS` bars before the last, as they were then (copies): a change to one is a correction. */\n readonly recent?: readonly OHLCBar[];\n /** The chart's last bar just after, the object itself: another writer's bar is another object. */\n readonly shownBar: OHLCBar | null;\n /** Fed during a replay: the bars went to the live series, out of sight. */\n readonly inReplay: boolean;\n}\n\n/**\n * A plain copy for the chart: a framework's state can be frozen, and its\n * proxies are not for reading in frames.\n */\nconst copy = (b: OHLCBar): OHLCBar => ({ time: b.time, open: b.open, high: b.high, low: b.low, close: b.close, volume: b.volume });\nconst lastOf = (bars: readonly OHLCBar[]): OHLCBar | null => (bars.length > 0 ? bars[bars.length - 1] : null);\n\n/** Whether the first `count` bars of `next` are those of `prev`. */\nfunction samePrefix(prev: readonly OHLCBar[], next: readonly OHLCBar[], count: number): boolean {\n for (let i = 0; i < count; i++) {\n if (!sameBar(prev[i], next[i])) return false;\n }\n return true;\n}\n\n/**\n * Whether the chart still shows what was fed: no stream or other code gave\n * it bars since. During a replay the bars shown are the replay's, and ticks\n * go to the live series beside them; after one, the live series is back,\n * and only its last time can tell. A last bar fed but not shown is fine\n * while extended hours are hidden: the chart keeps it aside.\n */\nfunction chartAsFed(chart: BarFeedHost, prev: FedBars): boolean {\n if (chart.isReplayActive()) return true;\n const shown = lastOf(chart.getData());\n if (prev.inReplay) return shown?.time === prev.last?.time;\n if (shown !== prev.shownBar) return false;\n return shown?.time === prev.last?.time || !chart.isExtendedHoursVisible();\n}\n\n/**\n * The bars of `next` from `from` on that differ from `recent` (the copies\n * kept of them): corrections, each with the same time and one the chart\n * can take; null when one isn't.\n */\nfunction correctionsIn(next: readonly OHLCBar[], recent: readonly OHLCBar[], from: number): OHLCBar[] | null {\n const corrections: OHLCBar[] = [];\n for (let i = 0; i < recent.length; i++) {\n const bar = next[from + i];\n if (sameBar(bar, recent[i])) continue;\n if (bar.time !== recent[i].time || !isValidBar(bar)) return null;\n corrections.push(copy(bar));\n }\n return corrections;\n}\n\n/** Each correction onto the chart; false when it has no `updateBar`, or refuses one. */\nfunction applyCorrections(chart: BarFeedHost, corrections: readonly OHLCBar[]): boolean {\n if (corrections.length === 0) return true;\n if (!chart.updateBar) return false;\n for (const bar of corrections) {\n if (!chart.updateBar(bar)) return false;\n }\n return true;\n}\n\n/** Copies of up to `CORRECTABLE_BARS` bars before the last of `bars`, never the first (another symbol on the same times changes it). */\nfunction recentOf(bars: readonly OHLCBar[]): OHLCBar[] {\n return bars.slice(Math.max(1, bars.length - 1 - CORRECTABLE_BARS), -1).map(copy);\n}\n\n/** The bars after the forming one, if each is valid and later than the one before; else null. */\nfunction addedAfter(next: readonly OHLCBar[], from: number): OHLCBar[] | null {\n const added: OHLCBar[] = [];\n for (let i = from; i < next.length; i++) {\n if (!isValidBar(next[i]) || !(next[i].time > next[i - 1].time)) return null;\n added.push(copy(next[i]));\n }\n return added;\n}\n\n/**\n * Feeds `next` as ticks when it goes on from what was fed: the bars before\n * the last as they were, or a few of them corrected, the last one changed\n * or bars added after it. Returns false when it doesn't, having fed no\n * tick and no bar added: the bars are then a new series.\n */\nfunction feedTicks(chart: BarFeedHost, next: readonly OHLCBar[], prev: FedBars): boolean {\n const p = prev.length;\n // A last bar the chart couldn't take was left out: what it shows isn't what was fed.\n if (p === 0 || !prev.last || !isValidBar(prev.last) || next.length < p || !chartAsFed(chart, prev)) return false;\n const recent = prev.recent ?? [];\n const settled = p - 1 - recent.length;\n // The same array, changed in place: only its end can have moved, and the\n // copies of its last bars tell. The one before, changed in place since\n // (cut short, say), can't be compared.\n if (next !== prev.source && (prev.source.length !== p || !samePrefix(prev.source, next, settled))) return false;\n const forming = next[p - 1];\n if (forming.time !== prev.last.time || !isValidBar(forming)) return false;\n const corrections = correctionsIn(next, recent, settled);\n const added = addedAfter(next, p);\n if (!corrections || !added) return false;\n // Before any tick: a chart that refuses one takes the bars as a new series instead.\n if (!applyCorrections(chart, corrections)) return false;\n if (!sameBar(forming, prev.last)) chart.updateLastBar(copy(forming));\n if (added.length === 1) chart.appendBar(added[0]);\n else if (added.length > 1) chart.appendBars(added);\n return true;\n}\n\n/**\n * Bars into the chart, as the framework components take their `data`. Bars\n * that go on from those fed before (the last one changed, or bars added after\n * it) go in as ticks (`updateLastBar`, `appendBar`, `appendBars`), as a live\n * feed's do: the view isn't reset, and only the end is computed again. A\n * change to one of the `CORRECTABLE_BARS` bars before the forming one (its\n * time the same) goes in as a correction (`updateBar`), the view kept too.\n * That holds for a new array (`[...bars, next]`) and for the same one\n * changed in place. Anything else is a new series (`setData`): other bars,\n * a bar the chart can't take, a correction it refuses or can't take (no\n * `updateBar`), or bars another writer gave the chart since. `prev` is what\n * the last call gave back (null for the first); the chart gets plain copies.\n */\nexport function feedBars(chart: BarFeedHost, next: readonly OHLCBar[], prev: FedBars | null): FedBars {\n if (!prev || !feedTicks(chart, next, prev)) chart.setData(next.map(copy));\n const last = next.length > 0 ? copy(next[next.length - 1]) : null;\n const inReplay = chart.isReplayActive();\n return { source: next, length: next.length, last, recent: recentOf(next), shownBar: inReplay ? null : lastOf(chart.getData()), inReplay };\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 layoutGroupedTreemap,\n renderHeatmap,\n GROUP_HEADER,\n} from '@tradecanvas/core';\nimport type { GroupRect, 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 cachedGroups: GroupRect[] = [];\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.applyLabel();\n this.recomputeLayout();\n this.requestRender();\n }\n\n /** What screen readers hear: `ariaLabel`, else the cells and groups it has. */\n private applyLabel(): void {\n const groups = new Set(this.currentData.map((c) => c.group).filter(Boolean)).size;\n const described = this.options.grouped && groups > 0\n ? `Market map of ${this.currentData.length} cells in ${groups} groups`\n : `Heatmap of ${this.currentData.length} cells`;\n this.setLabel(this.options.ariaLabel ?? described);\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 this.cachedGroups = [];\n if (this.options.grouped) {\n const weighted = this.currentData.map(c => ({\n id: c.id,\n weight: c.weight ?? (Math.abs(c.value) || 1),\n group: c.group,\n value: c.value,\n }));\n const { groups, cells } = layoutGroupedTreemap(weighted, bounds, padding, GROUP_HEADER);\n this.cachedRects = cells;\n this.cachedGroups = groups;\n } else 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, this.cachedGroups);\n }\n\n update(data: HeatmapCell[]): void {\n this.currentData = data;\n this.options = { ...this.options, data };\n this.applyLabel();\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.applyLabel();\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 { BaseFinanceChartOptions, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, FinanceCrosshair, canvasMeasure, type Measure } from '@tradecanvas/core';\n\ntype HoverOptions = BaseFinanceChartOptions & { crosshair?: boolean };\n\n/**\n * A finance chart that follows the pointer and answers clicks: it keeps the\n * layout it last drew, so a click finds what is under it without redrawing.\n */\nexport abstract class InteractiveChart<O extends HoverOptions, L> extends BaseFinanceChart {\n protected options: O;\n protected layout: L | null = null;\n /** What the cached layout was worked out for: a pointer move redraws without laying out again. */\n private layoutFor: { options: O; width: number; height: number; theme: Theme } | null = null;\n private readonly crosshair: FinanceCrosshair;\n private readonly onClick = (e: MouseEvent) => {\n const rect = this.canvas.getBoundingClientRect();\n if (this.layout) this.clickAt(this.layout, e.clientX - rect.left, e.clientY - rect.top);\n };\n private readonly onMove = (e: PointerEvent) => {\n if (!this.layout || !this.clickable()) return;\n const rect = this.canvas.getBoundingClientRect();\n this.canvas.style.cursor = this.hits(this.layout, e.clientX - rect.left, e.clientY - rect.top) ? 'pointer' : '';\n };\n\n constructor(container: HTMLElement, options: O) {\n super(container, options.theme);\n this.options = options;\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n this.canvas.addEventListener('click', this.onClick);\n this.canvas.addEventListener('pointermove', this.onMove);\n // describe() reads only `options`, set above: subclasses keep no state of their own.\n this.applyLabel();\n this.requestRender();\n }\n\n /** Where everything goes, for the chart's size and theme. */\n protected abstract compute(width: number, height: number, theme: Theme, measure: Measure): L;\n /** Draws the chart from its layout. */\n protected abstract draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: L): void;\n /** A sentence for screen readers when the options give none. */\n protected abstract describe(): string;\n /** Whether a click callback is set. */\n protected abstract clickable(): boolean;\n /** Whether something clickable is at (x, y). */\n protected abstract hits(layout: L, x: number, y: number): boolean;\n /** Calls the click callback for what is at (x, y). */\n protected abstract clickAt(layout: L, x: number, y: number): void;\n\n protected renderChart(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme): void {\n const pointer = this.options.crosshair === false ? null : this.crosshair.getPosition();\n const was = this.layoutFor;\n if (!this.layout || !was || was.options !== this.options || was.width !== width || was.height !== height || was.theme !== theme) {\n this.layout = this.compute(width, height, theme, canvasMeasure(ctx, theme));\n this.layoutFor = { options: this.options, width, height, theme };\n }\n this.draw(ctx, width, height, theme, pointer, this.layout);\n }\n\n setOptions(options: Partial<O>): void {\n this.options = { ...this.options, ...options };\n if ('theme' in options) this.setTheme(options.theme ?? 'dark');\n this.applyLabel();\n this.requestRender();\n }\n\n private applyLabel(): void {\n this.setLabel(this.options.ariaLabel ?? this.describe());\n }\n\n destroy(): void {\n this.crosshair.destroy();\n this.canvas.removeEventListener('click', this.onClick);\n this.canvas.removeEventListener('pointermove', this.onMove);\n super.destroy();\n }\n}\n","import type { BarChartOptions, ChartSeries, Theme } from '@tradecanvas/commons';\nimport { computeBarLayout, hitBar, renderBarChart, type BarLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/**\n * Bars by category: series side by side or stacked, up and down from zero,\n * upright or sideways. Net flows, volumes by session, returns by period.\n */\nexport class BarChart extends InteractiveChart<BarChartOptions, BarLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): BarLayout {\n return computeBarLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: BarLayout): void {\n renderBarChart(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const names = this.options.series.map((s) => s.name).join(', ');\n return `Bar chart of ${names}, ${this.options.categories.length} categories`;\n }\n\n protected clickable(): boolean {\n return this.options.onBarClick !== undefined;\n }\n\n protected hits(layout: BarLayout, x: number, y: number): boolean {\n return hitBar(layout, x, y) !== null;\n }\n\n protected clickAt(layout: BarLayout, x: number, y: number): void {\n const bar = hitBar(layout, x, y);\n if (bar) this.options.onBarClick?.({ category: bar.category, series: bar.series, value: bar.value, index: bar.index });\n }\n\n /** New values: the categories and their series. */\n update(categories: string[], series: ChartSeries[]): void {\n this.setOptions({ categories, series });\n }\n}\n","import type { DonutChartOptions, DonutSlice, Theme } from '@tradecanvas/commons';\nimport { computeDonutLayout, hitSlice, renderDonut, type DonutLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** Parts of a whole as a ring (or a pie): allocation, exposure, order flow by side. */\nexport class DonutChart extends InteractiveChart<DonutChartOptions, DonutLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): DonutLayout {\n return computeDonutLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: DonutLayout): void {\n renderDonut(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const parts = this.options.data.filter((s) => Number.isFinite(s.value) && s.value > 0).map((s) => s.label).join(', ');\n return `${(this.options.innerRadius ?? 0.6) > 0 ? 'Donut' : 'Pie'} chart of ${parts}`;\n }\n\n protected clickable(): boolean {\n return this.options.onSliceClick !== undefined;\n }\n\n protected hits(layout: DonutLayout, x: number, y: number): boolean {\n return hitSlice(layout, x, y) !== null;\n }\n\n protected clickAt(layout: DonutLayout, x: number, y: number): void {\n const arc = hitSlice(layout, x, y);\n if (arc) this.options.onSliceClick?.(arc.slice);\n }\n\n update(data: DonutSlice[]): void {\n this.setOptions({ data });\n }\n}\n","import type { ScatterChartOptions, ScatterSeries, Theme } from '@tradecanvas/commons';\nimport { computeScatterLayout, nearestPoint, renderScatter, type ScatterLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** Points on two value axes, bubbles when they have a size: risk against return, value against growth. */\nexport class ScatterChart extends InteractiveChart<ScatterChartOptions, ScatterLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): ScatterLayout {\n return computeScatterLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: ScatterLayout): void {\n renderScatter(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const points = this.options.series.reduce((n, s) => n + s.points.length, 0);\n const axes = this.options.xLabel && this.options.yLabel ? ` of ${this.options.yLabel} against ${this.options.xLabel}` : '';\n return `Scatter chart${axes}, ${points} points`;\n }\n\n protected clickable(): boolean {\n return this.options.onPointClick !== undefined;\n }\n\n protected hits(layout: ScatterLayout, x: number, y: number): boolean {\n return nearestPoint(layout, x, y) !== null;\n }\n\n protected clickAt(layout: ScatterLayout, x: number, y: number): void {\n const p = nearestPoint(layout, x, y);\n if (p) this.options.onPointClick?.(p.point, p.series);\n }\n\n update(series: ScatterSeries[]): void {\n this.setOptions({ series });\n }\n}\n","import type { HistogramOptions, Theme } from '@tradecanvas/commons';\nimport { computeHistogramLayout, renderHistogram, type HistogramLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** How values spread: daily returns, trade results, with lines at the mean or a VaR. */\nexport class HistogramChart extends InteractiveChart<HistogramOptions, HistogramLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): HistogramLayout {\n return computeHistogramLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: HistogramLayout): void {\n renderHistogram(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n return `Histogram of ${this.options.values.length} values`;\n }\n\n protected clickable(): boolean {\n return false;\n }\n\n protected hits(): boolean {\n return false;\n }\n\n protected clickAt(): void {}\n\n update(values: number[]): void {\n this.setOptions({ values });\n }\n}\n","import type { CalendarChartOptions, CalendarDay, Theme } from '@tradecanvas/commons';\nimport { computeCalendarLayout, hitDay, renderCalendar, type CalendarLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** A value a day on a calendar: daily returns, P&L, volume, a trading journal. */\nexport class CalendarChart extends InteractiveChart<CalendarChartOptions, CalendarLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): CalendarLayout {\n return computeCalendarLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: CalendarLayout): void {\n renderCalendar(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const dates = this.options.data.map((d) => d.date).filter((d) => /^\\d{4}-\\d{2}-\\d{2}$/.test(d)).sort();\n const from = this.options.from ?? dates[0];\n const to = this.options.to ?? dates[dates.length - 1];\n return from && to ? `Calendar of daily values from ${from} to ${to}` : 'Calendar of daily values';\n }\n\n protected clickable(): boolean {\n return this.options.onDayClick !== undefined;\n }\n\n protected hits(layout: CalendarLayout, x: number, y: number): boolean {\n return hitDay(layout, x, y)?.day !== undefined;\n }\n\n protected clickAt(layout: CalendarLayout, x: number, y: number): void {\n const day = hitDay(layout, x, y)?.day;\n if (day) this.options.onDayClick?.(day);\n }\n\n update(data: CalendarDay[]): void {\n this.setOptions({ data });\n }\n}\n","import type { MatrixChartOptions, Theme } from '@tradecanvas/commons';\nimport { computeMatrixLayout, hitMatrixCell, renderMatrix, type MatrixLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** Past this many names, the description gives counts instead. */\nconst MAX_NAMED = 12;\n\n/** A value for each row and column pair, coloured: correlations, volume by hour and weekday. */\nexport class MatrixChart extends InteractiveChart<MatrixChartOptions, MatrixLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): MatrixLayout {\n return computeMatrixLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: MatrixLayout): void {\n renderMatrix(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const { rows, columns } = this.options;\n if (!columns) return rows.length <= MAX_NAMED ? `Matrix of ${rows.join(', ')}` : `Matrix of ${rows.length} rows`;\n return rows.length + columns.length <= MAX_NAMED\n ? `Matrix of ${rows.join(', ')} by ${columns.join(', ')}`\n : `Matrix of ${rows.length} rows by ${columns.length} columns`;\n }\n\n protected clickable(): boolean {\n return this.options.onCellClick !== undefined;\n }\n\n protected hits(layout: MatrixLayout, x: number, y: number): boolean {\n return hitMatrixCell(layout, x, y) !== null;\n }\n\n protected clickAt(layout: MatrixLayout, x: number, y: number): void {\n const hit = hitMatrixCell(layout, x, y);\n if (hit) this.options.onCellClick?.(hit.cell);\n }\n\n /** New values for the same rows and columns; `setOptions` changes the names. */\n update(values: number[][]): void {\n this.setOptions({ values });\n }\n}\n","import type { CounterClockOptions, OHLCBar, Theme } from '@tradecanvas/commons';\nimport { computeCounterClockLayout, counterClockPhase, counterClockPoints, nearestCounterClockPoint, renderCounterClock, shownCount, type CounterClockLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/**\n * Counter-clock chart: average price against average volume, bar by bar, with\n * no time axis. A healthy cycle turns counter-clockwise: volume picks up,\n * price follows, volume fades, price follows it down.\n */\nexport class CounterClockChart extends InteractiveChart<CounterClockOptions, CounterClockLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): CounterClockLayout {\n return computeCounterClockLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: CounterClockLayout): void {\n renderCounterClock(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n return `Counter-clock chart of price against volume, ${this.options.period ?? 25}-bar averages`;\n }\n\n protected clickable(): boolean {\n return this.options.onPointClick !== undefined;\n }\n\n protected hits(layout: CounterClockLayout, x: number, y: number): boolean {\n return nearestCounterClockPoint(layout, x, y) !== null;\n }\n\n protected clickAt(layout: CounterClockLayout, x: number, y: number): void {\n const hit = nearestCounterClockPoint(layout, x, y);\n if (hit) this.options.onPointClick?.(hit.point);\n }\n\n /** The phase of the newest move, 1–8 counter-clockwise from volume rising (see `counterClockPhase`), or null. */\n getPhase(): number | null {\n return counterClockPhase(counterClockPoints(this.options.data, this.options.period ?? 25, shownCount(this.options)));\n }\n\n update(data: OHLCBar[]): void {\n this.setOptions({ data });\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/**\n * Subset of analytics RiskMetrics needed to render the stats strip. The\n * percentages are fractions, as @tradecanvas/analytics returns them: a\n * totalReturnPct of 0.12 shows as +12.00%.\n */\nexport interface RiskMetricsLike {\n /** Total return as a fraction: 0.12 is +12%. */\n totalReturnPct: number;\n /** Compound annual growth rate as a fraction. */\n cagr: number;\n sharpe: number;\n sortino: number;\n /**\n * The deepest fall from a running peak, as a fraction: 0.5 is 50%. Either\n * sign reads as a fall, since some callers sign their drawdowns.\n */\n maxDrawdownPct: number;\n /** Share of winning trades as a fraction. */\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\n/** Metrics arrive as fractions (0.12); the cards show percent (12.00%). */\nconst PERCENT = 100;\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/**\n * The headline stats rendered as cards above the charts. The drawdown is a\n * fall, so it reads with a minus sign whichever sign it arrives with, as the\n * Drawdown panel below plots it.\n */\nexport function selectKeyStats(metrics: RiskMetricsLike): DashboardStat[] {\n return [\n { label: 'Total Return', value: pct(metrics.totalReturnPct * PERCENT), tone: tone(metrics.totalReturnPct) },\n { label: 'CAGR', value: pct(metrics.cagr * PERCENT), 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(-Math.abs(metrics.maxDrawdownPct) * PERCENT), tone: 'negative' },\n { label: 'Win Rate', value: `${(metrics.winRate * PERCENT).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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"}
@@ -2,14 +2,20 @@ import { DataSeries, TimeFrame } from '@tradecanvas/commons';
2
2
  export interface ResampleOptions {
3
3
  /** 0 = Sunday, 1 = Monday (default) — anchor for weekly buckets. */
4
4
  weekStartsOn?: 0 | 1;
5
+ /**
6
+ * The exchange's zone (an IANA name): days, weeks, months and the hour
7
+ * frames that divide a day start at its midnight. Left out, UTC's.
8
+ */
9
+ timeZone?: string;
5
10
  }
6
11
  /**
7
12
  * Aggregate a finer OHLCV series into a coarser timeframe.
8
13
  *
9
- * Bars are grouped by calendar-aware bucket (see `timeframeBucketStart`):
10
- * open = first bar's open, high/low = extremes, close = last bar's close,
11
- * volume = sum. Input bars are assumed sorted ascending by `time` and are
12
- * never mutated.
14
+ * Bars are grouped by calendar-aware bucket (see `resampleBars` and
15
+ * `timeframeBucketStart`): open = first bar's open, high/low = extremes,
16
+ * close = last bar's close, volume = sum. Daily bars stamped at 00:00 UTC
17
+ * keep the dates they name. Input bars are assumed sorted ascending by
18
+ * `time` and are never mutated.
13
19
  *
14
20
  * Upsampling (target finer than source) cannot synthesize data — pass a target
15
21
  * coarser than the source. Use `inferTimeframeMs` to detect the source spacing.
@@ -1 +1 @@
1
- {"version":3,"file":"resampleOHLCV.d.ts","sourceRoot":"","sources":["../../src/io/resampleOHLCV.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAW,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAG3E,MAAM,WAAW,eAAe;IAC9B,oEAAoE;IACpE,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;CACtB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,SAAS,EACjB,IAAI,GAAE,eAAoB,GACzB,UAAU,CAkCZ;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAUzD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAGxE"}
1
+ {"version":3,"file":"resampleOHLCV.d.ts","sourceRoot":"","sources":["../../src/io/resampleOHLCV.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGlE,MAAM,WAAW,eAAe;IAC9B,oEAAoE;IACpE,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,SAAS,EACjB,IAAI,GAAE,eAAoB,GACzB,UAAU,CAEZ;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAUzD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAGxE"}
@@ -0,0 +1,52 @@
1
+ import { DataSeries, OHLCBar, ReplayStepsLoadPayload, TimeFrame } from '@tradecanvas/commons';
2
+ /** Finer bars ending before `before`, at most `limit` of them (a feed's page back). */
3
+ export type FinerSource = (before: number, limit: number) => Promise<DataSeries>;
4
+ /** Finer bars asked for in one request: the resampler's page and most venues' cap. */
5
+ export declare const REPLAY_PAGE_STEPS = 1000;
6
+ /** The least time between two requests (ms): at most two a second, kind to a venue's rate limit. */
7
+ export declare const MIN_REPLAY_ASK_GAP_MS = 500;
8
+ export interface ReplayStepLoaderOptions {
9
+ /** Where the finer bars come from; null when the feed can't page back. */
10
+ source: FinerSource | null;
11
+ step: TimeFrame;
12
+ /** Finer bars in one bar of the chart. */
13
+ ratio: number;
14
+ /** How long one bar of the chart is (ms), for the end of the last one. */
15
+ barMs: number;
16
+ /** The finer bars of the hours the chart shows. */
17
+ keep: (bars: DataSeries) => DataSeries;
18
+ report: (payload: ReplayStepsLoadPayload) => void;
19
+ now?: () => number;
20
+ }
21
+ /**
22
+ * The finer bars that shape a replay's bars as they form, fetched a page at
23
+ * a time for the bars it is about to play and kept by bar time, so a series
24
+ * rebuilt under the replay keeps them. A bar gets them only when its page
25
+ * reached back to its start; one request at a time; pages that land after
26
+ * `dispose()` are dropped (a feed can't be told to stop).
27
+ */
28
+ export declare class ReplayStepLoader {
29
+ private readonly options;
30
+ private readonly pieces;
31
+ /** Bars a page was asked for: not asked again until they are left behind. */
32
+ private readonly asked;
33
+ private inFlight;
34
+ private lastAsk;
35
+ /** No more pages: the feed failed, can't page back, or the replay went. */
36
+ private done;
37
+ private readonly now;
38
+ constructor(options: ReplayStepLoaderOptions);
39
+ /** The finer bars of the bar opening at `time`, when they are in. */
40
+ piecesOf(time: number): readonly OHLCBar[] | undefined;
41
+ /** Have the finer bars of `coarse[from]` and the `ahead` bars after it on their way. */
42
+ ensure(coarse: DataSeries, from: number, ahead: number): void;
43
+ /** Forget the bars before `time`: the replay is past them (a seek back asks again). */
44
+ evictBefore(time: number): void;
45
+ dispose(): void;
46
+ /** One page: the bars from `coarse[a]` that `REPLAY_PAGE_STEPS` finer ones cover, backward from the end of the last. */
47
+ private ask;
48
+ /** A page in: each of `bars` its finer bars, when the page reached back to its start. */
49
+ private take;
50
+ private finish;
51
+ }
52
+ //# sourceMappingURL=ReplayStepLoader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReplayStepLoader.d.ts","sourceRoot":"","sources":["../../src/replay/ReplayStepLoader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,sBAAsB,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEnG,uFAAuF;AACvF,MAAM,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AAEjF,sFAAsF;AACtF,eAAO,MAAM,iBAAiB,OAAO,CAAC;AACtC,oGAAoG;AACpG,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC,MAAM,WAAW,uBAAuB;IACtC,0EAA0E;IAC1E,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,SAAS,CAAC;IAChB,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,IAAI,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,UAAU,CAAC;IACvC,MAAM,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,IAAI,CAAC;IAClD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,qBAAa,gBAAgB;IAUf,OAAO,CAAC,QAAQ,CAAC,OAAO;IATpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IACvD,6EAA6E;IAC7E,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqB;IAC3C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAa;IAC5B,2EAA2E;IAC3E,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;gBAEN,OAAO,EAAE,uBAAuB;IAI7D,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,OAAO,EAAE,GAAG,SAAS;IAItD,wFAAwF;IACxF,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAgB7D,uFAAuF;IACvF,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK/B,OAAO,IAAI,IAAI;IAIf,wHAAwH;IACxH,OAAO,CAAC,GAAG;IAmBX,yFAAyF;IACzF,OAAO,CAAC,IAAI;IAyBZ,OAAO,CAAC,MAAM;CAIf"}
@@ -0,0 +1,44 @@
1
+ import { OHLCBar } from '@tradecanvas/commons';
2
+ /**
3
+ * How one bar of the chart forms in a replay. The bar walks a path of
4
+ * prices: from its finer bars when they are loaded, else from the bar itself
5
+ * (open, the extreme its direction says came first, the other, close). The
6
+ * replay's position is a bar and a fraction of it, so finer bars that land
7
+ * late change how the next bars form, never which bar is which.
8
+ */
9
+ export interface PathPoint {
10
+ price: number;
11
+ /** When it traded, as far as the bars tell: the finer bar's time. */
12
+ time: number;
13
+ /** How far into the bar (0..1) the replay is when it reaches this point. */
14
+ at: number;
15
+ }
16
+ export interface IntrabarPath {
17
+ bar: OHLCBar;
18
+ points: PathPoint[];
19
+ /** Volume traded by the end of each finer piece, scaled to the bar's own volume. */
20
+ volumeAt: {
21
+ at: number;
22
+ volume: number;
23
+ }[];
24
+ }
25
+ /**
26
+ * The path bar `bar` takes, from `finer` (its finer bars, sorted, all inside
27
+ * it) or from itself (also when they trade somewhere else). Each finer bar takes an equal share of the bar's time,
28
+ * and inside it the price moves at an even pace. The path is made to agree
29
+ * with `bar`: it starts at its open, ends at its close and reaches its high
30
+ * and low, so the last frame is the bar as the series has it (venues differ
31
+ * between intervals: auction closes, trades missing from the minutes).
32
+ */
33
+ export declare function intrabarPath(bar: OHLCBar, finer?: readonly OHLCBar[]): IntrabarPath;
34
+ /** The bar as it stands `fraction` of the way through it (clamped; NaN is its start). */
35
+ export declare function formingAt(path: IntrabarPath, fraction: number): OHLCBar;
36
+ /**
37
+ * Where reduced motion shows the bar `fraction` of the way through it: at
38
+ * the last point of the path reached by then, so the price steps from one
39
+ * point to the next without sliding between them.
40
+ */
41
+ export declare function pathStop(path: IntrabarPath, fraction: number): number;
42
+ /** The prices passed after `from` up to `to`, with their times, then where it is at `to` (for a paper account). */
43
+ export declare function pathMarks(path: IntrabarPath, from: number, to: number): [number, number][];
44
+ //# sourceMappingURL=intrabarPath.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intrabarPath.d.ts","sourceRoot":"","sources":["../../src/replay/intrabarPath.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,oFAAoF;IACpF,QAAQ,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC5C;AA0CD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,GAAE,SAAS,OAAO,EAAO,GAAG,YAAY,CAWvF;AAqDD,yFAAyF;AACzF,wBAAgB,SAAS,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAYvE;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQrE;AAED,mHAAmH;AACnH,wBAAgB,SAAS,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAW1F"}
@@ -0,0 +1,18 @@
1
+ import { TimeFrame } from '@tradecanvas/commons';
2
+ /** Finer intervals a replay may step through (those dividing the chart's interval are offered). */
3
+ export declare const REPLAY_STEP_CANDIDATES: readonly TimeFrame[];
4
+ /**
5
+ * The most finer bars `'auto'` puts in one bar of the chart. At a bar a
6
+ * second a bar lasts about 60 frames, so finer ones add nothing to see; it
7
+ * also keeps a page of 1,000 to 16 hourly bars.
8
+ */
9
+ export declare const MAX_STEPS_PER_BAR = 60;
10
+ /** Finer intervals than `chart` that divide it and that `has` (the feed serves, or the bars loaded build), finest first. */
11
+ export declare function replayStepChoices(chart: TimeFrame, has: (tf: TimeFrame) => boolean): TimeFrame[];
12
+ /**
13
+ * The interval of the finer bars for a replay of a `chart` chart: `'auto'`
14
+ * is the finest of the choices with at most MAX_STEPS_PER_BAR to a bar; an
15
+ * interval given is taken when it is one of them. Null when there is none.
16
+ */
17
+ export declare function resolveReplayStep(step: TimeFrame | 'auto', chart: TimeFrame, has: (tf: TimeFrame) => boolean): TimeFrame | null;
18
+ //# sourceMappingURL=replayStep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replayStep.d.ts","sourceRoot":"","sources":["../../src/replay/replayStep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGtD,mGAAmG;AACnG,eAAO,MAAM,sBAAsB,EAAE,SAAS,SAAS,EAA6D,CAAC;AAErH;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAEpC,4HAA4H;AAC5H,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,OAAO,GAAG,SAAS,EAAE,CAOhG;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,OAAO,GAAG,SAAS,GAAG,IAAI,CAK/H"}