@tradecanvas/core 0.8.2 → 0.9.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 (33) hide show
  1. package/dist/axis/PriceAxis.d.ts.map +1 -1
  2. package/dist/axis/TimeAxis.d.ts.map +1 -1
  3. package/dist/charts/VolumeProfileRenderer.d.ts +36 -0
  4. package/dist/charts/VolumeProfileRenderer.d.ts.map +1 -0
  5. package/dist/charts/index.d.ts +1 -0
  6. package/dist/charts/index.d.ts.map +1 -1
  7. package/dist/engine/RenderEngine.d.ts +2 -0
  8. package/dist/engine/RenderEngine.d.ts.map +1 -1
  9. package/dist/features/MeasureOverlay.d.ts +27 -0
  10. package/dist/features/MeasureOverlay.d.ts.map +1 -0
  11. package/dist/features/ReplayManager.d.ts +5 -0
  12. package/dist/features/ReplayManager.d.ts.map +1 -1
  13. package/dist/features/index.d.ts +1 -0
  14. package/dist/features/index.d.ts.map +1 -1
  15. package/dist/index.cjs +8 -3
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.js +821 -389
  18. package/dist/index.js.map +1 -1
  19. package/dist/interaction/AxisDragHandler.d.ts +32 -0
  20. package/dist/interaction/AxisDragHandler.d.ts.map +1 -0
  21. package/dist/interaction/CrosshairHandler.d.ts +9 -0
  22. package/dist/interaction/CrosshairHandler.d.ts.map +1 -1
  23. package/dist/interaction/InteractionManager.d.ts +32 -1
  24. package/dist/interaction/InteractionManager.d.ts.map +1 -1
  25. package/dist/interaction/PinnedTooltip.d.ts +39 -0
  26. package/dist/interaction/PinnedTooltip.d.ts.map +1 -0
  27. package/dist/interaction/index.d.ts +2 -0
  28. package/dist/interaction/index.d.ts.map +1 -1
  29. package/dist/ui/SessionBreaks.d.ts +7 -2
  30. package/dist/ui/SessionBreaks.d.ts.map +1 -1
  31. package/dist/viewport/Viewport.d.ts +6 -0
  32. package/dist/viewport/Viewport.d.ts.map +1 -1
  33. package/package.json +2 -2
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/engine/CanvasLayer.ts","../src/engine/LayerManager.ts","../src/engine/RenderLoop.ts","../src/engine/DPRManager.ts","../src/viewport/ScaleMapping.ts","../src/engine/RenderEngine.ts","../src/viewport/Viewport.ts","../src/viewport/DataWindow.ts","../src/charts/CandlestickRenderer.ts","../src/charts/LineRenderer.ts","../src/charts/AreaRenderer.ts","../src/charts/BarRenderer.ts","../src/charts/HollowCandleRenderer.ts","../src/charts/BaselineRenderer.ts","../src/charts/RenkoRenderer.ts","../src/charts/KagiRenderer.ts","../src/charts/PointAndFigureRenderer.ts","../src/charts/VolumeCandleRenderer.ts","../src/charts/EquivolumeRenderer.ts","../src/charts/HLCAreaRenderer.ts","../src/charts/StepLineRenderer.ts","../src/charts/LineWithMarkersRenderer.ts","../src/charts/VolumeRenderer.ts","../src/charts/CompareRenderer.ts","../src/charts/transforms/heikinAshi.ts","../src/charts/transforms/renko.ts","../src/charts/transforms/lineBreak.ts","../src/charts/transforms/kagi.ts","../src/charts/transforms/pointAndFigure.ts","../src/charts/transforms/rangeBars.ts","../src/indicators/IndicatorBase.ts","../src/indicators/IndicatorEngine.ts","../src/indicators/params.ts","../src/indicators/overlay/SMA.ts","../src/indicators/overlay/EMA.ts","../src/indicators/overlay/BollingerBands.ts","../src/indicators/overlay/VWAP.ts","../src/indicators/overlay/Ichimoku.ts","../src/indicators/overlay/ParabolicSAR.ts","../src/indicators/overlay/Supertrend.ts","../src/indicators/overlay/KeltnerChannel.ts","../src/indicators/overlay/DonchianChannel.ts","../src/indicators/overlay/PivotPoints.ts","../src/indicators/overlay/AnchoredVWAP.ts","../src/indicators/overlay/ZigZag.ts","../src/indicators/overlay/LinearRegressionChannel.ts","../src/indicators/overlay/HullMA.ts","../src/indicators/panel/AwesomeOscillator.ts","../src/indicators/panel/ChaikinOscillator.ts","../src/indicators/panel/RSI.ts","../src/indicators/panel/MACD.ts","../src/indicators/panel/Stochastic.ts","../src/indicators/panel/ATR.ts","../src/indicators/panel/ADX.ts","../src/indicators/panel/OBV.ts","../src/indicators/panel/WilliamsR.ts","../src/indicators/panel/CCI.ts","../src/indicators/panel/MFI.ts","../src/indicators/panel/Aroon.ts","../src/indicators/panel/ROC.ts","../src/indicators/panel/TSI.ts","../src/indicators/panel/CMF.ts","../src/indicators/panel/StdDev.ts","../src/indicators/panel/VolumeProfile.ts","../src/indicators/panel/AccumulationDistribution.ts","../src/indicators/panel/VROC.ts","../src/indicators/registry.ts","../src/indicators/worker/messages.ts","../src/indicators/worker/IndicatorWorkerHost.ts","../src/axis/GridRenderer.ts","../src/axis/PriceAxis.ts","../src/axis/TimeAxis.ts","../src/interaction/InteractionManager.ts","../src/interaction/PanHandler.ts","../src/interaction/ZoomHandler.ts","../src/interaction/CrosshairHandler.ts","../src/interaction/KeyboardHandler.ts","../src/interaction/CrosshairTooltip.ts","../src/events/EventBus.ts","../src/drawings/DrawingBase.ts","../src/drawings/DrawingManager.ts","../src/drawings/DrawingRenderer.ts","../src/drawings/tools/TrendLine.ts","../src/drawings/tools/HorizontalLine.ts","../src/drawings/tools/VerticalLine.ts","../src/drawings/tools/Ray.ts","../src/drawings/tools/ExtendedLine.ts","../src/drawings/tools/ParallelChannel.ts","../src/drawings/tools/RegressionChannel.ts","../src/drawings/tools/FibRetracement.ts","../src/drawings/tools/FibExtension.ts","../src/drawings/tools/Rectangle.ts","../src/drawings/tools/Ellipse.ts","../src/drawings/tools/Triangle.ts","../src/drawings/tools/Pitchfork.ts","../src/drawings/tools/ElliottWave.ts","../src/drawings/tools/PriceRange.ts","../src/drawings/tools/DateRange.ts","../src/drawings/tools/Measure.ts","../src/drawings/tools/TextAnnotation.ts","../src/drawings/tools/Arrow.ts","../src/drawings/tools/GannFan.ts","../src/drawings/tools/GannBox.ts","../src/drawings/tools/AnchoredVWAP.ts","../src/drawings/tools/VolumeProfileRange.ts","../src/drawings/tools/FibTimeZones.ts","../src/drawings/tools/index.ts","../src/trading/OrderRenderer.ts","../src/trading/positionFormat.ts","../src/trading/PositionRenderer.ts","../src/trading/DepthOverlay.ts","../src/trading/TradingDragHandler.ts","../src/trading/TradingContextMenu.ts","../src/trading/TradingManager.ts","../src/trading/TradingRenderer.ts","../src/realtime/Emitter.ts","../src/realtime/TickAggregator.ts","../src/realtime/ReconnectManager.ts","../src/realtime/CurrentPriceLine.ts","../src/realtime/StreamManager.ts","../src/realtime/ReplayController.ts","../src/realtime/adapters/binanceTypes.ts","../src/realtime/adapters/BinanceAdapter.ts","../src/realtime/adapters/MockAdapter.ts","../src/ui/ChartLegend.ts","../src/ui/Screenshot.ts","../src/ui/Watermark.ts","../src/ui/BarCountdown.ts","../src/ui/SessionBreaks.ts","../src/features/AlertManager.ts","../src/features/ReplayManager.ts","../src/features/ChartState.ts","../src/features/UndoRedoManager.ts","../src/features/DataExporter.ts","../src/features/SignalMarkerManager.ts","../src/features/TradeZoneManager.ts","../src/animation/Animator.ts","../src/finance/BaseFinanceChart.ts","../src/finance/FinanceCrosshair.ts","../src/finance/SparklineRenderer.ts","../src/finance/DepthChartRenderer.ts","../src/finance/EquityCurveRenderer.ts","../src/finance/HeatmapLayout.ts","../src/finance/HeatmapRenderer.ts","../src/finance/WaterfallRenderer.ts","../src/finance/GaugeRenderer.ts"],"sourcesContent":["import type { Size } from '@tradecanvas/commons';\n\nexport class CanvasLayer {\n readonly canvas: HTMLCanvasElement;\n readonly ctx: CanvasRenderingContext2D;\n private dpr = 1;\n\n constructor(\n container: HTMLElement,\n zIndex: number,\n ) {\n this.canvas = document.createElement('canvas');\n this.canvas.style.position = 'absolute';\n this.canvas.style.top = '0';\n this.canvas.style.left = '0';\n this.canvas.style.zIndex = String(zIndex);\n this.canvas.style.pointerEvents = 'none';\n this.ctx = this.canvas.getContext('2d')!;\n container.appendChild(this.canvas);\n }\n\n resize(size: Size, dpr: number): void {\n this.dpr = dpr;\n const w = Math.round(size.width * dpr);\n const h = Math.round(size.height * dpr);\n // Only resize if dimensions changed (avoids unnecessary canvas clear)\n if (this.canvas.width !== w || this.canvas.height !== h) {\n this.canvas.width = w;\n this.canvas.height = h;\n }\n this.canvas.style.width = `${size.width}px`;\n this.canvas.style.height = `${size.height}px`;\n this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n }\n\n clear(): void {\n // Reset to identity, clear physical pixels, restore DPR transform\n this.ctx.setTransform(1, 0, 0, 1, 0, 0);\n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n this.ctx.setTransform(this.dpr, 0, 0, this.dpr, 0, 0);\n }\n\n getSize(): Size {\n return {\n width: this.canvas.width / this.dpr,\n height: this.canvas.height / this.dpr,\n };\n }\n\n destroy(): void {\n this.canvas.remove();\n }\n}\n","import type { Size } from '@tradecanvas/commons';\nimport { LayerType } from '@tradecanvas/commons';\nimport { CanvasLayer } from './CanvasLayer.js';\n\nexport class LayerManager {\n private layers = new Map<LayerType, CanvasLayer>();\n\n constructor(private container: HTMLElement) {}\n\n createLayers(): void {\n // Destroy any existing layers first to prevent duplicates\n this.destroy();\n\n for (const type of [\n LayerType.Background,\n LayerType.Main,\n LayerType.Overlay,\n LayerType.UI,\n ]) {\n this.layers.set(type, new CanvasLayer(this.container, type));\n }\n }\n\n getLayer(type: LayerType): CanvasLayer | undefined {\n return this.layers.get(type);\n }\n\n resize(size: Size, dpr: number): void {\n for (const layer of this.layers.values()) {\n layer.resize(size, dpr);\n }\n }\n\n destroy(): void {\n for (const layer of this.layers.values()) {\n layer.destroy();\n }\n this.layers.clear();\n }\n}\n","import { LayerType } from '@tradecanvas/commons';\n\nexport type RenderCallback = (dirtyLayers: ReadonlySet<LayerType>) => void;\n\nexport class RenderLoop {\n private animFrameId = 0;\n private running = false;\n private dirtyLayers = new Set<LayerType>();\n // Swap set — avoids allocation per frame\n private swapLayers = new Set<LayerType>();\n private callback: RenderCallback | null = null;\n\n setCallback(cb: RenderCallback): void {\n this.callback = cb;\n }\n\n markDirty(layer: LayerType): void {\n this.dirtyLayers.add(layer);\n if (this.running && !this.animFrameId) {\n this.scheduleFrame();\n }\n }\n\n markAllDirty(): void {\n this.dirtyLayers.add(LayerType.Background);\n this.dirtyLayers.add(LayerType.Main);\n this.dirtyLayers.add(LayerType.Overlay);\n this.dirtyLayers.add(LayerType.UI);\n if (this.running && !this.animFrameId) {\n this.scheduleFrame();\n }\n }\n\n start(): void {\n this.running = true;\n this.markAllDirty();\n }\n\n stop(): void {\n this.running = false;\n if (this.animFrameId) {\n cancelAnimationFrame(this.animFrameId);\n this.animFrameId = 0;\n }\n }\n\n private scheduleFrame(): void {\n this.animFrameId = requestAnimationFrame(() => {\n this.animFrameId = 0;\n if (!this.running || !this.callback) return;\n if (this.dirtyLayers.size > 0) {\n // Swap sets to avoid allocation — pass current dirty set, clear it via swap\n const toRender = this.dirtyLayers;\n this.dirtyLayers = this.swapLayers;\n this.callback(toRender);\n toRender.clear();\n this.swapLayers = toRender;\n }\n });\n }\n}\n","import type { Size } from '@tradecanvas/commons';\n\nexport type ResizeCallback = (size: Size, dpr: number) => void;\n\nexport class DPRManager {\n private observer: ResizeObserver | null = null;\n private callback: ResizeCallback | null = null;\n private currentDpr = 1;\n private resizeScheduled = false;\n private cachedSize: Size;\n\n constructor(private container: HTMLElement) {\n this.currentDpr = window.devicePixelRatio || 1;\n this.cachedSize = { width: container.clientWidth, height: container.clientHeight };\n }\n\n getDpr(): number {\n return this.currentDpr;\n }\n\n getContainerSize(): Size {\n return this.cachedSize;\n }\n\n /** Read live container size (bypasses cache). Use when externally triggered. */\n readContainerSize(): Size {\n const w = this.container.clientWidth;\n const h = this.container.clientHeight;\n if (w !== this.cachedSize.width || h !== this.cachedSize.height) {\n this.cachedSize = { width: w, height: h };\n }\n return this.cachedSize;\n }\n\n onResize(cb: ResizeCallback): void {\n this.callback = cb;\n this.observer = new ResizeObserver(() => {\n // Debounce via rAF — collapse multiple resize events into one per frame\n if (this.resizeScheduled) return;\n this.resizeScheduled = true;\n requestAnimationFrame(() => {\n this.resizeScheduled = false;\n this.currentDpr = window.devicePixelRatio || 1;\n const newW = this.container.clientWidth;\n const newH = this.container.clientHeight;\n // Skip if size hasn't actually changed\n if (newW === this.cachedSize.width && newH === this.cachedSize.height) return;\n this.cachedSize = { width: newW, height: newH };\n this.callback?.(this.cachedSize, this.currentDpr);\n });\n });\n this.observer.observe(this.container);\n }\n\n destroy(): void {\n this.observer?.disconnect();\n this.observer = null;\n this.callback = null;\n }\n}\n","import type { ViewportState } from '@tradecanvas/commons';\n\nexport function barIndexToX(index: number, viewport: ViewportState): number {\n const barUnit = viewport.barWidth + viewport.barSpacing;\n return index * barUnit - viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n}\n\nexport function priceToY(price: number, viewport: ViewportState): number {\n const { min, max } = viewport.priceRange;\n if (viewport.logScale && min > 0 && max > 0) {\n const logMin = Math.log(min);\n const logMax = Math.log(max);\n const logRange = logMax - logMin;\n if (logRange === 0) return viewport.chartRect.y + viewport.chartRect.height / 2;\n const ratio = (Math.log(Math.max(price, Number.EPSILON)) - logMin) / logRange;\n return viewport.chartRect.y + viewport.chartRect.height * (1 - ratio);\n }\n const range = max - min;\n if (range === 0) return viewport.chartRect.y + viewport.chartRect.height / 2;\n const ratio = (price - min) / range;\n return viewport.chartRect.y + viewport.chartRect.height * (1 - ratio);\n}\n\nexport function xToBarIndex(x: number, viewport: ViewportState): number {\n const barUnit = viewport.barWidth + viewport.barSpacing;\n return Math.round((x - viewport.chartRect.x - viewport.barWidth / 2 + viewport.offset) / barUnit);\n}\n\nexport function yToPrice(y: number, viewport: ViewportState): number {\n const { min, max } = viewport.priceRange;\n const ratio = 1 - (y - viewport.chartRect.y) / viewport.chartRect.height;\n if (viewport.logScale && min > 0 && max > 0) {\n const logMin = Math.log(min);\n const logMax = Math.log(max);\n return Math.exp(logMin + (logMax - logMin) * ratio);\n }\n return min + (max - min) * ratio;\n}\n\n/**\n * Convert a bar timestamp to its data-array index via binary search.\n * Falls back to fractional interpolation when the timestamp falls between bars.\n * Returns -1 if data is empty.\n */\nexport function timestampToBarIndex(timestamp: number, data: ReadonlyArray<{ time: number }>): number {\n if (data.length === 0) return -1;\n // Fast path: exact match at boundaries\n if (timestamp <= data[0].time) return 0;\n if (timestamp >= data[data.length - 1].time) return data.length - 1;\n // Binary search\n let lo = 0, hi = data.length - 1;\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n if (data[mid].time === timestamp) return mid;\n if (data[mid].time < timestamp) lo = mid + 1;\n else hi = mid - 1;\n }\n // lo is the insertion point; interpolate between hi and lo\n if (lo >= data.length) return data.length - 1;\n if (hi < 0) return 0;\n const tLo = data[hi].time, tHi = data[lo].time;\n const frac = tHi !== tLo ? (timestamp - tLo) / (tHi - tLo) : 0;\n return hi + frac;\n}\n\n/**\n * Resolve an anchor `time` value to a (possibly fractional) bar index in the\n * current series. When `viewport.data` is set, `time` is interpreted as a real\n * timestamp and converted via `timestampToBarIndex`. Otherwise `time` is\n * already a bar index and is returned unchanged.\n */\nexport function resolveBarIndex(time: number, viewport: ViewportState): number {\n const data = viewport.data;\n if (data && data.length > 0) {\n return timestampToBarIndex(time, data);\n }\n return time;\n}\n\n/**\n * Map an anchor `time` value to its pixel x. Works whether `time` is a\n * timestamp (when `viewport.data` is set) or a bar index (legacy callers).\n */\nexport function timeToX(time: number, viewport: ViewportState): number {\n return barIndexToX(resolveBarIndex(time, viewport), viewport);\n}\n\n/**\n * Map a pixel x back to an anchor `time` value. Returns a real timestamp when\n * `viewport.data` is set (so the value survives timeframe switches), otherwise\n * returns a bar index for legacy callers.\n */\nexport function xToTime(x: number, viewport: ViewportState): number {\n const idx = xToBarIndex(x, viewport);\n const data = viewport.data;\n if (data && data.length > 0) {\n const clamped = Math.max(0, Math.min(data.length - 1, idx));\n return data[clamped].time;\n }\n return idx;\n}\n","import { LayerType } from '@tradecanvas/commons';\nimport type { Size, ViewportState, Theme, DataSeries, Rect } from '@tradecanvas/commons';\nimport { priceToY, yToPrice, xToBarIndex, barIndexToX } from '../viewport/ScaleMapping.js';\nimport { PRICE_AXIS_WIDTH, computeTickStep, formatPrice } from '@tradecanvas/commons';\nimport { LayerManager } from './LayerManager.js';\nimport { RenderLoop } from './RenderLoop.js';\nimport { DPRManager } from './DPRManager.js';\nimport type { CanvasLayer } from './CanvasLayer.js';\nimport type { ChartRendererInterface } from '../charts/ChartRenderer.js';\nimport type { GridRenderer } from '../axis/GridRenderer.js';\nimport type { PriceAxis } from '../axis/PriceAxis.js';\nimport type { TimeAxis } from '../axis/TimeAxis.js';\nimport type { CrosshairHandler } from '../interaction/CrosshairHandler.js';\nimport type { IndicatorEngine } from '../indicators/IndicatorEngine.js';\nimport type { DrawingRenderer } from '../drawings/DrawingRenderer.js';\nimport type { TradingRenderer } from '../trading/TradingRenderer.js';\nimport type { CurrentPriceLine } from '../realtime/CurrentPriceLine.js';\nimport type { ChartLegend } from '../ui/ChartLegend.js';\nimport type { Watermark } from '../ui/Watermark.js';\nimport type { BarCountdown } from '../ui/BarCountdown.js';\nimport type { SessionBreaks } from '../ui/SessionBreaks.js';\nimport type { VolumeRenderer } from '../charts/VolumeRenderer.js';\nimport type { CompareRenderer } from '../charts/CompareRenderer.js';\nimport type { AlertManager } from '../features/AlertManager.js';\nimport type { SignalMarkerManager } from '../features/SignalMarkerManager.js';\nimport type { TradeZoneManager } from '../features/TradeZoneManager.js';\n\nexport interface PanelRenderInfo {\n instanceId: string;\n rect: Rect;\n viewport: ViewportState;\n}\n\nexport interface RenderContext {\n chartRenderer: ChartRendererInterface | null;\n gridRenderer: GridRenderer | null;\n priceAxis: PriceAxis | null;\n timeAxis: TimeAxis | null;\n crosshairHandler: CrosshairHandler | null;\n indicatorEngine: IndicatorEngine | null;\n drawingRenderer: DrawingRenderer | null;\n tradingRenderer: TradingRenderer | null;\n currentPriceLine: CurrentPriceLine | null;\n chartLegend: ChartLegend | null;\n volumeRenderer: VolumeRenderer | null;\n watermark: Watermark | null;\n barCountdown: BarCountdown | null;\n sessionBreaks: SessionBreaks | null;\n compareRenderer: CompareRenderer | null;\n alertManager: AlertManager | null;\n signalMarkerManager: SignalMarkerManager | null;\n tradeZoneManager: TradeZoneManager | null;\n panels: PanelRenderInfo[];\n priceLimits?: { ceiling: number; floor: number; reference: number; colors?: { ceiling?: string; floor?: string; reference?: string } } | null;\n timeAxisY?: number;\n viewport: ViewportState;\n theme: Theme;\n data: DataSeries;\n /** BCP 47 locale for number formatting. Defaults to 'en-US' when not set. */\n numberLocale?: string;\n}\n\nexport class RenderEngine {\n readonly layerManager: LayerManager;\n readonly renderLoop: RenderLoop;\n readonly dprManager: DPRManager;\n private renderCtx: RenderContext | null = null;\n\n // Cached layer references — avoid Map lookup per frame\n private bgLayer: CanvasLayer | undefined;\n private mainLayer: CanvasLayer | undefined;\n private overlayLayer: CanvasLayer | undefined;\n private uiLayer: CanvasLayer | undefined;\n\n /**\n * Optional hook fired AFTER the canvas layers have been resized in\n * response to a container resize. The Chart class uses this to push the\n * new dimensions into its viewport + layout manager — without it, the\n * viewport keeps a stale chartRect forever and `scrollToEnd` / panning\n * compute against the wrong width.\n */\n onContainerResize: ((size: Size) => void) | null = null;\n\n constructor(container: HTMLElement) {\n this.layerManager = new LayerManager(container);\n this.renderLoop = new RenderLoop();\n this.dprManager = new DPRManager(container);\n\n this.layerManager.createLayers();\n this.cacheLayerRefs();\n\n this.renderLoop.setCallback((dirtyLayers) => this.render(dirtyLayers));\n\n this.dprManager.onResize((size, dpr) => {\n this.layerManager.resize(size, dpr);\n this.renderLoop.markAllDirty();\n // Notify the Chart so it can update viewport.chartRect + layout.\n // Without this, container resizes leave the viewport's idea of width\n // stuck at whatever it was at construction time.\n this.onContainerResize?.(size);\n });\n\n const size = this.dprManager.getContainerSize();\n const dpr = this.dprManager.getDpr();\n this.layerManager.resize(size, dpr);\n }\n\n private cacheLayerRefs(): void {\n this.bgLayer = this.layerManager.getLayer(LayerType.Background);\n this.mainLayer = this.layerManager.getLayer(LayerType.Main);\n this.overlayLayer = this.layerManager.getLayer(LayerType.Overlay);\n this.uiLayer = this.layerManager.getLayer(LayerType.UI);\n }\n\n setRenderContext(ctx: RenderContext): void {\n this.renderCtx = ctx;\n }\n\n start(): void {\n this.renderLoop.start();\n }\n\n stop(): void {\n this.renderLoop.stop();\n }\n\n requestRender(layer?: LayerType): void {\n if (layer !== undefined) {\n this.renderLoop.markDirty(layer);\n } else {\n this.renderLoop.markAllDirty();\n }\n }\n\n private render(dirtyLayers: ReadonlySet<LayerType>): void {\n const ctx = this.renderCtx;\n if (!ctx) return;\n const { viewport, theme, data } = ctx;\n const locale = ctx.numberLocale ?? 'en-US';\n\n // Skip rendering if viewport has zero dimensions\n if (viewport.chartRect.width <= 0 || viewport.chartRect.height <= 0) return;\n\n if (dirtyLayers.has(LayerType.Background) && this.bgLayer) {\n this.bgLayer.clear();\n ctx.gridRenderer?.render(this.bgLayer.ctx, viewport, theme);\n ctx.sessionBreaks?.render(this.bgLayer.ctx, viewport, theme, data);\n ctx.watermark?.render(this.bgLayer.ctx, viewport, theme);\n }\n\n if (dirtyLayers.has(LayerType.Main) && this.mainLayer) {\n this.mainLayer.clear();\n const c = this.mainLayer.ctx;\n\n // Clip main chart area\n c.save();\n c.beginPath();\n c.rect(viewport.chartRect.x, viewport.chartRect.y, viewport.chartRect.width, viewport.chartRect.height);\n c.clip();\n\n // Volume bars (drawn first, behind candles)\n ctx.volumeRenderer?.render(c, data, viewport, theme);\n ctx.chartRenderer?.render(c, data, viewport, theme);\n ctx.compareRenderer?.render(c, data, viewport, theme);\n ctx.indicatorEngine?.renderOverlays(c, viewport);\n\n c.restore();\n\n // Render panel indicators in their own clipped regions\n const panels = ctx.panels;\n const indicatorEngine = ctx.indicatorEngine;\n if (indicatorEngine && panels.length > 0) {\n // Cache font string once for all panels\n const panelFont = `10px ${theme.font.family}`;\n\n // Build descriptor lookup once per frame — avoids O(n*m) .find() per panel\n const panelDescs = indicatorEngine.getPanelIndicators();\n const descMap = new Map<string, typeof panelDescs[0]>();\n for (const d of panelDescs) descMap.set(d.instanceId, d);\n\n for (const panel of panels) {\n if (panel.rect.width <= 0 || panel.rect.height <= 0) continue;\n\n c.save();\n c.beginPath();\n c.rect(panel.rect.x, panel.rect.y, panel.rect.width, panel.rect.height);\n c.clip();\n\n const PANEL_HEADER_HEIGHT = 20;\n\n // Panel background\n c.fillStyle = theme.background;\n c.fillRect(panel.rect.x, panel.rect.y, panel.rect.width, panel.rect.height);\n\n // Thick divider bar at top of panel\n c.fillStyle = theme.axisLine;\n c.fillRect(panel.rect.x, panel.rect.y, panel.rect.width, 3);\n\n // Panel indicator name in header area\n c.fillStyle = theme.textSecondary;\n c.font = panelFont;\n c.textBaseline = 'top';\n c.textAlign = 'left';\n const desc = descMap.get(panel.instanceId);\n if (desc) {\n c.fillText(desc.descriptor.name, panel.rect.x + 6, panel.rect.y + 6);\n }\n\n // Clip indicator rendering to below the header\n c.save();\n c.beginPath();\n c.rect(panel.rect.x, panel.rect.y + PANEL_HEADER_HEIGHT, panel.rect.width, panel.rect.height - PANEL_HEADER_HEIGHT);\n c.clip();\n\n indicatorEngine.renderPanel(c, panel.instanceId, panel.viewport);\n\n c.restore();\n\n c.restore();\n }\n }\n }\n\n if (dirtyLayers.has(LayerType.Overlay) && this.overlayLayer) {\n this.overlayLayer.clear();\n const c = this.overlayLayer.ctx;\n\n // Price limit lines (ceiling/floor/reference)\n if (ctx.priceLimits) {\n this.renderPriceLimits(c, viewport, theme, ctx.priceLimits);\n }\n\n ctx.tradeZoneManager?.render(c, viewport, theme);\n ctx.drawingRenderer?.render(c, viewport);\n ctx.tradingRenderer?.render(c, viewport, theme);\n ctx.signalMarkerManager?.render(c, viewport, theme);\n ctx.alertManager?.render(c, viewport, theme);\n ctx.crosshairHandler?.render(c, viewport, theme);\n\n // Panel crosshair — draw crosshair lines in the hovered panel\n const cursorPos = ctx.crosshairHandler?.getPosition();\n if (cursorPos && ctx.panels.length > 0) {\n for (const panel of ctx.panels) {\n const pr = panel.rect;\n if (cursorPos.x >= pr.x && cursorPos.x <= pr.x + pr.width &&\n cursorPos.y >= pr.y && cursorPos.y <= pr.y + pr.height) {\n const pv = panel.viewport;\n // Vertical line (synced with main chart bar snapping)\n let cx = cursorPos.x;\n const barIdx = xToBarIndex(cx, pv);\n const snappedIdx = Math.max(0, Math.min((ctx.data?.length ?? 1) - 1, Math.round(barIdx)));\n cx = barIndexToX(snappedIdx, pv);\n\n c.save();\n c.beginPath();\n c.rect(pr.x, pr.y, pr.width, pr.height);\n c.clip();\n\n c.setLineDash([4, 4]);\n c.strokeStyle = theme.crosshair;\n c.lineWidth = 1;\n\n // Vertical\n c.beginPath();\n c.moveTo(Math.round(cx) + 0.5, pr.y);\n c.lineTo(Math.round(cx) + 0.5, pr.y + pr.height);\n c.stroke();\n\n // Horizontal\n c.beginPath();\n c.moveTo(pr.x, Math.round(cursorPos.y) + 0.5);\n c.lineTo(pr.x + pr.width, Math.round(cursorPos.y) + 0.5);\n c.stroke();\n\n c.setLineDash([]);\n c.restore();\n break;\n }\n }\n }\n }\n\n if (dirtyLayers.has(LayerType.UI) && this.uiLayer) {\n this.uiLayer.clear();\n const c = this.uiLayer.ctx;\n ctx.priceAxis?.render(c, viewport, theme);\n // Trading axis badges paint ON TOP of the regular price axis labels\n // so position entry prices and order trigger prices are always visible.\n ctx.tradingRenderer?.renderAxisBadges(c, viewport, theme);\n ctx.currentPriceLine?.render(c, viewport, theme);\n ctx.timeAxis?.render(c, viewport, theme, data, ctx.timeAxisY);\n ctx.chartLegend?.render(c, viewport, theme, data);\n ctx.barCountdown?.render(c, viewport, theme, data);\n\n // Panel Y-axis + crosshair value label + header values\n if (ctx.panels.length > 0) {\n const cursorPos2 = ctx.crosshairHandler?.getPosition();\n const indicatorEngine2 = ctx.indicatorEngine;\n const panelFont = `${theme.font.sizeSmall}px ${theme.font.family}`;\n\n // Build descriptor lookup once for UI layer panels\n let uiDescMap: Map<string, { instanceId: string; descriptor: any }> | undefined;\n if (indicatorEngine2) {\n const descs = indicatorEngine2.getPanelIndicators();\n uiDescMap = new Map();\n for (const d of descs) uiDescMap.set(d.instanceId, d);\n }\n\n for (const panel of ctx.panels) {\n const pv = panel.viewport;\n const pr = panel.rect;\n const { min, max } = pv.priceRange;\n const range = max - min;\n if (range <= 0 || pr.height <= 0) continue;\n\n const axisX = pr.x + pr.width;\n const insetRect = pv.chartRect; // already inset by header\n\n // --- Panel Y-axis ---\n // Axis line\n c.strokeStyle = theme.axisLine;\n c.lineWidth = 1;\n c.beginPath();\n c.moveTo(axisX + 0.5, pr.y);\n c.lineTo(axisX + 0.5, pr.y + pr.height);\n c.stroke();\n\n // Value labels\n const step = computeTickStep(min, max, 4);\n const firstVal = Math.ceil(min / step) * step;\n const precision = step < 1 ? Math.ceil(-Math.log10(step)) + 1 : step < 10 ? 1 : 0;\n\n c.font = panelFont;\n c.textBaseline = 'middle';\n c.textAlign = 'left';\n\n for (let val = firstVal; val <= max; val += step) {\n const y = priceToY(val, pv);\n if (y < insetRect.y || y > insetRect.y + insetRect.height) continue;\n // Tick mark\n c.strokeStyle = theme.axisLine;\n c.beginPath();\n c.moveTo(axisX, Math.round(y) + 0.5);\n c.lineTo(axisX + 4, Math.round(y) + 0.5);\n c.stroke();\n // Label\n c.fillStyle = theme.axisLabel;\n c.fillText(formatPrice(val, precision, locale), axisX + 6, y);\n }\n\n // --- Crosshair value badge on panel Y-axis ---\n if (cursorPos2 &&\n cursorPos2.x >= pr.x && cursorPos2.x <= pr.x + pr.width &&\n cursorPos2.y >= pr.y && cursorPos2.y <= pr.y + pr.height) {\n const hoverVal = yToPrice(cursorPos2.y, pv);\n const valText = formatPrice(hoverVal, precision, locale);\n c.font = `bold ${theme.font.sizeSmall}px ${theme.font.family}`;\n const tw = c.measureText(valText).width;\n const badgeW = Math.min(tw + 10, PRICE_AXIS_WIDTH - 2);\n\n c.fillStyle = theme.crosshair;\n c.fillRect(axisX + 1, cursorPos2.y - 9, badgeW, 18);\n c.fillStyle = theme.background;\n c.textBaseline = 'middle';\n c.textAlign = 'left';\n c.fillText(valText, axisX + 5, cursorPos2.y);\n }\n\n // --- Indicator values at crosshair bar in panel header ---\n if (cursorPos2 && indicatorEngine2) {\n const barIdx = xToBarIndex(cursorPos2.x, pv);\n const snappedIdx = Math.max(0, Math.min((data?.length ?? 1) - 1, Math.round(barIdx)));\n const output = indicatorEngine2.getOutput(panel.instanceId);\n if (output?.series && snappedIdx < output.series.length) {\n const val = output.series[snappedIdx];\n if (val) {\n const parts: string[] = [];\n for (const key in val) {\n const v = val[key];\n if (v !== undefined) parts.push(`${key}: ${v.toFixed(precision)}`);\n }\n if (parts.length > 0) {\n const desc = uiDescMap?.get(panel.instanceId);\n const nameWidth = desc ? c.measureText(desc.descriptor.name).width + 14 : 10;\n c.font = panelFont;\n c.fillStyle = theme.textSecondary;\n c.textBaseline = 'top';\n c.textAlign = 'left';\n c.fillText(parts.join(' '), pr.x + nameWidth, pr.y + 6);\n }\n }\n }\n }\n }\n }\n }\n }\n\n private renderPriceLimits(\n ctx: CanvasRenderingContext2D,\n viewport: ViewportState,\n theme: Theme,\n limits: NonNullable<RenderContext['priceLimits']>,\n ): void {\n const { chartRect } = viewport;\n const lines = [\n { price: limits.ceiling, color: limits.colors?.ceiling ?? '#FF00FF', label: 'CE' },\n { price: limits.floor, color: limits.colors?.floor ?? '#00FFFF', label: 'FL' },\n { price: limits.reference, color: limits.colors?.reference ?? '#FFD700', label: 'REF' },\n ];\n\n const boldFont = `bold 9px ${theme.font.family}`;\n const normalFont = `10px ${theme.font.family}`;\n\n for (const { price, color, label } of lines) {\n const y = priceToY(price, viewport);\n if (y < chartRect.y || y > chartRect.y + chartRect.height) continue;\n\n ctx.setLineDash([8, 4]);\n ctx.strokeStyle = color;\n ctx.lineWidth = 1;\n ctx.beginPath();\n ctx.moveTo(chartRect.x, Math.round(y) + 0.5);\n ctx.lineTo(chartRect.x + chartRect.width, Math.round(y) + 0.5);\n ctx.stroke();\n ctx.setLineDash([]);\n\n // Label\n ctx.font = boldFont;\n ctx.fillStyle = color;\n ctx.textBaseline = 'bottom';\n ctx.textAlign = 'left';\n ctx.fillText(`${label} ${price.toFixed(2)}`, chartRect.x + 4, y - 2);\n\n // Axis badge\n const axisX = chartRect.x + chartRect.width + 1;\n ctx.fillStyle = color;\n ctx.fillRect(axisX, y - 7, PRICE_AXIS_WIDTH - 2, 14);\n ctx.fillStyle = '#000';\n ctx.font = normalFont;\n ctx.textBaseline = 'middle';\n ctx.textAlign = 'left';\n ctx.fillText(price.toFixed(2), axisX + 4, y);\n }\n }\n\n destroy(): void {\n this.renderLoop.stop();\n this.dprManager.destroy();\n this.layerManager.destroy();\n }\n}\n","import type { ViewportState, Rect, DataSeries } from '@tradecanvas/commons';\nimport { clamp, computePriceRange } from '@tradecanvas/commons';\nimport { DEFAULT_BAR_WIDTH, DEFAULT_BAR_SPACING, PRICE_AXIS_WIDTH, TIME_AXIS_HEIGHT } from '@tradecanvas/commons';\n\nexport class Viewport {\n private state: ViewportState;\n private dataLength = 0;\n private minBarWidth: number;\n private maxBarWidth: number;\n private rightMarginBars: number;\n\n constructor(\n containerWidth: number,\n containerHeight: number,\n minBarWidth = 2,\n maxBarWidth = 30,\n rightMarginBars = 5,\n ) {\n this.minBarWidth = minBarWidth;\n this.maxBarWidth = maxBarWidth;\n this.rightMarginBars = rightMarginBars;\n const chartRect = this.computeChartRect(containerWidth, containerHeight);\n this.state = {\n visibleRange: { from: 0, to: 0 },\n priceRange: { min: 0, max: 1 },\n barWidth: DEFAULT_BAR_WIDTH,\n barSpacing: DEFAULT_BAR_SPACING,\n offset: 0,\n chartRect,\n };\n }\n\n /** Returns a snapshot (deep copy). Safe to store/pass. */\n getState(): ViewportState {\n return {\n visibleRange: { ...this.state.visibleRange },\n priceRange: { ...this.state.priceRange },\n barWidth: this.state.barWidth,\n barSpacing: this.state.barSpacing,\n offset: this.state.offset,\n chartRect: { ...this.state.chartRect },\n logScale: this.state.logScale,\n };\n }\n\n setLogScale(enabled: boolean): void {\n this.state.logScale = enabled;\n }\n\n isLogScale(): boolean {\n return this.state.logScale ?? false;\n }\n\n setRightMargin(bars: number): void {\n this.rightMarginBars = bars;\n }\n\n private computeChartRect(width: number, height: number): Rect {\n return {\n x: 0,\n y: 0,\n width: Math.max(0, width - PRICE_AXIS_WIDTH),\n height: Math.max(0, height - TIME_AXIS_HEIGHT),\n };\n }\n\n resize(width: number, height: number): void {\n this.state.chartRect = this.computeChartRect(width, height);\n this.clampOffset();\n }\n\n setChartRect(rect: Rect): void {\n this.state.chartRect = {\n x: rect.x,\n y: rect.y,\n width: Math.max(0, rect.width),\n height: Math.max(0, rect.height),\n };\n this.clampOffset();\n this.updateVisibleRange();\n }\n\n updateData(data: DataSeries, autoScale: boolean): void {\n this.dataLength = data.length;\n if (this.dataLength === 0) return;\n\n this.clampOffset();\n this.updateVisibleRange();\n\n if (autoScale) {\n this.state.priceRange = computePriceRange(\n data,\n this.state.visibleRange.from,\n Math.min(this.state.visibleRange.to, this.dataLength - 1),\n 0.08, // 8% padding for more breathing room\n );\n }\n }\n\n setPriceRange(min: number, max: number): void {\n this.state.priceRange = { min, max };\n }\n\n scrollBy(deltaPixels: number): void {\n this.state.offset += deltaPixels;\n this.clampOffset();\n this.updateVisibleRange();\n }\n\n /** Returns true if the viewport is scrolled to show the latest bars. */\n isAtEnd(): boolean {\n const barUnit = this.state.barWidth + this.state.barSpacing;\n const rightMarginPx = this.rightMarginBars * barUnit;\n const totalWidth = this.dataLength * barUnit;\n // Natural \"scrolled to end\" offset — may be negative when data is shorter\n // than the viewport (right-aligned with empty space on the left).\n const endOffset = totalWidth - this.state.chartRect.width + rightMarginPx;\n return this.state.offset >= endOffset - barUnit * 2;\n }\n\n scrollToEnd(): void {\n const barUnit = this.state.barWidth + this.state.barSpacing;\n const rightMarginPx = this.rightMarginBars * barUnit;\n const totalWidth = this.dataLength * barUnit;\n // Position last bar with rightMargin breathing room from the right edge.\n // For short data this offset is negative — that's intentional. It puts\n // the bars on the right side of the viewport with empty space on the\n // left, matching TradingView's behaviour for sparse charts.\n this.state.offset = totalWidth - this.state.chartRect.width + rightMarginPx;\n this.updateVisibleRange();\n }\n\n zoom(delta: number, centerX: number): void {\n const oldBarWidth = this.state.barWidth;\n const newBarWidth = clamp(\n oldBarWidth * (1 + delta),\n this.minBarWidth,\n this.maxBarWidth,\n );\n if (newBarWidth === oldBarWidth) return;\n\n const barUnit = this.state.barWidth + this.state.barSpacing;\n const centerBarIndex = (this.state.offset + centerX) / barUnit;\n\n this.state.barWidth = newBarWidth;\n const newBarUnit = newBarWidth + this.state.barSpacing;\n this.state.offset = centerBarIndex * newBarUnit - centerX;\n\n this.clampOffset();\n this.updateVisibleRange();\n }\n\n private clampOffset(): void {\n if (this.state.chartRect.width <= 0) return;\n const barUnit = this.state.barWidth + this.state.barSpacing;\n const totalWidth = this.dataLength * barUnit;\n const rightMarginPx = this.rightMarginBars * barUnit;\n\n // Natural \"scrolled to end\" offset — last bar `rightMarginPx` from the\n // right edge of the chart area. Positive when data overflows the\n // viewport, negative when data is shorter than the viewport.\n const endOffset = totalWidth - this.state.chartRect.width + rightMarginPx;\n\n let minOffset: number;\n let maxOffset: number;\n\n if (endOffset > 0) {\n // Long data: user can pan left to history or scroll right to the end.\n // Allow a half-viewport of \"empty space on the left\" past offset 0\n // for breathing room when looking at the oldest bars.\n minOffset = -(this.state.chartRect.width * 0.5);\n maxOffset = endOffset;\n } else {\n // Short data: lock the viewport to the right-aligned position. There's\n // nothing to scroll to — all bars fit, with empty space on the left.\n // TradingView does this same lock for sparse charts.\n minOffset = endOffset;\n maxOffset = endOffset;\n }\n\n this.state.offset = clamp(this.state.offset, minOffset, maxOffset);\n }\n\n private updateVisibleRange(): void {\n const barUnit = this.state.barWidth + this.state.barSpacing;\n if (barUnit <= 0 || this.state.chartRect.width <= 0) return;\n const from = Math.floor(this.state.offset / barUnit);\n const visibleBars = Math.ceil(this.state.chartRect.width / barUnit) + 1;\n const to = Math.min(from + visibleBars, this.dataLength - 1);\n this.state.visibleRange = { from: Math.max(0, from), to: Math.max(0, to) };\n }\n}\n","import type { DataSeries, ViewportState } from '@tradecanvas/commons';\nimport { sliceVisibleData } from '@tradecanvas/commons';\n\nexport function getVisibleData(data: DataSeries, viewport: ViewportState): DataSeries {\n return sliceVisibleData(data, viewport.visibleRange.from, viewport.visibleRange.to);\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\nexport class CandlestickRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n const barWidth = viewport.barWidth;\n const halfBar = barWidth / 2;\n\n // Pre-compute coordinate conversion constants (avoid function call overhead per bar)\n const barUnit = barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + halfBar;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n const chartY = viewport.chartRect.y;\n const chartH = viewport.chartRect.height;\n const priceScale = chartH / priceRange;\n\n // Inline coordinate conversions\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n // Batch: collect up/down wicks and bodies into Path2D objects — single draw call per color\n const upWickPath = new Path2D();\n const downWickPath = new Path2D();\n const upBodyPath = new Path2D();\n const downBodyPath = new Path2D();\n\n for (let i = from; i <= to && i < data.length; i++) {\n const bar = data[i];\n const x = toX(i);\n const highY = toY(bar.high);\n const lowY = toY(bar.low);\n const openY = toY(bar.open);\n const closeY = toY(bar.close);\n const isUp = bar.close >= bar.open;\n\n // Wick\n const wickPath = isUp ? upWickPath : downWickPath;\n wickPath.moveTo(x, highY);\n wickPath.lineTo(x, lowY);\n\n // Body\n const bodyTop = isUp ? closeY : openY;\n const bodyHeight = Math.max(Math.abs(closeY - openY), 1);\n const bodyPath = isUp ? upBodyPath : downBodyPath;\n bodyPath.rect(x - halfBar, bodyTop, barWidth, bodyHeight);\n }\n\n // Draw all up wicks\n ctx.strokeStyle = theme.candleUpWick;\n ctx.lineWidth = 1;\n ctx.stroke(upWickPath);\n\n // Draw all down wicks\n ctx.strokeStyle = theme.candleDownWick;\n ctx.stroke(downWickPath);\n\n // Draw all up bodies\n ctx.fillStyle = theme.candleUp;\n ctx.fill(upBodyPath);\n\n // Draw all down bodies\n ctx.fillStyle = theme.candleDown;\n ctx.fill(downBodyPath);\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\nexport class LineRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n if (from > to || data.length === 0) return;\n\n // Pre-compute constants\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n\n ctx.beginPath();\n ctx.strokeStyle = theme.lineColor;\n ctx.lineWidth = 2;\n ctx.lineJoin = 'round';\n\n let started = false;\n for (let i = from; i <= to && i < data.length; i++) {\n const x = i * barUnit + offsetX;\n const y = chartY + (max - data[i].close) * priceScale;\n if (!started) { ctx.moveTo(x, y); started = true; }\n else ctx.lineTo(x, y);\n }\n ctx.stroke();\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\nexport class AreaRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n if (from > to || data.length === 0) return;\n\n // Pre-compute constants\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n const chartY = viewport.chartRect.y;\n const chartH = viewport.chartRect.height;\n const priceScale = chartH / priceRange;\n const bottomY = chartY + chartH;\n\n // Build path in single pass\n const firstX = from * barUnit + offsetX;\n const firstY = chartY + (max - data[from].close) * priceScale;\n\n // Fill\n const gradient = ctx.createLinearGradient(0, chartY, 0, bottomY);\n gradient.addColorStop(0, theme.areaTopColor);\n gradient.addColorStop(1, theme.areaBottomColor);\n\n ctx.beginPath();\n ctx.moveTo(firstX, bottomY);\n ctx.lineTo(firstX, firstY);\n\n let lastX = firstX;\n for (let i = from + 1; i <= to && i < data.length; i++) {\n lastX = i * barUnit + offsetX;\n ctx.lineTo(lastX, chartY + (max - data[i].close) * priceScale);\n }\n\n ctx.lineTo(lastX, bottomY);\n ctx.closePath();\n ctx.fillStyle = gradient;\n ctx.fill();\n\n // Line on top\n ctx.beginPath();\n ctx.strokeStyle = theme.lineColor;\n ctx.lineWidth = 2;\n ctx.lineJoin = 'round';\n ctx.moveTo(firstX, firstY);\n for (let i = from + 1; i <= to && i < data.length; i++) {\n ctx.lineTo(i * barUnit + offsetX, chartY + (max - data[i].close) * priceScale);\n }\n ctx.stroke();\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\nexport class BarRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n const barWidth = viewport.barWidth;\n const halfBar = barWidth / 2;\n\n // Pre-compute constants\n const barUnit = barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + halfBar;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n // Batch by color using Path2D\n const upPath = new Path2D();\n const downPath = new Path2D();\n\n for (let i = from; i <= to && i < data.length; i++) {\n const bar = data[i];\n const x = toX(i);\n const isUp = bar.close >= bar.open;\n const path = isUp ? upPath : downPath;\n\n const highY = toY(bar.high);\n const lowY = toY(bar.low);\n const openY = toY(bar.open);\n const closeY = toY(bar.close);\n\n // Vertical line (high to low)\n path.moveTo(x, highY);\n path.lineTo(x, lowY);\n // Open tick (left)\n path.moveTo(x - halfBar, openY);\n path.lineTo(x, openY);\n // Close tick (right)\n path.moveTo(x, closeY);\n path.lineTo(x + halfBar, closeY);\n }\n\n ctx.lineWidth = 1;\n ctx.strokeStyle = theme.candleUp;\n ctx.stroke(upPath);\n ctx.strokeStyle = theme.candleDown;\n ctx.stroke(downPath);\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\n/**\n * Hollow Candle: filled body when close < open (bearish), hollow when close >= open (bullish).\n * Color based on close vs previous close (not open).\n */\nexport class HollowCandleRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n const barWidth = viewport.barWidth;\n const halfBar = barWidth / 2;\n\n // Pre-compute coordinate conversion constants\n const barUnit = barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + halfBar;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n // Path2D objects batched by color and type\n const upWickPath = new Path2D();\n const downWickPath = new Path2D();\n const upHollowRects: { x: number; y: number; w: number; h: number }[] = [];\n const downHollowRects: { x: number; y: number; w: number; h: number }[] = [];\n const upFilledPath = new Path2D();\n const downFilledPath = new Path2D();\n\n for (let i = from; i <= to && i < data.length; i++) {\n const bar = data[i];\n const x = toX(i);\n const isBullish = bar.close >= bar.open;\n const isRising = i === 0 || bar.close >= data[i - 1].close;\n\n const highY = toY(bar.high);\n const lowY = toY(bar.low);\n const openY = toY(bar.open);\n const closeY = toY(bar.close);\n const bodyTop = Math.min(openY, closeY);\n const bodyHeight = Math.max(Math.abs(closeY - openY), 1);\n\n // Wick\n const wickPath = isRising ? upWickPath : downWickPath;\n wickPath.moveTo(x, highY);\n wickPath.lineTo(x, lowY);\n\n if (isBullish) {\n // Hollow body - collect rects for strokeRect batching\n const rects = isRising ? upHollowRects : downHollowRects;\n rects.push({ x: x - halfBar, y: bodyTop, w: barWidth, h: bodyHeight });\n } else {\n // Filled body\n const fillPath = isRising ? upFilledPath : downFilledPath;\n fillPath.rect(x - halfBar, bodyTop, barWidth, bodyHeight);\n }\n }\n\n // Draw wicks (lineWidth = 1)\n ctx.lineWidth = 1;\n ctx.strokeStyle = theme.candleUp;\n ctx.stroke(upWickPath);\n ctx.strokeStyle = theme.candleDown;\n ctx.stroke(downWickPath);\n\n // Draw filled bodies\n ctx.fillStyle = theme.candleUp;\n ctx.fill(upFilledPath);\n ctx.fillStyle = theme.candleDown;\n ctx.fill(downFilledPath);\n\n // Draw hollow bodies (strokeRect - must iterate but no per-bar beginPath/stroke)\n ctx.lineWidth = 1.5;\n ctx.strokeStyle = theme.candleUp;\n for (const r of upHollowRects) {\n ctx.strokeRect(r.x, r.y, r.w, r.h);\n }\n ctx.strokeStyle = theme.candleDown;\n for (const r of downHollowRects) {\n ctx.strokeRect(r.x, r.y, r.w, r.h);\n }\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\n/**\n * Baseline chart: line chart split at a baseline price.\n * Above baseline = green (bullish), below = red (bearish).\n * Fill with gradient on each side.\n */\nexport class BaselineRenderer implements ChartRendererInterface {\n private baselinePrice: number | null = null;\n\n setBaseline(price: number): void {\n this.baselinePrice = price;\n }\n\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n if (from > to || data.length === 0) return;\n\n const barWidth = viewport.barWidth;\n const halfBar = barWidth / 2;\n\n // Pre-compute coordinate conversion constants\n const barUnit = barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + halfBar;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n // Auto-detect baseline as average of visible range if not set\n const baseline = this.baselinePrice ?? this.computeBaseline(data, from, to);\n const baselineY = toY(baseline);\n const { chartRect } = viewport;\n\n // Collect points using pre-computed conversions\n const xs: number[] = [];\n const ys: number[] = [];\n for (let i = from; i <= to && i < data.length; i++) {\n xs.push(toX(i));\n ys.push(toY(data[i].close));\n }\n if (xs.length < 2) return;\n\n const lastIdx = xs.length - 1;\n\n // Fill above baseline (bullish) using Path2D\n ctx.save();\n const clipAbove = new Path2D();\n clipAbove.rect(chartRect.x, chartRect.y, chartRect.width, baselineY - chartRect.y);\n ctx.clip(clipAbove);\n\n const fillAbovePath = new Path2D();\n fillAbovePath.moveTo(xs[0], baselineY);\n for (let i = 0; i <= lastIdx; i++) fillAbovePath.lineTo(xs[i], ys[i]);\n fillAbovePath.lineTo(xs[lastIdx], baselineY);\n fillAbovePath.closePath();\n ctx.fillStyle = `${theme.candleUp}20`;\n ctx.fill(fillAbovePath);\n ctx.restore();\n\n // Fill below baseline (bearish) using Path2D\n ctx.save();\n const clipBelow = new Path2D();\n clipBelow.rect(chartRect.x, baselineY, chartRect.width, chartRect.y + chartRect.height - baselineY);\n ctx.clip(clipBelow);\n\n const fillBelowPath = new Path2D();\n fillBelowPath.moveTo(xs[0], baselineY);\n for (let i = 0; i <= lastIdx; i++) fillBelowPath.lineTo(xs[i], ys[i]);\n fillBelowPath.lineTo(xs[lastIdx], baselineY);\n fillBelowPath.closePath();\n ctx.fillStyle = `${theme.candleDown}20`;\n ctx.fill(fillBelowPath);\n ctx.restore();\n\n // Line segments batched by color using Path2D\n const abovePath = new Path2D();\n const belowPath = new Path2D();\n for (let i = 1; i <= lastIdx; i++) {\n const path = ys[i] <= baselineY ? abovePath : belowPath;\n path.moveTo(xs[i - 1], ys[i - 1]);\n path.lineTo(xs[i], ys[i]);\n }\n ctx.lineWidth = 2;\n ctx.strokeStyle = theme.candleUp;\n ctx.stroke(abovePath);\n ctx.strokeStyle = theme.candleDown;\n ctx.stroke(belowPath);\n\n // Baseline dashed line\n ctx.setLineDash([6, 4]);\n ctx.strokeStyle = theme.textSecondary;\n ctx.lineWidth = 1;\n const baselinePath = new Path2D();\n baselinePath.moveTo(chartRect.x, baselineY);\n baselinePath.lineTo(chartRect.x + chartRect.width, baselineY);\n ctx.stroke(baselinePath);\n ctx.setLineDash([]);\n }\n\n private computeBaseline(data: DataSeries, from: number, to: number): number {\n let sum = 0;\n let count = 0;\n for (let i = from; i <= to && i < data.length; i++) {\n sum += data[i].close;\n count++;\n }\n return count > 0 ? sum / count : 0;\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\n/**\n * Renders Renko bricks. Data should already be transformed via toRenko().\n * Each brick is a solid colored rectangle (no wicks).\n */\nexport class RenkoRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n const barWidth = viewport.barWidth;\n const halfBar = barWidth / 2;\n\n // Pre-compute coordinate conversion constants\n const barUnit = barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + halfBar;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n // Batch fills and strokes by color using Path2D\n const upFillPath = new Path2D();\n const downFillPath = new Path2D();\n const upStrokePath = new Path2D();\n const downStrokePath = new Path2D();\n\n for (let i = from; i <= to && i < data.length; i++) {\n const bar = data[i];\n const x = toX(i);\n const isUp = bar.close >= bar.open;\n\n const topY = toY(Math.max(bar.open, bar.close));\n const bottomY = toY(Math.min(bar.open, bar.close));\n const height = Math.max(bottomY - topY, 1);\n\n const rectX = x - halfBar;\n if (isUp) {\n upFillPath.rect(rectX, topY, barWidth, height);\n upStrokePath.rect(rectX, topY, barWidth, height);\n } else {\n downFillPath.rect(rectX, topY, barWidth, height);\n downStrokePath.rect(rectX, topY, barWidth, height);\n }\n }\n\n // Draw all fills then all strokes, grouped by color\n ctx.fillStyle = theme.candleUp;\n ctx.fill(upFillPath);\n ctx.fillStyle = theme.candleDown;\n ctx.fill(downFillPath);\n\n ctx.lineWidth = 1;\n ctx.strokeStyle = theme.candleUp;\n ctx.stroke(upStrokePath);\n ctx.strokeStyle = theme.candleDown;\n ctx.stroke(downStrokePath);\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\n/**\n * Renders Kagi lines. Data should already be transformed via toKagi().\n * Thick lines (yang) for up, thin lines (yin) for down.\n */\nexport class KagiRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n const barWidth = viewport.barWidth;\n const halfBar = barWidth / 2;\n\n // Pre-compute coordinate conversion constants\n const barUnit = barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + halfBar;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n // Batch paths by direction: yang (up/thick) and yin (down/thin)\n const yangPath = new Path2D();\n const yinPath = new Path2D();\n\n for (let i = from; i <= to && i < data.length; i++) {\n const bar = data[i];\n const x = toX(i);\n const isUp = bar.close >= bar.open;\n\n const topY = toY(bar.high);\n const bottomY = toY(bar.low);\n\n // Vertical line\n const path = isUp ? yangPath : yinPath;\n path.moveTo(x, topY);\n path.lineTo(x, bottomY);\n\n // Horizontal connector to next bar\n if (i < to && i + 1 < data.length) {\n const nextX = toX(i + 1);\n const connectY = isUp ? bottomY : topY;\n path.moveTo(x, connectY);\n path.lineTo(nextX, connectY);\n }\n }\n\n // Draw yang (up) lines - thick\n ctx.strokeStyle = theme.candleUp;\n ctx.lineWidth = 3;\n ctx.stroke(yangPath);\n\n // Draw yin (down) lines - thin\n ctx.strokeStyle = theme.candleDown;\n ctx.lineWidth = 1;\n ctx.stroke(yinPath);\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\n/**\n * Renders Point & Figure chart. Data should be transformed via toPointAndFigure().\n * X for up columns, O for down columns.\n */\nexport class PointAndFigureRenderer implements ChartRendererInterface {\n private boxSize = 1;\n\n setBoxSize(size: number): void {\n this.boxSize = size;\n }\n\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n const barWidth = viewport.barWidth;\n const halfBar = barWidth / 2;\n\n // Pre-compute coordinate conversion constants\n const barUnit = barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + halfBar;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n const boxPixelHeight = Math.abs(this.boxSize * priceScale);\n const symbolSize = Math.min(halfBar * 0.8, boxPixelHeight * 0.8);\n const s = symbolSize * 0.5;\n\n // Batch X strokes and O strokes into separate Path2D objects\n const xPath = new Path2D();\n const oPath = new Path2D();\n\n for (let i = from; i <= to && i < data.length; i++) {\n const bar = data[i];\n const x = toX(i);\n const isX = bar.close >= bar.open; // X column (up)\n\n const topPrice = bar.high;\n const bottomPrice = bar.low;\n const numBoxes = Math.max(1, Math.round((topPrice - bottomPrice) / this.boxSize));\n\n for (let j = 0; j < numBoxes; j++) {\n const price = bottomPrice + (j + 0.5) * this.boxSize;\n const y = toY(price);\n\n if (isX) {\n // Draw X into path\n xPath.moveTo(x - s, y - s);\n xPath.lineTo(x + s, y + s);\n xPath.moveTo(x + s, y - s);\n xPath.lineTo(x - s, y + s);\n } else {\n // Draw O into path\n oPath.moveTo(x + s, y);\n oPath.arc(x, y, s, 0, Math.PI * 2);\n }\n }\n }\n\n // Stroke all X symbols at once\n ctx.lineWidth = 1.5;\n ctx.strokeStyle = theme.candleUp;\n ctx.stroke(xPath);\n\n // Stroke all O symbols at once\n ctx.strokeStyle = theme.candleDown;\n ctx.stroke(oPath);\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\nexport class VolumeCandleRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0 || from > to || data.length === 0) return;\n\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n const maxBarWidth = viewport.barWidth;\n\n let maxVolume = 0;\n for (let i = from; i <= to && i < data.length; i++) {\n if (data[i].volume > maxVolume) maxVolume = data[i].volume;\n }\n if (maxVolume === 0) maxVolume = 1;\n\n const upWickPath = new Path2D();\n const downWickPath = new Path2D();\n const upBodyPath = new Path2D();\n const downBodyPath = new Path2D();\n\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n for (let i = from; i <= to && i < data.length; i++) {\n const bar = data[i];\n const x = toX(i);\n const highY = toY(bar.high);\n const lowY = toY(bar.low);\n const openY = toY(bar.open);\n const closeY = toY(bar.close);\n const isUp = bar.close >= bar.open;\n\n const volRatio = Math.max(0.2, bar.volume / maxVolume);\n const w = maxBarWidth * volRatio;\n const halfW = w / 2;\n\n const wickPath = isUp ? upWickPath : downWickPath;\n wickPath.moveTo(x, highY);\n wickPath.lineTo(x, lowY);\n\n const bodyTop = isUp ? closeY : openY;\n const bodyHeight = Math.max(Math.abs(closeY - openY), 1);\n const bodyPath = isUp ? upBodyPath : downBodyPath;\n bodyPath.rect(x - halfW, bodyTop, w, bodyHeight);\n }\n\n ctx.strokeStyle = theme.candleUpWick;\n ctx.lineWidth = 1;\n ctx.stroke(upWickPath);\n\n ctx.strokeStyle = theme.candleDownWick;\n ctx.stroke(downWickPath);\n\n ctx.fillStyle = theme.candleUp;\n ctx.fill(upBodyPath);\n\n ctx.fillStyle = theme.candleDown;\n ctx.fill(downBodyPath);\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\n/**\n * Equivolume (Richard Arms) — boxes spanning the full high/low range with\n * width proportional to volume share. Color tracks close vs previous close\n * (not open/close), which is the classical convention.\n */\nexport class EquivolumeRenderer implements ChartRendererInterface {\n render(\n ctx: CanvasRenderingContext2D,\n data: DataSeries,\n viewport: ViewportState,\n theme: Theme,\n ): void {\n const { from, to } = viewport.visibleRange;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0 || from > to || data.length === 0) return;\n\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n const maxBoxWidth = viewport.barWidth;\n\n let maxVolume = 0;\n for (let i = from; i <= to && i < data.length; i++) {\n if (data[i].volume > maxVolume) maxVolume = data[i].volume;\n }\n if (maxVolume === 0) maxVolume = 1;\n\n const upBodyPath = new Path2D();\n const downBodyPath = new Path2D();\n const upEdgePath = new Path2D();\n const downEdgePath = new Path2D();\n\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n for (let i = from; i <= to && i < data.length; i++) {\n const bar = data[i];\n const prev = i > 0 ? data[i - 1] : bar;\n const x = toX(i);\n const highY = toY(bar.high);\n const lowY = toY(bar.low);\n const isUp = bar.close >= prev.close;\n\n const volRatio = Math.max(0.15, bar.volume / maxVolume);\n const w = maxBoxWidth * volRatio;\n const halfW = w / 2;\n const height = Math.max(lowY - highY, 1);\n\n const bodyPath = isUp ? upBodyPath : downBodyPath;\n const edgePath = isUp ? upEdgePath : downEdgePath;\n bodyPath.rect(x - halfW, highY, w, height);\n edgePath.rect(x - halfW, highY, w, height);\n }\n\n ctx.fillStyle = withAlpha(theme.candleUp, 0.55);\n ctx.fill(upBodyPath);\n ctx.fillStyle = withAlpha(theme.candleDown, 0.55);\n ctx.fill(downBodyPath);\n\n ctx.lineWidth = 1;\n ctx.strokeStyle = theme.candleUpWick;\n ctx.stroke(upEdgePath);\n ctx.strokeStyle = theme.candleDownWick;\n ctx.stroke(downEdgePath);\n }\n}\n\nfunction withAlpha(color: string, alpha: number): string {\n if (color.startsWith('#')) {\n const a = Math.round(Math.max(0, Math.min(1, alpha)) * 255)\n .toString(16)\n .padStart(2, '0');\n if (color.length === 7) return `${color}${a}`;\n if (color.length === 9) return `${color.slice(0, 7)}${a}`;\n }\n return color;\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\nexport class HLCAreaRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n if (from > to || data.length === 0) return;\n\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n const highPoints: { x: number; y: number }[] = [];\n const lowPoints: { x: number; y: number }[] = [];\n\n for (let i = from; i <= to && i < data.length; i++) {\n const x = toX(i);\n highPoints.push({ x, y: toY(data[i].high) });\n lowPoints.push({ x, y: toY(data[i].low) });\n }\n\n if (highPoints.length === 0) return;\n\n const gradient = ctx.createLinearGradient(0, chartY, 0, chartY + viewport.chartRect.height);\n gradient.addColorStop(0, theme.areaTopColor);\n gradient.addColorStop(1, theme.areaBottomColor);\n\n ctx.beginPath();\n ctx.moveTo(highPoints[0].x, highPoints[0].y);\n for (let i = 1; i < highPoints.length; i++) {\n ctx.lineTo(highPoints[i].x, highPoints[i].y);\n }\n for (let i = lowPoints.length - 1; i >= 0; i--) {\n ctx.lineTo(lowPoints[i].x, lowPoints[i].y);\n }\n ctx.closePath();\n ctx.fillStyle = gradient;\n ctx.fill();\n\n ctx.beginPath();\n ctx.strokeStyle = theme.lineColor;\n ctx.lineWidth = 2;\n ctx.lineJoin = 'round';\n for (let i = from; i <= to && i < data.length; i++) {\n const x = toX(i);\n const y = toY(data[i].close);\n if (i === from) ctx.moveTo(x, y);\n else ctx.lineTo(x, y);\n }\n ctx.stroke();\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\nexport class StepLineRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n if (from > to || data.length === 0) return;\n\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n ctx.beginPath();\n ctx.strokeStyle = theme.lineColor;\n ctx.lineWidth = 2;\n ctx.lineJoin = 'miter';\n\n let prevY = 0;\n for (let i = from; i <= to && i < data.length; i++) {\n const x = toX(i);\n const y = toY(data[i].close);\n if (i === from) {\n ctx.moveTo(x, y);\n } else {\n ctx.lineTo(x, prevY);\n ctx.lineTo(x, y);\n }\n prevY = y;\n }\n ctx.stroke();\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\nexport class LineWithMarkersRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n if (from > to || data.length === 0) return;\n\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n ctx.beginPath();\n ctx.strokeStyle = theme.lineColor;\n ctx.lineWidth = 2;\n ctx.lineJoin = 'round';\n\n const points: { x: number; y: number }[] = [];\n\n for (let i = from; i <= to && i < data.length; i++) {\n const x = toX(i);\n const y = toY(data[i].close);\n points.push({ x, y });\n if (i === from) ctx.moveTo(x, y);\n else ctx.lineTo(x, y);\n }\n ctx.stroke();\n\n const markerRadius = Math.max(2, Math.min(4, viewport.barWidth * 0.3));\n const markerPath = new Path2D();\n for (const { x, y } of points) {\n markerPath.moveTo(x + markerRadius, y);\n markerPath.arc(x, y, markerRadius, 0, Math.PI * 2);\n }\n\n ctx.fillStyle = theme.lineColor;\n ctx.fill(markerPath);\n\n ctx.strokeStyle = theme.background;\n ctx.lineWidth = 1;\n ctx.stroke(markerPath);\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\n\n/**\n * Renders volume histogram bars at the bottom of the main chart area.\n * Semi-transparent, colored by candle direction.\n * Height proportional to volume, occupying bottom 15-25% of chart.\n */\nexport class VolumeRenderer {\n private visible = true;\n private heightRatio = 0.2; // 20% of chart height\n\n setVisible(v: boolean): void { this.visible = v; }\n setHeightRatio(r: number): void { this.heightRatio = Math.max(0.05, Math.min(0.5, r)); }\n\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n if (!this.visible || data.length === 0) return;\n\n const { from, to } = viewport.visibleRange;\n const { chartRect } = viewport;\n const barWidth = viewport.barWidth;\n const halfBar = barWidth / 2;\n\n // Pre-compute constants\n const barUnit = barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + chartRect.x + halfBar;\n\n // Find max volume in visible range\n let maxVol = 0;\n for (let i = from; i <= to && i < data.length; i++) {\n if (data[i].volume > maxVol) maxVol = data[i].volume;\n }\n if (maxVol === 0) return;\n\n const volumeAreaHeight = chartRect.height * this.heightRatio;\n const volumeBottom = chartRect.y + chartRect.height;\n const volScale = volumeAreaHeight / maxVol;\n\n // Batch by color\n const upPath = new Path2D();\n const downPath = new Path2D();\n\n for (let i = from; i <= to && i < data.length; i++) {\n const bar = data[i];\n const x = i * barUnit + offsetX;\n const barHeight = bar.volume * volScale;\n const path = bar.close >= bar.open ? upPath : downPath;\n path.rect(x - halfBar, volumeBottom - barHeight, barWidth, barHeight);\n }\n\n ctx.globalAlpha = 0.35;\n ctx.fillStyle = theme.candleUp;\n ctx.fill(upPath);\n ctx.fillStyle = theme.candleDown;\n ctx.fill(downPath);\n ctx.globalAlpha = 1;\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport { barIndexToX, priceToY } from '../viewport/ScaleMapping.js';\n\nexport interface CompareSymbol {\n id: string;\n label: string;\n data: DataSeries;\n color: string;\n lineWidth?: number;\n visible: boolean;\n}\n\n/**\n * Renders comparison overlays on the main chart.\n * Each compare symbol is normalized to percentage change from the first visible bar,\n * then mapped onto the main chart's price axis.\n */\nexport class CompareRenderer {\n private symbols = new Map<string, CompareSymbol>();\n private mode: 'percent' | 'absolute' = 'percent';\n\n setMode(mode: 'percent' | 'absolute'): void {\n this.mode = mode;\n }\n\n addSymbol(symbol: CompareSymbol): void {\n this.symbols.set(symbol.id, symbol);\n }\n\n removeSymbol(id: string): void {\n this.symbols.delete(id);\n }\n\n setSymbolData(id: string, data: DataSeries): void {\n const sym = this.symbols.get(id);\n if (sym) sym.data = data;\n }\n\n setSymbolVisible(id: string, visible: boolean): void {\n const sym = this.symbols.get(id);\n if (sym) sym.visible = visible;\n }\n\n getSymbols(): CompareSymbol[] {\n return Array.from(this.symbols.values());\n }\n\n clear(): void {\n this.symbols.clear();\n }\n\n render(\n ctx: CanvasRenderingContext2D,\n mainData: DataSeries,\n viewport: ViewportState,\n theme: Theme,\n ): void {\n if (this.symbols.size === 0 || mainData.length === 0) return;\n\n const { chartRect } = viewport;\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(chartRect.x, chartRect.y, chartRect.width, chartRect.height);\n ctx.clip();\n\n for (const sym of this.symbols.values()) {\n if (!sym.visible || sym.data.length === 0) continue;\n this.renderSymbol(ctx, sym, mainData, viewport, theme);\n }\n\n ctx.restore();\n }\n\n private renderSymbol(\n ctx: CanvasRenderingContext2D,\n sym: CompareSymbol,\n mainData: DataSeries,\n viewport: ViewportState,\n _theme: Theme,\n ): void {\n const { chartRect } = viewport;\n\n // Find the first visible bar index for the main data\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const firstVisibleIdx = Math.max(0, Math.floor(viewport.offset / barUnit));\n\n if (firstVisibleIdx >= mainData.length || firstVisibleIdx >= sym.data.length) return;\n\n const mainBase = mainData[firstVisibleIdx].close;\n const symBase = sym.data[firstVisibleIdx].close;\n\n if (mainBase === 0 || symBase === 0) return;\n\n ctx.strokeStyle = sym.color;\n ctx.lineWidth = sym.lineWidth ?? 1.5;\n ctx.lineJoin = 'round';\n ctx.beginPath();\n\n let started = false;\n const lastIdx = Math.min(mainData.length, sym.data.length);\n\n for (let i = firstVisibleIdx; i < lastIdx; i++) {\n const x = barIndexToX(i, viewport);\n if (x < chartRect.x - barUnit) continue;\n if (x > chartRect.x + chartRect.width + barUnit) break;\n\n let y: number;\n if (this.mode === 'percent') {\n // Percentage change from base, mapped to main chart's price scale\n const pctChange = (sym.data[i].close - symBase) / symBase;\n const mappedPrice = mainBase * (1 + pctChange);\n y = priceToY(mappedPrice, viewport);\n } else {\n y = priceToY(sym.data[i].close, viewport);\n }\n\n if (!started) {\n ctx.moveTo(x, y);\n started = true;\n } else {\n ctx.lineTo(x, y);\n }\n }\n\n ctx.stroke();\n\n // Draw label\n if (started) {\n const labelIdx = Math.min(firstVisibleIdx + 2, lastIdx - 1);\n const labelX = barIndexToX(labelIdx, viewport) + 4;\n let labelY: number;\n if (this.mode === 'percent') {\n const pct = (sym.data[labelIdx].close - symBase) / symBase;\n labelY = priceToY(mainBase * (1 + pct), viewport) - 4;\n } else {\n labelY = priceToY(sym.data[labelIdx].close, viewport) - 4;\n }\n ctx.fillStyle = sym.color;\n ctx.font = `bold 10px sans-serif`;\n ctx.textBaseline = 'bottom';\n ctx.textAlign = 'left';\n ctx.fillText(sym.label, labelX, labelY);\n }\n }\n}\n","import type { OHLCBar, DataSeries } from '@tradecanvas/commons';\n\n/**\n * Transform OHLC data to Heikin Ashi.\n * HA Close = (O+H+L+C) / 4\n * HA Open = (prev HA Open + prev HA Close) / 2\n * HA High = max(H, HA Open, HA Close)\n * HA Low = min(L, HA Open, HA Close)\n */\nexport function toHeikinAshi(data: DataSeries): DataSeries {\n if (data.length === 0) return [];\n\n const result: OHLCBar[] = [];\n let prevOpen = data[0].open;\n let prevClose = (data[0].open + data[0].high + data[0].low + data[0].close) / 4;\n\n for (let i = 0; i < data.length; i++) {\n const bar = data[i];\n const haClose = (bar.open + bar.high + bar.low + bar.close) / 4;\n const haOpen = i === 0 ? bar.open : (prevOpen + prevClose) / 2;\n const haHigh = Math.max(bar.high, haOpen, haClose);\n const haLow = Math.min(bar.low, haOpen, haClose);\n\n result.push({\n time: bar.time,\n open: haOpen,\n high: haHigh,\n low: haLow,\n close: haClose,\n volume: bar.volume,\n });\n\n prevOpen = haOpen;\n prevClose = haClose;\n }\n\n return result;\n}\n","import type { OHLCBar, DataSeries } from '@tradecanvas/commons';\n\nexport interface RenkoConfig {\n brickSize: number; // Price change per brick\n useATR?: boolean; // Auto-calculate brick size from ATR\n atrPeriod?: number; // Default: 14\n}\n\n/**\n * Transform OHLC data to Renko bricks.\n * Each brick represents a fixed price movement.\n * No time axis — bricks form only when price moves by brickSize.\n */\nexport function toRenko(data: DataSeries, config: RenkoConfig): DataSeries {\n if (data.length === 0) return [];\n\n let brickSize = config.brickSize;\n if (config.useATR && data.length > (config.atrPeriod ?? 14)) {\n brickSize = computeATRBrickSize(data, config.atrPeriod ?? 14);\n }\n if (brickSize <= 0) brickSize = 1;\n\n const bricks: OHLCBar[] = [];\n let lastClose = Math.round(data[0].close / brickSize) * brickSize;\n let lastTime = data[0].time;\n\n for (let i = 1; i < data.length; i++) {\n const price = data[i].close;\n const diff = price - lastClose;\n const numBricks = Math.floor(Math.abs(diff) / brickSize);\n\n if (numBricks >= 1) {\n const direction = diff > 0 ? 1 : -1;\n for (let j = 0; j < numBricks; j++) {\n const open = lastClose;\n lastClose += direction * brickSize;\n bricks.push({\n time: lastTime++, // Increment for ordering\n open,\n high: Math.max(open, lastClose),\n low: Math.min(open, lastClose),\n close: lastClose,\n volume: data[i].volume / numBricks,\n });\n }\n }\n }\n\n return bricks;\n}\n\nfunction computeATRBrickSize(data: DataSeries, period: number): number {\n let atr = 0;\n for (let i = 1; i <= Math.min(period, data.length - 1); i++) {\n const tr = Math.max(\n data[i].high - data[i].low,\n Math.abs(data[i].high - data[i - 1].close),\n Math.abs(data[i].low - data[i - 1].close),\n );\n atr += tr;\n }\n return atr / period;\n}\n","import type { OHLCBar, DataSeries } from '@tradecanvas/commons';\n\n/**\n * Three Line Break chart.\n * A new line is drawn only when the closing price exceeds the high or low\n * of the prior N lines (default: 3).\n */\nexport function toLineBreak(data: DataSeries, lineCount = 3): DataSeries {\n if (data.length === 0) return [];\n\n const lines: OHLCBar[] = [];\n let idx = 0;\n\n // First line\n lines.push({\n time: idx++,\n open: data[0].open,\n high: Math.max(data[0].open, data[0].close),\n low: Math.min(data[0].open, data[0].close),\n close: data[0].close,\n volume: data[0].volume,\n });\n\n for (let i = 1; i < data.length; i++) {\n const price = data[i].close;\n const lastLine = lines[lines.length - 1];\n const isUp = lastLine.close >= lastLine.open;\n\n // Look back N lines for reversal detection\n const lookback = Math.min(lineCount, lines.length);\n let highestHigh = -Infinity;\n let lowestLow = Infinity;\n for (let j = lines.length - lookback; j < lines.length; j++) {\n highestHigh = Math.max(highestHigh, lines[j].high);\n lowestLow = Math.min(lowestLow, lines[j].low);\n }\n\n if (isUp && price > lastLine.close) {\n // Continuation up\n lines.push({\n time: idx++,\n open: lastLine.close,\n high: price,\n low: lastLine.close,\n close: price,\n volume: data[i].volume,\n });\n } else if (!isUp && price < lastLine.close) {\n // Continuation down\n lines.push({\n time: idx++,\n open: lastLine.close,\n high: lastLine.close,\n low: price,\n close: price,\n volume: data[i].volume,\n });\n } else if (isUp && price < lowestLow) {\n // Reversal down\n lines.push({\n time: idx++,\n open: lastLine.close,\n high: lastLine.close,\n low: price,\n close: price,\n volume: data[i].volume,\n });\n } else if (!isUp && price > highestHigh) {\n // Reversal up\n lines.push({\n time: idx++,\n open: lastLine.close,\n high: price,\n low: lastLine.close,\n close: price,\n volume: data[i].volume,\n });\n }\n }\n\n return lines;\n}\n","import type { OHLCBar, DataSeries } from '@tradecanvas/commons';\n\n/**\n * Kagi chart.\n * Changes direction when price reverses by the reversal amount.\n * Thick lines (yang) for uptrends, thin lines (yin) for downtrends.\n */\nexport function toKagi(data: DataSeries, reversalPercent = 4): DataSeries {\n if (data.length < 2) return data.slice();\n\n const lines: OHLCBar[] = [];\n let direction = data[1].close >= data[0].close ? 1 : -1;\n let high = data[0].close;\n let low = data[0].close;\n let lineStart = data[0].close;\n let idx = 0;\n\n for (let i = 1; i < data.length; i++) {\n const price = data[i].close;\n const reversal = lineStart * (reversalPercent / 100);\n\n if (direction === 1) {\n if (price > high) high = price;\n if (high - price >= reversal) {\n // Finish up line, start down\n lines.push({\n time: idx++,\n open: lineStart,\n high,\n low: lineStart,\n close: high,\n volume: data[i].volume,\n });\n direction = -1;\n lineStart = high;\n low = price;\n high = price;\n }\n } else {\n if (price < low) low = price;\n if (price - low >= reversal) {\n // Finish down line, start up\n lines.push({\n time: idx++,\n open: lineStart,\n high: lineStart,\n low,\n close: low,\n volume: data[i].volume,\n });\n direction = 1;\n lineStart = low;\n high = price;\n low = price;\n }\n }\n }\n\n // Close final line\n if (direction === 1) {\n lines.push({ time: idx, open: lineStart, high, low: lineStart, close: high, volume: 0 });\n } else {\n lines.push({ time: idx, open: lineStart, high: lineStart, low, close: low, volume: 0 });\n }\n\n return lines;\n}\n","import type { OHLCBar, DataSeries } from '@tradecanvas/commons';\n\n/**\n * Point & Figure chart.\n * X columns for rising prices, O columns for falling prices.\n * Reversal requires N boxes (default: 3) in the opposite direction.\n */\nexport function toPointAndFigure(data: DataSeries, boxSize: number, reversalBoxes = 3): DataSeries {\n if (data.length === 0 || boxSize <= 0) return [];\n\n const columns: OHLCBar[] = [];\n let direction = 0; // 1 = X (up), -1 = O (down)\n let colHigh = 0;\n let colLow = 0;\n let idx = 0;\n\n // Initialize\n const startPrice = Math.round(data[0].close / boxSize) * boxSize;\n colHigh = startPrice;\n colLow = startPrice;\n direction = 1;\n\n for (let i = 1; i < data.length; i++) {\n const price = data[i].close;\n const roundedPrice = Math.round(price / boxSize) * boxSize;\n\n if (direction === 1) {\n if (roundedPrice > colHigh) {\n colHigh = roundedPrice;\n } else if (colHigh - roundedPrice >= boxSize * reversalBoxes) {\n // Close X column, start O column\n columns.push({\n time: idx++,\n open: colLow,\n high: colHigh,\n low: colLow,\n close: colHigh, // X = up\n volume: data[i].volume,\n });\n direction = -1;\n colLow = roundedPrice;\n colHigh = colHigh - boxSize;\n }\n } else {\n if (roundedPrice < colLow) {\n colLow = roundedPrice;\n } else if (roundedPrice - colLow >= boxSize * reversalBoxes) {\n // Close O column, start X column\n columns.push({\n time: idx++,\n open: colHigh,\n high: colHigh,\n low: colLow,\n close: colLow, // O = down\n volume: data[i].volume,\n });\n direction = 1;\n colHigh = roundedPrice;\n colLow = colLow + boxSize;\n }\n }\n }\n\n // Close final column\n columns.push({\n time: idx,\n open: direction === 1 ? colLow : colHigh,\n high: colHigh,\n low: colLow,\n close: direction === 1 ? colHigh : colLow,\n volume: 0,\n });\n\n return columns;\n}\n","import type { OHLCBar, DataSeries } from '@tradecanvas/commons';\r\n\r\nexport interface RangeBarsConfig {\r\n /** Price distance per range bar. Each bar is closed when (high - low) >= rangeSize. */\r\n rangeSize: number;\r\n}\r\n\r\n/**\r\n * Transform OHLC data into fixed-range bars. Each bar's price range\r\n * (high - low) is capped at `rangeSize`; a new bar starts as soon as the cap\r\n * is met. Like Renko, range bars have no time axis — emitted timestamps are\r\n * monotonically incremented to preserve ordering for the renderer.\r\n *\r\n * Approximation: input is OHLC, not tick-level. We replay each bar's\r\n * extremes in the order implied by its candle direction (up bar:\r\n * low→high→close; down bar: high→low→close) which is the standard\r\n * approach for OHLC-derived range bars.\r\n */\r\nexport function toRangeBars(data: DataSeries, config: RangeBarsConfig): DataSeries {\r\n if (data.length === 0 || config.rangeSize <= 0) return [];\r\n\r\n const out: OHLCBar[] = [];\r\n let timeCursor = data[0].time;\r\n\r\n let openPrice = data[0].open;\r\n let curHigh = openPrice;\r\n let curLow = openPrice;\r\n let curVolume = 0;\r\n\r\n const pushExtreme = (price: number, vol: number) => {\r\n if (price > curHigh) curHigh = price;\r\n if (price < curLow) curLow = price;\r\n curVolume += vol;\r\n\r\n while (curHigh - curLow >= config.rangeSize) {\r\n const upward = price >= openPrice;\r\n const closePrice = upward\r\n ? openPrice + config.rangeSize\r\n : openPrice - config.rangeSize;\r\n out.push({\r\n time: timeCursor++,\r\n open: openPrice,\r\n high: upward ? closePrice : openPrice,\r\n low: upward ? openPrice : closePrice,\r\n close: closePrice,\r\n volume: curVolume,\r\n });\r\n openPrice = closePrice;\r\n curHigh = closePrice;\r\n curLow = closePrice;\r\n curVolume = 0;\r\n }\r\n };\r\n\r\n for (const bar of data) {\r\n const isUp = bar.close >= bar.open;\r\n const order = isUp ? [bar.low, bar.high, bar.close] : [bar.high, bar.low, bar.close];\r\n const volPer = bar.volume / order.length;\r\n for (const px of order) pushExtreme(px, volPer);\r\n }\r\n\r\n return out;\r\n}\r\n","import type {\n IndicatorPlugin,\n IndicatorDescriptor,\n IndicatorConfig,\n IndicatorOutput,\n ResolvedIndicatorStyle,\n DataSeries,\n ViewportState,\n Point,\n} from '@tradecanvas/commons';\nimport { barIndexToX, priceToY } from '../viewport/ScaleMapping.js';\n\nexport abstract class IndicatorBase implements IndicatorPlugin {\n abstract descriptor: IndicatorDescriptor;\n abstract calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput;\n abstract render(\n ctx: CanvasRenderingContext2D,\n output: IndicatorOutput,\n viewport: ViewportState,\n style: ResolvedIndicatorStyle,\n ): void;\n\n protected drawLine(\n ctx: CanvasRenderingContext2D,\n points: Point[],\n color: string,\n lineWidth: number,\n ): void {\n if (points.length < 2) return;\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = lineWidth;\n ctx.lineJoin = 'round';\n ctx.moveTo(points[0].x, points[0].y);\n for (let i = 1; i < points.length; i++) {\n ctx.lineTo(points[i].x, points[i].y);\n }\n ctx.stroke();\n }\n\n protected drawBand(\n ctx: CanvasRenderingContext2D,\n upper: Point[],\n lower: Point[],\n fillColor: string,\n ): void {\n if (upper.length < 2 || lower.length < 2) return;\n ctx.beginPath();\n ctx.moveTo(upper[0].x, upper[0].y);\n for (let i = 1; i < upper.length; i++) {\n ctx.lineTo(upper[i].x, upper[i].y);\n }\n for (let i = lower.length - 1; i >= 0; i--) {\n ctx.lineTo(lower[i].x, lower[i].y);\n }\n ctx.closePath();\n ctx.fillStyle = fillColor;\n ctx.fill();\n }\n\n protected drawHistogram(\n ctx: CanvasRenderingContext2D,\n data: { x: number; y: number; baseY: number; color: string }[],\n barWidth: number,\n ): void {\n const halfBar = barWidth / 2;\n for (const bar of data) {\n ctx.fillStyle = bar.color;\n const top = Math.min(bar.y, bar.baseY);\n const height = Math.abs(bar.y - bar.baseY);\n ctx.fillRect(bar.x - halfBar, top, barWidth, Math.max(height, 1));\n }\n }\n\n protected valuesToPoints(\n output: IndicatorOutput,\n key: string,\n data: DataSeries,\n viewport: ViewportState,\n ): Point[] {\n const points: Point[] = [];\n const { from, to } = viewport.visibleRange;\n for (let i = from; i <= to && i < data.length; i++) {\n const val = output.values.get(data[i].time);\n if (val && val[key] !== undefined) {\n points.push({\n x: barIndexToX(i, viewport),\n y: priceToY(val[key]!, viewport),\n });\n }\n }\n return points;\n }\n}\n","import type {\n IndicatorPlugin,\n IndicatorConfig,\n IndicatorOutput,\n IndicatorDescriptor,\n ResolvedIndicatorStyle,\n DataSeries,\n ViewportState,\n} from '@tradecanvas/commons';\n\ninterface IndicatorInstance {\n plugin: IndicatorPlugin;\n config: IndicatorConfig;\n output: IndicatorOutput | null;\n style: ResolvedIndicatorStyle;\n}\n\nlet nextId = 1;\n\nexport class IndicatorEngine {\n private registry = new Map<string, IndicatorPlugin>();\n private instances = new Map<string, IndicatorInstance>();\n\n register(plugin: IndicatorPlugin): void {\n this.registry.set(plugin.descriptor.id, plugin);\n }\n\n getAvailableIndicators(): IndicatorDescriptor[] {\n return Array.from(this.registry.values()).map((p) => p.descriptor);\n }\n\n addIndicator(\n id: string,\n params: Record<string, number | string | boolean> = {},\n data?: DataSeries,\n ): string {\n const plugin = this.registry.get(id);\n if (!plugin) throw new Error(`Unknown indicator: ${id}`);\n\n const instanceId = `tc_${id}_${nextId++}`;\n const config: IndicatorConfig = {\n id,\n instanceId,\n params: { ...plugin.descriptor.defaultConfig, ...params } as Record<string, number | string | boolean>,\n visible: true,\n };\n\n const defaultColors = ['#2196F3', '#FF9800', '#4CAF50', '#E91E63', '#9C27B0'];\n const style: ResolvedIndicatorStyle = {\n colors: config.style?.colors ?? defaultColors,\n lineWidths: config.style?.lineWidths ?? [1.5],\n opacity: config.style?.opacity ?? 1,\n };\n\n const instance: IndicatorInstance = { plugin, config, output: null, style };\n\n if (data) {\n instance.output = plugin.calculate(data, config);\n }\n\n this.instances.set(instanceId, instance);\n return instanceId;\n }\n\n removeIndicator(instanceId: string): void {\n this.instances.delete(instanceId);\n }\n\n updateIndicator(instanceId: string, params: Record<string, number | string | boolean>, data?: DataSeries): void {\n const instance = this.instances.get(instanceId);\n if (!instance) return;\n Object.assign(instance.config.params, params);\n if (data) {\n instance.output = instance.plugin.calculate(data, instance.config);\n }\n }\n\n recalculateAll(data: DataSeries): void {\n for (const instance of this.instances.values()) {\n instance.output = instance.plugin.calculate(data, instance.config);\n }\n }\n\n getOutput(instanceId: string): IndicatorOutput | null {\n return this.instances.get(instanceId)?.output ?? null;\n }\n\n renderOverlays(ctx: CanvasRenderingContext2D, viewport: ViewportState): void {\n for (const instance of this.instances.values()) {\n if (!instance.output || !instance.config.visible) continue;\n if (instance.plugin.descriptor.placement !== 'overlay') continue;\n instance.plugin.render(ctx, instance.output, viewport, instance.style);\n }\n }\n\n renderPanel(\n ctx: CanvasRenderingContext2D,\n instanceId: string,\n viewport: ViewportState,\n ): void {\n const instance = this.instances.get(instanceId);\n if (!instance?.output || !instance.config.visible) return;\n instance.plugin.render(ctx, instance.output, viewport, instance.style);\n }\n\n /** Get config for an active indicator instance */\n getIndicatorConfig(instanceId: string): IndicatorConfig | null {\n return this.instances.get(instanceId)?.config ?? null;\n }\n\n /** Get descriptor for an active indicator instance */\n getIndicatorDescriptor(instanceId: string): IndicatorDescriptor | null {\n return this.instances.get(instanceId)?.plugin.descriptor ?? null;\n }\n\n /** List all active indicator instances with their current config */\n getActiveIndicators(): { instanceId: string; id: string; params: Record<string, unknown>; descriptor: IndicatorDescriptor }[] {\n const result: { instanceId: string; id: string; params: Record<string, unknown>; descriptor: IndicatorDescriptor }[] = [];\n for (const [instanceId, instance] of this.instances) {\n result.push({\n instanceId,\n id: instance.config.id,\n params: { ...instance.config.params },\n descriptor: instance.plugin.descriptor,\n });\n }\n return result;\n }\n\n /** Update indicator style (colors, line widths) at runtime */\n updateIndicatorStyle(instanceId: string, style: Partial<ResolvedIndicatorStyle>): void {\n const instance = this.instances.get(instanceId);\n if (!instance) return;\n Object.assign(instance.style, style);\n }\n\n /** Compute the min/max of all visible overlay indicator values within a bar index range. */\n getOverlayPriceRange(from: number, to: number): { min: number; max: number } | null {\n let gMin = Infinity;\n let gMax = -Infinity;\n\n for (const instance of this.instances.values()) {\n if (!instance.output || !instance.config.visible) continue;\n if (instance.plugin.descriptor.placement !== 'overlay') continue;\n\n let idx = 0;\n for (const [, val] of instance.output.values) {\n if (idx >= from && idx <= to) {\n for (const key in val) {\n const v = val[key];\n if (v !== undefined && isFinite(v)) {\n if (v < gMin) gMin = v;\n if (v > gMax) gMax = v;\n }\n }\n }\n idx++;\n }\n }\n\n if (gMin === Infinity) return null;\n return { min: gMin, max: gMax };\n }\n\n getPanelIndicators(): { instanceId: string; descriptor: IndicatorDescriptor }[] {\n const result: { instanceId: string; descriptor: IndicatorDescriptor }[] = [];\n for (const [id, instance] of this.instances) {\n if (instance.plugin.descriptor.placement === 'panel') {\n result.push({ instanceId: id, descriptor: instance.plugin.descriptor });\n }\n }\n return result;\n }\n}\n","import type { IndicatorConfig } from '@tradecanvas/commons';\r\n\r\n/**\r\n * Safely read a numeric indicator parameter. Falls back to `defaultValue` when\r\n * the param is missing or cannot be coerced to a finite number. Replaces ad-hoc\r\n * `config.params.foo as number` casts that silently propagate NaN.\r\n */\r\nexport function getNumberParam(\r\n config: IndicatorConfig,\r\n key: string,\r\n defaultValue: number,\r\n): number {\r\n const raw = config.params[key];\r\n if (typeof raw === 'number' && Number.isFinite(raw)) return raw;\r\n if (typeof raw === 'string') {\r\n const parsed = Number(raw);\r\n if (Number.isFinite(parsed)) return parsed;\r\n }\r\n return defaultValue;\r\n}\r\n\r\n/** Same as getNumberParam, but clamps to >= min and rounds to int. */\r\nexport function getIntParam(\r\n config: IndicatorConfig,\r\n key: string,\r\n defaultValue: number,\r\n min = 1,\r\n): number {\r\n const v = getNumberParam(config, key, defaultValue);\r\n return Math.max(min, Math.floor(v));\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class SMAIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'sma',\r\n name: 'Simple Moving Average',\r\n placement: 'overlay' as const,\r\n defaultConfig: { period: 20 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 20, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n let sum = 0;\r\n for (let i = 0; i < data.length; i++) {\r\n sum += data[i].close;\r\n if (i >= period) sum -= data[i - period].close;\r\n if (i >= period - 1) {\r\n const val: IndicatorValue = { value: sum / period };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.value === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = priceToY(val.value, viewport);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class EMAIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'ema',\r\n name: 'Exponential Moving Average',\r\n placement: 'overlay' as const,\r\n defaultConfig: { period: 20 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 20, 1);\r\n const multiplier = 2 / (period + 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n let ema = 0;\r\n for (let i = 0; i < data.length; i++) {\r\n if (i < period - 1) {\r\n ema += data[i].close;\r\n continue;\r\n }\r\n if (i === period - 1) {\r\n ema = (ema + data[i].close) / period;\r\n } else {\r\n ema = (data[i].close - ema) * multiplier + ema;\r\n }\r\n const val: IndicatorValue = { value: ema };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.value === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = priceToY(val.value, viewport);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam, getNumberParam } from '../params.js';\r\nimport { withAlpha } from '@tradecanvas/commons';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class BollingerBandsIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'bb',\r\n name: 'Bollinger Bands',\r\n placement: 'overlay' as const,\r\n defaultConfig: { period: 20, stdDev: 2 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 20, 1);\r\n const stdDevMult = getNumberParam(config, 'stdDev', 2);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n // Running sum and sum-of-squares for O(n) calculation\r\n let sum = 0;\r\n let sumSq = 0;\r\n\r\n for (let i = 0; i < data.length; i++) {\r\n const c = data[i].close;\r\n sum += c;\r\n sumSq += c * c;\r\n\r\n if (i >= period) {\r\n const old = data[i - period].close;\r\n sum -= old;\r\n sumSq -= old * old;\r\n }\r\n\r\n if (i >= period - 1) {\r\n const sma = sum / period;\r\n // variance = E[x²] - (E[x])²\r\n const variance = sumSq / period - sma * sma;\r\n const stdDev = Math.sqrt(Math.max(0, variance));\r\n\r\n const val: IndicatorValue = {\r\n middle: sma,\r\n upper: sma + stdDevMult * stdDev,\r\n lower: sma - stdDevMult * stdDev,\r\n };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n // Build point arrays in a single pass — reuse arrays via length reset\r\n let count = 0;\r\n const maxPts = to - from + 1;\r\n const upperXs = new Float64Array(maxPts);\r\n const upperYs = new Float64Array(maxPts);\r\n const middleXs = new Float64Array(maxPts);\r\n const middleYs = new Float64Array(maxPts);\r\n const lowerXs = new Float64Array(maxPts);\r\n const lowerYs = new Float64Array(maxPts);\r\n\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.upper === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n upperXs[count] = x; upperYs[count] = priceToY(val.upper!, viewport);\r\n middleXs[count] = x; middleYs[count] = priceToY(val.middle!, viewport);\r\n lowerXs[count] = x; lowerYs[count] = priceToY(val.lower!, viewport);\r\n count++;\r\n }\r\n\r\n if (count < 2) return;\r\n\r\n // Band fill\r\n ctx.beginPath();\r\n ctx.moveTo(upperXs[0], upperYs[0]);\r\n for (let i = 1; i < count; i++) ctx.lineTo(upperXs[i], upperYs[i]);\r\n for (let i = count - 1; i >= 0; i--) ctx.lineTo(lowerXs[i], lowerYs[i]);\r\n ctx.closePath();\r\n ctx.fillStyle = withAlpha(style.colors[0], 0.1);\r\n ctx.fill();\r\n\r\n // Upper line\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n ctx.moveTo(upperXs[0], upperYs[0]);\r\n for (let i = 1; i < count; i++) ctx.lineTo(upperXs[i], upperYs[i]);\r\n ctx.stroke();\r\n\r\n // Middle line\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[1] ?? style.colors[0];\r\n ctx.moveTo(middleXs[0], middleYs[0]);\r\n for (let i = 1; i < count; i++) ctx.lineTo(middleXs[i], middleYs[i]);\r\n ctx.stroke();\r\n\r\n // Lower line\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.moveTo(lowerXs[0], lowerYs[0]);\r\n for (let i = 1; i < count; i++) ctx.lineTo(lowerXs[i], lowerYs[i]);\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\nimport { IndicatorBase } from '../IndicatorBase.js';\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\n\nexport class VWAPIndicator extends IndicatorBase {\n descriptor = {\n id: 'vwap',\n name: 'Volume Weighted Average Price',\n placement: 'overlay' as const,\n defaultConfig: {},\n };\n\n calculate(data: DataSeries, _config: IndicatorConfig): IndicatorOutput {\n const values = new Map<number, IndicatorValue>();\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\n let cumulativeVolume = 0;\n let cumulativeVolumePrice = 0;\n\n for (let i = 0; i < data.length; i++) {\n const typicalPrice = (data[i].high + data[i].low + data[i].close) / 3;\n cumulativeVolume += data[i].volume;\n cumulativeVolumePrice += typicalPrice * data[i].volume;\n if (cumulativeVolume > 0) {\n const val: IndicatorValue = { value: cumulativeVolumePrice / cumulativeVolume };\n values.set(data[i].time, val);\n series[i] = val;\n }\n }\n return { values, series };\n }\n\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\n const series = output.series;\n if (!series) return;\n const { from, to } = viewport.visibleRange;\n\n ctx.beginPath();\n ctx.strokeStyle = style.colors[0];\n ctx.lineWidth = style.lineWidths[0];\n ctx.lineJoin = 'round';\n\n let started = false;\n for (let i = from; i <= to && i < series.length; i++) {\n const val = series[i];\n if (!val || val.value === undefined) continue;\n const x = barIndexToX(i, viewport);\n const y = priceToY(val.value, viewport);\n if (!started) { ctx.moveTo(x, y); started = true; }\n else ctx.lineTo(x, y);\n }\n ctx.stroke();\n }\n}\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { withAlpha } from '@tradecanvas/commons';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class IchimokuIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'ichimoku',\r\n name: 'Ichimoku Cloud',\r\n placement: 'overlay' as const,\r\n defaultConfig: { tenkan: 9, kijun: 26, senkou: 52, displacement: 26 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const tenkanPeriod = getIntParam(config, 'tenkan', 9, 1);\r\n const kijunPeriod = getIntParam(config, 'kijun', 26, 1);\r\n const senkouBPeriod = getIntParam(config, 'senkou', 52, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n // Precompute rolling high/low for each period using deque-style sliding window\r\n const rollingHL = (period: number): { highs: Float64Array; lows: Float64Array } => {\r\n const highs = new Float64Array(data.length);\r\n const lows = new Float64Array(data.length);\r\n for (let i = 0; i < data.length; i++) {\r\n let high = -Infinity;\r\n let low = Infinity;\r\n const start = Math.max(0, i - period + 1);\r\n for (let j = start; j <= i; j++) {\r\n if (data[j].high > high) high = data[j].high;\r\n if (data[j].low < low) low = data[j].low;\r\n }\r\n highs[i] = high;\r\n lows[i] = low;\r\n }\r\n return { highs, lows };\r\n };\r\n\r\n const tenkanHL = rollingHL(tenkanPeriod);\r\n const kijunHL = rollingHL(kijunPeriod);\r\n const senkouBHL = rollingHL(senkouBPeriod);\r\n\r\n for (let i = 0; i < data.length; i++) {\r\n const val: IndicatorValue = {};\r\n\r\n if (i >= tenkanPeriod - 1) {\r\n val.tenkan = (tenkanHL.highs[i] + tenkanHL.lows[i]) / 2;\r\n }\r\n if (i >= kijunPeriod - 1) {\r\n val.kijun = (kijunHL.highs[i] + kijunHL.lows[i]) / 2;\r\n }\r\n if (val.tenkan !== undefined && val.kijun !== undefined) {\r\n val.senkouA = (val.tenkan + val.kijun) / 2;\r\n }\r\n if (i >= senkouBPeriod - 1) {\r\n val.senkouB = (senkouBHL.highs[i] + senkouBHL.lows[i]) / 2;\r\n }\r\n if (i >= kijunPeriod - 1) {\r\n val.chikou = data[i].close;\r\n }\r\n\r\n if (val.tenkan !== undefined || val.kijun !== undefined || val.senkouA !== undefined || val.senkouB !== undefined) {\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n // Single pass to collect points using typed arrays\r\n const maxPts = to - from + 1;\r\n const tenkanXs = new Float64Array(maxPts); const tenkanYs = new Float64Array(maxPts); let tenkanN = 0;\r\n const kijunXs = new Float64Array(maxPts); const kijunYs = new Float64Array(maxPts); let kijunN = 0;\r\n const senkouAXs = new Float64Array(maxPts); const senkouAYs = new Float64Array(maxPts); let senkouAN = 0;\r\n const senkouBXs = new Float64Array(maxPts); const senkouBYs = new Float64Array(maxPts); let senkouBN = 0;\r\n\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val) continue;\r\n const x = barIndexToX(i, viewport);\r\n if (val.tenkan !== undefined) { tenkanXs[tenkanN] = x; tenkanYs[tenkanN] = priceToY(val.tenkan, viewport); tenkanN++; }\r\n if (val.kijun !== undefined) { kijunXs[kijunN] = x; kijunYs[kijunN] = priceToY(val.kijun, viewport); kijunN++; }\r\n if (val.senkouA !== undefined) { senkouAXs[senkouAN] = x; senkouAYs[senkouAN] = priceToY(val.senkouA, viewport); senkouAN++; }\r\n if (val.senkouB !== undefined) { senkouBXs[senkouBN] = x; senkouBYs[senkouBN] = priceToY(val.senkouB, viewport); senkouBN++; }\r\n }\r\n\r\n // Cloud fill\r\n if (senkouAN > 1 && senkouBN > 1) {\r\n const n = Math.min(senkouAN, senkouBN);\r\n ctx.beginPath();\r\n ctx.moveTo(senkouAXs[0], senkouAYs[0]);\r\n for (let i = 1; i < n; i++) ctx.lineTo(senkouAXs[i], senkouAYs[i]);\r\n for (let i = n - 1; i >= 0; i--) ctx.lineTo(senkouBXs[i], senkouBYs[i]);\r\n ctx.closePath();\r\n ctx.fillStyle = withAlpha(style.colors[2] ?? '#26A69A', 0.15);\r\n ctx.fill();\r\n }\r\n\r\n // Lines — set state once per line\r\n const drawTypedLine = (xs: Float64Array, ys: Float64Array, n: number, color: string, lw: number) => {\r\n if (n < 2) return;\r\n ctx.beginPath();\r\n ctx.strokeStyle = color;\r\n ctx.lineWidth = lw;\r\n ctx.lineJoin = 'round';\r\n ctx.moveTo(xs[0], ys[0]);\r\n for (let i = 1; i < n; i++) ctx.lineTo(xs[i], ys[i]);\r\n ctx.stroke();\r\n };\r\n\r\n drawTypedLine(tenkanXs, tenkanYs, tenkanN, style.colors[0], style.lineWidths[0]);\r\n drawTypedLine(kijunXs, kijunYs, kijunN, style.colors[1] ?? '#FF9800', style.lineWidths[0]);\r\n drawTypedLine(senkouAXs, senkouAYs, senkouAN, style.colors[2] ?? '#26A69A', 1);\r\n drawTypedLine(senkouBXs, senkouBYs, senkouBN, style.colors[3] ?? '#EF5350', 1);\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getNumberParam } from '../params.js';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class ParabolicSARIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'psar',\r\n name: 'Parabolic SAR',\r\n placement: 'overlay' as const,\r\n defaultConfig: { step: 0.02, max: 0.2 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const stepVal = getNumberParam(config, 'step', 0.02);\r\n const maxVal = getNumberParam(config, 'max', 0.2);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n if (data.length < 2) return { values, series };\r\n\r\n let isUpTrend = data[1].close > data[0].close;\r\n let af = stepVal;\r\n let ep = isUpTrend ? data[0].high : data[0].low;\r\n let sar = isUpTrend ? data[0].low : data[0].high;\r\n\r\n const val0: IndicatorValue = { value: sar, trend: isUpTrend ? 1 : -1 };\r\n values.set(data[0].time, val0);\r\n series[0] = val0;\r\n\r\n for (let i = 1; i < data.length; i++) {\r\n const prevSar = sar;\r\n sar = prevSar + af * (ep - prevSar);\r\n\r\n if (isUpTrend) {\r\n sar = Math.min(sar, data[i - 1].low);\r\n if (i >= 2) sar = Math.min(sar, data[i - 2].low);\r\n\r\n if (data[i].low < sar) {\r\n isUpTrend = false;\r\n sar = ep;\r\n ep = data[i].low;\r\n af = stepVal;\r\n } else {\r\n if (data[i].high > ep) {\r\n ep = data[i].high;\r\n af = Math.min(af + stepVal, maxVal);\r\n }\r\n }\r\n } else {\r\n sar = Math.max(sar, data[i - 1].high);\r\n if (i >= 2) sar = Math.max(sar, data[i - 2].high);\r\n\r\n if (data[i].high > sar) {\r\n isUpTrend = true;\r\n sar = ep;\r\n ep = data[i].high;\r\n af = stepVal;\r\n } else {\r\n if (data[i].low < ep) {\r\n ep = data[i].low;\r\n af = Math.min(af + stepVal, maxVal);\r\n }\r\n }\r\n }\r\n\r\n const val: IndicatorValue = { value: sar, trend: isUpTrend ? 1 : -1 };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n const dotRadius = Math.max(1.5, viewport.barWidth * 0.15);\r\n\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.value === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = priceToY(val.value, viewport);\r\n ctx.beginPath();\r\n ctx.arc(x, y, dotRadius, 0, Math.PI * 2);\r\n ctx.fillStyle = val.trend === 1 ? (style.colors[0]) : (style.colors[1] ?? '#EF5350');\r\n ctx.fill();\r\n }\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam, getNumberParam } from '../params.js';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class SupertrendIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'supertrend',\r\n name: 'Supertrend',\r\n placement: 'overlay' as const,\r\n defaultConfig: { period: 10, multiplier: 3 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 10, 1);\r\n const multiplier = getNumberParam(config, 'multiplier', 3);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n if (data.length < period) return { values, series };\r\n\r\n // ATR\r\n const trueRanges: number[] = [data[0].high - data[0].low];\r\n for (let i = 1; i < data.length; i++) {\r\n trueRanges.push(Math.max(\r\n data[i].high - data[i].low,\r\n Math.abs(data[i].high - data[i - 1].close),\r\n Math.abs(data[i].low - data[i - 1].close),\r\n ));\r\n }\r\n\r\n let atr = 0;\r\n for (let i = 0; i < period; i++) atr += trueRanges[i];\r\n atr /= period;\r\n\r\n let upperBand = 0, lowerBand = 0;\r\n let prevUpperBand = 0, prevLowerBand = 0;\r\n let supertrend = 0;\r\n let prevSupertrend = 0;\r\n let direction = 1;\r\n\r\n for (let i = period - 1; i < data.length; i++) {\r\n if (i > period - 1) {\r\n atr = (atr * (period - 1) + trueRanges[i]) / period;\r\n }\r\n\r\n const hl2 = (data[i].high + data[i].low) / 2;\r\n const basicUpper = hl2 + multiplier * atr;\r\n const basicLower = hl2 - multiplier * atr;\r\n\r\n upperBand = (basicUpper < prevUpperBand || data[i - 1].close > prevUpperBand) ? basicUpper : prevUpperBand;\r\n lowerBand = (basicLower > prevLowerBand || data[i - 1].close < prevLowerBand) ? basicLower : prevLowerBand;\r\n\r\n if (prevSupertrend === prevUpperBand) {\r\n supertrend = data[i].close <= upperBand ? upperBand : lowerBand;\r\n } else {\r\n supertrend = data[i].close >= lowerBand ? lowerBand : upperBand;\r\n }\r\n\r\n direction = supertrend === lowerBand ? 1 : -1;\r\n\r\n const val: IndicatorValue = { value: supertrend, trend: direction };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n\r\n prevUpperBand = upperBand;\r\n prevLowerBand = lowerBand;\r\n prevSupertrend = supertrend;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n const upColor = style.colors[0];\r\n const downColor = style.colors[1] ?? '#EF5350';\r\n\r\n // Draw segments per trend direction\r\n let prevX = 0, prevY = 0, prevTrend = 0;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.value === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = priceToY(val.value, viewport);\r\n const trend = val.trend ?? 1;\r\n\r\n if (prevTrend !== 0) {\r\n ctx.beginPath();\r\n ctx.strokeStyle = trend === 1 ? upColor : downColor;\r\n ctx.lineWidth = style.lineWidths[0] + 0.5;\r\n ctx.moveTo(prevX, prevY);\r\n ctx.lineTo(x, y);\r\n ctx.stroke();\r\n }\r\n\r\n prevX = x;\r\n prevY = y;\r\n prevTrend = trend;\r\n }\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam, getNumberParam } from '../params.js';\r\nimport { withAlpha } from '@tradecanvas/commons';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class KeltnerChannelIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'keltner',\r\n name: 'Keltner Channel',\r\n placement: 'overlay' as const,\r\n defaultConfig: { emaPeriod: 20, atrPeriod: 10, multiplier: 1.5 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const emaPeriod = getIntParam(config, 'emaPeriod', 20, 1);\r\n const atrPeriod = getIntParam(config, 'atrPeriod', 10, 1);\r\n const mult = getNumberParam(config, 'multiplier', 1.5);\r\n const values = new Map<number, IndicatorValue>();\r\n if (data.length < Math.max(emaPeriod, atrPeriod)) return { values };\r\n\r\n // EMA of close\r\n const emaMult = 2 / (emaPeriod + 1);\r\n let ema = data[0].close;\r\n const emaArr: number[] = [ema];\r\n for (let i = 1; i < data.length; i++) {\r\n ema = (data[i].close - ema) * emaMult + ema;\r\n emaArr.push(ema);\r\n }\r\n\r\n // ATR\r\n const trArr: number[] = [data[0].high - data[0].low];\r\n for (let i = 1; i < data.length; i++) {\r\n trArr.push(Math.max(\r\n data[i].high - data[i].low,\r\n Math.abs(data[i].high - data[i - 1].close),\r\n Math.abs(data[i].low - data[i - 1].close),\r\n ));\r\n }\r\n\r\n let atr = 0;\r\n for (let i = 0; i < atrPeriod; i++) atr += trArr[i];\r\n atr /= atrPeriod;\r\n\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n const start = Math.max(emaPeriod, atrPeriod) - 1;\r\n for (let i = start; i < data.length; i++) {\r\n if (i > start) {\r\n atr = (atr * (atrPeriod - 1) + trArr[i]) / atrPeriod;\r\n }\r\n const val: IndicatorValue = {\r\n middle: emaArr[i],\r\n upper: emaArr[i] + mult * atr,\r\n lower: emaArr[i] - mult * atr,\r\n };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n const upperPts: { x: number; y: number }[] = [];\r\n const middlePts: { x: number; y: number }[] = [];\r\n const lowerPts: { x: number; y: number }[] = [];\r\n\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val) continue;\r\n const x = barIndexToX(i, viewport);\r\n if (val.upper !== undefined) upperPts.push({ x, y: priceToY(val.upper, viewport) });\r\n if (val.middle !== undefined) middlePts.push({ x, y: priceToY(val.middle, viewport) });\r\n if (val.lower !== undefined) lowerPts.push({ x, y: priceToY(val.lower, viewport) });\r\n }\r\n\r\n this.drawBand(ctx, upperPts, lowerPts, withAlpha(style.colors[0], 0.08));\r\n this.drawLine(ctx, upperPts, style.colors[0], style.lineWidths[0]);\r\n this.drawLine(ctx, middlePts, style.colors[1] ?? style.colors[0], style.lineWidths[0]);\r\n this.drawLine(ctx, lowerPts, style.colors[0], style.lineWidths[0]);\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { withAlpha } from '@tradecanvas/commons';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class DonchianChannelIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'donchian',\r\n name: 'Donchian Channel',\r\n placement: 'overlay' as const,\r\n defaultConfig: { period: 20 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 20, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n for (let i = period - 1; i < data.length; i++) {\r\n let high = -Infinity, low = Infinity;\r\n for (let j = i - period + 1; j <= i; j++) {\r\n if (data[j].high > high) high = data[j].high;\r\n if (data[j].low < low) low = data[j].low;\r\n }\r\n const val: IndicatorValue = {\r\n upper: high,\r\n middle: (high + low) / 2,\r\n lower: low,\r\n };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n const upperPts: { x: number; y: number }[] = [];\r\n const middlePts: { x: number; y: number }[] = [];\r\n const lowerPts: { x: number; y: number }[] = [];\r\n\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val) continue;\r\n const x = barIndexToX(i, viewport);\r\n if (val.upper !== undefined) upperPts.push({ x, y: priceToY(val.upper, viewport) });\r\n if (val.middle !== undefined) middlePts.push({ x, y: priceToY(val.middle, viewport) });\r\n if (val.lower !== undefined) lowerPts.push({ x, y: priceToY(val.lower, viewport) });\r\n }\r\n\r\n this.drawBand(ctx, upperPts, lowerPts, withAlpha(style.colors[0], 0.08));\r\n this.drawLine(ctx, upperPts, style.colors[0], style.lineWidths[0]);\r\n this.drawLine(ctx, middlePts, style.colors[1] ?? '#787B86', 1);\r\n this.drawLine(ctx, lowerPts, style.colors[0], style.lineWidths[0]);\r\n }\r\n}\r\n","import type {\r\n DataSeries,\r\n IndicatorConfig,\r\n IndicatorOutput,\r\n IndicatorValue,\r\n ResolvedIndicatorStyle,\r\n ViewportState,\r\n} from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\nconst LEVEL_KEYS = ['s3', 's2', 's1', 'pp', 'r1', 'r2', 'r3'] as const;\r\ntype LevelKey = (typeof LEVEL_KEYS)[number];\r\n\r\nexport class PivotPointsIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'pivots',\r\n name: 'Pivot Points (Classic)',\r\n placement: 'overlay' as const,\r\n defaultConfig: { lookback: 24 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const lookback = getIntParam(config, 'lookback', 24, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n if (data.length <= lookback) return { values, series };\r\n\r\n for (let i = lookback; i < data.length; i++) {\r\n let high = -Infinity;\r\n let low = Infinity;\r\n for (let j = i - lookback; j < i; j++) {\r\n if (data[j].high > high) high = data[j].high;\r\n if (data[j].low < low) low = data[j].low;\r\n }\r\n const close = data[i - 1].close;\r\n const pp = (high + low + close) / 3;\r\n const range = high - low;\r\n const val: IndicatorValue = {\r\n pp,\r\n r1: 2 * pp - low,\r\n s1: 2 * pp - high,\r\n r2: pp + range,\r\n s2: pp - range,\r\n r3: high + 2 * (pp - low),\r\n s3: low - 2 * (high - pp),\r\n };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(\r\n ctx: CanvasRenderingContext2D,\r\n output: IndicatorOutput,\r\n viewport: ViewportState,\r\n style: ResolvedIndicatorStyle,\r\n ): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n const ppColor = style.colors[0];\r\n const rColor = style.colors[1] ?? '#EF5350';\r\n const sColor = style.colors[2] ?? '#26A69A';\r\n const lineWidth = style.lineWidths[0];\r\n\r\n const colorFor = (key: LevelKey): string => {\r\n if (key === 'pp') return ppColor;\r\n return key.startsWith('r') ? rColor : sColor;\r\n };\r\n\r\n for (const key of LEVEL_KEYS) {\r\n ctx.beginPath();\r\n ctx.strokeStyle = colorFor(key);\r\n ctx.lineWidth = key === 'pp' ? lineWidth : Math.max(1, lineWidth - 1);\r\n if (key !== 'pp') ctx.setLineDash([4, 3]);\r\n\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n const v = val?.[key];\r\n if (v === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = priceToY(v, viewport);\r\n if (!started) {\r\n ctx.moveTo(x, y);\r\n started = true;\r\n } else {\r\n ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n ctx.setLineDash([]);\r\n }\r\n }\r\n}\r\n","import type {\r\n DataSeries,\r\n IndicatorConfig,\r\n IndicatorOutput,\r\n IndicatorValue,\r\n ResolvedIndicatorStyle,\r\n ViewportState,\r\n} from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getNumberParam } from '../params.js';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\n/**\r\n * Anchored VWAP — VWAP that resets at a chosen anchor.\r\n * Anchor is provided as a unix-ms timestamp via params.anchorTime.\r\n * If anchorTime is missing or precedes the dataset, behaves like regular VWAP.\r\n */\r\nexport class AnchoredVWAPIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'avwap',\r\n name: 'Anchored VWAP',\r\n placement: 'overlay' as const,\r\n defaultConfig: { anchorTime: 0 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const anchorTime = getNumberParam(config, 'anchorTime', 0);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n let anchorIdx = 0;\r\n if (anchorTime > 0) {\r\n anchorIdx = data.findIndex((b) => b.time >= anchorTime);\r\n if (anchorIdx < 0) return { values, series };\r\n }\r\n\r\n let cumVol = 0;\r\n let cumVolPrice = 0;\r\n for (let i = anchorIdx; i < data.length; i++) {\r\n const typical = (data[i].high + data[i].low + data[i].close) / 3;\r\n cumVol += data[i].volume;\r\n cumVolPrice += typical * data[i].volume;\r\n if (cumVol > 0) {\r\n const val: IndicatorValue = { value: cumVolPrice / cumVol };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(\r\n ctx: CanvasRenderingContext2D,\r\n output: IndicatorOutput,\r\n viewport: ViewportState,\r\n style: ResolvedIndicatorStyle,\r\n ): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.value === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = priceToY(val.value, viewport);\r\n if (!started) {\r\n ctx.moveTo(x, y);\r\n started = true;\r\n } else {\r\n ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type {\r\n DataSeries,\r\n IndicatorConfig,\r\n IndicatorOutput,\r\n IndicatorValue,\r\n ResolvedIndicatorStyle,\r\n ViewportState,\r\n} from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getNumberParam } from '../params.js';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\n/**\r\n * ZigZag — connects swing highs/lows that exceed a percentage move threshold.\r\n * Pivots are written to series[i].pivot (price) when bar i is a confirmed swing.\r\n * meta.pivots holds the ordered list of pivot bar indices for fast rendering.\r\n */\r\nexport class ZigZagIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'zigzag',\r\n name: 'ZigZag',\r\n placement: 'overlay' as const,\r\n defaultConfig: { deviation: 5 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const devPct = Math.max(0.01, getNumberParam(config, 'deviation', 5)) / 100;\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n if (data.length < 2) return { values, series, meta: { pivots: [] } };\r\n\r\n const pivots: { idx: number; price: number; type: 'high' | 'low' }[] = [];\r\n let direction: 'up' | 'down' | null = null;\r\n let lastPivotIdx = 0;\r\n let lastPivotPrice = data[0].close;\r\n\r\n for (let i = 1; i < data.length; i++) {\r\n const high = data[i].high;\r\n const low = data[i].low;\r\n\r\n if (direction === null) {\r\n if (high >= lastPivotPrice * (1 + devPct)) {\r\n pivots.push({ idx: lastPivotIdx, price: lastPivotPrice, type: 'low' });\r\n direction = 'up';\r\n lastPivotIdx = i;\r\n lastPivotPrice = high;\r\n } else if (low <= lastPivotPrice * (1 - devPct)) {\r\n pivots.push({ idx: lastPivotIdx, price: lastPivotPrice, type: 'high' });\r\n direction = 'down';\r\n lastPivotIdx = i;\r\n lastPivotPrice = low;\r\n }\r\n continue;\r\n }\r\n\r\n if (direction === 'up') {\r\n if (high > lastPivotPrice) {\r\n lastPivotIdx = i;\r\n lastPivotPrice = high;\r\n } else if (low <= lastPivotPrice * (1 - devPct)) {\r\n pivots.push({ idx: lastPivotIdx, price: lastPivotPrice, type: 'high' });\r\n direction = 'down';\r\n lastPivotIdx = i;\r\n lastPivotPrice = low;\r\n }\r\n } else {\r\n if (low < lastPivotPrice) {\r\n lastPivotIdx = i;\r\n lastPivotPrice = low;\r\n } else if (high >= lastPivotPrice * (1 + devPct)) {\r\n pivots.push({ idx: lastPivotIdx, price: lastPivotPrice, type: 'low' });\r\n direction = 'up';\r\n lastPivotIdx = i;\r\n lastPivotPrice = high;\r\n }\r\n }\r\n }\r\n\r\n pivots.push({\r\n idx: lastPivotIdx,\r\n price: lastPivotPrice,\r\n type: direction === 'up' ? 'high' : 'low',\r\n });\r\n\r\n for (const p of pivots) {\r\n const val: IndicatorValue = { pivot: p.price };\r\n values.set(data[p.idx].time, val);\r\n series[p.idx] = val;\r\n }\r\n\r\n return { values, series, meta: { pivots } };\r\n }\r\n\r\n render(\r\n ctx: CanvasRenderingContext2D,\r\n output: IndicatorOutput,\r\n viewport: ViewportState,\r\n style: ResolvedIndicatorStyle,\r\n ): void {\r\n const pivots = output.meta?.pivots as\r\n | { idx: number; price: number }[]\r\n | undefined;\r\n if (!pivots || pivots.length < 2) return;\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n\r\n for (let k = 0; k < pivots.length; k++) {\r\n const p = pivots[k];\r\n const x = barIndexToX(p.idx, viewport);\r\n const y = priceToY(p.price, viewport);\r\n if (k === 0) ctx.moveTo(x, y);\r\n else ctx.lineTo(x, y);\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type {\r\n DataSeries,\r\n IndicatorConfig,\r\n IndicatorOutput,\r\n IndicatorValue,\r\n ResolvedIndicatorStyle,\r\n ViewportState,\r\n} from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam, getNumberParam } from '../params.js';\r\nimport { withAlpha } from '@tradecanvas/commons';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\n/**\r\n * Linear Regression Channel — fits a least-squares line over the trailing `period` closes\r\n * and offsets it by `stdDev` standard deviations of residuals to form upper/lower bands.\r\n */\r\nexport class LinearRegressionChannelIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'lrc',\r\n name: 'Linear Regression Channel',\r\n placement: 'overlay' as const,\r\n defaultConfig: { period: 100, stdDev: 2 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 100, 2);\r\n const dev = getNumberParam(config, 'stdDev', 2);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n if (data.length < period) return { values, series };\r\n\r\n for (let i = period - 1; i < data.length; i++) {\r\n const start = i - period + 1;\r\n let sumX = 0;\r\n let sumY = 0;\r\n let sumXY = 0;\r\n let sumXX = 0;\r\n for (let k = 0; k < period; k++) {\r\n const x = k;\r\n const y = data[start + k].close;\r\n sumX += x;\r\n sumY += y;\r\n sumXY += x * y;\r\n sumXX += x * x;\r\n }\r\n const denom = period * sumXX - sumX * sumX;\r\n if (denom === 0) continue;\r\n const slope = (period * sumXY - sumX * sumY) / denom;\r\n const intercept = (sumY - slope * sumX) / period;\r\n\r\n let sse = 0;\r\n for (let k = 0; k < period; k++) {\r\n const fitted = slope * k + intercept;\r\n const resid = data[start + k].close - fitted;\r\n sse += resid * resid;\r\n }\r\n const sd = Math.sqrt(sse / period);\r\n const mid = slope * (period - 1) + intercept;\r\n const val: IndicatorValue = {\r\n middle: mid,\r\n upper: mid + dev * sd,\r\n lower: mid - dev * sd,\r\n slope,\r\n };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(\r\n ctx: CanvasRenderingContext2D,\r\n output: IndicatorOutput,\r\n viewport: ViewportState,\r\n style: ResolvedIndicatorStyle,\r\n ): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n const upperPts: { x: number; y: number }[] = [];\r\n const middlePts: { x: number; y: number }[] = [];\r\n const lowerPts: { x: number; y: number }[] = [];\r\n\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val) continue;\r\n const x = barIndexToX(i, viewport);\r\n if (val.middle !== undefined) middlePts.push({ x, y: priceToY(val.middle, viewport) });\r\n if (val.upper !== undefined) upperPts.push({ x, y: priceToY(val.upper, viewport) });\r\n if (val.lower !== undefined) lowerPts.push({ x, y: priceToY(val.lower, viewport) });\r\n }\r\n\r\n this.drawBand(ctx, upperPts, lowerPts, withAlpha(style.colors[0], 0.08));\r\n this.drawLine(ctx, upperPts, style.colors[0], style.lineWidths[0]);\r\n this.drawLine(ctx, middlePts, style.colors[1] ?? style.colors[0], style.lineWidths[0]);\r\n this.drawLine(ctx, lowerPts, style.colors[0], style.lineWidths[0]);\r\n }\r\n}\r\n","import type {\r\n DataSeries,\r\n IndicatorConfig,\r\n IndicatorOutput,\r\n IndicatorValue,\r\n ResolvedIndicatorStyle,\r\n ViewportState,\r\n} from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\nimport { getIntParam } from '../params.js';\r\n\r\n/**\r\n * Hull Moving Average — HMA(n) = WMA( 2*WMA(close, n/2) - WMA(close, n), sqrt(n) )\r\n * Designed to reduce lag while preserving smoothness.\r\n */\r\nexport class HullMAIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'hma',\r\n name: 'Hull Moving Average',\r\n placement: 'overlay' as const,\r\n defaultConfig: { period: 21 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 21, 2);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n if (data.length < period) return { values, series };\r\n\r\n const closes = data.map((b) => b.close);\r\n const halfPeriod = Math.max(2, Math.floor(period / 2));\r\n const sqrtPeriod = Math.max(2, Math.floor(Math.sqrt(period)));\r\n\r\n const wmaFull = wma(closes, period);\r\n const wmaHalf = wma(closes, halfPeriod);\r\n const diff = closes.map((_, i) =>\r\n wmaFull[i] === null || wmaHalf[i] === null ? null : 2 * (wmaHalf[i] as number) - (wmaFull[i] as number),\r\n );\r\n const hma = wmaNullable(diff, sqrtPeriod);\r\n\r\n for (let i = 0; i < data.length; i++) {\r\n if (hma[i] === null) continue;\r\n const val: IndicatorValue = { value: hma[i] as number };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(\r\n ctx: CanvasRenderingContext2D,\r\n output: IndicatorOutput,\r\n viewport: ViewportState,\r\n style: ResolvedIndicatorStyle,\r\n ): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.value === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = priceToY(val.value, viewport);\r\n if (!started) {\r\n ctx.moveTo(x, y);\r\n started = true;\r\n } else {\r\n ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n\r\nfunction wma(data: number[], period: number): (number | null)[] {\r\n const out: (number | null)[] = new Array(data.length).fill(null);\r\n if (data.length < period) return out;\r\n const denom = (period * (period + 1)) / 2;\r\n for (let i = period - 1; i < data.length; i++) {\r\n let sum = 0;\r\n for (let k = 0; k < period; k++) {\r\n sum += data[i - k] * (period - k);\r\n }\r\n out[i] = sum / denom;\r\n }\r\n return out;\r\n}\r\n\r\nfunction wmaNullable(data: (number | null)[], period: number): (number | null)[] {\r\n const out: (number | null)[] = new Array(data.length).fill(null);\r\n const denom = (period * (period + 1)) / 2;\r\n for (let i = period - 1; i < data.length; i++) {\r\n let sum = 0;\r\n let ok = true;\r\n for (let k = 0; k < period; k++) {\r\n const v = data[i - k];\r\n if (v === null) {\r\n ok = false;\r\n break;\r\n }\r\n sum += v * (period - k);\r\n }\r\n if (ok) out[i] = sum / denom;\r\n }\r\n return out;\r\n}\r\n","import type {\r\n DataSeries,\r\n IndicatorConfig,\r\n IndicatorOutput,\r\n IndicatorValue,\r\n ResolvedIndicatorStyle,\r\n ViewportState,\r\n} from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class AwesomeOscillatorIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'ao',\r\n name: 'Awesome Oscillator',\r\n placement: 'panel' as const,\r\n defaultConfig: { fast: 5, slow: 34 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const fast = getIntParam(config, 'fast', 5, 1);\r\n const slow = getIntParam(config, 'slow', 34, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n if (data.length < slow) return { values, series };\r\n\r\n const median: number[] = new Array(data.length);\r\n for (let i = 0; i < data.length; i++) {\r\n median[i] = (data[i].high + data[i].low) / 2;\r\n }\r\n\r\n let fastSum = 0;\r\n let slowSum = 0;\r\n let prevAo: number | undefined;\r\n for (let i = 0; i < data.length; i++) {\r\n slowSum += median[i];\r\n if (i >= slow) slowSum -= median[i - slow];\r\n fastSum += median[i];\r\n if (i >= fast) fastSum -= median[i - fast];\r\n\r\n if (i >= slow - 1) {\r\n const ao = fastSum / fast - slowSum / slow;\r\n const up = prevAo === undefined ? true : ao >= prevAo;\r\n const val: IndicatorValue = { value: ao, up: up ? 1 : 0 };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n prevAo = ao;\r\n }\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(\r\n ctx: CanvasRenderingContext2D,\r\n output: IndicatorOutput,\r\n viewport: ViewportState,\r\n style: ResolvedIndicatorStyle,\r\n ): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n let minVal = Infinity;\r\n let maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const v = series[i]?.value;\r\n if (v === undefined) continue;\r\n if (v < minVal) minVal = v;\r\n if (v > maxVal) maxVal = v;\r\n }\r\n if (minVal === Infinity) return;\r\n const absMax = Math.max(Math.abs(minVal), Math.abs(maxVal)) || 1;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v + absMax) / (2 * absMax));\r\n const zeroY = toY(0);\r\n const halfBar = viewport.barWidth / 2;\r\n\r\n const upColor = style.colors[0] ?? '#26A69A';\r\n const downColor = style.colors[1] ?? '#EF5350';\r\n\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.value === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n const top = Math.min(y, zeroY);\r\n const h = Math.max(Math.abs(y - zeroY), 1);\r\n ctx.fillStyle = val.up ? upColor : downColor;\r\n ctx.fillRect(x - halfBar, top, viewport.barWidth, h);\r\n }\r\n }\r\n}\r\n","import type {\r\n DataSeries,\r\n IndicatorConfig,\r\n IndicatorOutput,\r\n IndicatorValue,\r\n ResolvedIndicatorStyle,\r\n ViewportState,\r\n} from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\nimport { getIntParam } from '../params.js';\r\n\r\n/**\r\n * Chaikin Oscillator = EMA(ADL, fast) - EMA(ADL, slow)\r\n * where ADL = cumulative Σ Money Flow Volume,\r\n * and Money Flow Volume = ((close - low) - (high - close)) / (high - low) * volume.\r\n */\r\nexport class ChaikinOscillatorIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'chaikinOsc',\r\n name: 'Chaikin Oscillator',\r\n placement: 'panel' as const,\r\n defaultConfig: { fast: 3, slow: 10 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const fast = getIntParam(config, 'fast', 3, 1);\r\n const slow = getIntParam(config, 'slow', 10, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n if (data.length < slow) return { values, series };\r\n\r\n const fastMult = 2 / (fast + 1);\r\n const slowMult = 2 / (slow + 1);\r\n\r\n let adl = 0;\r\n let emaFast = 0;\r\n let emaSlow = 0;\r\n\r\n for (let i = 0; i < data.length; i++) {\r\n const { high, low, close, volume } = data[i];\r\n const range = high - low;\r\n const mfm = range === 0 ? 0 : ((close - low) - (high - close)) / range;\r\n adl += mfm * volume;\r\n\r\n if (i === 0) {\r\n emaFast = adl;\r\n emaSlow = adl;\r\n } else {\r\n emaFast = (adl - emaFast) * fastMult + emaFast;\r\n emaSlow = (adl - emaSlow) * slowMult + emaSlow;\r\n }\r\n\r\n if (i >= slow - 1) {\r\n const osc = emaFast - emaSlow;\r\n const val: IndicatorValue = { value: osc, adl };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(\r\n ctx: CanvasRenderingContext2D,\r\n output: IndicatorOutput,\r\n viewport: ViewportState,\r\n style: ResolvedIndicatorStyle,\r\n ): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n let minVal = Infinity;\r\n let maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const v = series[i]?.value;\r\n if (v === undefined) continue;\r\n if (v < minVal) minVal = v;\r\n if (v > maxVal) maxVal = v;\r\n }\r\n if (minVal === Infinity) return;\r\n const absMax = Math.max(Math.abs(minVal), Math.abs(maxVal)) || 1;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v + absMax) / (2 * absMax));\r\n const zeroY = toY(0);\r\n const halfBar = viewport.barWidth / 2;\r\n\r\n const upColor = style.colors[0] ?? '#26A69A';\r\n const downColor = style.colors[1] ?? '#EF5350';\r\n\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.value === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n const top = Math.min(y, zeroY);\r\n const h = Math.max(Math.abs(y - zeroY), 1);\r\n ctx.fillStyle = val.value >= 0 ? upColor : downColor;\r\n ctx.fillRect(x - halfBar, top, viewport.barWidth, h);\r\n }\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class RSIIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'rsi',\r\n name: 'Relative Strength Index',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 14 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 14, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n if (data.length < period + 1) return { values, series };\r\n\r\n let avgGain = 0;\r\n let avgLoss = 0;\r\n\r\n for (let i = 1; i <= period; i++) {\r\n const change = data[i].close - data[i - 1].close;\r\n if (change > 0) avgGain += change;\r\n else avgLoss -= change;\r\n }\r\n avgGain /= period;\r\n avgLoss /= period;\r\n\r\n const rsi = avgLoss === 0 ? 100 : 100 - 100 / (1 + avgGain / avgLoss);\r\n const val0: IndicatorValue = { value: rsi };\r\n values.set(data[period].time, val0);\r\n series[period] = val0;\r\n\r\n for (let i = period + 1; i < data.length; i++) {\r\n const change = data[i].close - data[i - 1].close;\r\n const gain = change > 0 ? change : 0;\r\n const loss = change < 0 ? -change : 0;\r\n avgGain = (avgGain * (period - 1) + gain) / period;\r\n avgLoss = (avgLoss * (period - 1) + loss) / period;\r\n const rs = avgLoss === 0 ? 100 : 100 - 100 / (1 + avgGain / avgLoss);\r\n const val: IndicatorValue = { value: rs };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n const toY = (val: number) => chartRect.y + chartRect.height * (1 - val / 100);\r\n\r\n // Overbought/oversold levels — single path\r\n ctx.strokeStyle = style.colors[1] ?? '#787B86';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n ctx.beginPath();\r\n for (const level of [30, 70]) {\r\n const y = toY(level);\r\n ctx.moveTo(chartRect.x, y);\r\n ctx.lineTo(chartRect.x + chartRect.width, y);\r\n }\r\n ctx.stroke();\r\n ctx.setLineDash([]);\r\n\r\n // RSI line\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.value === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class MACDIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'macd',\r\n name: 'MACD',\r\n placement: 'panel' as const,\r\n defaultConfig: { fast: 12, slow: 26, signal: 9 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const fast = getIntParam(config, 'fast', 12, 1);\r\n const slow = getIntParam(config, 'slow', 26, 1);\r\n const signalPeriod = getIntParam(config, 'signal', 9, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n if (data.length < slow) return { values, series };\r\n\r\n // Compute EMA incrementally without storing full arrays\r\n const fastMult = 2 / (fast + 1);\r\n const slowMult = 2 / (slow + 1);\r\n const signalMult = 2 / (signalPeriod + 1);\r\n\r\n let fastEma = data[0].close;\r\n let slowEma = data[0].close;\r\n let sig = 0;\r\n let sigStarted = false;\r\n\r\n for (let i = 0; i < data.length; i++) {\r\n const c = data[i].close;\r\n if (i === 0) { fastEma = c; slowEma = c; }\r\n else { fastEma = (c - fastEma) * fastMult + fastEma; slowEma = (c - slowEma) * slowMult + slowEma; }\r\n\r\n if (i >= slow - 1) {\r\n const macd = fastEma - slowEma;\r\n if (!sigStarted) { sig = macd; sigStarted = true; }\r\n else { sig = (macd - sig) * signalMult + sig; }\r\n const histogram = macd - sig;\r\n const val: IndicatorValue = { macd, signal: sig, histogram };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n // Find range for scaling — single pass\r\n let minVal = Infinity;\r\n let maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val) continue;\r\n if (val.macd !== undefined) { if (val.macd < minVal) minVal = val.macd; if (val.macd > maxVal) maxVal = val.macd; }\r\n if (val.signal !== undefined) { if (val.signal < minVal) minVal = val.signal; if (val.signal > maxVal) maxVal = val.signal; }\r\n if (val.histogram !== undefined) { if (val.histogram < minVal) minVal = val.histogram; if (val.histogram > maxVal) maxVal = val.histogram; }\r\n }\r\n if (minVal === Infinity) return;\r\n const range = maxVal - minVal || 1;\r\n\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - minVal) / range);\r\n const zeroY = toY(0);\r\n const halfBar = viewport.barWidth / 2;\r\n\r\n // Single pass: histogram + collect MACD/signal points\r\n const posColor = style.colors[2] ?? '#26A69A';\r\n const negColor = style.colors[3] ?? '#EF5350';\r\n const macdColor = style.colors[0];\r\n const signalColor = style.colors[1] ?? '#FF9800';\r\n\r\n // Histogram — batch by color: two paths\r\n ctx.beginPath();\r\n const posPath = new Path2D();\r\n const negPath = new Path2D();\r\n\r\n let macdStarted = false;\r\n let sigStarted = false;\r\n const macdPath = new Path2D();\r\n const sigPath = new Path2D();\r\n\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val) continue;\r\n const x = barIndexToX(i, viewport);\r\n\r\n if (val.histogram !== undefined) {\r\n const y = toY(val.histogram);\r\n const top = Math.min(y, zeroY);\r\n const h = Math.max(Math.abs(y - zeroY), 1);\r\n if (val.histogram >= 0) posPath.rect(x - halfBar, top, viewport.barWidth, h);\r\n else negPath.rect(x - halfBar, top, viewport.barWidth, h);\r\n }\r\n\r\n if (val.macd !== undefined) {\r\n const y = toY(val.macd);\r\n if (!macdStarted) { macdPath.moveTo(x, y); macdStarted = true; }\r\n else macdPath.lineTo(x, y);\r\n }\r\n if (val.signal !== undefined) {\r\n const y = toY(val.signal);\r\n if (!sigStarted) { sigPath.moveTo(x, y); sigStarted = true; }\r\n else sigPath.lineTo(x, y);\r\n }\r\n }\r\n\r\n // Draw histogram\r\n ctx.fillStyle = posColor;\r\n ctx.fill(posPath);\r\n ctx.fillStyle = negColor;\r\n ctx.fill(negPath);\r\n\r\n // Draw lines\r\n ctx.strokeStyle = macdColor;\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n ctx.stroke(macdPath);\r\n\r\n ctx.strokeStyle = signalColor;\r\n ctx.stroke(sigPath);\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class StochasticIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'stochastic',\r\n name: 'Stochastic Oscillator',\r\n placement: 'panel' as const,\r\n defaultConfig: { kPeriod: 14, dPeriod: 3, smooth: 3 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const kPeriod = getIntParam(config, 'kPeriod', 14, 1);\r\n const dPeriod = getIntParam(config, 'dPeriod', 3, 1);\r\n const smooth = getIntParam(config, 'smooth', 3, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n if (data.length < kPeriod) return { values, series };\r\n\r\n // Raw %K\r\n const rawK: number[] = [];\r\n for (let i = 0; i < data.length; i++) {\r\n if (i < kPeriod - 1) { rawK.push(0); continue; }\r\n let high = -Infinity;\r\n let low = Infinity;\r\n for (let j = i - kPeriod + 1; j <= i; j++) {\r\n if (data[j].high > high) high = data[j].high;\r\n if (data[j].low < low) low = data[j].low;\r\n }\r\n rawK.push(high === low ? 50 : ((data[i].close - low) / (high - low)) * 100);\r\n }\r\n\r\n // Smoothed %K (SMA of raw %K)\r\n const kValues: number[] = [];\r\n for (let i = 0; i < rawK.length; i++) {\r\n if (i < kPeriod - 1 + smooth - 1) { kValues.push(0); continue; }\r\n let sum = 0;\r\n for (let j = i - smooth + 1; j <= i; j++) sum += rawK[j];\r\n kValues.push(sum / smooth);\r\n }\r\n\r\n // %D (SMA of %K)\r\n const startIdx = kPeriod - 1 + smooth - 1;\r\n for (let i = startIdx; i < kValues.length; i++) {\r\n const val: IndicatorValue = { k: kValues[i] };\r\n if (i >= startIdx + dPeriod - 1) {\r\n let sum = 0;\r\n for (let j = i - dPeriod + 1; j <= i; j++) sum += kValues[j];\r\n val.d = sum / dPeriod;\r\n }\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n const toY = (val: number) => chartRect.y + chartRect.height * (1 - val / 100);\r\n\r\n // Levels\r\n ctx.strokeStyle = style.colors[2] ?? '#787B86';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n for (const level of [20, 80]) {\r\n const y = toY(level);\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, y);\r\n ctx.lineTo(chartRect.x + chartRect.width, y);\r\n ctx.stroke();\r\n }\r\n ctx.setLineDash([]);\r\n\r\n // %K line\r\n const drawLine = (key: string, color: string) => {\r\n ctx.beginPath();\r\n ctx.strokeStyle = color;\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val[key] === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val[key]!);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n ctx.stroke();\r\n };\r\n\r\n drawLine('k', style.colors[0]);\r\n drawLine('d', style.colors[1] ?? '#FF9800');\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class ATRIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'atr',\r\n name: 'Average True Range',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 14 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 14, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n if (data.length < 2) return { values, series };\r\n\r\n const trueRanges: number[] = [data[0].high - data[0].low];\r\n for (let i = 1; i < data.length; i++) {\r\n const tr = Math.max(\r\n data[i].high - data[i].low,\r\n Math.abs(data[i].high - data[i - 1].close),\r\n Math.abs(data[i].low - data[i - 1].close),\r\n );\r\n trueRanges.push(tr);\r\n }\r\n\r\n let atr = 0;\r\n for (let i = 0; i < period; i++) atr += trueRanges[i];\r\n atr /= period;\r\n const val0: IndicatorValue = { value: atr };\r\n values.set(data[period - 1].time, val0);\r\n series[period - 1] = val0;\r\n\r\n for (let i = period; i < data.length; i++) {\r\n atr = (atr * (period - 1) + trueRanges[i]) / period;\r\n const val: IndicatorValue = { value: atr };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n let minVal = Infinity;\r\n let maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n minVal = Math.min(minVal, val.value);\r\n maxVal = Math.max(maxVal, val.value);\r\n }\r\n }\r\n if (minVal === Infinity) return;\r\n const range = maxVal - minVal || 1;\r\n const padding = range * 0.1;\r\n const adjMin = minVal - padding;\r\n const adjMax = maxVal + padding;\r\n const adjRange = adjMax - adjMin;\r\n\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - adjMin) / adjRange);\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class ADXIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'adx',\r\n name: 'Average Directional Index',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 14 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 14, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n if (data.length < period * 2) return { values, series };\r\n\r\n const trArr: number[] = [];\r\n const plusDM: number[] = [];\r\n const minusDM: number[] = [];\r\n\r\n for (let i = 1; i < data.length; i++) {\r\n const tr = Math.max(\r\n data[i].high - data[i].low,\r\n Math.abs(data[i].high - data[i - 1].close),\r\n Math.abs(data[i].low - data[i - 1].close),\r\n );\r\n trArr.push(tr);\r\n\r\n const upMove = data[i].high - data[i - 1].high;\r\n const downMove = data[i - 1].low - data[i].low;\r\n plusDM.push(upMove > downMove && upMove > 0 ? upMove : 0);\r\n minusDM.push(downMove > upMove && downMove > 0 ? downMove : 0);\r\n }\r\n\r\n // Smoothed values\r\n let smoothTR = 0;\r\n let smoothPlusDM = 0;\r\n let smoothMinusDM = 0;\r\n for (let i = 0; i < period; i++) {\r\n smoothTR += trArr[i];\r\n smoothPlusDM += plusDM[i];\r\n smoothMinusDM += minusDM[i];\r\n }\r\n\r\n const dxValues: number[] = [];\r\n\r\n for (let i = period; i < trArr.length; i++) {\r\n if (i > period) {\r\n smoothTR = smoothTR - smoothTR / period + trArr[i];\r\n smoothPlusDM = smoothPlusDM - smoothPlusDM / period + plusDM[i];\r\n smoothMinusDM = smoothMinusDM - smoothMinusDM / period + minusDM[i];\r\n }\r\n\r\n const plusDI = smoothTR !== 0 ? (smoothPlusDM / smoothTR) * 100 : 0;\r\n const minusDI = smoothTR !== 0 ? (smoothMinusDM / smoothTR) * 100 : 0;\r\n const diSum = plusDI + minusDI;\r\n const dx = diSum !== 0 ? Math.abs(plusDI - minusDI) / diSum * 100 : 0;\r\n dxValues.push(dx);\r\n\r\n const dataIdx = i + 1;\r\n const val: IndicatorValue = { plusDI, minusDI, dx };\r\n values.set(data[dataIdx].time, val);\r\n series[dataIdx] = val;\r\n }\r\n\r\n // ADX = smoothed DX\r\n if (dxValues.length >= period) {\r\n let adx = 0;\r\n for (let i = 0; i < period; i++) adx += dxValues[i];\r\n adx /= period;\r\n\r\n const startDataIdx = period * 2;\r\n if (startDataIdx < data.length) {\r\n const existing = values.get(data[startDataIdx].time);\r\n if (existing) existing.adx = adx;\r\n if (series[startDataIdx]) series[startDataIdx]!.adx = adx;\r\n }\r\n\r\n for (let i = period; i < dxValues.length; i++) {\r\n adx = (adx * (period - 1) + dxValues[i]) / period;\r\n const dataIdx = i + period + 1;\r\n if (dataIdx < data.length) {\r\n const existing = values.get(data[dataIdx].time);\r\n if (existing) existing.adx = adx;\r\n if (series[dataIdx]) series[dataIdx]!.adx = adx;\r\n }\r\n }\r\n }\r\n\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n const toY = (val: number) => chartRect.y + chartRect.height * (1 - val / 100);\r\n\r\n const drawLine = (key: string, color: string) => {\r\n ctx.beginPath();\r\n ctx.strokeStyle = color;\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val[key] === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val[key]!);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n ctx.stroke();\r\n };\r\n\r\n drawLine('adx', style.colors[0]);\r\n drawLine('plusDI', style.colors[1] ?? '#26A69A');\r\n drawLine('minusDI', style.colors[2] ?? '#EF5350');\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\nimport { IndicatorBase } from '../IndicatorBase.js';\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\n\nexport class OBVIndicator extends IndicatorBase {\n descriptor = {\n id: 'obv',\n name: 'On Balance Volume',\n placement: 'panel' as const,\n defaultConfig: {},\n };\n\n calculate(data: DataSeries, _config: IndicatorConfig): IndicatorOutput {\n const values = new Map<number, IndicatorValue>();\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\n if (data.length === 0) return { values, series };\n\n let obv = 0;\n const val0: IndicatorValue = { value: obv };\n values.set(data[0].time, val0);\n series[0] = val0;\n\n for (let i = 1; i < data.length; i++) {\n if (data[i].close > data[i - 1].close) obv += data[i].volume;\n else if (data[i].close < data[i - 1].close) obv -= data[i].volume;\n const val: IndicatorValue = { value: obv };\n values.set(data[i].time, val);\n series[i] = val;\n }\n return { values, series };\n }\n\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\n const series = output.series;\n if (!series) return;\n const { chartRect } = viewport;\n const { from, to } = viewport.visibleRange;\n\n let minVal = Infinity;\n let maxVal = -Infinity;\n for (let i = from; i <= to && i < series.length; i++) {\n const val = series[i];\n if (val && val.value !== undefined) {\n minVal = Math.min(minVal, val.value);\n maxVal = Math.max(maxVal, val.value);\n }\n }\n if (minVal === Infinity) return;\n const range = maxVal - minVal || 1;\n const padding = range * 0.1;\n const adjMin = minVal - padding;\n const adjRange = (maxVal + padding) - adjMin;\n\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - adjMin) / adjRange);\n\n ctx.beginPath();\n ctx.strokeStyle = style.colors[0];\n ctx.lineWidth = style.lineWidths[0];\n ctx.lineJoin = 'round';\n\n let started = false;\n for (let i = from; i <= to && i < series.length; i++) {\n const val = series[i];\n if (val && val.value !== undefined) {\n const x = barIndexToX(i, viewport);\n const y = toY(val.value);\n if (!started) { ctx.moveTo(x, y); started = true; }\n else ctx.lineTo(x, y);\n }\n }\n ctx.stroke();\n }\n}\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class WilliamsRIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'williamsR',\r\n name: 'Williams %R',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 14 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 14, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n for (let i = period - 1; i < data.length; i++) {\r\n let highestHigh = -Infinity;\r\n let lowestLow = Infinity;\r\n for (let j = i - period + 1; j <= i; j++) {\r\n if (data[j].high > highestHigh) highestHigh = data[j].high;\r\n if (data[j].low < lowestLow) lowestLow = data[j].low;\r\n }\r\n const wr = highestHigh === lowestLow ? -50 : ((highestHigh - data[i].close) / (highestHigh - lowestLow)) * -100;\r\n const val: IndicatorValue = { value: wr };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v + 100) / 100);\r\n\r\n // Levels at -20 and -80\r\n ctx.strokeStyle = style.colors[1] ?? '#787B86';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n for (const level of [-20, -80]) {\r\n const y = toY(level);\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, y);\r\n ctx.lineTo(chartRect.x + chartRect.width, y);\r\n ctx.stroke();\r\n }\r\n ctx.setLineDash([]);\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class CCIIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'cci',\r\n name: 'Commodity Channel Index',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 20 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 20, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n for (let i = period - 1; i < data.length; i++) {\r\n let sumTP = 0;\r\n for (let j = i - period + 1; j <= i; j++) {\r\n sumTP += (data[j].high + data[j].low + data[j].close) / 3;\r\n }\r\n const meanTP = sumTP / period;\r\n let sumDev = 0;\r\n for (let j = i - period + 1; j <= i; j++) {\r\n const tp = (data[j].high + data[j].low + data[j].close) / 3;\r\n sumDev += Math.abs(tp - meanTP);\r\n }\r\n const meanDev = sumDev / period;\r\n const tp = (data[i].high + data[i].low + data[i].close) / 3;\r\n const cci = meanDev === 0 ? 0 : (tp - meanTP) / (0.015 * meanDev);\r\n const val: IndicatorValue = { value: cci };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n let minVal = Infinity, maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n minVal = Math.min(minVal, val.value);\r\n maxVal = Math.max(maxVal, val.value);\r\n }\r\n }\r\n if (minVal === Infinity) return;\r\n const range = maxVal - minVal || 1;\r\n const pad = range * 0.1;\r\n const adjMin = minVal - pad, adjMax = maxVal + pad, adjRange = adjMax - adjMin;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - adjMin) / adjRange);\r\n\r\n // Levels at +100, 0, -100\r\n ctx.strokeStyle = style.colors[1] ?? '#787B86';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n for (const level of [-100, 0, 100]) {\r\n if (level >= adjMin && level <= adjMax) {\r\n const y = toY(level);\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, y);\r\n ctx.lineTo(chartRect.x + chartRect.width, y);\r\n ctx.stroke();\r\n }\r\n }\r\n ctx.setLineDash([]);\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class MFIIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'mfi',\r\n name: 'Money Flow Index',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 14 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 14, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n if (data.length < period + 1) return { values, series };\r\n\r\n const typicalPrices = data.map((b) => (b.high + b.low + b.close) / 3);\r\n const rawMF = typicalPrices.map((tp, i) => tp * data[i].volume);\r\n\r\n for (let i = period; i < data.length; i++) {\r\n let posFlow = 0, negFlow = 0;\r\n for (let j = i - period + 1; j <= i; j++) {\r\n if (typicalPrices[j] > typicalPrices[j - 1]) posFlow += rawMF[j];\r\n else if (typicalPrices[j] < typicalPrices[j - 1]) negFlow += rawMF[j];\r\n }\r\n const mfi = negFlow === 0 ? 100 : 100 - 100 / (1 + posFlow / negFlow);\r\n const val: IndicatorValue = { value: mfi };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - v / 100);\r\n\r\n ctx.strokeStyle = style.colors[1] ?? '#787B86';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n for (const level of [20, 80]) {\r\n const y = toY(level);\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, y);\r\n ctx.lineTo(chartRect.x + chartRect.width, y);\r\n ctx.stroke();\r\n }\r\n ctx.setLineDash([]);\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class AroonIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'aroon',\r\n name: 'Aroon',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 25 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 25, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n for (let i = period; i < data.length; i++) {\r\n let highIdx = 0, lowIdx = 0;\r\n let high = -Infinity, low = Infinity;\r\n for (let j = 0; j <= period; j++) {\r\n const k = i - period + j;\r\n if (data[k].high > high) { high = data[k].high; highIdx = j; }\r\n if (data[k].low < low) { low = data[k].low; lowIdx = j; }\r\n }\r\n const val: IndicatorValue = {\r\n up: (highIdx / period) * 100,\r\n down: (lowIdx / period) * 100,\r\n };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - v / 100);\r\n\r\n const drawLine = (key: string, color: string) => {\r\n ctx.beginPath();\r\n ctx.strokeStyle = color;\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val[key] === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val[key]!);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n ctx.stroke();\r\n };\r\n\r\n drawLine('up', style.colors[0]);\r\n drawLine('down', style.colors[1] ?? '#EF5350');\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class ROCIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'roc',\r\n name: 'Rate of Change',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 12 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 12, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n for (let i = period; i < data.length; i++) {\r\n const prev = data[i - period].close;\r\n const roc = prev === 0 ? 0 : ((data[i].close - prev) / prev) * 100;\r\n const val: IndicatorValue = { value: roc };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n let minVal = Infinity, maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n minVal = Math.min(minVal, val.value);\r\n maxVal = Math.max(maxVal, val.value);\r\n }\r\n }\r\n if (minVal === Infinity) return;\r\n const range = maxVal - minVal || 1;\r\n const pad = range * 0.1;\r\n const adjMin = minVal - pad, adjMax = maxVal + pad, adjRange = adjMax - adjMin;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - adjMin) / adjRange);\r\n\r\n // Zero line\r\n if (0 >= adjMin && 0 <= adjMax) {\r\n ctx.strokeStyle = style.colors[1] ?? '#787B86';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n const y = toY(0);\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, y);\r\n ctx.lineTo(chartRect.x + chartRect.width, y);\r\n ctx.stroke();\r\n ctx.setLineDash([]);\r\n }\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class TSIIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'tsi',\r\n name: 'True Strength Index',\r\n placement: 'panel' as const,\r\n defaultConfig: { longPeriod: 25, shortPeriod: 13, signalPeriod: 7 },\r\n };\r\n\r\n private emaSmooth(values: number[], period: number): number[] {\r\n const mult = 2 / (period + 1);\r\n const result: number[] = [values[0]];\r\n for (let i = 1; i < values.length; i++) {\r\n result.push((values[i] - result[i - 1]) * mult + result[i - 1]);\r\n }\r\n return result;\r\n }\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const longP = getIntParam(config, 'longPeriod', 25, 1);\r\n const shortP = getIntParam(config, 'shortPeriod', 13, 1);\r\n const sigP = getIntParam(config, 'signalPeriod', 7, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n if (data.length < 2) return { values, series };\r\n\r\n const momentum: number[] = [];\r\n const absMomentum: number[] = [];\r\n for (let i = 1; i < data.length; i++) {\r\n const m = data[i].close - data[i - 1].close;\r\n momentum.push(m);\r\n absMomentum.push(Math.abs(m));\r\n }\r\n\r\n const smoothMom = this.emaSmooth(this.emaSmooth(momentum, longP), shortP);\r\n const smoothAbsMom = this.emaSmooth(this.emaSmooth(absMomentum, longP), shortP);\r\n\r\n const tsiValues: number[] = [];\r\n for (let i = 0; i < smoothMom.length; i++) {\r\n tsiValues.push(smoothAbsMom[i] === 0 ? 0 : (smoothMom[i] / smoothAbsMom[i]) * 100);\r\n }\r\n\r\n const signalLine = this.emaSmooth(tsiValues, sigP);\r\n\r\n for (let i = 0; i < tsiValues.length; i++) {\r\n const dataIdx = i + 1;\r\n if (dataIdx < data.length) {\r\n const val: IndicatorValue = {\r\n tsi: tsiValues[i],\r\n signal: signalLine[i],\r\n };\r\n values.set(data[dataIdx].time, val);\r\n series[dataIdx] = val;\r\n }\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n let minVal = Infinity, maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val) continue;\r\n if (val.tsi !== undefined) { minVal = Math.min(minVal, val.tsi); maxVal = Math.max(maxVal, val.tsi); }\r\n if (val.signal !== undefined) { minVal = Math.min(minVal, val.signal); maxVal = Math.max(maxVal, val.signal); }\r\n }\r\n if (minVal === Infinity) return;\r\n const range = maxVal - minVal || 1;\r\n const pad = range * 0.1;\r\n const adjMin = minVal - pad, adjMax = maxVal + pad, adjRange = adjMax - adjMin;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - adjMin) / adjRange);\r\n\r\n // Zero line\r\n if (0 >= adjMin && 0 <= adjMax) {\r\n ctx.strokeStyle = '#787B86';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, toY(0));\r\n ctx.lineTo(chartRect.x + chartRect.width, toY(0));\r\n ctx.stroke();\r\n ctx.setLineDash([]);\r\n }\r\n\r\n const drawLine = (key: string, color: string) => {\r\n ctx.beginPath();\r\n ctx.strokeStyle = color;\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val[key] === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val[key]!);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n ctx.stroke();\r\n };\r\n\r\n drawLine('tsi', style.colors[0]);\r\n drawLine('signal', style.colors[1] ?? '#FF9800');\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class CMFIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'cmf',\r\n name: 'Chaikin Money Flow',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 20 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 20, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n for (let i = period - 1; i < data.length; i++) {\r\n let mfvSum = 0, volSum = 0;\r\n for (let j = i - period + 1; j <= i; j++) {\r\n const hl = data[j].high - data[j].low;\r\n const mfm = hl === 0 ? 0 : ((data[j].close - data[j].low) - (data[j].high - data[j].close)) / hl;\r\n mfvSum += mfm * data[j].volume;\r\n volSum += data[j].volume;\r\n }\r\n const val: IndicatorValue = { value: volSum === 0 ? 0 : mfvSum / volSum };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n let minVal = Infinity, maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n minVal = Math.min(minVal, val.value);\r\n maxVal = Math.max(maxVal, val.value);\r\n }\r\n }\r\n if (minVal === Infinity) return;\r\n const range = maxVal - minVal || 1;\r\n const pad = range * 0.1;\r\n const adjMin = minVal - pad, adjMax = maxVal + pad, adjRange = adjMax - adjMin;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - adjMin) / adjRange);\r\n\r\n // Zero line\r\n if (0 >= adjMin && 0 <= adjMax) {\r\n ctx.strokeStyle = '#787B86';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, toY(0));\r\n ctx.lineTo(chartRect.x + chartRect.width, toY(0));\r\n ctx.stroke();\r\n ctx.setLineDash([]);\r\n }\r\n\r\n // Histogram bars\r\n const halfBar = viewport.barWidth / 2;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n const zeroY = toY(0);\r\n ctx.fillStyle = val.value >= 0 ? (style.colors[0]) : (style.colors[1] ?? '#EF5350');\r\n const top = Math.min(y, zeroY);\r\n ctx.fillRect(x - halfBar, top, viewport.barWidth, Math.max(Math.abs(y - zeroY), 1));\r\n }\r\n }\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class StdDevIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'stddev',\r\n name: 'Standard Deviation',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 20 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 20, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n for (let i = period - 1; i < data.length; i++) {\r\n let sum = 0;\r\n for (let j = i - period + 1; j <= i; j++) sum += data[j].close;\r\n const mean = sum / period;\r\n let variance = 0;\r\n for (let j = i - period + 1; j <= i; j++) {\r\n const d = data[j].close - mean;\r\n variance += d * d;\r\n }\r\n const val: IndicatorValue = { value: Math.sqrt(variance / period) };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n let minVal = Infinity, maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n minVal = Math.min(minVal, val.value);\r\n maxVal = Math.max(maxVal, val.value);\r\n }\r\n }\r\n if (minVal === Infinity) return;\r\n const range = maxVal - minVal || 1;\r\n const pad = range * 0.1;\r\n const adjMin = minVal - pad, adjRange = (maxVal + pad) - adjMin;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - adjMin) / adjRange);\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\n\r\nexport class VolumeProfileIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'volumeProfile',\r\n name: 'Volume Profile',\r\n placement: 'panel' as const,\r\n defaultConfig: { rows: 24 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const rows = getIntParam(config, 'rows', 24, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n if (data.length === 0) return { values, series };\r\n\r\n let minPrice = Infinity, maxPrice = -Infinity;\r\n for (const bar of data) {\r\n if (bar.low < minPrice) minPrice = bar.low;\r\n if (bar.high > maxPrice) maxPrice = bar.high;\r\n }\r\n\r\n const range = maxPrice - minPrice || 1;\r\n const rowHeight = range / rows;\r\n const bins = new Array(rows).fill(0);\r\n\r\n for (const bar of data) {\r\n const typicalPrice = (bar.high + bar.low + bar.close) / 3;\r\n const bin = Math.min(rows - 1, Math.floor((typicalPrice - minPrice) / rowHeight));\r\n bins[bin] += bar.volume;\r\n }\r\n\r\n // Store bins as values keyed by a synthetic timestamp (row index)\r\n for (let i = 0; i < rows; i++) {\r\n const price = minPrice + (i + 0.5) * rowHeight;\r\n values.set(i, { price, volume: bins[i], rowIndex: i });\r\n }\r\n\r\n return {\r\n values,\r\n series,\r\n meta: { minPrice, maxPrice, rows, rowHeight, bins, maxVolume: Math.max(...bins) },\r\n };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const { chartRect } = viewport;\r\n const meta = output.meta as { minPrice: number; maxPrice: number; rows: number; rowHeight: number; bins: number[]; maxVolume: number } | undefined;\r\n if (!meta || meta.maxVolume === 0) return;\r\n\r\n const { minPrice, rows, rowHeight, bins, maxVolume } = meta;\r\n const barHeight = chartRect.height / rows;\r\n const maxBarWidth = chartRect.width * 0.3;\r\n\r\n for (let i = 0; i < rows; i++) {\r\n const price = minPrice + (i + 0.5) * rowHeight;\r\n const ratio = (price - viewport.priceRange.min) / (viewport.priceRange.max - viewport.priceRange.min);\r\n const y = chartRect.y + chartRect.height * (1 - ratio);\r\n const width = (bins[i] / maxVolume) * maxBarWidth;\r\n\r\n ctx.fillStyle = bins[i] > maxVolume * 0.7\r\n ? (style.colors[1] ?? 'rgba(255, 152, 0, 0.5)')\r\n : (style.colors[0] ?? 'rgba(33, 150, 243, 0.3)');\r\n ctx.fillRect(chartRect.x, y - barHeight / 2, width, Math.max(barHeight - 1, 1));\r\n }\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\nimport { IndicatorBase } from '../IndicatorBase.js';\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\n\nexport class AccumulationDistributionIndicator extends IndicatorBase {\n descriptor = {\n id: 'ad',\n name: 'Accumulation/Distribution',\n placement: 'panel' as const,\n defaultConfig: {},\n };\n\n calculate(data: DataSeries, _config: IndicatorConfig): IndicatorOutput {\n const values = new Map<number, IndicatorValue>();\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\n if (data.length === 0) return { values, series };\n\n let ad = 0;\n for (let i = 0; i < data.length; i++) {\n const hl = data[i].high - data[i].low;\n const mfm = hl === 0 ? 0 : ((data[i].close - data[i].low) - (data[i].high - data[i].close)) / hl;\n ad += mfm * data[i].volume;\n const val: IndicatorValue = { value: ad };\n values.set(data[i].time, val);\n series[i] = val;\n }\n return { values, series };\n }\n\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\n const series = output.series;\n if (!series) return;\n const { chartRect } = viewport;\n const { from, to } = viewport.visibleRange;\n\n let minVal = Infinity, maxVal = -Infinity;\n for (let i = from; i <= to && i < series.length; i++) {\n const val = series[i];\n if (val && val.value !== undefined) {\n minVal = Math.min(minVal, val.value);\n maxVal = Math.max(maxVal, val.value);\n }\n }\n if (minVal === Infinity) return;\n const range = maxVal - minVal || 1;\n const pad = range * 0.1;\n const adjMin = minVal - pad, adjRange = (maxVal + pad) - adjMin;\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - adjMin) / adjRange);\n\n ctx.beginPath();\n ctx.strokeStyle = style.colors[0];\n ctx.lineWidth = style.lineWidths[0];\n ctx.lineJoin = 'round';\n let started = false;\n for (let i = from; i <= to && i < series.length; i++) {\n const val = series[i];\n if (val && val.value !== undefined) {\n const x = barIndexToX(i, viewport);\n const y = toY(val.value);\n if (!started) { ctx.moveTo(x, y); started = true; }\n else ctx.lineTo(x, y);\n }\n }\n ctx.stroke();\n }\n}\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class VROCIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'vroc',\r\n name: 'Volume Rate of Change',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 14 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 14, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n for (let i = period; i < data.length; i++) {\r\n const prev = data[i - period].volume;\r\n const vroc = prev === 0 ? 0 : ((data[i].volume - prev) / prev) * 100;\r\n const val: IndicatorValue = { value: vroc };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n let minVal = Infinity, maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n minVal = Math.min(minVal, val.value);\r\n maxVal = Math.max(maxVal, val.value);\r\n }\r\n }\r\n if (minVal === Infinity) return;\r\n const range = maxVal - minVal || 1;\r\n const pad = range * 0.1;\r\n const adjMin = minVal - pad, adjMax = maxVal + pad, adjRange = adjMax - adjMin;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - adjMin) / adjRange);\r\n\r\n // Zero line\r\n if (0 >= adjMin && 0 <= adjMax) {\r\n ctx.strokeStyle = '#787B86';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, toY(0));\r\n ctx.lineTo(chartRect.x + chartRect.width, toY(0));\r\n ctx.stroke();\r\n ctx.setLineDash([]);\r\n }\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { IndicatorEngine } from './IndicatorEngine.js';\r\n// Overlays\r\nimport { SMAIndicator } from './overlay/SMA.js';\r\nimport { EMAIndicator } from './overlay/EMA.js';\r\nimport { BollingerBandsIndicator } from './overlay/BollingerBands.js';\r\nimport { VWAPIndicator } from './overlay/VWAP.js';\r\nimport { IchimokuIndicator } from './overlay/Ichimoku.js';\r\nimport { ParabolicSARIndicator } from './overlay/ParabolicSAR.js';\r\nimport { SupertrendIndicator } from './overlay/Supertrend.js';\r\nimport { KeltnerChannelIndicator } from './overlay/KeltnerChannel.js';\r\nimport { DonchianChannelIndicator } from './overlay/DonchianChannel.js';\r\nimport { PivotPointsIndicator } from './overlay/PivotPoints.js';\r\nimport { AnchoredVWAPIndicator } from './overlay/AnchoredVWAP.js';\r\nimport { ZigZagIndicator } from './overlay/ZigZag.js';\r\nimport { LinearRegressionChannelIndicator } from './overlay/LinearRegressionChannel.js';\r\nimport { HullMAIndicator } from './overlay/HullMA.js';\r\nimport { AwesomeOscillatorIndicator } from './panel/AwesomeOscillator.js';\r\nimport { ChaikinOscillatorIndicator } from './panel/ChaikinOscillator.js';\r\n// Panels\r\nimport { RSIIndicator } from './panel/RSI.js';\r\nimport { MACDIndicator } from './panel/MACD.js';\r\nimport { StochasticIndicator } from './panel/Stochastic.js';\r\nimport { ATRIndicator } from './panel/ATR.js';\r\nimport { ADXIndicator } from './panel/ADX.js';\r\nimport { OBVIndicator } from './panel/OBV.js';\r\nimport { WilliamsRIndicator } from './panel/WilliamsR.js';\r\nimport { CCIIndicator } from './panel/CCI.js';\r\nimport { MFIIndicator } from './panel/MFI.js';\r\nimport { AroonIndicator } from './panel/Aroon.js';\r\nimport { ROCIndicator } from './panel/ROC.js';\r\nimport { TSIIndicator } from './panel/TSI.js';\r\nimport { CMFIndicator } from './panel/CMF.js';\r\nimport { StdDevIndicator } from './panel/StdDev.js';\r\nimport { VolumeProfileIndicator } from './panel/VolumeProfile.js';\r\nimport { AccumulationDistributionIndicator } from './panel/AccumulationDistribution.js';\r\nimport { VROCIndicator } from './panel/VROC.js';\r\n\r\nexport function registerBuiltInIndicators(engine: IndicatorEngine): void {\r\n // Overlays\r\n engine.register(new SMAIndicator());\r\n engine.register(new EMAIndicator());\r\n engine.register(new BollingerBandsIndicator());\r\n engine.register(new VWAPIndicator());\r\n engine.register(new IchimokuIndicator());\r\n engine.register(new ParabolicSARIndicator());\r\n engine.register(new SupertrendIndicator());\r\n engine.register(new KeltnerChannelIndicator());\r\n engine.register(new DonchianChannelIndicator());\r\n engine.register(new PivotPointsIndicator());\r\n engine.register(new AnchoredVWAPIndicator());\r\n engine.register(new ZigZagIndicator());\r\n engine.register(new LinearRegressionChannelIndicator());\r\n engine.register(new HullMAIndicator());\r\n // Panels\r\n engine.register(new RSIIndicator());\r\n engine.register(new MACDIndicator());\r\n engine.register(new StochasticIndicator());\r\n engine.register(new ATRIndicator());\r\n engine.register(new ADXIndicator());\r\n engine.register(new OBVIndicator());\r\n engine.register(new WilliamsRIndicator());\r\n engine.register(new CCIIndicator());\r\n engine.register(new MFIIndicator());\r\n engine.register(new AroonIndicator());\r\n engine.register(new ROCIndicator());\r\n engine.register(new TSIIndicator());\r\n engine.register(new CMFIndicator());\r\n engine.register(new StdDevIndicator());\r\n engine.register(new VolumeProfileIndicator());\r\n engine.register(new AccumulationDistributionIndicator());\r\n engine.register(new VROCIndicator());\r\n engine.register(new AwesomeOscillatorIndicator());\r\n engine.register(new ChaikinOscillatorIndicator());\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput } from '@tradecanvas/commons';\r\n\r\n/** Request sent from main thread → worker. */\r\nexport type IndicatorWorkerRequest =\r\n | {\r\n type: 'calculate';\r\n requestId: number;\r\n indicatorId: string;\r\n config: IndicatorConfig;\r\n data: DataSeries;\r\n }\r\n | { type: 'ping'; requestId: number };\r\n\r\n/** Response posted from worker → main thread. */\r\nexport type IndicatorWorkerResponse =\r\n | { type: 'result'; requestId: number; output: IndicatorOutput }\r\n | { type: 'pong'; requestId: number }\r\n | { type: 'error'; requestId: number; message: string };\r\n\r\nexport function isWorkerResponse(value: unknown): value is IndicatorWorkerResponse {\r\n if (typeof value !== 'object' || value === null) return false;\r\n const v = value as { type?: unknown; requestId?: unknown };\r\n if (typeof v.requestId !== 'number') return false;\r\n return v.type === 'result' || v.type === 'pong' || v.type === 'error';\r\n}\r\n","import type {\r\n DataSeries,\r\n IndicatorConfig,\r\n IndicatorOutput,\r\n IndicatorPlugin,\r\n} from '@tradecanvas/commons';\r\nimport { isWorkerResponse } from './messages.js';\r\nimport type { IndicatorWorkerRequest, IndicatorWorkerResponse } from './messages.js';\r\n\r\n/**\r\n * A minimal worker shape — easier to mock than the full DOM `Worker`.\r\n * Real `Worker` instances satisfy this interface; tests can pass a stub.\r\n */\r\nexport interface WorkerLike {\r\n postMessage(msg: unknown): void;\r\n addEventListener(\r\n type: 'message' | 'error' | 'messageerror',\r\n listener: (ev: MessageEvent | ErrorEvent) => void,\r\n ): void;\r\n removeEventListener(\r\n type: 'message' | 'error' | 'messageerror',\r\n listener: (ev: MessageEvent | ErrorEvent) => void,\r\n ): void;\r\n terminate(): void;\r\n}\r\n\r\ninterface PendingRequest {\r\n resolve: (output: IndicatorOutput) => void;\r\n reject: (err: Error) => void;\r\n timer: ReturnType<typeof setTimeout> | null;\r\n}\r\n\r\nexport interface IndicatorWorkerHostOptions {\r\n /** Synchronous fallback registry. Used when no worker is provided. */\r\n fallbackPlugins?: Map<string, IndicatorPlugin>;\r\n /** Per-request timeout in ms. Default 30s. Set to 0 to disable. */\r\n timeoutMs?: number;\r\n}\r\n\r\n/**\r\n * Main-thread façade for indicator calculations. When a `Worker` is provided,\r\n * `calculate()` posts the request and resolves with the worker's response.\r\n * Without a worker, it falls back to synchronous calculation against\r\n * `fallbackPlugins` — useful for SSR, tests, or as a safety net.\r\n *\r\n * Render is intentionally NOT routed through the worker because it needs\r\n * `CanvasRenderingContext2D`. This class only offloads `calculate()`.\r\n */\r\nexport class IndicatorWorkerHost {\r\n private worker: WorkerLike | null;\r\n private fallbackPlugins: Map<string, IndicatorPlugin>;\r\n private timeoutMs: number;\r\n private nextRequestId = 1;\r\n private pending = new Map<number, PendingRequest>();\r\n private messageHandler: (ev: MessageEvent | ErrorEvent) => void;\r\n\r\n constructor(worker: WorkerLike | null, options: IndicatorWorkerHostOptions = {}) {\r\n this.worker = worker;\r\n this.fallbackPlugins = options.fallbackPlugins ?? new Map();\r\n this.timeoutMs = options.timeoutMs ?? 30_000;\r\n this.messageHandler = (ev) => this.handleMessage(ev);\r\n if (this.worker) {\r\n this.worker.addEventListener('message', this.messageHandler);\r\n this.worker.addEventListener('error', this.messageHandler);\r\n }\r\n }\r\n\r\n /** True when a worker is attached. False means calls run synchronously. */\r\n hasWorker(): boolean {\r\n return this.worker !== null;\r\n }\r\n\r\n registerFallbackPlugin(plugin: IndicatorPlugin): void {\r\n this.fallbackPlugins.set(plugin.descriptor.id, plugin);\r\n }\r\n\r\n /**\r\n * Compute an indicator output. Routes through the worker when present,\r\n * otherwise calls the fallback plugin synchronously.\r\n */\r\n async calculate(\r\n indicatorId: string,\r\n config: IndicatorConfig,\r\n data: DataSeries,\r\n ): Promise<IndicatorOutput> {\r\n if (!this.worker) {\r\n const plugin = this.fallbackPlugins.get(indicatorId);\r\n if (!plugin) throw new Error(`Unknown indicator: ${indicatorId}`);\r\n return plugin.calculate(data, config);\r\n }\r\n\r\n const requestId = this.nextRequestId++;\r\n const req: IndicatorWorkerRequest = {\r\n type: 'calculate',\r\n requestId,\r\n indicatorId,\r\n config,\r\n data,\r\n };\r\n\r\n return new Promise<IndicatorOutput>((resolve, reject) => {\r\n const entry: PendingRequest = { resolve, reject, timer: null };\r\n if (this.timeoutMs > 0) {\r\n entry.timer = setTimeout(() => {\r\n this.pending.delete(requestId);\r\n reject(new Error(`Indicator worker timeout (${this.timeoutMs}ms): ${indicatorId}`));\r\n }, this.timeoutMs);\r\n }\r\n this.pending.set(requestId, entry);\r\n this.worker!.postMessage(req);\r\n });\r\n }\r\n\r\n /** Issue a ping; resolves when the worker responds. Useful for health checks. */\r\n ping(): Promise<void> {\r\n if (!this.worker) return Promise.resolve();\r\n const requestId = this.nextRequestId++;\r\n return new Promise<void>((resolve, reject) => {\r\n const entry: PendingRequest = {\r\n resolve: () => resolve(),\r\n reject,\r\n timer:\r\n this.timeoutMs > 0\r\n ? setTimeout(() => {\r\n this.pending.delete(requestId);\r\n reject(new Error('Indicator worker ping timeout'));\r\n }, this.timeoutMs)\r\n : null,\r\n };\r\n this.pending.set(requestId, entry);\r\n this.worker!.postMessage({ type: 'ping', requestId });\r\n });\r\n }\r\n\r\n terminate(): void {\r\n if (this.worker) {\r\n this.worker.removeEventListener('message', this.messageHandler);\r\n this.worker.removeEventListener('error', this.messageHandler);\r\n this.worker.terminate();\r\n this.worker = null;\r\n }\r\n for (const entry of this.pending.values()) {\r\n if (entry.timer) clearTimeout(entry.timer);\r\n entry.reject(new Error('Indicator worker terminated'));\r\n }\r\n this.pending.clear();\r\n }\r\n\r\n private handleMessage(ev: MessageEvent | ErrorEvent): void {\r\n const data = (ev as MessageEvent).data;\r\n if (data !== undefined) {\r\n if (!isWorkerResponse(data)) return;\r\n this.dispatchResponse(data);\r\n return;\r\n }\r\n\r\n // No data field → treat as an error event. Reject all pending requests.\r\n const message = (ev as ErrorEvent).message ?? 'Indicator worker error';\r\n for (const [id, entry] of this.pending) {\r\n if (entry.timer) clearTimeout(entry.timer);\r\n entry.reject(new Error(message));\r\n this.pending.delete(id);\r\n }\r\n }\r\n\r\n private dispatchResponse(res: IndicatorWorkerResponse): void {\r\n const entry = this.pending.get(res.requestId);\r\n if (!entry) return;\r\n this.pending.delete(res.requestId);\r\n if (entry.timer) clearTimeout(entry.timer);\r\n\r\n if (res.type === 'error') {\r\n entry.reject(new Error(res.message));\r\n return;\r\n }\r\n if (res.type === 'pong') {\r\n entry.resolve(undefined as unknown as IndicatorOutput);\r\n return;\r\n }\r\n entry.resolve(res.output);\r\n }\r\n}\r\n","import type { ViewportState, Theme } from '@tradecanvas/commons';\nimport { computeTickStep } from '@tradecanvas/commons';\n\nexport class GridRenderer {\n private visible = true;\n\n setVisible(v: boolean): void { this.visible = v; }\n isVisible(): boolean { return this.visible; }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n if (!this.visible) return;\n const { chartRect, priceRange } = viewport;\n ctx.strokeStyle = theme.grid;\n ctx.lineWidth = 1;\n\n const range = priceRange.max - priceRange.min;\n if (range <= 0) return;\n const invRange = 1 / range;\n\n // Single path for all grid lines — one stroke call\n ctx.beginPath();\n\n // Horizontal grid lines (price levels)\n const priceStep = computeTickStep(priceRange.min, priceRange.max, 8);\n const firstPrice = Math.ceil(priceRange.min / priceStep) * priceStep;\n for (let price = firstPrice; price <= priceRange.max; price += priceStep) {\n const y = Math.round(chartRect.y + chartRect.height * (1 - (price - priceRange.min) * invRange)) + 0.5;\n ctx.moveTo(chartRect.x, y);\n ctx.lineTo(chartRect.x + chartRect.width, y);\n }\n\n // Vertical grid lines (time intervals)\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const barsPerGrid = Math.max(1, Math.ceil(80 / barUnit));\n const { from, to } = viewport.visibleRange;\n const offsetX = -viewport.offset + chartRect.x + viewport.barWidth / 2;\n for (let i = from; i <= to; i++) {\n if (i % barsPerGrid !== 0) continue;\n const x = Math.round(i * barUnit + offsetX) + 0.5;\n ctx.moveTo(x, chartRect.y);\n ctx.lineTo(x, chartRect.y + chartRect.height);\n }\n\n ctx.stroke();\n }\n}\n","import type { ViewportState, Theme } from '@tradecanvas/commons';\nimport { computeTickStep, formatPrice, PRICE_AXIS_WIDTH } from '@tradecanvas/commons';\n\nexport class PriceAxis {\n private locale = 'en-US';\n\n setLocale(locale: string): void {\n this.locale = locale;\n }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n const { chartRect, priceRange } = viewport;\n const axisX = chartRect.x + chartRect.width;\n const range = priceRange.max - priceRange.min;\n if (range <= 0) return;\n const invRange = 1 / range;\n\n // Axis line\n ctx.strokeStyle = theme.axisLine;\n ctx.lineWidth = 1;\n ctx.beginPath();\n ctx.moveTo(axisX + 0.5, chartRect.y);\n ctx.lineTo(axisX + 0.5, chartRect.y + chartRect.height);\n ctx.stroke();\n\n // Compute labels\n const step = computeTickStep(priceRange.min, priceRange.max, 8);\n const firstPrice = Math.ceil(priceRange.min / step) * step;\n const precision = step < 1 ? Math.ceil(-Math.log10(step)) + 1 : 2;\n const font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n\n // Collect label positions\n const labels: { y: number; text: string }[] = [];\n for (let price = firstPrice; price <= priceRange.max; price += step) {\n const y = chartRect.y + chartRect.height * (1 - (price - priceRange.min) * invRange);\n labels.push({ y, text: formatPrice(price, precision, this.locale) });\n }\n\n ctx.font = font;\n ctx.textBaseline = 'middle';\n ctx.textAlign = 'left';\n\n // Batch: all backgrounds first\n ctx.fillStyle = theme.axisLabelBackground;\n for (const { y } of labels) {\n ctx.fillRect(axisX + 1, y - 8, PRICE_AXIS_WIDTH - 2, 16);\n }\n\n // Batch: all text labels\n ctx.fillStyle = theme.axisLabel;\n for (const { y, text } of labels) {\n ctx.fillText(text, axisX + 5, y);\n }\n }\n}\n","import type { ViewportState, Theme, DataSeries } from '@tradecanvas/commons';\n\n// Reusable Date object — avoid allocation per bar\nconst _date = new Date();\nconst _pad2 = (n: number) => n < 10 ? '0' + n : '' + n;\n\n// Detect user's UTC offset once\nconst UTC_OFFSET_MIN = new Date().getTimezoneOffset();\nconst UTC_OFFSET_H = -UTC_OFFSET_MIN / 60;\nconst TZ_LABEL = `UTC${UTC_OFFSET_H >= 0 ? '+' : ''}${UTC_OFFSET_H}`;\n\nexport class TimeAxis {\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme, data: DataSeries, axisYOverride?: number): void {\n const { chartRect } = viewport;\n const axisY = axisYOverride ?? (chartRect.y + chartRect.height);\n\n // Axis line\n ctx.strokeStyle = theme.axisLine;\n ctx.lineWidth = 1;\n ctx.beginPath();\n ctx.moveTo(chartRect.x, axisY + 0.5);\n ctx.lineTo(chartRect.x + chartRect.width, axisY + 0.5);\n ctx.stroke();\n\n // Time labels\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const minLabelSpacing = 80;\n const barsPerLabel = Math.max(1, Math.ceil(minLabelSpacing / barUnit));\n const { from, to } = viewport.visibleRange;\n const offsetX = -viewport.offset + chartRect.x + viewport.barWidth / 2;\n\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n ctx.textBaseline = 'top';\n ctx.textAlign = 'center';\n ctx.fillStyle = theme.axisLabel;\n\n // Detect timeframe from bar spacing (approximate)\n let prevDay = -1;\n\n for (let i = from; i <= to && i < data.length; i++) {\n if (i % barsPerLabel !== 0) continue;\n const x = i * barUnit + offsetX;\n\n // Handle both milliseconds and seconds timestamps\n const rawTime = data[i].time;\n const timeMs = rawTime > 1e12 ? rawTime : rawTime * 1000;\n _date.setTime(timeMs);\n\n const day = _date.getDate();\n const month = _date.getMonth() + 1;\n const hours = _date.getHours();\n const minutes = _date.getMinutes();\n\n // Smart format: show date on day change, time otherwise\n let label: string;\n if (day !== prevDay) {\n label = `${month}/${day}`;\n prevDay = day;\n } else {\n label = `${_pad2(hours)}:${_pad2(minutes)}`;\n }\n\n ctx.fillText(label, x, axisY + 5);\n }\n\n // ─── Timezone indicator (bottom-right, like TradingView) ───\n const tzX = chartRect.x + chartRect.width - 4;\n const tzY = axisY + 4;\n ctx.font = `${theme.font.sizeSmall - 1}px ${theme.font.family}`;\n ctx.textAlign = 'right';\n ctx.textBaseline = 'top';\n ctx.fillStyle = theme.textSecondary;\n ctx.fillText(TZ_LABEL, tzX, tzY);\n }\n}\n","import type { Point, ViewportState } from '@tradecanvas/commons';\nimport type { PanHandler } from './PanHandler.js';\nimport type { ZoomHandler } from './ZoomHandler.js';\nimport type { CrosshairHandler } from './CrosshairHandler.js';\nimport type { DrawingManager } from '../drawings/DrawingManager.js';\nimport type { TradingManager } from '../trading/TradingManager.js';\n\nexport class InteractionManager {\n private panHandler: PanHandler | null = null;\n private zoomHandler: ZoomHandler | null = null;\n private crosshairHandler: CrosshairHandler | null = null;\n private drawingManager: DrawingManager | null = null;\n private tradingManager: TradingManager | null = null;\n private viewportGetter: (() => ViewportState) | null = null;\n private onOverlayDirty: (() => void) | null = null;\n private boundHandlers: (() => void)[] = [];\n\n // Touch state\n private lastTouchDist = 0;\n private lastTouchMid: Point = { x: 0, y: 0 };\n private touchActive = false;\n\n // Cached bounding rect — avoid a layout read per mousemove.\n // Invalidated on pointerdown, window resize, and explicit calls.\n private cachedRect: DOMRect | null = null;\n\n constructor(private element: HTMLElement) {}\n\n setOverlayDirtyCallback(cb: () => void): void { this.onOverlayDirty = cb; }\n\n setPanHandler(handler: PanHandler): void { this.panHandler = handler; }\n setZoomHandler(handler: ZoomHandler): void { this.zoomHandler = handler; }\n setCrosshairHandler(handler: CrosshairHandler): void { this.crosshairHandler = handler; }\n\n setDrawingManager(manager: DrawingManager, viewportGetter: () => ViewportState): void {\n this.drawingManager = manager;\n this.viewportGetter = viewportGetter;\n }\n\n setTradingManager(manager: TradingManager, viewportGetter: () => ViewportState): void {\n this.tradingManager = manager;\n this.viewportGetter = viewportGetter;\n }\n\n attach(): void {\n const getVP = () => this.viewportGetter?.() ?? null;\n\n // --- Mouse events ---\n const onMouseDown = (e: MouseEvent) => {\n // Cheap refresh point — ensures the rect is current for the\n // interaction that follows (drag, pan, draw, etc.).\n this.invalidateRect();\n const pos = this.getMousePos(e);\n const vp = getVP();\n if (this.tradingManager && vp && this.tradingManager.onPointerDown(pos, vp)) return;\n if (this.drawingManager && vp && this.drawingManager.onPointerDown(pos, vp)) return;\n this.panHandler?.onPointerDown(pos);\n };\n\n const onMouseMove = (e: MouseEvent) => {\n const pos = this.getMousePos(e);\n const vp = getVP();\n if (this.tradingManager && vp && this.tradingManager.onPointerMove(pos, vp)) {\n this.crosshairHandler?.onPointerMove(pos);\n this.onOverlayDirty?.();\n return;\n }\n if (this.drawingManager && vp && this.drawingManager.onPointerMove(pos, vp)) {\n this.crosshairHandler?.onPointerMove(pos);\n this.onOverlayDirty?.();\n return;\n }\n this.panHandler?.onPointerMove(pos);\n this.crosshairHandler?.onPointerMove(pos);\n this.onOverlayDirty?.();\n };\n\n const onMouseUp = () => {\n if (this.tradingManager?.onPointerUp()) return;\n if (this.drawingManager?.onPointerUp()) return;\n this.panHandler?.onPointerUp();\n };\n\n const onMouseLeave = () => {\n this.panHandler?.onPointerUp();\n this.drawingManager?.onPointerUp();\n this.tradingManager?.onPointerUp();\n this.crosshairHandler?.onPointerLeave();\n this.onOverlayDirty?.();\n };\n\n const onWheel = (e: WheelEvent) => {\n e.preventDefault();\n const pos = this.getMousePos(e);\n this.zoomHandler?.onWheel(e.deltaY, pos);\n };\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (this.drawingManager?.onKeyDown(e.key, e.ctrlKey || e.metaKey)) e.preventDefault();\n };\n\n const onContextMenu = (e: MouseEvent) => {\n const vp = getVP();\n if (!this.tradingManager || !vp) return;\n const shown = this.tradingManager.onContextMenu(this.getMousePos(e), vp);\n // Only suppress the native menu when the trading context menu actually\n // opened — otherwise users with trading disabled lose right-click entirely.\n if (shown) e.preventDefault();\n };\n\n // --- Touch events ---\n const onTouchStart = (e: TouchEvent) => {\n e.preventDefault();\n this.invalidateRect();\n if (e.touches.length === 1) {\n // Single finger: pan\n const pos = this.getTouchPos(e.touches[0]);\n this.panHandler?.onPointerDown(pos);\n this.crosshairHandler?.onPointerMove(pos);\n this.touchActive = true;\n } else if (e.touches.length === 2) {\n // Two fingers: start pinch-to-zoom\n this.panHandler?.onPointerUp(); // Stop panning\n this.lastTouchDist = this.getTouchDistance(e.touches[0], e.touches[1]);\n this.lastTouchMid = this.getTouchMidpoint(e.touches[0], e.touches[1]);\n this.touchActive = true;\n }\n };\n\n const onTouchMove = (e: TouchEvent) => {\n e.preventDefault();\n if (e.touches.length === 1 && this.touchActive) {\n const pos = this.getTouchPos(e.touches[0]);\n this.panHandler?.onPointerMove(pos);\n this.crosshairHandler?.onPointerMove(pos);\n } else if (e.touches.length === 2) {\n const dist = this.getTouchDistance(e.touches[0], e.touches[1]);\n const mid = this.getTouchMidpoint(e.touches[0], e.touches[1]);\n\n // Pinch zoom\n if (this.lastTouchDist > 0) {\n const scale = dist / this.lastTouchDist;\n const delta = (scale - 1) * 0.5; // Dampen\n this.zoomHandler?.onWheel(-delta * 100, mid);\n }\n\n // Two-finger pan\n const dx = this.lastTouchMid.x - mid.x;\n if (Math.abs(dx) > 1) {\n this.panHandler?.onPointerDown(this.lastTouchMid);\n this.panHandler?.onPointerMove(mid);\n }\n\n this.lastTouchDist = dist;\n this.lastTouchMid = mid;\n }\n this.onOverlayDirty?.();\n };\n\n const onTouchEnd = (e: TouchEvent) => {\n if (e.touches.length === 0) {\n this.panHandler?.onPointerUp();\n this.crosshairHandler?.onPointerLeave();\n this.touchActive = false;\n this.lastTouchDist = 0;\n } else if (e.touches.length === 1) {\n // Went from 2 fingers to 1: restart pan\n const pos = this.getTouchPos(e.touches[0]);\n this.panHandler?.onPointerDown(pos);\n }\n };\n\n const onWindowResize = () => this.invalidateRect();\n const onElementScroll = () => this.invalidateRect();\n\n // Attach all — mouseup on document so we catch it even if cursor leaves the chart\n this.element.addEventListener('mousedown', onMouseDown);\n this.element.addEventListener('mousemove', onMouseMove);\n document.addEventListener('mouseup', onMouseUp);\n this.element.addEventListener('mouseleave', onMouseLeave);\n this.element.addEventListener('wheel', onWheel, { passive: false });\n this.element.addEventListener('contextmenu', onContextMenu);\n this.element.addEventListener('touchstart', onTouchStart, { passive: false });\n this.element.addEventListener('touchmove', onTouchMove, { passive: false });\n this.element.addEventListener('touchend', onTouchEnd);\n document.addEventListener('keydown', onKeyDown);\n window.addEventListener('resize', onWindowResize);\n this.element.addEventListener('scroll', onElementScroll, { passive: true });\n\n this.boundHandlers.push(\n () => this.element.removeEventListener('mousedown', onMouseDown),\n () => this.element.removeEventListener('mousemove', onMouseMove),\n () => document.removeEventListener('mouseup', onMouseUp),\n () => this.element.removeEventListener('mouseleave', onMouseLeave),\n () => this.element.removeEventListener('wheel', onWheel),\n () => this.element.removeEventListener('contextmenu', onContextMenu),\n () => this.element.removeEventListener('touchstart', onTouchStart),\n () => this.element.removeEventListener('touchmove', onTouchMove),\n () => this.element.removeEventListener('touchend', onTouchEnd),\n () => document.removeEventListener('keydown', onKeyDown),\n () => window.removeEventListener('resize', onWindowResize),\n () => this.element.removeEventListener('scroll', onElementScroll),\n );\n }\n\n detach(): void {\n for (const remove of this.boundHandlers) remove();\n this.boundHandlers = [];\n this.cachedRect = null;\n }\n\n /** Force the cached bounding rect to be re-read on next access. */\n invalidateRect(): void {\n this.cachedRect = null;\n }\n\n private getRect(): DOMRect {\n if (!this.cachedRect) {\n this.cachedRect = this.element.getBoundingClientRect();\n }\n return this.cachedRect;\n }\n\n private getMousePos(e: MouseEvent): Point {\n const rect = this.getRect();\n return { x: e.clientX - rect.left, y: e.clientY - rect.top };\n }\n\n private getTouchPos(touch: Touch): Point {\n const rect = this.getRect();\n return { x: touch.clientX - rect.left, y: touch.clientY - rect.top };\n }\n\n private getTouchDistance(a: Touch, b: Touch): number {\n return Math.hypot(b.clientX - a.clientX, b.clientY - a.clientY);\n }\n\n private getTouchMidpoint(a: Touch, b: Touch): Point {\n const rect = this.getRect();\n return {\n x: (a.clientX + b.clientX) / 2 - rect.left,\n y: (a.clientY + b.clientY) / 2 - rect.top,\n };\n }\n}\n","import type { Point } from '@tradecanvas/commons';\n\nexport type PanCallback = (deltaX: number) => void;\n\n/**\n * Handles drag-to-pan with momentum/inertia scrolling.\n * On release, velocity decays smoothly over ~500ms.\n */\nexport class PanHandler {\n private dragging = false;\n private lastX = 0;\n private lastTime = 0;\n private velocity = 0;\n private momentumId = 0;\n private callback: PanCallback;\n private friction = 0.92;\n\n constructor(callback: PanCallback) {\n this.callback = callback;\n }\n\n onPointerDown(pos: Point): void {\n this.dragging = true;\n this.lastX = pos.x;\n this.lastTime = Date.now();\n this.velocity = 0;\n this.stopMomentum();\n }\n\n onPointerMove(pos: Point): void {\n if (!this.dragging) return;\n const now = Date.now();\n const delta = this.lastX - pos.x;\n const dt = now - this.lastTime;\n\n // Track velocity (pixels per ms)\n if (dt > 0) {\n this.velocity = delta / dt;\n }\n\n this.lastX = pos.x;\n this.lastTime = now;\n this.callback(delta);\n }\n\n onPointerUp(): void {\n if (!this.dragging) return;\n this.dragging = false;\n\n // Start momentum if flick was fast enough\n if (Math.abs(this.velocity) > 0.1) {\n this.startMomentum();\n }\n }\n\n private startMomentum(): void {\n this.stopMomentum();\n let v = this.velocity * 16; // Convert to pixels per frame (~16ms)\n\n const tick = () => {\n v *= this.friction;\n if (Math.abs(v) < 0.5) {\n this.momentumId = 0;\n return;\n }\n this.callback(v);\n this.momentumId = requestAnimationFrame(tick);\n };\n\n this.momentumId = requestAnimationFrame(tick);\n }\n\n private stopMomentum(): void {\n if (this.momentumId) {\n cancelAnimationFrame(this.momentumId);\n this.momentumId = 0;\n }\n }\n}\n","import type { Point } from '@tradecanvas/commons';\n\nexport type ZoomCallback = (delta: number, centerX: number) => void;\n\n/**\n * Coalesces rapid wheel events into a single callback per animation frame.\n * Accumulates delta across all wheel events within a frame, then fires once.\n */\nexport class ZoomHandler {\n private callback: ZoomCallback;\n private sensitivity: number;\n\n // rAF coalescing state\n private pendingDelta = 0;\n private pendingCenterX = 0;\n private rafId = 0;\n\n constructor(callback: ZoomCallback, sensitivity = 0.001) {\n this.callback = callback;\n this.sensitivity = sensitivity;\n }\n\n onWheel(deltaY: number, pos: Point): void {\n this.pendingDelta += -deltaY * this.sensitivity;\n this.pendingCenterX = pos.x;\n\n if (!this.rafId) {\n this.rafId = requestAnimationFrame(() => {\n this.rafId = 0;\n const delta = this.pendingDelta;\n const cx = this.pendingCenterX;\n this.pendingDelta = 0;\n this.callback(delta, cx);\n });\n }\n }\n\n dispose(): void {\n if (this.rafId) {\n cancelAnimationFrame(this.rafId);\n this.rafId = 0;\n }\n }\n}\n","import type { Point, ViewportState, Theme, DataSeries } from '@tradecanvas/commons';\nimport { formatPrice, PRICE_AXIS_WIDTH } from '@tradecanvas/commons';\nimport { xToBarIndex, yToPrice, barIndexToX } from '../viewport/ScaleMapping.js';\n\nexport type CrosshairCallback = (barIndex: number | null, point: Point | null) => void;\n\nexport type CrosshairMode = 'normal' | 'magnet' | 'hidden';\n\nexport class CrosshairHandler {\n private position: Point | null = null;\n private callback: CrosshairCallback | null = null;\n private data: DataSeries = [];\n private magnetMode = true;\n private mode: CrosshairMode = 'magnet';\n private pricePrecision = 2;\n private locale = 'en-US';\n\n // Deferred callback state — avoid calling during render\n private pendingBarIndex: number | null = null;\n private pendingPoint: Point | null = null;\n private callbackScheduled = false;\n private lastCallbackBarIndex = -1;\n\n setCallback(cb: CrosshairCallback): void {\n this.callback = cb;\n }\n\n setData(data: DataSeries): void {\n this.data = data;\n }\n\n setMagnetMode(enabled: boolean): void {\n this.magnetMode = enabled;\n this.mode = enabled ? 'magnet' : 'normal';\n }\n\n setMode(mode: CrosshairMode): void {\n this.mode = mode;\n this.magnetMode = mode === 'magnet';\n }\n\n getMode(): CrosshairMode {\n return this.mode;\n }\n\n setPricePrecision(precision: number): void {\n this.pricePrecision = precision;\n }\n\n setLocale(locale: string): void {\n this.locale = locale;\n }\n\n getPosition(): Point | null {\n return this.position;\n }\n\n onPointerMove(pos: Point): void {\n this.position = pos;\n }\n\n onPointerLeave(): void {\n this.position = null;\n this.pendingBarIndex = null;\n this.pendingPoint = null;\n this.lastCallbackBarIndex = -1;\n this.flushCallback(null, null);\n }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n if (!this.position || this.mode === 'hidden') return;\n const { chartRect } = viewport;\n let { x, y } = this.position;\n\n if (x < chartRect.x || x > chartRect.x + chartRect.width) return;\n if (y < chartRect.y || y > chartRect.y + chartRect.height) return;\n\n let barIndex = xToBarIndex(x, viewport);\n barIndex = Math.max(0, Math.min(this.data.length - 1, barIndex));\n\n if (this.magnetMode && barIndex >= 0 && barIndex < this.data.length) {\n x = barIndexToX(barIndex, viewport);\n }\n\n // Defer callback — only fire if bar changed, and fire AFTER render via microtask\n if (barIndex !== this.lastCallbackBarIndex) {\n this.pendingBarIndex = barIndex;\n this.pendingPoint = { x, y };\n this.lastCallbackBarIndex = barIndex;\n this.scheduleCallback();\n }\n\n // Draw crosshair lines — minimal work, no DOM, no allocations\n ctx.setLineDash([4, 4]);\n ctx.strokeStyle = theme.crosshair;\n ctx.lineWidth = 1;\n\n ctx.beginPath();\n ctx.moveTo(Math.round(x) + 0.5, chartRect.y);\n ctx.lineTo(Math.round(x) + 0.5, chartRect.y + chartRect.height);\n ctx.stroke();\n\n ctx.beginPath();\n ctx.moveTo(chartRect.x, Math.round(y) + 0.5);\n ctx.lineTo(chartRect.x + chartRect.width, Math.round(y) + 0.5);\n ctx.stroke();\n\n ctx.setLineDash([]);\n\n // Price label on Y axis\n const price = yToPrice(y, viewport);\n const priceText = formatPrice(price, this.pricePrecision, this.locale);\n const labelX = chartRect.x + chartRect.width + 1;\n ctx.fillStyle = theme.axisLabelBackground;\n ctx.fillRect(labelX, y - 10, PRICE_AXIS_WIDTH - 2, 20);\n ctx.fillStyle = theme.axisLabel;\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n ctx.textBaseline = 'middle';\n ctx.textAlign = 'left';\n ctx.fillText(priceText, labelX + 5, y);\n }\n\n /** Fire callback outside of render frame via microtask */\n private scheduleCallback(): void {\n if (this.callbackScheduled) return;\n this.callbackScheduled = true;\n queueMicrotask(() => {\n this.callbackScheduled = false;\n this.flushCallback(this.pendingBarIndex, this.pendingPoint);\n });\n }\n\n private flushCallback(barIndex: number | null, point: Point | null): void {\n this.callback?.(barIndex, point);\n }\n}\n","/**\n * Keyboard navigation for chart.\n * Arrow keys: navigate bars. +/-: zoom. Home/End: jump to start/end.\n * Shift+Arrow: fast navigation (10 bars). Double-click: fit content.\n */\nexport interface KeyboardCallbacks {\n scrollBars: (count: number) => void;\n zoom: (delta: number) => void;\n goToStart: () => void;\n goToEnd: () => void;\n fitContent: () => void;\n}\n\nexport class KeyboardHandler {\n private callbacks: KeyboardCallbacks;\n private enabled = true;\n\n constructor(callbacks: KeyboardCallbacks) {\n this.callbacks = callbacks;\n }\n\n setEnabled(v: boolean): void {\n this.enabled = v;\n }\n\n handleKey(e: KeyboardEvent): boolean {\n if (!this.enabled) return false;\n\n const shift = e.shiftKey;\n const step = shift ? 10 : 1;\n\n switch (e.key) {\n case 'ArrowLeft':\n this.callbacks.scrollBars(-step);\n return true;\n case 'ArrowRight':\n this.callbacks.scrollBars(step);\n return true;\n case 'ArrowUp':\n case '+':\n case '=':\n this.callbacks.zoom(0.1);\n return true;\n case 'ArrowDown':\n case '-':\n this.callbacks.zoom(-0.1);\n return true;\n case 'Home':\n this.callbacks.goToStart();\n return true;\n case 'End':\n this.callbacks.goToEnd();\n return true;\n case ' ':\n this.callbacks.fitContent();\n return true;\n default:\n return false;\n }\n }\n}\n","import type { OHLCBar, Theme, Point } from '@tradecanvas/commons';\n\n/**\n * High-performance floating tooltip.\n * Pre-builds DOM structure once, updates only textContent on hover.\n * No innerHTML, no offsetWidth reads, no layout thrashing.\n */\nexport class CrosshairTooltip {\n private el: HTMLElement | null = null;\n private visible = false;\n\n // Pre-built child nodes — updated via textContent (no reflow)\n private timeEl!: HTMLElement;\n private openEl!: HTMLElement;\n private highEl!: HTMLElement;\n private lowEl!: HTMLElement;\n private closeEl!: HTMLElement;\n private changeEl!: HTMLElement;\n private volEl!: HTMLElement;\n\n // Cached dimensions (measured once, avoids offsetWidth reads)\n private measuredWidth = 155;\n private measuredHeight = 95;\n private measured = false;\n\n create(container: HTMLElement): void {\n if (this.el) return;\n\n this.el = document.createElement('div');\n Object.assign(this.el.style, {\n position: 'absolute',\n display: 'none',\n padding: '6px 10px',\n borderRadius: '4px',\n fontSize: '11px',\n fontFamily: '-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,sans-serif',\n lineHeight: '1.5',\n pointerEvents: 'none',\n zIndex: '100',\n whiteSpace: 'nowrap',\n willChange: 'transform', // GPU layer for smooth repositioning\n });\n\n // Pre-build structure with reusable spans\n this.timeEl = this.addLine(this.el);\n const row1 = this.addLine(this.el);\n const row2 = this.addLine(this.el);\n this.changeEl = this.addLine(this.el);\n this.volEl = this.addLine(this.el);\n\n // O/H in row1, L/C in row2\n row1.append(this.label('O '), this.openEl = this.val(), this.label(' H '), this.highEl = this.val());\n row2.append(this.label('L '), this.lowEl = this.val(), this.label(' C '), this.closeEl = this.val());\n\n container.appendChild(this.el);\n }\n\n show(pos: Point, bar: OHLCBar, theme: Theme, containerRect: { width: number; height: number }): void {\n if (!this.el) return;\n\n const isUp = bar.close >= bar.open;\n const color = isUp ? theme.candleUp : theme.candleDown;\n\n // Fast number formatting (avoid toLocaleString)\n const fmt = (v: number) => v.toFixed(2);\n\n // Update text only (no DOM structure changes, no reflow)\n const d = new Date(bar.time);\n this.timeEl.textContent = `${d.getMonth() + 1}/${d.getDate()} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`;\n this.timeEl.style.color = theme.textSecondary;\n\n this.openEl.textContent = fmt(bar.open);\n this.highEl.textContent = fmt(bar.high);\n this.lowEl.textContent = fmt(bar.low);\n this.closeEl.textContent = fmt(bar.close);\n\n this.openEl.style.color = color;\n this.highEl.style.color = color;\n this.lowEl.style.color = color;\n this.closeEl.style.color = color;\n\n const change = bar.close - bar.open;\n const pct = bar.open !== 0 ? (change / bar.open * 100) : 0;\n const sign = change >= 0 ? '+' : '';\n this.changeEl.textContent = `${sign}${fmt(change)} (${sign}${pct.toFixed(2)}%)`;\n this.changeEl.style.color = color;\n\n const v = bar.volume;\n this.volEl.textContent = `Vol ${v >= 1e6 ? (v / 1e6).toFixed(1) + 'M' : v >= 1e3 ? (v / 1e3).toFixed(1) + 'K' : v.toFixed(0)}`;\n this.volEl.style.color = theme.textSecondary;\n\n // Style — use theme tokens with alpha overlay\n // Detect dark vs light theme by parsing the background luminance\n const isDark = isDarkColor(theme.background);\n this.el.style.background = isDark\n ? withAlpha(theme.background, 0.95)\n : withAlpha(theme.background, 0.97);\n this.el.style.border = `1px solid ${theme.axisLine}`;\n this.el.style.boxShadow = isDark\n ? '0 4px 12px rgba(0,0,0,0.5)'\n : '0 4px 12px rgba(0,0,0,0.15)';\n this.el.style.color = theme.text;\n // Backdrop blur for depth (optional, browser-dependent)\n this.el.style.backdropFilter = 'blur(8px)';\n\n // Measure once after first show\n if (!this.measured && this.visible) {\n this.measuredWidth = this.el.offsetWidth;\n this.measuredHeight = this.el.offsetHeight;\n this.measured = true;\n }\n\n // Position using transform (no layout trigger, GPU-composited)\n let x = pos.x + 16;\n let y = pos.y - 40;\n if (x + this.measuredWidth > containerRect.width - 80) x = pos.x - this.measuredWidth - 16;\n if (y < 4) y = 4;\n if (y + this.measuredHeight > containerRect.height) y = containerRect.height - this.measuredHeight - 4;\n\n this.el.style.transform = `translate(${Math.round(x)}px, ${Math.round(y)}px)`;\n this.el.style.left = '0';\n this.el.style.top = '0';\n\n if (!this.visible) {\n this.el.style.display = 'block';\n this.visible = true;\n }\n }\n\n hide(): void {\n if (this.el && this.visible) {\n this.el.style.display = 'none';\n this.visible = false;\n }\n }\n\n isVisible(): boolean {\n return this.visible;\n }\n\n destroy(): void {\n this.el?.remove();\n this.el = null;\n this.visible = false;\n this.measured = false;\n }\n\n private addLine(parent: HTMLElement): HTMLElement {\n const div = document.createElement('div');\n parent.appendChild(div);\n return div;\n }\n\n private label(text: string): HTMLSpanElement {\n const span = document.createElement('span');\n span.textContent = text;\n span.style.opacity = '0.6';\n return span;\n }\n\n private val(): HTMLSpanElement {\n return document.createElement('span');\n }\n}\n\n/** Detect if a hex/rgb color is dark (luminance < 0.5) */\nfunction isDarkColor(color: string): boolean {\n // Parse hex like #0f1729 or #fff\n if (color.startsWith('#')) {\n const hex = color.slice(1);\n const full = hex.length === 3\n ? hex.split('').map(c => c + c).join('')\n : hex.slice(0, 6);\n const r = parseInt(full.slice(0, 2), 16);\n const g = parseInt(full.slice(2, 4), 16);\n const b = parseInt(full.slice(4, 6), 16);\n // Relative luminance approximation (sRGB)\n const luma = (0.299 * r + 0.587 * g + 0.114 * b) / 255;\n return luma < 0.5;\n }\n // Parse rgb(r, g, b) or rgba(r, g, b, a)\n const m = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (m) {\n const r = parseInt(m[1]), g = parseInt(m[2]), b = parseInt(m[3]);\n const luma = (0.299 * r + 0.587 * g + 0.114 * b) / 255;\n return luma < 0.5;\n }\n return true; // assume dark if unknown\n}\n\n/** Add alpha to a hex color */\nfunction withAlpha(color: string, alpha: number): string {\n if (color.startsWith('#')) {\n const hex = color.slice(1);\n const full = hex.length === 3\n ? hex.split('').map(c => c + c).join('')\n : hex.slice(0, 6);\n const r = parseInt(full.slice(0, 2), 16);\n const g = parseInt(full.slice(2, 4), 16);\n const b = parseInt(full.slice(4, 6), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n }\n return color;\n}\n","import type { ChartEventType, ChartEvent, TauriBridgeOptions } from '@tradecanvas/commons';\n\ntype Listener = (event: ChartEvent) => void;\n\ndeclare global {\n interface Window {\n __TAURI__?: {\n event: {\n emit(event: string, payload: unknown): Promise<void>;\n };\n };\n }\n}\n\nexport class EventBus {\n private listeners = new Map<ChartEventType, Set<Listener>>();\n private tauriBridge: TauriBridgeOptions | null = null;\n\n on(type: ChartEventType, listener: Listener): void {\n let set = this.listeners.get(type);\n if (!set) {\n set = new Set();\n this.listeners.set(type, set);\n }\n set.add(listener);\n }\n\n off(type: ChartEventType, listener: Listener): void {\n this.listeners.get(type)?.delete(listener);\n }\n\n emit(type: ChartEventType, payload: unknown): void {\n const event: ChartEvent = {\n type,\n timestamp: Date.now(),\n payload,\n };\n\n const set = this.listeners.get(type);\n if (set) {\n for (const listener of set) {\n listener(event);\n }\n }\n\n if (this.tauriBridge?.enabled && window.__TAURI__) {\n const prefix = this.tauriBridge.eventPrefix ?? 'tc-chart';\n window.__TAURI__.event.emit(`${prefix}:${type}`, event).catch(() => {});\n }\n }\n\n enableTauriBridge(options: TauriBridgeOptions): void {\n this.tauriBridge = options;\n }\n\n disableTauriBridge(): void {\n this.tauriBridge = null;\n }\n\n destroy(): void {\n this.listeners.clear();\n this.tauriBridge = null;\n }\n}\n","import type {\n DrawingPlugin,\n DrawingDescriptor,\n DrawingState,\n DrawingStyle,\n Point,\n ViewportState,\n AnchorPoint,\n} from '@tradecanvas/commons';\nimport { priceToY, timeToX, xToTime, yToPrice } from '../viewport/ScaleMapping.js';\n\nexport abstract class DrawingBase implements DrawingPlugin {\n abstract descriptor: DrawingDescriptor;\n\n abstract render(\n ctx: CanvasRenderingContext2D,\n state: DrawingState,\n viewport: ViewportState,\n selected: boolean,\n ): void;\n\n abstract hitTest(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): boolean;\n\n hitTestAnchor(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): number {\n for (let i = 0; i < state.anchors.length; i++) {\n const px = this.anchorToPixel(state.anchors[i], viewport);\n const dist = Math.hypot(point.x - px.x, point.y - px.y);\n if (dist <= tolerance) return i;\n }\n return -1;\n }\n\n protected anchorToPixel(anchor: AnchorPoint, viewport: ViewportState): Point {\n const x = timeToX(anchor.time, viewport);\n const y = priceToY(anchor.price, viewport);\n return { x, y };\n }\n\n protected pixelToAnchor(point: Point, viewport: ViewportState): AnchorPoint {\n const time = xToTime(point.x, viewport);\n const price = yToPrice(point.y, viewport);\n return { time, price };\n }\n\n protected applyLineStyle(ctx: CanvasRenderingContext2D, style: DrawingStyle): void {\n ctx.strokeStyle = style.color;\n ctx.lineWidth = style.lineWidth;\n switch (style.lineStyle) {\n case 'dashed': ctx.setLineDash([6, 4]); break;\n case 'dotted': ctx.setLineDash([2, 2]); break;\n default: ctx.setLineDash([]); break;\n }\n }\n\n protected resetLineStyle(ctx: CanvasRenderingContext2D): void {\n ctx.setLineDash([]);\n }\n\n protected renderAnchorHandles(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState): void {\n const size = 4;\n ctx.fillStyle = '#FFFFFF';\n ctx.strokeStyle = state.style.color;\n ctx.lineWidth = 1;\n for (const anchor of state.anchors) {\n const p = this.anchorToPixel(anchor, viewport);\n ctx.fillRect(p.x - size, p.y - size, size * 2, size * 2);\n ctx.strokeRect(p.x - size, p.y - size, size * 2, size * 2);\n }\n }\n\n protected distanceToLine(point: Point, p1: Point, p2: Point): number {\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const lenSq = dx * dx + dy * dy;\n if (lenSq === 0) return Math.hypot(point.x - p1.x, point.y - p1.y);\n let t = ((point.x - p1.x) * dx + (point.y - p1.y) * dy) / lenSq;\n t = Math.max(0, Math.min(1, t));\n const projX = p1.x + t * dx;\n const projY = p1.y + t * dy;\n return Math.hypot(point.x - projX, point.y - projY);\n }\n\n protected distanceToInfiniteLine(point: Point, p1: Point, p2: Point): number {\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const len = Math.hypot(dx, dy);\n if (len === 0) return Math.hypot(point.x - p1.x, point.y - p1.y);\n return Math.abs(dx * (p1.y - point.y) - dy * (p1.x - point.x)) / len;\n }\n}\n","import type {\n DrawingPlugin,\n DrawingState,\n DrawingToolType,\n DrawingStyle,\n Point,\n ViewportState,\n OHLCBar,\n} from '@tradecanvas/commons';\nimport { timestampToBarIndex, xToTime, yToPrice } from '../viewport/ScaleMapping.js';\nimport type { UndoRedoManager } from '../features/UndoRedoManager.js';\n\ntype DrawingEventCallback = (event: string, data: unknown) => void;\n\nexport type DrawingInteractionState = 'idle' | 'creating' | 'selected' | 'moving' | 'resizing';\nexport type MagnetMode = 'none' | 'magnet';\n\nlet nextDrawingId = 1;\n\n/**\n * Shallow clone tailored for DrawingState. Avoids `structuredClone` in hot\n * paths (drag, resize, duplicate) where the well-known shape lets us spread\n * much faster than the structured-clone algorithm.\n */\nfunction cloneDrawing(d: DrawingState): DrawingState {\n return {\n ...d,\n anchors: d.anchors.map((a) => ({ ...a })),\n style: { ...d.style },\n meta: d.meta ? { ...d.meta } : undefined,\n };\n}\n\nexport class DrawingManager {\n private registry = new Map<DrawingToolType, DrawingPlugin>();\n private drawings: DrawingState[] = [];\n private state: DrawingInteractionState = 'idle';\n private activeTool: DrawingToolType | null = null;\n private activeStyle: DrawingStyle = {\n color: '#2196F3',\n lineWidth: 1,\n lineStyle: 'solid',\n fillColor: 'rgba(33, 150, 243, 0.1)',\n fillOpacity: 0.1,\n fontSize: 12,\n };\n private creatingDrawing: DrawingState | null = null;\n private committedAnchors = 0; // how many anchors have been clicked (not preview)\n private previewAnchor: { time: number; price: number } | null = null;\n private selectedDrawingId: string | null = null;\n private dragAnchorIndex = -1;\n private dragStartPoint: Point | null = null;\n private dragStartAnchors: { time: number; price: number }[] = [];\n private dragBeforeState: DrawingState | null = null;\n private eventCallback: DrawingEventCallback | null = null;\n private requestRender: (() => void) | null = null;\n private undoRedo: UndoRedoManager | null = null;\n private magnetMode: MagnetMode = 'none';\n private dataGetter: (() => OHLCBar[]) | null = null;\n private displayDataGetter: (() => OHLCBar[]) | null = null;\n\n register(plugin: DrawingPlugin): void {\n this.registry.set(plugin.descriptor.type, plugin);\n }\n\n setEventCallback(cb: DrawingEventCallback): void {\n this.eventCallback = cb;\n }\n\n setRequestRender(cb: () => void): void {\n this.requestRender = cb;\n }\n\n setUndoRedoManager(mgr: UndoRedoManager): void {\n this.undoRedo = mgr;\n }\n\n setMagnetMode(mode: MagnetMode): void {\n this.magnetMode = mode;\n }\n\n getMagnetMode(): MagnetMode {\n return this.magnetMode;\n }\n\n setDataGetter(getter: () => OHLCBar[]): void {\n this.dataGetter = getter;\n }\n\n /** Set a separate getter for display data (e.g. Heikin Ashi transformed). Used by magnet snap. */\n setDisplayDataGetter(getter: () => OHLCBar[]): void {\n this.displayDataGetter = getter;\n }\n\n // --- Magnet snap ---\n\n /**\n * Snap an in-progress anchor to the closest OHLC value of the underlying\n * bar. `time` is interpreted as a timestamp when `viewport.data` is set\n * (the modern, recommended mode) or as a bar index otherwise. The returned\n * `time` matches the input convention so the caller doesn't need to know.\n */\n private snapToOHLC(time: number, price: number, viewport?: ViewportState): { time: number; price: number } {\n if (this.magnetMode === 'none' || !this.dataGetter) {\n return { time, price };\n }\n // Use display data for magnet snap (matches what's visually rendered, e.g. Heikin Ashi)\n const data = this.displayDataGetter?.() ?? this.dataGetter();\n if (data.length === 0) return { time, price };\n\n const useTimestamps = !!(viewport?.data && viewport.data.length > 0);\n const idx = Math.max(\n 0,\n Math.min(\n data.length - 1,\n Math.round(useTimestamps ? timestampToBarIndex(time, data) : time),\n ),\n );\n const bar = data[idx];\n\n // Find closest OHLC value\n const candidates = [bar.open, bar.high, bar.low, bar.close];\n let closest = candidates[0];\n let minDist = Math.abs(price - closest);\n for (let i = 1; i < candidates.length; i++) {\n const d = Math.abs(price - candidates[i]);\n if (d < minDist) { minDist = d; closest = candidates[i]; }\n }\n\n // Only snap if within a reasonable pixel distance (magnet radius)\n if (viewport) {\n const pxPerPrice = viewport.chartRect.height / (viewport.priceRange.max - viewport.priceRange.min || 1);\n const distPx = minDist * pxPerPrice;\n if (distPx > 30) {\n // Too far — don't snap, use the raw input position (bar-aligned).\n return { time: useTimestamps ? bar.time : idx, price };\n }\n }\n\n return { time: useTimestamps ? bar.time : idx, price: closest };\n }\n\n // --- Undo / Redo ---\n\n undo(): boolean {\n if (!this.undoRedo) return false;\n const action = this.undoRedo.undo();\n if (!action) return false;\n this.applyUndoAction(action);\n return true;\n }\n\n redo(): boolean {\n if (!this.undoRedo) return false;\n const action = this.undoRedo.redo();\n if (!action) return false;\n this.applyRedoAction(action);\n return true;\n }\n\n private applyUndoAction(action: import('../features/UndoRedoManager.js').UndoableAction): void {\n switch (action.type) {\n case 'drawingCreate':\n // Undo create = remove\n if (action.after) {\n this.drawings = this.drawings.filter(d => d.id !== action.after!.id);\n }\n break;\n case 'drawingRemove':\n // Undo remove = restore\n if (action.before) {\n this.drawings.push(action.before);\n }\n break;\n case 'drawingModify':\n // Undo modify = restore before state\n if (action.before) {\n const idx = this.drawings.findIndex(d => d.id === action.before!.id);\n if (idx >= 0) this.drawings[idx] = structuredClone(action.before);\n }\n break;\n }\n this.selectedDrawingId = null;\n this.state = 'idle';\n this.requestRender?.();\n }\n\n private applyRedoAction(action: import('../features/UndoRedoManager.js').UndoableAction): void {\n switch (action.type) {\n case 'drawingCreate':\n // Redo create = add again\n if (action.after) {\n this.drawings.push(structuredClone(action.after));\n }\n break;\n case 'drawingRemove':\n // Redo remove = remove again\n if (action.before) {\n this.drawings = this.drawings.filter(d => d.id !== action.before!.id);\n }\n break;\n case 'drawingModify':\n // Redo modify = apply after state\n if (action.after) {\n const idx = this.drawings.findIndex(d => d.id === action.after!.id);\n if (idx >= 0) this.drawings[idx] = structuredClone(action.after);\n }\n break;\n }\n this.selectedDrawingId = null;\n this.state = 'idle';\n this.requestRender?.();\n }\n\n // --- Bulk operations (TradingView-like) ---\n\n lockAllDrawings(): void {\n for (const d of this.drawings) d.locked = true;\n this.requestRender?.();\n }\n\n unlockAllDrawings(): void {\n for (const d of this.drawings) d.locked = false;\n this.requestRender?.();\n }\n\n hideAllDrawings(): void {\n for (const d of this.drawings) d.visible = false;\n this.selectedDrawingId = null;\n this.state = 'idle';\n this.requestRender?.();\n }\n\n showAllDrawings(): void {\n for (const d of this.drawings) d.visible = true;\n this.requestRender?.();\n }\n\n // --- Tool selection ---\n\n setActiveTool(type: DrawingToolType | null): void {\n this.activeTool = type;\n this.state = type ? 'creating' : 'idle';\n this.creatingDrawing = null;\n this.committedAnchors = 0;\n this.previewAnchor = null;\n }\n\n getActiveTool(): DrawingToolType | null {\n return this.activeTool;\n }\n\n setStyle(style: Partial<DrawingStyle>): void {\n Object.assign(this.activeStyle, style);\n }\n\n // --- Pointer events (returns true if consumed) ---\n\n onPointerDown(pos: Point, viewport: ViewportState): boolean {\n if (this.state === 'creating' && this.activeTool) {\n return this.handleCreationClick(pos, viewport);\n }\n\n if (this.state === 'idle' || this.state === 'selected') {\n return this.handleSelectionClick(pos, viewport);\n }\n\n return false;\n }\n\n onPointerMove(pos: Point, viewport: ViewportState): boolean {\n if (this.state === 'creating' && this.creatingDrawing) {\n const plugin = this.registry.get(this.creatingDrawing.type);\n if (plugin && this.committedAnchors < plugin.descriptor.requiredAnchors) {\n const rawTime = xToTime(pos.x, viewport);\n const rawPrice = yToPrice(pos.y, viewport);\n this.previewAnchor = this.snapToOHLC(rawTime, rawPrice, viewport);\n this.requestRender?.();\n return true;\n }\n }\n\n if (this.state === 'moving' && this.selectedDrawingId && this.dragStartPoint) {\n return this.handleMove(pos, viewport);\n }\n\n if (this.state === 'resizing' && this.selectedDrawingId && this.dragAnchorIndex >= 0) {\n return this.handleResize(pos, viewport);\n }\n\n return false;\n }\n\n onPointerUp(): boolean {\n if (this.state === 'moving' || this.state === 'resizing') {\n // Record undo for the completed move/resize\n if (this.dragBeforeState && this.selectedDrawingId) {\n const drawing = this.drawings.find(d => d.id === this.selectedDrawingId);\n if (drawing) {\n this.undoRedo?.push({\n type: 'drawingModify',\n before: this.dragBeforeState,\n after: cloneDrawing(drawing),\n });\n }\n }\n this.state = 'selected';\n this.dragStartPoint = null;\n this.dragStartAnchors = [];\n this.dragAnchorIndex = -1;\n this.dragBeforeState = null;\n return true;\n }\n return false;\n }\n\n onKeyDown(key: string, ctrlKey = false): boolean {\n // Ctrl+D to duplicate selected drawing\n if (ctrlKey && (key === 'd' || key === 'D')) {\n if (this.state === 'selected' && this.selectedDrawingId) {\n if (this.duplicateDrawing(this.selectedDrawingId)) return true;\n }\n }\n\n // Ctrl+Z / Ctrl+Y for undo/redo\n if (ctrlKey && (key === 'z' || key === 'Z')) {\n if (this.undo()) { return true; }\n }\n if (ctrlKey && (key === 'y' || key === 'Y')) {\n if (this.redo()) { return true; }\n }\n\n if (key === 'Escape') {\n if (this.state === 'creating') {\n this.setActiveTool(null);\n this.requestRender?.();\n return true;\n }\n if (this.state === 'selected') {\n this.selectedDrawingId = null;\n this.state = 'idle';\n this.requestRender?.();\n return true;\n }\n }\n if (key === 'Delete' || key === 'Backspace') {\n if (this.state === 'selected' && this.selectedDrawingId) {\n const drawing = this.drawings.find(d => d.id === this.selectedDrawingId);\n if (drawing?.locked) return false; // Can't delete locked drawings\n this.removeDrawing(this.selectedDrawingId);\n this.selectedDrawingId = null;\n this.state = 'idle';\n this.requestRender?.();\n return true;\n }\n }\n return false;\n }\n\n // --- Drawing CRUD ---\n\n getDrawings(): DrawingState[] {\n return this.drawings;\n }\n\n setDrawings(states: DrawingState[]): void {\n this.drawings = this.upgradeLegacyAnchors(states);\n this.requestRender?.();\n }\n\n /**\n * Auto-migrate legacy bar-index anchors to real timestamps when data is\n * available. Heuristic: anchors with `time < 1e9` are treated as bar indices\n * (timestamps in seconds are > 1e9 for any date after 2001-09-09), and\n * upgraded by looking up the corresponding bar's timestamp. Anchors that\n * already look like timestamps are passed through untouched. Idempotent.\n */\n private upgradeLegacyAnchors(states: DrawingState[]): DrawingState[] {\n const data = this.dataGetter?.();\n if (!data || data.length === 0) return states;\n const TIMESTAMP_THRESHOLD = 1e9;\n return states.map(d => ({\n ...d,\n anchors: d.anchors.map(a => {\n if (a.time >= TIMESTAMP_THRESHOLD) return a;\n const idx = Math.max(0, Math.min(data.length - 1, Math.round(a.time)));\n return { ...a, time: data[idx].time };\n }),\n }));\n }\n\n removeDrawing(id: string): void {\n const removed = this.drawings.find(d => d.id === id);\n this.drawings = this.drawings.filter((d) => d.id !== id);\n if (removed) {\n this.undoRedo?.push({\n type: 'drawingRemove',\n before: structuredClone(removed),\n after: null,\n });\n }\n this.eventCallback?.('drawingRemove', { id });\n this.requestRender?.();\n }\n\n duplicateDrawing(id: string): string | null {\n const drawing = this.drawings.find(d => d.id === id);\n if (!drawing) return null;\n\n const newDrawing: DrawingState = structuredClone(drawing);\n newDrawing.id = `tc_drawing_${nextDrawingId++}`;\n // Offset by 3 bars so the copy is visually distinct. When anchors are\n // timestamps, \"3 bars\" means 3 × median bar interval in the current\n // series; when anchors are bar indices (legacy / no data), it's literal.\n const timeOffset = this.computeBarOffsetTime(3);\n newDrawing.anchors = newDrawing.anchors.map(a => ({\n ...a,\n time: a.time + timeOffset,\n }));\n newDrawing.locked = false;\n\n this.drawings.push(newDrawing);\n this.undoRedo?.push({\n type: 'drawingCreate',\n before: null,\n after: structuredClone(newDrawing),\n });\n this.selectedDrawingId = newDrawing.id;\n this.state = 'selected';\n this.eventCallback?.('drawingCreate', { drawing: newDrawing });\n this.requestRender?.();\n return newDrawing.id;\n }\n\n clearDrawings(): void {\n this.drawings = [];\n this.selectedDrawingId = null;\n this.state = 'idle';\n this.requestRender?.();\n }\n\n getSelectedDrawingId(): string | null {\n return this.selectedDrawingId;\n }\n\n // --- Render ---\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState): void {\n // Clip to chart area so drawings don't bleed into axis areas\n ctx.save();\n ctx.beginPath();\n ctx.rect(viewport.chartRect.x, viewport.chartRect.y, viewport.chartRect.width, viewport.chartRect.height);\n ctx.clip();\n\n for (const drawing of this.drawings) {\n if (!drawing.visible) continue;\n const plugin = this.registry.get(drawing.type);\n if (!plugin) continue;\n const isSelected = drawing.id === this.selectedDrawingId;\n plugin.render(ctx, drawing, viewport, isSelected);\n }\n\n // Render drawing being created (with preview anchor)\n if (this.creatingDrawing && this.committedAnchors > 0) {\n const plugin = this.registry.get(this.creatingDrawing.type);\n if (plugin) {\n // Build preview state: committed anchors + optional preview anchor\n const previewState: DrawingState = {\n ...this.creatingDrawing,\n anchors: this.previewAnchor\n ? [...this.creatingDrawing.anchors, this.previewAnchor]\n : [...this.creatingDrawing.anchors],\n };\n plugin.render(ctx, previewState, viewport, false);\n }\n }\n\n ctx.restore();\n }\n\n // --- Internal ---\n\n /**\n * Compute the offset (in anchor-time units) equivalent to `n` bars.\n * When the viewport carries data and anchors are timestamps, this is\n * `n × median bar interval`; otherwise it's just `n` (bar-index mode).\n */\n private computeBarOffsetTime(n: number): number {\n const data = this.dataGetter?.();\n if (!data || data.length < 2) return n;\n // Only meaningful in timestamp mode — detect via data presence.\n // Use median of the last few intervals to be robust against gaps.\n const sampleStart = Math.max(0, data.length - 20);\n const intervals: number[] = [];\n for (let i = sampleStart + 1; i < data.length; i++) {\n intervals.push(data[i].time - data[i - 1].time);\n }\n if (intervals.length === 0) return n;\n intervals.sort((a, b) => a - b);\n const median = intervals[Math.floor(intervals.length / 2)];\n return n * median;\n }\n\n private handleCreationClick(pos: Point, viewport: ViewportState): boolean {\n if (!this.activeTool) return false;\n const plugin = this.registry.get(this.activeTool);\n if (!plugin) return false;\n\n const rawTime = xToTime(pos.x, viewport);\n const rawPrice = yToPrice(pos.y, viewport);\n const anchor = this.snapToOHLC(rawTime, rawPrice, viewport);\n\n if (!this.creatingDrawing) {\n // First click: start creation\n this.creatingDrawing = {\n id: `tc_drawing_${nextDrawingId++}`,\n type: this.activeTool,\n anchors: [anchor],\n style: { ...this.activeStyle },\n visible: true,\n locked: false,\n };\n this.committedAnchors = 1;\n this.previewAnchor = null;\n\n if (plugin.descriptor.requiredAnchors === 1) {\n this.finalizeCreation();\n }\n this.requestRender?.();\n return true;\n }\n\n // Subsequent click: commit the anchor\n this.creatingDrawing.anchors.push(anchor);\n this.committedAnchors++;\n this.previewAnchor = null;\n\n if (this.committedAnchors >= plugin.descriptor.requiredAnchors) {\n this.finalizeCreation();\n }\n\n this.requestRender?.();\n return true;\n }\n\n private finalizeCreation(): void {\n if (!this.creatingDrawing) return;\n this.drawings.push(this.creatingDrawing);\n this.selectedDrawingId = this.creatingDrawing.id;\n // Record undo action\n this.undoRedo?.push({\n type: 'drawingCreate',\n before: null,\n after: structuredClone(this.creatingDrawing),\n });\n this.eventCallback?.('drawingCreate', { drawing: this.creatingDrawing });\n this.creatingDrawing = null;\n this.committedAnchors = 0;\n this.previewAnchor = null;\n this.activeTool = null;\n this.state = 'selected';\n }\n\n private handleSelectionClick(pos: Point, viewport: ViewportState): boolean {\n const tolerance = 8;\n\n // If already selected, check for anchor drag\n if (this.selectedDrawingId) {\n const drawing = this.drawings.find((d) => d.id === this.selectedDrawingId);\n if (drawing && !drawing.locked) {\n const plugin = this.registry.get(drawing.type);\n if (plugin) {\n const anchorIdx = plugin.hitTestAnchor(pos, drawing, viewport, tolerance);\n if (anchorIdx >= 0) {\n this.state = 'resizing';\n this.dragAnchorIndex = anchorIdx;\n this.dragStartPoint = pos;\n this.dragBeforeState = cloneDrawing(drawing);\n return true;\n }\n if (plugin.hitTest(pos, drawing, viewport, tolerance)) {\n this.state = 'moving';\n this.dragStartPoint = pos;\n this.dragStartAnchors = drawing.anchors.map((a) => ({ ...a }));\n this.dragBeforeState = cloneDrawing(drawing);\n return true;\n }\n }\n }\n }\n\n // Try to select a drawing\n for (let i = this.drawings.length - 1; i >= 0; i--) {\n const drawing = this.drawings[i];\n if (!drawing.visible) continue;\n const plugin = this.registry.get(drawing.type);\n if (!plugin) continue;\n if (plugin.hitTest(pos, drawing, viewport, tolerance)) {\n this.selectedDrawingId = drawing.id;\n this.state = 'selected';\n this.requestRender?.();\n return true;\n }\n }\n\n // Clicked empty space — deselect\n if (this.selectedDrawingId) {\n this.selectedDrawingId = null;\n this.state = 'idle';\n this.requestRender?.();\n }\n return false;\n }\n\n private handleMove(pos: Point, viewport: ViewportState): boolean {\n const drawing = this.drawings.find((d) => d.id === this.selectedDrawingId);\n if (!drawing || !this.dragStartPoint) return false;\n\n // Translate by anchor-time delta. In timestamp mode this is a wall-clock\n // seconds difference; in bar-index mode it's a bar-count difference —\n // `xToTime` returns whichever unit the viewport is set up for.\n const dTime = xToTime(pos.x, viewport) - xToTime(this.dragStartPoint.x, viewport);\n const dPrice = yToPrice(pos.y, viewport) - yToPrice(this.dragStartPoint.y, viewport);\n\n drawing.anchors = this.dragStartAnchors.map((a) => ({\n time: a.time + dTime,\n price: a.price + dPrice,\n }));\n\n this.requestRender?.();\n return true;\n }\n\n private handleResize(pos: Point, viewport: ViewportState): boolean {\n const drawing = this.drawings.find((d) => d.id === this.selectedDrawingId);\n if (!drawing || this.dragAnchorIndex < 0) return false;\n\n drawing.anchors[this.dragAnchorIndex] = {\n time: xToTime(pos.x, viewport),\n price: yToPrice(pos.y, viewport),\n };\n\n this.requestRender?.();\n return true;\n }\n}\n","import type { ViewportState } from '@tradecanvas/commons';\nimport type { DrawingManager } from './DrawingManager.js';\n\nexport class DrawingRenderer {\n constructor(private manager: DrawingManager) {}\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState): void {\n this.manager.render(ctx, viewport);\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class TrendLineTool extends DrawingBase {\n descriptor = { type: 'trendLine' as const, name: 'Trend Line', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p2.x, p2.y);\n ctx.stroke();\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n return this.distanceToLine(point, p1, p2) <= tolerance;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\nimport { priceToY } from '../../viewport/ScaleMapping.js';\n\nexport class HorizontalLineTool extends DrawingBase {\n descriptor = { type: 'horizontalLine' as const, name: 'Horizontal Line', requiredAnchors: 1 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 1) return;\n const y = priceToY(state.anchors[0].price, viewport);\n const { chartRect } = viewport;\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(chartRect.x, y);\n ctx.lineTo(chartRect.x + chartRect.width, y);\n ctx.stroke();\n this.resetLineStyle(ctx);\n\n // Price label\n ctx.fillStyle = state.style.color;\n ctx.font = '11px sans-serif';\n ctx.textBaseline = 'bottom';\n ctx.fillText(state.anchors[0].price.toFixed(2), chartRect.x + 4, y - 3);\n\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 1) return false;\n const y = priceToY(state.anchors[0].price, viewport);\n return Math.abs(point.y - y) <= tolerance && point.x >= viewport.chartRect.x && point.x <= viewport.chartRect.x + viewport.chartRect.width;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class VerticalLineTool extends DrawingBase {\n descriptor = { type: 'verticalLine' as const, name: 'Vertical Line', requiredAnchors: 1 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 1) return;\n const p = this.anchorToPixel(state.anchors[0], viewport);\n const { chartRect } = viewport;\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(p.x, chartRect.y);\n ctx.lineTo(p.x, chartRect.y + chartRect.height);\n ctx.stroke();\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 1) return false;\n const p = this.anchorToPixel(state.anchors[0], viewport);\n const { chartRect } = viewport;\n return Math.abs(point.x - p.x) <= tolerance &&\n point.y >= chartRect.y && point.y <= chartRect.y + chartRect.height;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class RayTool extends DrawingBase {\n descriptor = { type: 'ray' as const, name: 'Ray', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const { chartRect } = viewport;\n\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const len = Math.hypot(dx, dy);\n if (len === 0) return;\n\n // Extend to chart edge\n const maxDist = Math.hypot(chartRect.width, chartRect.height) * 2;\n const endX = p1.x + (dx / len) * maxDist;\n const endY = p1.y + (dy / len) * maxDist;\n\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(endX, endY);\n ctx.stroke();\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n // Only test in the ray direction (from p1 toward p2)\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const t = ((point.x - p1.x) * dx + (point.y - p1.y) * dy) / (dx * dx + dy * dy);\n if (t < 0) return false;\n return this.distanceToInfiniteLine(point, p1, p2) <= tolerance;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class ExtendedLineTool extends DrawingBase {\n descriptor = { type: 'extendedLine' as const, name: 'Extended Line', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const { chartRect } = viewport;\n\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const len = Math.hypot(dx, dy);\n if (len === 0) return;\n\n const maxDist = Math.hypot(chartRect.width, chartRect.height) * 2;\n const startX = p1.x - (dx / len) * maxDist;\n const startY = p1.y - (dy / len) * maxDist;\n const endX = p1.x + (dx / len) * maxDist;\n const endY = p1.y + (dy / len) * maxDist;\n\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(startX, startY);\n ctx.lineTo(endX, endY);\n ctx.stroke();\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n return this.distanceToInfiniteLine(point, p1, p2) <= tolerance;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class ParallelChannelTool extends DrawingBase {\n descriptor = { type: 'parallelChannel' as const, name: 'Parallel Channel', requiredAnchors: 3 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p2.x, p2.y);\n ctx.stroke();\n\n if (state.anchors.length >= 3) {\n const p3 = this.anchorToPixel(state.anchors[2], viewport);\n // Perpendicular offset from baseline (p1→p2)\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const len = Math.hypot(dx, dy) || 1;\n const nx = -dy / len;\n const ny = dx / len;\n const perpDist = (p3.x - p1.x) * nx + (p3.y - p1.y) * ny;\n const p1b = { x: p1.x + nx * perpDist, y: p1.y + ny * perpDist };\n const p2b = { x: p2.x + nx * perpDist, y: p2.y + ny * perpDist };\n\n ctx.beginPath();\n ctx.moveTo(p1b.x, p1b.y);\n ctx.lineTo(p2b.x, p2b.y);\n ctx.stroke();\n\n // Fill between\n if (state.style.fillColor) {\n ctx.fillStyle = state.style.fillColor;\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p2.x, p2.y);\n ctx.lineTo(p2b.x, p2b.y);\n ctx.lineTo(p1b.x, p1b.y);\n ctx.closePath();\n ctx.fill();\n }\n }\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n if (this.distanceToLine(point, p1, p2) <= tolerance) return true;\n if (state.anchors.length >= 3) {\n const p3 = this.anchorToPixel(state.anchors[2], viewport);\n // Perpendicular offset from baseline (p1→p2)\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const len = Math.hypot(dx, dy) || 1;\n const nx = -dy / len;\n const ny = dx / len;\n const perpDist = (p3.x - p1.x) * nx + (p3.y - p1.y) * ny;\n const p1b = { x: p1.x + nx * perpDist, y: p1.y + ny * perpDist };\n const p2b = { x: p2.x + nx * perpDist, y: p2.y + ny * perpDist };\n if (this.distanceToLine(point, p1b, p2b) <= tolerance) return true;\n }\n return false;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class RegressionChannelTool extends DrawingBase {\n descriptor = { type: 'regressionChannel' as const, name: 'Regression Channel', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n\n // Draw center line\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p2.x, p2.y);\n ctx.stroke();\n\n // Draw parallel channel lines (fixed offset)\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const len = Math.hypot(dx, dy);\n if (len === 0) { this.resetLineStyle(ctx); return; }\n // Channel width scales with line length (20% of length, min 10px, max 100px)\n const channelOffset = Math.max(10, Math.min(len * 0.2, 100));\n const nx = -dy / len * channelOffset;\n const ny = dx / len * channelOffset;\n\n ctx.setLineDash([4, 4]);\n ctx.beginPath();\n ctx.moveTo(p1.x + nx, p1.y + ny);\n ctx.lineTo(p2.x + nx, p2.y + ny);\n ctx.stroke();\n ctx.beginPath();\n ctx.moveTo(p1.x - nx, p1.y - ny);\n ctx.lineTo(p2.x - nx, p2.y - ny);\n ctx.stroke();\n\n if (state.style.fillColor) {\n ctx.fillStyle = state.style.fillColor;\n ctx.beginPath();\n ctx.moveTo(p1.x + nx, p1.y + ny);\n ctx.lineTo(p2.x + nx, p2.y + ny);\n ctx.lineTo(p2.x - nx, p2.y - ny);\n ctx.lineTo(p1.x - nx, p1.y - ny);\n ctx.closePath();\n ctx.fill();\n }\n\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const len = Math.hypot(p2.x - p1.x, p2.y - p1.y);\n const channelOffset = Math.max(10, Math.min(len * 0.2, 100));\n return this.distanceToLine(point, p1, p2) <= tolerance + channelOffset;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\nimport { priceToY } from '../../viewport/ScaleMapping.js';\n\nconst FIB_LEVELS = [0, 0.236, 0.382, 0.5, 0.618, 0.786, 1];\n\nexport class FibRetracementTool extends DrawingBase {\n descriptor = { type: 'fibRetracement' as const, name: 'Fibonacci Retracement', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const { chartRect } = viewport;\n const priceHigh = state.anchors[0].price;\n const priceLow = state.anchors[1].price;\n const priceRange = priceHigh - priceLow;\n\n ctx.font = '11px sans-serif';\n ctx.textBaseline = 'middle';\n\n for (const level of FIB_LEVELS) {\n const price = priceLow + priceRange * (1 - level);\n const y = priceToY(price, viewport);\n\n this.applyLineStyle(ctx, state.style);\n ctx.globalAlpha = level === 0 || level === 1 ? 1 : 0.7;\n ctx.beginPath();\n ctx.moveTo(chartRect.x, y);\n ctx.lineTo(chartRect.x + chartRect.width, y);\n ctx.stroke();\n\n // Label\n ctx.fillStyle = state.style.color;\n ctx.textAlign = 'left';\n ctx.fillText(`${(level * 100).toFixed(1)}% (${price.toFixed(2)})`, chartRect.x + 4, y - 2);\n }\n\n ctx.globalAlpha = 1;\n\n // Fill between levels\n if (state.style.fillColor) {\n for (let i = 0; i < FIB_LEVELS.length - 1; i++) {\n const priceA = priceLow + priceRange * (1 - FIB_LEVELS[i]);\n const priceB = priceLow + priceRange * (1 - FIB_LEVELS[i + 1]);\n const yA = priceToY(priceA, viewport);\n const yB = priceToY(priceB, viewport);\n ctx.fillStyle = state.style.fillColor;\n ctx.globalAlpha = 0.05 + i * 0.02;\n ctx.fillRect(chartRect.x, Math.min(yA, yB), chartRect.width, Math.abs(yB - yA));\n }\n ctx.globalAlpha = 1;\n }\n\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const { chartRect } = viewport;\n if (point.x < chartRect.x - tolerance || point.x > chartRect.x + chartRect.width + tolerance) return false;\n const priceHigh = state.anchors[0].price;\n const priceLow = state.anchors[1].price;\n const priceRange = priceHigh - priceLow;\n for (const level of FIB_LEVELS) {\n const price = priceLow + priceRange * (1 - level);\n const y = priceToY(price, viewport);\n if (Math.abs(point.y - y) <= tolerance) return true;\n }\n return false;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\nimport { priceToY } from '../../viewport/ScaleMapping.js';\n\nconst EXT_LEVELS = [0, 0.618, 1, 1.618, 2, 2.618, 3.618, 4.236];\n\nexport class FibExtensionTool extends DrawingBase {\n descriptor = { type: 'fibExtension' as const, name: 'Fibonacci Extension', requiredAnchors: 3 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 3) {\n if (state.anchors.length === 2) {\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p2.x, p2.y);\n ctx.stroke();\n this.resetLineStyle(ctx);\n }\n return;\n }\n\n const { chartRect } = viewport;\n const priceA = state.anchors[0].price;\n const priceB = state.anchors[1].price;\n const priceC = state.anchors[2].price;\n const swing = priceA - priceB;\n\n ctx.font = '11px sans-serif';\n ctx.textBaseline = 'middle';\n ctx.textAlign = 'left';\n\n for (const level of EXT_LEVELS) {\n const price = priceC + swing * level;\n const y = priceToY(price, viewport);\n\n this.applyLineStyle(ctx, state.style);\n ctx.globalAlpha = level === 0 || level === 1 ? 1 : 0.6;\n ctx.beginPath();\n ctx.moveTo(chartRect.x, y);\n ctx.lineTo(chartRect.x + chartRect.width, y);\n ctx.stroke();\n\n ctx.fillStyle = state.style.color;\n ctx.fillText(`${(level * 100).toFixed(1)}%`, chartRect.x + 4, y - 2);\n }\n\n ctx.globalAlpha = 1;\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 3) return false;\n const { chartRect } = viewport;\n if (point.x < chartRect.x - tolerance || point.x > chartRect.x + chartRect.width + tolerance) return false;\n const swing = state.anchors[0].price - state.anchors[1].price;\n for (const level of EXT_LEVELS) {\n const price = state.anchors[2].price + swing * level;\n const y = priceToY(price, viewport);\n if (Math.abs(point.y - y) <= tolerance) return true;\n }\n return false;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class RectangleTool extends DrawingBase {\n descriptor = { type: 'rectangle' as const, name: 'Rectangle', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const x = Math.min(p1.x, p2.x), y = Math.min(p1.y, p2.y);\n const w = Math.abs(p2.x - p1.x), h = Math.abs(p2.y - p1.y);\n\n if (state.style.fillColor) {\n ctx.fillStyle = state.style.fillColor;\n ctx.fillRect(x, y, w, h);\n }\n this.applyLineStyle(ctx, state.style);\n ctx.strokeRect(x, y, w, h);\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const x1 = Math.min(p1.x, p2.x) - tolerance, y1 = Math.min(p1.y, p2.y) - tolerance;\n const x2 = Math.max(p1.x, p2.x) + tolerance, y2 = Math.max(p1.y, p2.y) + tolerance;\n if (point.x < x1 || point.x > x2 || point.y < y1 || point.y > y2) return false;\n // Check if near border\n const ix1 = Math.min(p1.x, p2.x) + tolerance, iy1 = Math.min(p1.y, p2.y) + tolerance;\n const ix2 = Math.max(p1.x, p2.x) - tolerance, iy2 = Math.max(p1.y, p2.y) - tolerance;\n return !(point.x > ix1 && point.x < ix2 && point.y > iy1 && point.y < iy2) || !!state.style.fillColor;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class EllipseTool extends DrawingBase {\n descriptor = { type: 'ellipse' as const, name: 'Ellipse', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const cx = (p1.x + p2.x) / 2, cy = (p1.y + p2.y) / 2;\n const rx = Math.abs(p2.x - p1.x) / 2, ry = Math.abs(p2.y - p1.y) / 2;\n\n ctx.beginPath();\n ctx.ellipse(cx, cy, Math.max(rx, 1), Math.max(ry, 1), 0, 0, Math.PI * 2);\n if (state.style.fillColor) {\n ctx.fillStyle = state.style.fillColor;\n ctx.fill();\n }\n this.applyLineStyle(ctx, state.style);\n ctx.stroke();\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const cx = (p1.x + p2.x) / 2, cy = (p1.y + p2.y) / 2;\n const rx = Math.max(Math.abs(p2.x - p1.x) / 2, 1);\n const ry = Math.max(Math.abs(p2.y - p1.y) / 2, 1);\n const dx = (point.x - cx) / rx, dy = (point.y - cy) / ry;\n const dist = Math.sqrt(dx * dx + dy * dy);\n // Normalized tolerance: tolerance pixels mapped to ellipse-normalized space\n const normTol = tolerance / Math.max(Math.min(rx, ry), 4);\n // Hit if within the stroke band around the ellipse edge (dist ≈ 1)\n return state.style.fillColor ? dist <= 1 + normTol : Math.abs(dist - 1) <= normTol;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class TriangleTool extends DrawingBase {\n descriptor = { type: 'triangle' as const, name: 'Triangle', requiredAnchors: 3 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 3) {\n if (state.anchors.length === 2) {\n const a = this.anchorToPixel(state.anchors[0], viewport);\n const b = this.anchorToPixel(state.anchors[1], viewport);\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(a.x, a.y);\n ctx.lineTo(b.x, b.y);\n ctx.stroke();\n this.resetLineStyle(ctx);\n }\n return;\n }\n const pts = state.anchors.map((a) => this.anchorToPixel(a, viewport));\n\n ctx.beginPath();\n ctx.moveTo(pts[0].x, pts[0].y);\n ctx.lineTo(pts[1].x, pts[1].y);\n ctx.lineTo(pts[2].x, pts[2].y);\n ctx.closePath();\n\n if (state.style.fillColor) {\n ctx.fillStyle = state.style.fillColor;\n ctx.fill();\n }\n this.applyLineStyle(ctx, state.style);\n ctx.stroke();\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 3) return false;\n const pts = state.anchors.map((a) => this.anchorToPixel(a, viewport));\n // Check if near edges\n for (let i = 0; i < 3; i++) {\n const j = (i + 1) % 3;\n if (this.distanceToLine(point, pts[i], pts[j]) <= tolerance) return true;\n }\n return false;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class PitchforkTool extends DrawingBase {\n descriptor = { type: 'pitchfork' as const, name: \"Andrews' Pitchfork\", requiredAnchors: 3 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 3) {\n if (state.anchors.length === 2) {\n const a = this.anchorToPixel(state.anchors[0], viewport);\n const b = this.anchorToPixel(state.anchors[1], viewport);\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(a.x, a.y);\n ctx.lineTo(b.x, b.y);\n ctx.stroke();\n this.resetLineStyle(ctx);\n }\n return;\n }\n\n const p0 = this.anchorToPixel(state.anchors[0], viewport);\n const p1 = this.anchorToPixel(state.anchors[1], viewport);\n const p2 = this.anchorToPixel(state.anchors[2], viewport);\n const mid = { x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2 };\n\n // Median line (from p0 through midpoint of p1-p2)\n const dx = mid.x - p0.x, dy = mid.y - p0.y;\n const len = Math.hypot(dx, dy) || 1;\n const ext = Math.hypot(viewport.chartRect.width, viewport.chartRect.height);\n const endX = p0.x + (dx / len) * ext;\n const endY = p0.y + (dy / len) * ext;\n\n this.applyLineStyle(ctx, state.style);\n\n // Median line\n ctx.beginPath();\n ctx.moveTo(p0.x, p0.y);\n ctx.lineTo(endX, endY);\n ctx.stroke();\n\n // Upper prong (from p1 parallel to median)\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p1.x + (dx / len) * ext, p1.y + (dy / len) * ext);\n ctx.stroke();\n\n // Lower prong (from p2 parallel to median)\n ctx.beginPath();\n ctx.moveTo(p2.x, p2.y);\n ctx.lineTo(p2.x + (dx / len) * ext, p2.y + (dy / len) * ext);\n ctx.stroke();\n\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 3) return false;\n const p0 = this.anchorToPixel(state.anchors[0], viewport);\n const p1 = this.anchorToPixel(state.anchors[1], viewport);\n const p2 = this.anchorToPixel(state.anchors[2], viewport);\n const mid = { x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2 };\n if (this.distanceToInfiniteLine(point, p0, mid) <= tolerance) return true;\n const dx = mid.x - p0.x, dy = mid.y - p0.y;\n const p1end = { x: p1.x + dx, y: p1.y + dy };\n const p2end = { x: p2.x + dx, y: p2.y + dy };\n if (this.distanceToInfiniteLine(point, p1, p1end) <= tolerance) return true;\n if (this.distanceToInfiniteLine(point, p2, p2end) <= tolerance) return true;\n return false;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nconst WAVE_LABELS = ['1', '2', '3', '4', '5', 'A', 'B', 'C'];\n\nexport class ElliottWaveTool extends DrawingBase {\n descriptor = { type: 'elliottWave' as const, name: 'Elliott Wave', requiredAnchors: 8 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const pts = state.anchors.map((a) => this.anchorToPixel(a, viewport));\n\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) {\n ctx.lineTo(pts[i].x, pts[i].y);\n }\n ctx.stroke();\n this.resetLineStyle(ctx);\n\n // Labels\n ctx.font = 'bold 12px sans-serif';\n ctx.fillStyle = state.style.color;\n ctx.textAlign = 'center';\n for (let i = 0; i < pts.length && i < WAVE_LABELS.length; i++) {\n const offsetY = i % 2 === 0 ? -12 : 12;\n ctx.textBaseline = offsetY < 0 ? 'bottom' : 'top';\n ctx.fillText(WAVE_LABELS[i], pts[i].x, pts[i].y + offsetY);\n }\n\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const pts = state.anchors.map((a) => this.anchorToPixel(a, viewport));\n for (let i = 0; i < pts.length - 1; i++) {\n if (this.distanceToLine(point, pts[i], pts[i + 1]) <= tolerance) return true;\n }\n return false;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class PriceRangeTool extends DrawingBase {\n descriptor = { type: 'priceRange' as const, name: 'Price Range', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const x = Math.min(p1.x, p2.x), w = Math.abs(p2.x - p1.x);\n const top = Math.min(p1.y, p2.y), h = Math.abs(p2.y - p1.y);\n\n // Fill\n const isUp = state.anchors[1].price > state.anchors[0].price;\n ctx.fillStyle = isUp ? 'rgba(38, 166, 154, 0.15)' : 'rgba(239, 83, 80, 0.15)';\n ctx.fillRect(x, top, w, h);\n\n this.applyLineStyle(ctx, state.style);\n ctx.strokeRect(x, top, w, h);\n this.resetLineStyle(ctx);\n\n // Label\n const priceDiff = state.anchors[1].price - state.anchors[0].price;\n const pctChange = state.anchors[0].price !== 0 ? (priceDiff / state.anchors[0].price * 100) : 0;\n const label = `${priceDiff >= 0 ? '+' : ''}${priceDiff.toFixed(2)} (${pctChange >= 0 ? '+' : ''}${pctChange.toFixed(2)}%)`;\n\n ctx.font = '12px sans-serif';\n ctx.fillStyle = isUp ? '#26A69A' : '#EF5350';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, x + w / 2, top + h / 2);\n\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const x1 = Math.min(p1.x, p2.x), x2 = Math.max(p1.x, p2.x);\n const y1 = Math.min(p1.y, p2.y), y2 = Math.max(p1.y, p2.y);\n return point.x >= x1 - tolerance && point.x <= x2 + tolerance && point.y >= y1 - tolerance && point.y <= y2 + tolerance;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\nimport { resolveBarIndex } from '../../viewport/ScaleMapping.js';\n\nexport class DateRangeTool extends DrawingBase {\n descriptor = { type: 'dateRange' as const, name: 'Date Range', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const { chartRect } = viewport;\n const x1 = Math.min(p1.x, p2.x), x2 = Math.max(p1.x, p2.x);\n\n ctx.fillStyle = 'rgba(33, 150, 243, 0.08)';\n ctx.fillRect(x1, chartRect.y, x2 - x1, chartRect.height);\n\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(x1, chartRect.y);\n ctx.lineTo(x1, chartRect.y + chartRect.height);\n ctx.stroke();\n ctx.beginPath();\n ctx.moveTo(x2, chartRect.y);\n ctx.lineTo(x2, chartRect.y + chartRect.height);\n ctx.stroke();\n this.resetLineStyle(ctx);\n\n // Bars count — compute via resolved bar indices so the label reflects the\n // actual span on the current timeframe (anchor.time may be a timestamp).\n const idx0 = resolveBarIndex(state.anchors[0].time, viewport);\n const idx1 = resolveBarIndex(state.anchors[1].time, viewport);\n const bars = Math.max(0, Math.round(Math.abs(idx1 - idx0)));\n ctx.font = '12px sans-serif';\n ctx.fillStyle = state.style.color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.fillText(`${bars} bars`, (x1 + x2) / 2, chartRect.y + 4);\n\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const { chartRect } = viewport;\n const x1 = Math.min(p1.x, p2.x), x2 = Math.max(p1.x, p2.x);\n return point.x >= x1 - tolerance && point.x <= x2 + tolerance &&\n point.y >= chartRect.y && point.y <= chartRect.y + chartRect.height;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\nimport { resolveBarIndex } from '../../viewport/ScaleMapping.js';\n\nexport class MeasureTool extends DrawingBase {\n descriptor = { type: 'measure' as const, name: 'Measure', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n\n // Dotted line from p1 to p2\n this.applyLineStyle(ctx, state.style);\n ctx.setLineDash([4, 4]); // Always dashed for measure\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p2.x, p2.y);\n ctx.stroke();\n this.resetLineStyle(ctx);\n\n // Info label — resolve bar indices so the bar count is correct even when\n // anchor.time is a real timestamp (timestamp mode is the new default).\n const priceDiff = state.anchors[1].price - state.anchors[0].price;\n const idx0 = resolveBarIndex(state.anchors[0].time, viewport);\n const idx1 = resolveBarIndex(state.anchors[1].time, viewport);\n const barsDiff = Math.max(0, Math.round(Math.abs(idx1 - idx0)));\n const pctChange = state.anchors[0].price !== 0 ? (priceDiff / state.anchors[0].price * 100) : 0;\n\n const lines = [\n `Price: ${priceDiff >= 0 ? '+' : ''}${priceDiff.toFixed(2)} (${pctChange >= 0 ? '+' : ''}${pctChange.toFixed(2)}%)`,\n `Bars: ${barsDiff}`,\n ];\n\n const midX = (p1.x + p2.x) / 2;\n const midY = (p1.y + p2.y) / 2;\n\n ctx.font = '11px sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'bottom';\n\n // Background\n const maxWidth = Math.max(...lines.map((l) => ctx.measureText(l).width));\n ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';\n ctx.fillRect(midX - maxWidth / 2 - 6, midY - lines.length * 14 - 4, maxWidth + 12, lines.length * 14 + 8);\n\n ctx.fillStyle = '#FFFFFF';\n for (let i = 0; i < lines.length; i++) {\n ctx.fillText(lines[i], midX, midY - (lines.length - 1 - i) * 14);\n }\n\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n return this.distanceToLine(point, p1, p2) <= tolerance;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\r\nimport { DrawingBase } from '../DrawingBase.js';\r\n\r\n/**\r\n * Pull annotation text from `style.text`, then `meta.text`, then a literal default.\r\n * Pure helper — exported so it can be unit-tested without a canvas.\r\n */\r\nexport function resolveAnnotationText(state: DrawingState, fallback = 'Text'): string {\r\n if (typeof state.style.text === 'string' && state.style.text.length > 0) {\r\n return state.style.text;\r\n }\r\n const metaText = state.meta?.text;\r\n if (typeof metaText === 'string' && metaText.length > 0) return metaText;\r\n return fallback;\r\n}\r\n\r\nexport class TextAnnotationTool extends DrawingBase {\r\n descriptor = { type: 'text' as const, name: 'Text', requiredAnchors: 1 };\r\n\r\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\r\n if (state.anchors.length < 1) return;\r\n const p = this.anchorToPixel(state.anchors[0], viewport);\r\n const text = resolveAnnotationText(state);\r\n const fontSize = state.style.fontSize || 14;\r\n\r\n ctx.font = `${fontSize}px sans-serif`;\r\n ctx.fillStyle = state.style.color;\r\n ctx.textAlign = 'left';\r\n ctx.textBaseline = 'top';\r\n\r\n if (selected) {\r\n const metrics = ctx.measureText(text);\r\n ctx.strokeStyle = state.style.color;\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([3, 3]);\r\n ctx.strokeRect(p.x - 2, p.y - 2, metrics.width + 4, fontSize + 4);\r\n ctx.setLineDash([]);\r\n }\r\n\r\n ctx.fillText(text, p.x, p.y);\r\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\r\n }\r\n\r\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\r\n if (state.anchors.length < 1) return false;\r\n const p = this.anchorToPixel(state.anchors[0], viewport);\r\n const fontSize = state.style.fontSize || 14;\r\n const textWidth = 80; // approximate\r\n return point.x >= p.x - tolerance && point.x <= p.x + textWidth + tolerance && point.y >= p.y - tolerance && point.y <= p.y + fontSize + tolerance;\r\n }\r\n}\r\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class ArrowTool extends DrawingBase {\n descriptor = { type: 'arrow' as const, name: 'Arrow', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p2.x, p2.y);\n ctx.stroke();\n\n // Arrowhead\n const angle = Math.atan2(p2.y - p1.y, p2.x - p1.x);\n const headLen = 12;\n ctx.beginPath();\n ctx.moveTo(p2.x, p2.y);\n ctx.lineTo(p2.x - headLen * Math.cos(angle - Math.PI / 6), p2.y - headLen * Math.sin(angle - Math.PI / 6));\n ctx.lineTo(p2.x - headLen * Math.cos(angle + Math.PI / 6), p2.y - headLen * Math.sin(angle + Math.PI / 6));\n ctx.closePath();\n ctx.fillStyle = state.style.color;\n ctx.fill();\n\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n return this.distanceToLine(point, p1, p2) <= tolerance;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\n/**\n * Gann Fan drawing tool.\n * Two anchors define the 1x1 angle (45°). Additional ratio lines fan out\n * from the first anchor: 1x1, 1x2, 2x1, 1x3, 3x1, 1x4, 4x1, 1x8, 8x1.\n */\n\nconst GANN_RATIOS = [\n { label: '8x1', ratio: 8 },\n { label: '4x1', ratio: 4 },\n { label: '3x1', ratio: 3 },\n { label: '2x1', ratio: 2 },\n { label: '1x1', ratio: 1 },\n { label: '1x2', ratio: 0.5 },\n { label: '1x3', ratio: 1 / 3 },\n { label: '1x4', ratio: 0.25 },\n { label: '1x8', ratio: 0.125 },\n];\n\nexport class GannFanTool extends DrawingBase {\n descriptor = { type: 'gannFan' as const, name: 'Gann Fan', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n\n // The 1x1 line goes from p1 to p2. We use it to compute the unit scale.\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n\n if (Math.abs(dx) < 1) return;\n\n // The unit price-per-bar in pixel space is defined by the 1x1 angle\n const unitSlope = dy / dx;\n const direction = dx > 0 ? 1 : -1;\n const { chartRect } = viewport;\n const extendX = direction > 0\n ? chartRect.x + chartRect.width\n : chartRect.x;\n\n this.applyLineStyle(ctx, state.style);\n\n for (const { label, ratio } of GANN_RATIOS) {\n const slope = unitSlope * ratio;\n const farX = extendX;\n const farY = p1.y + slope * (farX - p1.x);\n\n ctx.globalAlpha = ratio === 1 ? 1 : 0.5;\n ctx.lineWidth = ratio === 1 ? state.style.lineWidth : Math.max(0.5, state.style.lineWidth * 0.7);\n\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(farX, farY);\n ctx.stroke();\n\n // Label at the end\n const labelX = farX - direction * 4;\n const labelY = farY;\n if (labelY > chartRect.y && labelY < chartRect.y + chartRect.height) {\n ctx.globalAlpha = 0.7;\n ctx.fillStyle = state.style.color;\n ctx.font = '9px sans-serif';\n ctx.textAlign = direction > 0 ? 'right' : 'left';\n ctx.textBaseline = 'bottom';\n ctx.fillText(label, labelX, labelY - 2);\n }\n }\n\n ctx.globalAlpha = 1;\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n\n if (Math.abs(dx) < 1) return false;\n\n const unitSlope = dy / dx;\n const direction = dx > 0 ? 1 : -1;\n const { chartRect } = viewport;\n const extendX = direction > 0\n ? chartRect.x + chartRect.width\n : chartRect.x;\n\n for (const { ratio } of GANN_RATIOS) {\n const slope = unitSlope * ratio;\n const farX = extendX;\n const farY = p1.y + slope * (farX - p1.x);\n const dist = this.distanceToLine(point, p1, { x: farX, y: farY });\n if (dist <= tolerance) return true;\n }\n return false;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\n/**\n * Gann Box drawing tool.\n * Two anchors define a rectangular region. The box is subdivided by\n * Gann angles (diagonal lines) and horizontal/vertical price/time divisions.\n */\n\nconst DIVISIONS = [0, 0.25, 0.333, 0.5, 0.667, 0.75, 1];\n\nexport class GannBoxTool extends DrawingBase {\n descriptor = { type: 'gannBox' as const, name: 'Gann Box', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n\n const left = Math.min(p1.x, p2.x);\n const right = Math.max(p1.x, p2.x);\n const top = Math.min(p1.y, p2.y);\n const bottom = Math.max(p1.y, p2.y);\n const w = right - left;\n const h = bottom - top;\n\n if (w < 2 || h < 2) return;\n\n this.applyLineStyle(ctx, state.style);\n\n // Outer rectangle\n ctx.strokeRect(left, top, w, h);\n\n // Horizontal divisions\n ctx.save();\n ctx.globalAlpha = 0.35;\n for (const d of DIVISIONS) {\n if (d === 0 || d === 1) continue;\n const y = top + h * d;\n ctx.beginPath();\n ctx.moveTo(left, y);\n ctx.lineTo(right, y);\n ctx.stroke();\n }\n\n // Vertical divisions\n for (const d of DIVISIONS) {\n if (d === 0 || d === 1) continue;\n const x = left + w * d;\n ctx.beginPath();\n ctx.moveTo(x, top);\n ctx.lineTo(x, bottom);\n ctx.stroke();\n }\n\n // Diagonal lines (Gann angles)\n ctx.globalAlpha = 0.5;\n ctx.setLineDash([4, 3]);\n\n // Main diagonal\n ctx.beginPath();\n ctx.moveTo(left, top);\n ctx.lineTo(right, bottom);\n ctx.stroke();\n\n // Anti-diagonal\n ctx.beginPath();\n ctx.moveTo(right, top);\n ctx.lineTo(left, bottom);\n ctx.stroke();\n\n ctx.restore();\n this.resetLineStyle(ctx);\n\n // Labels for divisions\n ctx.fillStyle = state.style.color;\n ctx.font = '8px sans-serif';\n ctx.globalAlpha = 0.6;\n ctx.textBaseline = 'bottom';\n ctx.textAlign = 'right';\n for (const d of DIVISIONS) {\n if (d === 0 || d === 1) continue;\n const y = top + h * d;\n ctx.fillText(`${(d * 100).toFixed(0)}%`, left - 3, y);\n }\n ctx.globalAlpha = 1;\n\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n\n const left = Math.min(p1.x, p2.x);\n const right = Math.max(p1.x, p2.x);\n const top = Math.min(p1.y, p2.y);\n const bottom = Math.max(p1.y, p2.y);\n\n // Check outer edges\n if (Math.abs(point.x - left) <= tolerance && point.y >= top - tolerance && point.y <= bottom + tolerance) return true;\n if (Math.abs(point.x - right) <= tolerance && point.y >= top - tolerance && point.y <= bottom + tolerance) return true;\n if (Math.abs(point.y - top) <= tolerance && point.x >= left - tolerance && point.x <= right + tolerance) return true;\n if (Math.abs(point.y - bottom) <= tolerance && point.x >= left - tolerance && point.x <= right + tolerance) return true;\n\n // Check diagonals\n const dist1 = this.distanceToLine(point, { x: left, y: top }, { x: right, y: bottom });\n if (dist1 <= tolerance) return true;\n const dist2 = this.distanceToLine(point, { x: right, y: top }, { x: left, y: bottom });\n if (dist2 <= tolerance) return true;\n\n return false;\n }\n}\n","import type { DrawingState, Point, ViewportState, DataSeries } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\nimport { barIndexToX, priceToY, resolveBarIndex } from '../../viewport/ScaleMapping.js';\n\n/**\n * Anchored VWAP drawing tool.\n * One anchor sets the start bar. The VWAP line is computed from that bar\n * to the end of visible data using cumulative (price * volume) / volume.\n * Optionally renders +/-1 and +/-2 standard deviation bands.\n */\nexport class AnchoredVWAPTool extends DrawingBase {\n descriptor = { type: 'anchoredVWAP' as const, name: 'Anchored VWAP', requiredAnchors: 1 };\n\n private dataGetter: (() => DataSeries) | null = null;\n private showBands = true;\n\n setDataGetter(getter: () => DataSeries): void {\n this.dataGetter = getter;\n }\n\n setShowBands(show: boolean): void {\n this.showBands = show;\n }\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 1 || !this.dataGetter) return;\n\n const data = this.dataGetter();\n const startIdx = Math.max(0, Math.round(resolveBarIndex(state.anchors[0].time, viewport)));\n if (startIdx >= data.length) return;\n\n // Compute anchored VWAP from startIdx to end\n const { vwap, upper1, lower1, upper2, lower2 } = this.computeVWAP(data, startIdx);\n\n const { chartRect } = viewport;\n const barUnit = viewport.barWidth + viewport.barSpacing;\n\n // Draw VWAP line\n this.applyLineStyle(ctx, state.style);\n ctx.lineWidth = state.style.lineWidth + 0.5;\n\n this.drawLine(ctx, vwap, startIdx, viewport, chartRect, barUnit);\n\n // Draw bands\n if (this.showBands && vwap.length > 1) {\n ctx.globalAlpha = 0.4;\n ctx.lineWidth = Math.max(0.5, state.style.lineWidth * 0.6);\n ctx.setLineDash([4, 3]);\n\n this.drawLine(ctx, upper1, startIdx, viewport, chartRect, barUnit);\n this.drawLine(ctx, lower1, startIdx, viewport, chartRect, barUnit);\n\n ctx.globalAlpha = 0.25;\n this.drawLine(ctx, upper2, startIdx, viewport, chartRect, barUnit);\n this.drawLine(ctx, lower2, startIdx, viewport, chartRect, barUnit);\n\n ctx.globalAlpha = 1;\n }\n\n this.resetLineStyle(ctx);\n\n // Label\n if (vwap.length > 0) {\n const lastPrice = vwap[vwap.length - 1];\n const lastIdx = startIdx + vwap.length - 1;\n const x = barIndexToX(lastIdx, viewport);\n const y = priceToY(lastPrice, viewport);\n if (x >= chartRect.x && x <= chartRect.x + chartRect.width) {\n ctx.fillStyle = state.style.color;\n ctx.font = 'bold 9px sans-serif';\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.fillText(`AVWAP ${lastPrice.toFixed(2)}`, x + 6, y);\n }\n }\n\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n private drawLine(\n ctx: CanvasRenderingContext2D,\n prices: number[],\n startIdx: number,\n viewport: ViewportState,\n chartRect: { x: number; width: number },\n barUnit: number,\n ): void {\n ctx.beginPath();\n let started = false;\n for (let i = 0; i < prices.length; i++) {\n const x = barIndexToX(startIdx + i, viewport);\n if (x < chartRect.x - barUnit) continue;\n if (x > chartRect.x + chartRect.width + barUnit) break;\n const y = priceToY(prices[i], viewport);\n if (!started) {\n ctx.moveTo(x, y);\n started = true;\n } else {\n ctx.lineTo(x, y);\n }\n }\n ctx.stroke();\n }\n\n private computeVWAP(data: DataSeries, startIdx: number): {\n vwap: number[];\n upper1: number[];\n lower1: number[];\n upper2: number[];\n lower2: number[];\n } {\n const len = data.length - startIdx;\n const vwap: number[] = new Array(len);\n const upper1: number[] = new Array(len);\n const lower1: number[] = new Array(len);\n const upper2: number[] = new Array(len);\n const lower2: number[] = new Array(len);\n\n let cumPV = 0;\n let cumV = 0;\n let cumPV2 = 0; // For standard deviation\n\n for (let i = 0; i < len; i++) {\n const bar = data[startIdx + i];\n const tp = (bar.high + bar.low + bar.close) / 3; // Typical price\n const vol = bar.volume ?? 1;\n\n cumPV += tp * vol;\n cumV += vol;\n cumPV2 += tp * tp * vol;\n\n const v = cumV > 0 ? cumPV / cumV : tp;\n vwap[i] = v;\n\n // Standard deviation of price from VWAP\n const variance = cumV > 0 ? (cumPV2 / cumV) - v * v : 0;\n const stdDev = Math.sqrt(Math.max(0, variance));\n\n upper1[i] = v + stdDev;\n lower1[i] = v - stdDev;\n upper2[i] = v + 2 * stdDev;\n lower2[i] = v - 2 * stdDev;\n }\n\n return { vwap, upper1, lower1, upper2, lower2 };\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 1 || !this.dataGetter) return false;\n\n const data = this.dataGetter();\n const startIdx = Math.max(0, Math.round(resolveBarIndex(state.anchors[0].time, viewport)));\n if (startIdx >= data.length) return false;\n\n const { vwap } = this.computeVWAP(data, startIdx);\n\n // Check if point is close to any segment of the VWAP line\n for (let i = 1; i < vwap.length; i++) {\n const p1x = barIndexToX(startIdx + i - 1, viewport);\n const p1y = priceToY(vwap[i - 1], viewport);\n const p2x = barIndexToX(startIdx + i, viewport);\n const p2y = priceToY(vwap[i], viewport);\n const dist = this.distanceToLine(point, { x: p1x, y: p1y }, { x: p2x, y: p2y });\n if (dist <= tolerance) return true;\n }\n\n return false;\n }\n}\n","import type { DrawingState, Point, ViewportState, DataSeries } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\nimport { barIndexToX, priceToY, resolveBarIndex } from '../../viewport/ScaleMapping.js';\n\n/**\n * Volume Profile (Visible/Fixed Range) drawing tool.\n * Two anchors define a time range. The tool computes volume distribution\n * across price levels within that range and renders a horizontal histogram.\n */\nexport class VolumeProfileRangeTool extends DrawingBase {\n descriptor = { type: 'volumeProfileRange' as const, name: 'Volume Profile (Range)', requiredAnchors: 2 };\n\n private dataGetter: (() => DataSeries) | null = null;\n private numBins = 40;\n\n setDataGetter(getter: () => DataSeries): void {\n this.dataGetter = getter;\n }\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2 || !this.dataGetter) return;\n\n const data = this.dataGetter();\n const idx0 = Math.round(resolveBarIndex(state.anchors[0].time, viewport));\n const idx1 = Math.round(resolveBarIndex(state.anchors[1].time, viewport));\n const startIdx = Math.max(0, Math.min(idx0, idx1));\n const endIdx = Math.min(data.length - 1, Math.max(idx0, idx1));\n\n if (startIdx >= data.length || endIdx < 0 || startIdx > endIdx) return;\n\n // Find price range within the selected bars\n let pMin = Infinity, pMax = -Infinity;\n for (let i = startIdx; i <= endIdx; i++) {\n if (data[i].low < pMin) pMin = data[i].low;\n if (data[i].high > pMax) pMax = data[i].high;\n }\n if (pMin >= pMax) return;\n\n // Build volume histogram\n const binSize = (pMax - pMin) / this.numBins;\n const bins = new Float64Array(this.numBins);\n let maxBinVol = 0;\n\n for (let i = startIdx; i <= endIdx; i++) {\n const bar = data[i];\n const vol = bar.volume ?? 1;\n // Distribute volume across the bins the bar spans\n const lowBin = Math.max(0, Math.floor((bar.low - pMin) / binSize));\n const highBin = Math.min(this.numBins - 1, Math.floor((bar.high - pMin) / binSize));\n const span = highBin - lowBin + 1;\n const volPerBin = vol / span;\n for (let b = lowBin; b <= highBin; b++) {\n bins[b] += volPerBin;\n if (bins[b] > maxBinVol) maxBinVol = bins[b];\n }\n }\n\n if (maxBinVol === 0) return;\n\n // Find POC (Point of Control)\n let pocBin = 0;\n for (let i = 1; i < this.numBins; i++) {\n if (bins[i] > bins[pocBin]) pocBin = i;\n }\n\n // Render histogram on the right side of the selected range\n const rightX = barIndexToX(endIdx, viewport) + viewport.barWidth;\n const maxBarWidth = 100; // Max histogram bar width in pixels\n const color = state.style.color;\n const pocColor = state.style.fillColor ?? '#FF9800';\n\n ctx.save();\n\n for (let b = 0; b < this.numBins; b++) {\n const ratio = bins[b] / maxBinVol;\n const barW = ratio * maxBarWidth;\n\n const priceTop = pMin + (b + 1) * binSize;\n const priceBot = pMin + b * binSize;\n const yTop = priceToY(priceTop, viewport);\n const yBot = priceToY(priceBot, viewport);\n const barH = Math.abs(yBot - yTop);\n\n ctx.globalAlpha = 0.35;\n ctx.fillStyle = b === pocBin ? pocColor : color;\n ctx.fillRect(rightX, Math.min(yTop, yBot), barW, Math.max(1, barH - 0.5));\n }\n\n // POC line\n const pocPrice = pMin + (pocBin + 0.5) * binSize;\n const pocY = priceToY(pocPrice, viewport);\n ctx.globalAlpha = 0.7;\n ctx.strokeStyle = pocColor;\n ctx.lineWidth = 1;\n ctx.setLineDash([4, 3]);\n ctx.beginPath();\n const leftX = barIndexToX(startIdx, viewport) - viewport.barWidth / 2;\n ctx.moveTo(leftX, pocY);\n ctx.lineTo(rightX + maxBarWidth, pocY);\n ctx.stroke();\n\n // POC label\n ctx.fillStyle = pocColor;\n ctx.font = '9px sans-serif';\n ctx.textAlign = 'left';\n ctx.textBaseline = 'bottom';\n ctx.globalAlpha = 0.8;\n ctx.fillText(`POC ${pocPrice.toFixed(2)}`, rightX + maxBarWidth + 4, pocY - 2);\n\n ctx.restore();\n\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n\n const left = Math.min(p1.x, p2.x) - tolerance;\n const right = Math.max(p1.x, p2.x) + 100 + tolerance; // +100 for histogram width\n const top = Math.min(p1.y, p2.y) - tolerance;\n const bottom = Math.max(p1.y, p2.y) + tolerance;\n\n return point.x >= left && point.x <= right && point.y >= top && point.y <= bottom;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\nimport { timeToX } from '../../viewport/ScaleMapping.js';\n\n/**\n * Vertical lines at Fibonacci intervals (1, 2, 3, 5, 8, 13, 21, 34, 55)\n * measured from a two-anchor time span. The first anchor defines time 0,\n * the second defines the unit (1× span). Each level i draws a vertical line\n * at `anchorA.time + (anchorB.time - anchorA.time) * fib[i]`.\n *\n * Useful for projecting future turning points based on prior swing duration.\n */\nconst FIB_TIME_LEVELS = [1, 2, 3, 5, 8, 13, 21, 34, 55];\n\nexport class FibTimeZonesTool extends DrawingBase {\n descriptor = {\n type: 'fibTimeZones' as const,\n name: 'Fibonacci Time Zones',\n requiredAnchors: 2,\n };\n\n render(\n ctx: CanvasRenderingContext2D,\n state: DrawingState,\n viewport: ViewportState,\n selected: boolean,\n ): void {\n if (state.anchors.length < 2) return;\n const anchorA = state.anchors[0];\n const anchorB = state.anchors[1];\n const unit = anchorB.time - anchorA.time;\n if (unit === 0) return;\n\n const { chartRect } = viewport;\n ctx.font = '11px sans-serif';\n ctx.textBaseline = 'top';\n ctx.textAlign = 'center';\n\n this.applyLineStyle(ctx, state.style);\n for (const mult of FIB_TIME_LEVELS) {\n const t = anchorA.time + unit * mult;\n const x = timeToX(t, viewport);\n if (x < chartRect.x || x > chartRect.x + chartRect.width) continue;\n\n ctx.globalAlpha = mult === 1 ? 1 : 0.55;\n ctx.beginPath();\n ctx.moveTo(x, chartRect.y);\n ctx.lineTo(x, chartRect.y + chartRect.height);\n ctx.stroke();\n\n ctx.fillStyle = state.style.color;\n ctx.fillText(String(mult), x, chartRect.y + 2);\n }\n ctx.globalAlpha = 1;\n this.resetLineStyle(ctx);\n\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): boolean {\n if (state.anchors.length < 2) return false;\n const anchorA = state.anchors[0];\n const anchorB = state.anchors[1];\n const unit = anchorB.time - anchorA.time;\n if (unit === 0) return false;\n const { chartRect } = viewport;\n if (point.y < chartRect.y || point.y > chartRect.y + chartRect.height) {\n return false;\n }\n for (const mult of FIB_TIME_LEVELS) {\n const t = anchorA.time + unit * mult;\n const x = timeToX(t, viewport);\n if (Math.abs(point.x - x) <= tolerance) return true;\n }\n return false;\n }\n}\n","export { TrendLineTool } from './TrendLine.js';\nexport { HorizontalLineTool } from './HorizontalLine.js';\nexport { VerticalLineTool } from './VerticalLine.js';\nexport { RayTool } from './Ray.js';\nexport { ExtendedLineTool } from './ExtendedLine.js';\nexport { ParallelChannelTool } from './ParallelChannel.js';\nexport { RegressionChannelTool } from './RegressionChannel.js';\nexport { FibRetracementTool } from './FibRetracement.js';\nexport { FibExtensionTool } from './FibExtension.js';\nexport { RectangleTool } from './Rectangle.js';\nexport { EllipseTool } from './Ellipse.js';\nexport { TriangleTool } from './Triangle.js';\nexport { PitchforkTool } from './Pitchfork.js';\nexport { ElliottWaveTool } from './ElliottWave.js';\nexport { PriceRangeTool } from './PriceRange.js';\nexport { DateRangeTool } from './DateRange.js';\nexport { MeasureTool } from './Measure.js';\nexport { TextAnnotationTool } from './TextAnnotation.js';\nexport { ArrowTool } from './Arrow.js';\nexport { GannFanTool } from './GannFan.js';\nexport { GannBoxTool } from './GannBox.js';\nexport { AnchoredVWAPTool } from './AnchoredVWAP.js';\nexport { VolumeProfileRangeTool } from './VolumeProfileRange.js';\nexport { FibTimeZonesTool } from './FibTimeZones.js';\n\nimport type { DrawingManager } from '../DrawingManager.js';\nimport { TrendLineTool } from './TrendLine.js';\nimport { HorizontalLineTool } from './HorizontalLine.js';\nimport { VerticalLineTool } from './VerticalLine.js';\nimport { RayTool } from './Ray.js';\nimport { ExtendedLineTool } from './ExtendedLine.js';\nimport { ParallelChannelTool } from './ParallelChannel.js';\nimport { RegressionChannelTool } from './RegressionChannel.js';\nimport { FibRetracementTool } from './FibRetracement.js';\nimport { FibExtensionTool } from './FibExtension.js';\nimport { RectangleTool } from './Rectangle.js';\nimport { EllipseTool } from './Ellipse.js';\nimport { TriangleTool } from './Triangle.js';\nimport { PitchforkTool } from './Pitchfork.js';\nimport { ElliottWaveTool } from './ElliottWave.js';\nimport { PriceRangeTool } from './PriceRange.js';\nimport { DateRangeTool } from './DateRange.js';\nimport { MeasureTool } from './Measure.js';\nimport { TextAnnotationTool } from './TextAnnotation.js';\nimport { ArrowTool } from './Arrow.js';\nimport { GannFanTool } from './GannFan.js';\nimport { GannBoxTool } from './GannBox.js';\nimport { AnchoredVWAPTool } from './AnchoredVWAP.js';\nimport { VolumeProfileRangeTool } from './VolumeProfileRange.js';\nimport { FibTimeZonesTool } from './FibTimeZones.js';\n\nexport function registerBuiltInDrawingTools(manager: DrawingManager): void {\n manager.register(new TrendLineTool());\n manager.register(new HorizontalLineTool());\n manager.register(new VerticalLineTool());\n manager.register(new RayTool());\n manager.register(new ExtendedLineTool());\n manager.register(new ParallelChannelTool());\n manager.register(new RegressionChannelTool());\n manager.register(new FibRetracementTool());\n manager.register(new FibExtensionTool());\n manager.register(new RectangleTool());\n manager.register(new EllipseTool());\n manager.register(new TriangleTool());\n manager.register(new PitchforkTool());\n manager.register(new ElliottWaveTool());\n manager.register(new PriceRangeTool());\n manager.register(new DateRangeTool());\n manager.register(new MeasureTool());\n manager.register(new TextAnnotationTool());\n manager.register(new ArrowTool());\n manager.register(new GannFanTool());\n manager.register(new GannBoxTool());\n manager.register(new AnchoredVWAPTool());\n manager.register(new VolumeProfileRangeTool());\n manager.register(new FibTimeZonesTool());\n}\n","import type { TradingOrder, TradingConfig, ViewportState, Theme } from '@tradecanvas/commons';\nimport { priceToY } from '../viewport/ScaleMapping.js';\nimport { PRICE_AXIS_WIDTH } from '@tradecanvas/commons';\n\nexport interface DragState {\n orderId: string;\n sourceType: 'order' | 'stopLoss' | 'takeProfit';\n startPrice: number;\n currentPrice: number;\n}\n\nexport class OrderRenderer {\n render(\n ctx: CanvasRenderingContext2D,\n orders: TradingOrder[],\n viewport: ViewportState,\n theme: Theme,\n config: TradingConfig,\n dragState: DragState | null,\n ): void {\n const buyColor = config.orderColors?.buy ?? '#26A69A';\n const sellColor = config.orderColors?.sell ?? '#EF5350';\n const { chartRect } = viewport;\n\n for (const order of orders) {\n const isDragging = dragState?.orderId === order.id && dragState.sourceType === 'order';\n const price = isDragging ? dragState!.currentPrice : order.price;\n const y = priceToY(price, viewport);\n\n if (y < chartRect.y || y > chartRect.y + chartRect.height) continue;\n\n const color = order.side === 'buy' ? buyColor : sellColor;\n\n // Dashed order line\n ctx.setLineDash([6, 4]);\n ctx.strokeStyle = color;\n ctx.lineWidth = 1;\n ctx.beginPath();\n ctx.moveTo(chartRect.x, Math.round(y) + 0.5);\n ctx.lineTo(chartRect.x + chartRect.width, Math.round(y) + 0.5);\n ctx.stroke();\n ctx.setLineDash([]);\n\n // Order type label (left side)\n const label = order.label ?? order.type.toUpperCase();\n ctx.font = `bold 10px ${theme.font.family}`;\n const labelWidth = ctx.measureText(label).width + 8;\n ctx.fillStyle = color;\n ctx.fillRect(chartRect.x + 4, y - 8, labelWidth, 16);\n ctx.fillStyle = '#FFFFFF';\n ctx.textBaseline = 'middle';\n ctx.textAlign = 'left';\n ctx.fillText(label, chartRect.x + 8, y);\n\n // Price + qty badge on axis — rendered separately via renderAxisBadges()\n // on the UI layer so it paints on top of the price axis labels.\n\n // Side indicator (small triangle)\n const triX = chartRect.x + 4 + labelWidth + 6;\n ctx.fillStyle = color;\n ctx.beginPath();\n if (order.side === 'buy') {\n ctx.moveTo(triX, y + 4);\n ctx.lineTo(triX + 5, y - 2);\n ctx.lineTo(triX + 10, y + 4);\n } else {\n ctx.moveTo(triX, y - 4);\n ctx.lineTo(triX + 5, y + 2);\n ctx.lineTo(triX + 10, y - 4);\n }\n ctx.fill();\n\n // Ghost line at original price if dragging\n if (isDragging) {\n const origY = priceToY(dragState!.startPrice, viewport);\n ctx.setLineDash([2, 4]);\n ctx.strokeStyle = color;\n ctx.globalAlpha = 0.3;\n ctx.beginPath();\n ctx.moveTo(chartRect.x, Math.round(origY) + 0.5);\n ctx.lineTo(chartRect.x + chartRect.width, Math.round(origY) + 0.5);\n ctx.stroke();\n ctx.globalAlpha = 1;\n ctx.setLineDash([]);\n }\n }\n }\n\n /**\n * Draw order price badges on the price axis. Called from the UI layer\n * so they paint ON TOP of the regular axis tick labels.\n */\n renderAxisBadges(\n ctx: CanvasRenderingContext2D,\n orders: TradingOrder[],\n viewport: ViewportState,\n theme: Theme,\n config: TradingConfig,\n dragState: DragState | null,\n ): void {\n const buyColor = config.orderColors?.buy ?? '#26A69A';\n const sellColor = config.orderColors?.sell ?? '#EF5350';\n const precision = config.pricePrecision ?? 2;\n const { chartRect } = viewport;\n const axisX = chartRect.x + chartRect.width + 1;\n\n for (const order of orders) {\n const isDragging = dragState?.orderId === order.id && dragState.sourceType === 'order';\n const price = isDragging ? dragState!.currentPrice : order.price;\n const y = priceToY(price, viewport);\n if (y < chartRect.y || y > chartRect.y + chartRect.height) continue;\n\n const color = order.side === 'buy' ? buyColor : sellColor;\n const priceText = `${price.toFixed(precision)} x ${order.quantity}`;\n ctx.font = `11px ${theme.font.family}`;\n const badgeWidth = ctx.measureText(priceText).width + 10;\n ctx.fillStyle = color;\n ctx.fillRect(axisX, y - 9, Math.min(badgeWidth, PRICE_AXIS_WIDTH - 2), 18);\n ctx.fillStyle = '#FFFFFF';\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.fillText(priceText, axisX + 5, y);\n }\n }\n\n hitTest(\n y: number,\n orders: TradingOrder[],\n viewport: ViewportState,\n tolerance: number,\n ): TradingOrder | null {\n for (const order of orders) {\n if (order.draggable === false) continue;\n const orderY = priceToY(order.price, viewport);\n if (Math.abs(y - orderY) <= tolerance) return order;\n }\n return null;\n }\n}\n","import type {\r\n PnLThreshold,\r\n PositionLabelContext,\r\n TradingPosition,\r\n} from '@tradecanvas/commons';\r\n\r\n/**\r\n * Compute live P&L context for a position. Pure — no canvas, no side effects.\r\n * `closedQuantity` is clamped into [0, quantity]; remaining open quantity drives the P&L.\r\n */\r\nexport function buildPositionLabelContext(\r\n pos: TradingPosition,\r\n currentPrice: number,\r\n precision: number,\r\n): PositionLabelContext {\r\n const closed = Math.min(Math.max(pos.closedQuantity ?? 0, 0), pos.quantity);\r\n const open = pos.quantity - closed;\r\n const direction = pos.side === 'buy' ? 1 : -1;\r\n const pnl = (currentPrice - pos.entryPrice) * open * direction;\r\n const pnlPct =\r\n pos.entryPrice === 0\r\n ? 0\r\n : ((currentPrice - pos.entryPrice) / pos.entryPrice) * 100 * direction;\r\n return {\r\n side: pos.side,\r\n quantity: pos.quantity,\r\n closedQuantity: closed,\r\n openQuantity: open,\r\n entryPrice: pos.entryPrice,\r\n currentPrice,\r\n pnl,\r\n pnlPct,\r\n precision,\r\n };\r\n}\r\n\r\nconst TOKEN_RE = /\\{(side|qty|closedQty|openQty|entry|price|pnl|pnlPct|pnlSign)\\}/g;\r\n\r\nexport function formatPositionLabel(\r\n template: string,\r\n ctx: PositionLabelContext,\r\n): string {\r\n return template.replace(TOKEN_RE, (_, key: string) => {\r\n switch (key) {\r\n case 'side':\r\n return ctx.side.toUpperCase();\r\n case 'qty':\r\n return String(ctx.quantity);\r\n case 'closedQty':\r\n return String(ctx.closedQuantity);\r\n case 'openQty':\r\n return String(ctx.openQuantity);\r\n case 'entry':\r\n return ctx.entryPrice.toFixed(ctx.precision);\r\n case 'price':\r\n return ctx.currentPrice.toFixed(ctx.precision);\r\n case 'pnl':\r\n return ctx.pnl.toFixed(ctx.precision);\r\n case 'pnlPct':\r\n return `${ctx.pnlPct.toFixed(2)}%`;\r\n case 'pnlSign':\r\n return ctx.pnl >= 0 ? '+' : '';\r\n default:\r\n return '';\r\n }\r\n });\r\n}\r\n\r\nexport const DEFAULT_POSITION_LABEL =\r\n '{side} {qty} | P&L: {pnlSign}{pnl}';\r\n\r\nexport function resolvePositionLabel(\r\n template: string | ((ctx: PositionLabelContext) => string) | undefined,\r\n ctx: PositionLabelContext,\r\n): string {\r\n if (typeof template === 'function') return template(ctx);\r\n return formatPositionLabel(template ?? DEFAULT_POSITION_LABEL, ctx);\r\n}\r\n\r\n/**\r\n * Pick the color matching `pnl` from a threshold list. The chosen entry is the\r\n * highest one whose `pnl` ≤ the live P&L. Returns `fallback` when no entry qualifies.\r\n */\r\nexport function pickPnLColor(\r\n pnl: number,\r\n thresholds: PnLThreshold[] | undefined,\r\n fallback: string,\r\n): string {\r\n if (!thresholds || thresholds.length === 0) return fallback;\r\n const sorted = [...thresholds].sort((a, b) => a.pnl - b.pnl);\r\n let chosen: string | undefined;\r\n for (const t of sorted) {\r\n if (pnl >= t.pnl) chosen = t.color;\r\n else break;\r\n }\r\n return chosen ?? fallback;\r\n}\r\n","import type { TradingPosition, TradingConfig, ViewportState, Theme } from '@tradecanvas/commons';\r\nimport { priceToY } from '../viewport/ScaleMapping.js';\r\nimport { PRICE_AXIS_WIDTH } from '@tradecanvas/commons';\r\nimport {\r\n buildPositionLabelContext,\r\n pickPnLColor,\r\n resolvePositionLabel,\r\n} from './positionFormat.js';\r\n\r\nexport class PositionRenderer {\r\n render(\r\n ctx: CanvasRenderingContext2D,\r\n positions: TradingPosition[],\r\n currentPrice: number | null,\r\n viewport: ViewportState,\r\n theme: Theme,\r\n config: TradingConfig,\r\n ): void {\r\n const { chartRect } = viewport;\r\n const profitColor = config.positionColors?.profit ?? '#26A69A';\r\n const lossColor = config.positionColors?.loss ?? '#EF5350';\r\n const entryColor = config.positionColors?.entry ?? '#2196F3';\r\n const precision = config.pricePrecision ?? 2;\r\n\r\n for (const pos of positions) {\r\n const entryY = priceToY(pos.entryPrice, viewport);\r\n\r\n // Entry line\r\n ctx.strokeStyle = entryColor;\r\n ctx.lineWidth = 1.5;\r\n ctx.setLineDash([]);\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, Math.round(entryY) + 0.5);\r\n ctx.lineTo(chartRect.x + chartRect.width, Math.round(entryY) + 0.5);\r\n ctx.stroke();\r\n\r\n // P&L zone\r\n if (currentPrice !== null) {\r\n const currentY = priceToY(currentPrice, viewport);\r\n const labelCtx = buildPositionLabelContext(pos, currentPrice, precision);\r\n const pnl = labelCtx.pnl;\r\n const isProfit = pnl >= 0;\r\n const fallbackZone = isProfit ? profitColor : lossColor;\r\n const zoneColor = pickPnLColor(pnl, config.pnlThresholds, fallbackZone);\r\n\r\n ctx.fillStyle = zoneColor;\r\n ctx.globalAlpha = 0.08;\r\n const top = Math.min(entryY, currentY);\r\n const height = Math.abs(currentY - entryY);\r\n ctx.fillRect(chartRect.x, top, chartRect.width, height);\r\n ctx.globalAlpha = 1;\r\n\r\n // Partial-close strip on the left edge — proportional dim band signalling\r\n // the closed fraction of the position.\r\n if (labelCtx.closedQuantity > 0 && pos.quantity > 0) {\r\n const closedFrac = labelCtx.closedQuantity / pos.quantity;\r\n ctx.fillStyle = entryColor;\r\n ctx.globalAlpha = 0.25;\r\n ctx.fillRect(chartRect.x, top, Math.max(2, chartRect.width * closedFrac * 0.04) + 2, height);\r\n ctx.globalAlpha = 1;\r\n }\r\n\r\n const pnlText = resolvePositionLabel(config.positionLabel, labelCtx);\r\n ctx.font = `bold 11px ${theme.font.family}`;\r\n const lblWidth = ctx.measureText(pnlText).width + 12;\r\n const lblX = chartRect.x + 8;\r\n ctx.fillStyle = zoneColor;\r\n ctx.globalAlpha = 0.9;\r\n ctx.fillRect(lblX, entryY - 10, lblWidth, 20);\r\n ctx.globalAlpha = 1;\r\n ctx.fillStyle = '#FFFFFF';\r\n ctx.textBaseline = 'middle';\r\n ctx.textAlign = 'left';\r\n ctx.fillText(pnlText, lblX + 6, entryY);\r\n }\r\n\r\n // Entry badge on axis — rendered separately via renderAxisBadges()\r\n // on the UI layer so it paints on top of the price axis labels.\r\n\r\n // SL line\r\n if (pos.stopLoss !== undefined) {\r\n const slY = priceToY(pos.stopLoss, viewport);\r\n ctx.setLineDash([4, 4]);\r\n ctx.strokeStyle = lossColor;\r\n ctx.lineWidth = 1;\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, Math.round(slY) + 0.5);\r\n ctx.lineTo(chartRect.x + chartRect.width, Math.round(slY) + 0.5);\r\n ctx.stroke();\r\n\r\n ctx.font = `bold 10px ${theme.font.family}`;\r\n ctx.fillStyle = lossColor;\r\n ctx.fillRect(chartRect.x + 4, slY - 8, 24, 16);\r\n ctx.fillStyle = '#FFFFFF';\r\n ctx.textAlign = 'left';\r\n ctx.textBaseline = 'middle';\r\n ctx.fillText('SL', chartRect.x + 8, slY);\r\n }\r\n\r\n // TP line\r\n if (pos.takeProfit !== undefined) {\r\n const tpY = priceToY(pos.takeProfit, viewport);\r\n ctx.setLineDash([4, 4]);\r\n ctx.strokeStyle = profitColor;\r\n ctx.lineWidth = 1;\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, Math.round(tpY) + 0.5);\r\n ctx.lineTo(chartRect.x + chartRect.width, Math.round(tpY) + 0.5);\r\n ctx.stroke();\r\n\r\n ctx.font = `bold 10px ${theme.font.family}`;\r\n ctx.fillStyle = profitColor;\r\n ctx.fillRect(chartRect.x + 4, tpY - 8, 24, 16);\r\n ctx.fillStyle = '#FFFFFF';\r\n ctx.textAlign = 'left';\r\n ctx.textBaseline = 'middle';\r\n ctx.fillText('TP', chartRect.x + 8, tpY);\r\n }\r\n\r\n ctx.setLineDash([]);\r\n }\r\n }\r\n\r\n /**\r\n * Draw position entry badges on the price axis. Called from the UI layer\r\n * so they paint ON TOP of the regular axis tick labels.\r\n */\r\n renderAxisBadges(\r\n ctx: CanvasRenderingContext2D,\r\n positions: TradingPosition[],\r\n viewport: ViewportState,\r\n theme: Theme,\r\n config: TradingConfig,\r\n ): void {\r\n const { chartRect } = viewport;\r\n const entryColor = config.positionColors?.entry ?? '#2196F3';\r\n const precision = config.pricePrecision ?? 2;\r\n const axisX = chartRect.x + chartRect.width + 1;\r\n\r\n for (const pos of positions) {\r\n const entryY = priceToY(pos.entryPrice, viewport);\r\n ctx.fillStyle = entryColor;\r\n ctx.fillRect(axisX, entryY - 9, PRICE_AXIS_WIDTH - 2, 18);\r\n ctx.fillStyle = '#FFFFFF';\r\n ctx.font = `11px ${theme.font.family}`;\r\n ctx.textAlign = 'left';\r\n ctx.textBaseline = 'middle';\r\n ctx.fillText(pos.entryPrice.toFixed(precision), axisX + 5, entryY);\r\n }\r\n }\r\n}\r\n","import type { DepthData, TradingConfig, ViewportState } from '@tradecanvas/commons';\nimport { priceToY } from '../viewport/ScaleMapping.js';\n\nexport class DepthOverlay {\n render(\n ctx: CanvasRenderingContext2D,\n depth: DepthData,\n viewport: ViewportState,\n config: TradingConfig,\n ): void {\n if (!config.depthOverlay?.enabled) return;\n\n const { chartRect } = viewport;\n const bidColor = config.depthOverlay.bidColor ?? 'rgba(38,166,154,0.15)';\n const askColor = config.depthOverlay.askColor ?? 'rgba(239,83,80,0.15)';\n const maxWidth = config.depthOverlay.maxWidth ?? 100;\n\n // Compute cumulative volumes\n let maxCumVol = 0;\n const bidCum: { price: number; cumVol: number }[] = [];\n let cumVol = 0;\n for (const level of depth.bids) {\n cumVol += level.volume;\n bidCum.push({ price: level.price, cumVol });\n if (cumVol > maxCumVol) maxCumVol = cumVol;\n }\n\n const askCum: { price: number; cumVol: number }[] = [];\n cumVol = 0;\n for (const level of depth.asks) {\n cumVol += level.volume;\n askCum.push({ price: level.price, cumVol });\n if (cumVol > maxCumVol) maxCumVol = cumVol;\n }\n\n if (maxCumVol === 0) return;\n\n // Estimate bar height from price spacing\n const barHeight = Math.max(1, (depth.bids.length > 1\n ? Math.abs(priceToY(depth.bids[0].price, viewport) - priceToY(depth.bids[1].price, viewport))\n : 4));\n\n const rightEdge = chartRect.x + chartRect.width;\n\n // Draw bids (right-aligned, growing left)\n ctx.fillStyle = bidColor;\n for (const { price, cumVol: cv } of bidCum) {\n const y = priceToY(price, viewport);\n if (y < chartRect.y || y > chartRect.y + chartRect.height) continue;\n const barW = (cv / maxCumVol) * maxWidth;\n ctx.fillRect(rightEdge - barW, y - barHeight / 2, barW, barHeight);\n }\n\n // Draw asks\n ctx.fillStyle = askColor;\n for (const { price, cumVol: cv } of askCum) {\n const y = priceToY(price, viewport);\n if (y < chartRect.y || y > chartRect.y + chartRect.height) continue;\n const barW = (cv / maxCumVol) * maxWidth;\n ctx.fillRect(rightEdge - barW, y - barHeight / 2, barW, barHeight);\n }\n }\n}\n","import type { TradingOrder, TradingPosition, ViewportState, Point } from '@tradecanvas/commons';\nimport { priceToY, yToPrice } from '../viewport/ScaleMapping.js';\nimport type { DragState } from './OrderRenderer.js';\n\nexport interface DragResult {\n sourceType: 'order' | 'stopLoss' | 'takeProfit';\n id: string;\n newPrice: number;\n previousPrice: number;\n}\n\nexport class TradingDragHandler {\n private dragState: DragState | null = null;\n private startY = 0;\n private dragging = false;\n\n constructor(private dragThreshold = 3) {}\n\n onPointerDown(\n pos: Point,\n orders: TradingOrder[],\n positions: TradingPosition[],\n viewport: ViewportState,\n tolerance: number,\n ): boolean {\n // Check order lines\n for (const order of orders) {\n if (order.draggable === false) continue;\n const y = priceToY(order.price, viewport);\n if (Math.abs(pos.y - y) <= tolerance) {\n this.dragState = {\n orderId: order.id,\n sourceType: 'order',\n startPrice: order.price,\n currentPrice: order.price,\n };\n this.startY = pos.y;\n this.dragging = false;\n return true;\n }\n }\n\n // Check SL/TP lines on positions\n for (const pos2 of positions) {\n if (pos2.stopLoss !== undefined) {\n const slY = priceToY(pos2.stopLoss, viewport);\n if (Math.abs(pos.y - slY) <= tolerance) {\n this.dragState = {\n orderId: pos2.id,\n sourceType: 'stopLoss',\n startPrice: pos2.stopLoss,\n currentPrice: pos2.stopLoss,\n };\n this.startY = pos.y;\n this.dragging = false;\n return true;\n }\n }\n if (pos2.takeProfit !== undefined) {\n const tpY = priceToY(pos2.takeProfit, viewport);\n if (Math.abs(pos.y - tpY) <= tolerance) {\n this.dragState = {\n orderId: pos2.id,\n sourceType: 'takeProfit',\n startPrice: pos2.takeProfit,\n currentPrice: pos2.takeProfit,\n };\n this.startY = pos.y;\n this.dragging = false;\n return true;\n }\n }\n }\n\n return false;\n }\n\n onPointerMove(pos: Point, viewport: ViewportState): boolean {\n if (!this.dragState) return false;\n\n if (!this.dragging) {\n if (Math.abs(pos.y - this.startY) < this.dragThreshold) return true;\n this.dragging = true;\n }\n\n this.dragState.currentPrice = yToPrice(pos.y, viewport);\n return true;\n }\n\n onPointerUp(): DragResult | null {\n if (!this.dragState) return null;\n const state = this.dragState;\n this.dragState = null;\n\n if (!this.dragging) return null;\n this.dragging = false;\n\n return {\n sourceType: state.sourceType,\n id: state.orderId,\n newPrice: state.currentPrice,\n previousPrice: state.startPrice,\n };\n }\n\n getDragState(): DragState | null {\n return this.dragState;\n }\n\n isActive(): boolean {\n return this.dragState !== null;\n }\n}\n","import type { OrderPlaceIntent, TradingConfig, Point } from '@tradecanvas/commons';\n\nexport class TradingContextMenu {\n private menuElement: HTMLElement | null = null;\n private removeHandler: (() => void) | null = null;\n onItemSelect: ((intent: OrderPlaceIntent) => void) | null = null;\n\n show(pos: Point, price: number, container: HTMLElement, config: TradingConfig): void {\n this.hide();\n if (!config.contextMenu?.enabled) return;\n\n const precision = config.pricePrecision ?? 2;\n const priceStr = price.toFixed(precision);\n\n const menu = document.createElement('div');\n menu.style.cssText = `\n position: absolute;\n left: ${pos.x}px;\n top: ${pos.y}px;\n background: #1e222d;\n border: 1px solid #363a45;\n border-radius: 6px;\n padding: 4px 0;\n z-index: 1000;\n min-width: 180px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.4);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n font-size: 12px;\n `;\n\n const items: { label: string; intent: OrderPlaceIntent }[] = [\n { label: `Buy Limit @ ${priceStr}`, intent: { side: 'buy', type: 'limit', price } },\n { label: `Sell Limit @ ${priceStr}`, intent: { side: 'sell', type: 'limit', price } },\n { label: `Buy Stop @ ${priceStr}`, intent: { side: 'buy', type: 'stop', price } },\n { label: `Sell Stop @ ${priceStr}`, intent: { side: 'sell', type: 'stop', price } },\n ];\n\n for (const item of items) {\n const el = document.createElement('div');\n const isBuy = item.intent.side === 'buy';\n el.textContent = item.label;\n el.style.cssText = `\n padding: 6px 12px;\n cursor: pointer;\n color: ${isBuy ? '#26A69A' : '#EF5350'};\n transition: background 0.1s;\n `;\n el.addEventListener('mouseenter', () => { el.style.background = '#2a2e39'; });\n el.addEventListener('mouseleave', () => { el.style.background = 'transparent'; });\n el.addEventListener('click', () => {\n this.onItemSelect?.(item.intent);\n this.hide();\n });\n menu.appendChild(el);\n }\n\n container.appendChild(menu);\n this.menuElement = menu;\n\n // Close on outside click or Escape\n const closeHandler = (e: Event) => {\n if (e instanceof KeyboardEvent && e.key === 'Escape') {\n this.hide();\n } else if (e instanceof MouseEvent && !menu.contains(e.target as Node)) {\n this.hide();\n }\n };\n document.addEventListener('mousedown', closeHandler);\n document.addEventListener('keydown', closeHandler);\n this.removeHandler = () => {\n document.removeEventListener('mousedown', closeHandler);\n document.removeEventListener('keydown', closeHandler);\n };\n }\n\n hide(): void {\n this.menuElement?.remove();\n this.menuElement = null;\n this.removeHandler?.();\n this.removeHandler = null;\n }\n\n destroy(): void {\n this.hide();\n this.onItemSelect = null;\n }\n}\n","import type {\n TradingOrder,\n TradingPosition,\n DepthData,\n TradingConfig,\n ViewportState,\n Theme,\n Point,\n} from '@tradecanvas/commons';\nimport { DEFAULT_TRADING_CONFIG } from '@tradecanvas/commons';\nimport { yToPrice } from '../viewport/ScaleMapping.js';\nimport { OrderRenderer } from './OrderRenderer.js';\nimport { PositionRenderer } from './PositionRenderer.js';\nimport { DepthOverlay } from './DepthOverlay.js';\nimport { TradingDragHandler } from './TradingDragHandler.js';\nimport { TradingContextMenu } from './TradingContextMenu.js';\n\nexport class TradingManager {\n private orders: TradingOrder[] = [];\n private positions: TradingPosition[] = [];\n private depthData: DepthData | null = null;\n private currentPrice: number | null = null;\n private config: TradingConfig;\n\n private orderRenderer = new OrderRenderer();\n private positionRenderer = new PositionRenderer();\n private depthOverlay = new DepthOverlay();\n private dragHandler: TradingDragHandler;\n private contextMenu = new TradingContextMenu();\n\n private requestRender: (() => void) | null = null;\n private eventCallback: ((event: string, data: unknown) => void) | null = null;\n private container: HTMLElement | null = null;\n\n constructor(config?: Partial<TradingConfig>) {\n this.config = { ...DEFAULT_TRADING_CONFIG, ...config };\n this.dragHandler = new TradingDragHandler(this.config.dragThreshold);\n\n this.contextMenu.onItemSelect = (intent) => {\n this.eventCallback?.('orderPlace', intent);\n };\n }\n\n setContainer(container: HTMLElement): void {\n this.container = container;\n }\n\n setRequestRender(cb: () => void): void {\n this.requestRender = cb;\n }\n\n setEventCallback(cb: (event: string, data: unknown) => void): void {\n this.eventCallback = cb;\n }\n\n // --- State ---\n\n setOrders(orders: TradingOrder[]): void {\n this.orders = orders;\n this.requestRender?.();\n }\n\n setPositions(positions: TradingPosition[]): void {\n this.positions = positions;\n this.requestRender?.();\n }\n\n setDepthData(depth: DepthData | null): void {\n this.depthData = depth;\n this.requestRender?.();\n }\n\n setCurrentPrice(price: number): void {\n this.currentPrice = price;\n this.requestRender?.();\n }\n\n setConfig(config: Partial<TradingConfig>): void {\n Object.assign(this.config, config);\n this.requestRender?.();\n }\n\n // --- Pointer events ---\n\n onPointerDown(pos: Point, viewport: ViewportState): boolean {\n if (!this.config.enabled) return false;\n return this.dragHandler.onPointerDown(pos, this.orders, this.positions, viewport, 8);\n }\n\n onPointerMove(pos: Point, viewport: ViewportState): boolean {\n if (!this.dragHandler.isActive()) return false;\n const consumed = this.dragHandler.onPointerMove(pos, viewport);\n if (consumed) this.requestRender?.();\n return consumed;\n }\n\n onPointerUp(): boolean {\n const result = this.dragHandler.onPointerUp();\n if (result) {\n if (result.sourceType === 'order') {\n this.eventCallback?.('orderModify', {\n orderId: result.id,\n newPrice: result.newPrice,\n previousPrice: result.previousPrice,\n });\n } else {\n this.eventCallback?.('positionModify', {\n positionId: result.id,\n [result.sourceType]: result.newPrice,\n });\n }\n this.requestRender?.();\n return true;\n }\n return false;\n }\n\n onContextMenu(pos: Point, viewport: ViewportState): boolean {\n if (!this.config.enabled || !this.config.contextMenu?.enabled || !this.container) return false;\n const price = yToPrice(pos.y, viewport);\n this.contextMenu.show(pos, price, this.container, this.config);\n return true;\n }\n\n // --- Render ---\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n if (!this.config.enabled) return;\n\n // Depth overlay (back)\n if (this.depthData) {\n this.depthOverlay.render(ctx, this.depthData, viewport, this.config);\n }\n\n // Positions (middle)\n if (this.positions.length > 0) {\n this.positionRenderer.render(ctx, this.positions, this.currentPrice, viewport, theme, this.config);\n }\n\n // Orders (front)\n if (this.orders.length > 0) {\n this.orderRenderer.render(ctx, this.orders, viewport, theme, this.config, this.dragHandler.getDragState());\n }\n }\n\n /**\n * Draw position/order price badges on the price axis. Intended for the\n * UI layer so they paint ON TOP of the regular axis labels.\n */\n renderAxisBadges(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n if (!this.config.enabled) return;\n if (this.positions.length > 0) {\n this.positionRenderer.renderAxisBadges(ctx, this.positions, viewport, theme, this.config);\n }\n if (this.orders.length > 0) {\n this.orderRenderer.renderAxisBadges(ctx, this.orders, viewport, theme, this.config, this.dragHandler.getDragState());\n }\n }\n\n destroy(): void {\n this.contextMenu.destroy();\n }\n}\n","import type { ViewportState, Theme } from '@tradecanvas/commons';\nimport type { TradingManager } from './TradingManager.js';\n\nexport class TradingRenderer {\n constructor(private manager: TradingManager) {}\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n this.manager.render(ctx, viewport, theme);\n }\n\n /**\n * Draw position/order price badges on the price axis. Call this from the\n * UI layer AFTER priceAxis.render() so the badges paint on top of the\n * regular tick labels — matching MT4/MT5 behaviour.\n */\n renderAxisBadges(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n this.manager.renderAxisBadges(ctx, viewport, theme);\n }\n}\n","/**\n * Typed event emitter. Foundation for adapters and stream manager.\n * Keeps listeners in insertion order, supports once() for one-shot listeners.\n */\nexport class Emitter<EventMap extends Record<string, unknown>> {\n private listeners = new Map<keyof EventMap, Set<(data: any) => void>>();\n\n on<K extends keyof EventMap>(event: K, listener: (data: EventMap[K]) => void): () => void {\n let set = this.listeners.get(event);\n if (!set) {\n set = new Set();\n this.listeners.set(event, set);\n }\n set.add(listener);\n return () => set!.delete(listener);\n }\n\n once<K extends keyof EventMap>(event: K, listener: (data: EventMap[K]) => void): () => void {\n const wrapper = (data: EventMap[K]) => {\n unsub();\n listener(data);\n };\n const unsub = this.on(event, wrapper);\n return unsub;\n }\n\n off<K extends keyof EventMap>(event: K, listener: (data: EventMap[K]) => void): void {\n this.listeners.get(event)?.delete(listener);\n }\n\n protected emit<K extends keyof EventMap>(event: K, data: EventMap[K]): void {\n const set = this.listeners.get(event);\n if (set) {\n for (const listener of set) {\n listener(data);\n }\n }\n }\n\n removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","import type { OHLCBar, TimeFrame, RawTick, AggregatedBar } from '@tradecanvas/commons';\nimport { timeframeToMs } from '@tradecanvas/commons';\nimport { Emitter } from './Emitter.js';\n\ninterface AggregatorEvents {\n bar: AggregatedBar; // bar updated (forming)\n barClose: AggregatedBar; // bar closed (finalized)\n [key: string]: unknown;\n}\n\n/**\n * Aggregates raw ticks into OHLCV bars aligned to timeframe boundaries.\n *\n * Handles:\n * - Tick-to-bar conversion with proper timeframe alignment\n * - Bar close detection (when time crosses boundary)\n * - Volume accumulation\n * - Tick counting\n *\n * Note: Emitted bars are references to internal state.\n * Listeners MUST NOT mutate them — treat as readonly.\n */\nexport class TickAggregator extends Emitter<AggregatorEvents> {\n private currentBar: AggregatedBar | null = null;\n private timeframeMs: number;\n\n // Ring buffer for tick storage — O(1) push and eviction\n private tickRing: RawTick[];\n private ringHead = 0;\n private ringCount = 0;\n private readonly ringCapacity: number;\n\n constructor(\n _timeframe: TimeFrame,\n bufferSize = 1000,\n ) {\n super();\n this.timeframeMs = timeframeToMs(_timeframe);\n this.ringCapacity = bufferSize;\n this.tickRing = new Array<RawTick>(bufferSize);\n }\n\n setTimeframe(tf: TimeFrame): void {\n this.timeframeMs = timeframeToMs(tf);\n this.currentBar = null;\n this.ringHead = 0;\n this.ringCount = 0;\n }\n\n processTick(tick: RawTick): void {\n // Ring buffer push — O(1)\n const writeIdx = (this.ringHead + this.ringCount) % this.ringCapacity;\n this.tickRing[writeIdx] = tick;\n if (this.ringCount < this.ringCapacity) {\n this.ringCount++;\n } else {\n // Buffer full — advance head, dropping oldest tick\n this.ringHead = (this.ringHead + 1) % this.ringCapacity;\n }\n\n const barTime = this.alignToTimeframe(tick.time);\n\n if (!this.currentBar || this.currentBar.time !== barTime) {\n // Close previous bar\n if (this.currentBar) {\n this.currentBar.closed = true;\n this.emit('barClose', this.currentBar);\n }\n\n // Start new bar\n this.currentBar = {\n time: barTime,\n open: tick.price,\n high: tick.price,\n low: tick.price,\n close: tick.price,\n volume: tick.volume,\n closed: false,\n tickCount: 1,\n };\n } else {\n // Update current bar\n this.currentBar.high = Math.max(this.currentBar.high, tick.price);\n this.currentBar.low = Math.min(this.currentBar.low, tick.price);\n this.currentBar.close = tick.price;\n this.currentBar.volume += tick.volume;\n this.currentBar.tickCount++;\n }\n\n this.emit('bar', this.currentBar);\n }\n\n /**\n * Process a pre-formed bar (from adapter that already provides OHLCV).\n * Detects close by checking if this bar's time differs from current.\n */\n processBar(bar: OHLCBar, closed: boolean): void {\n if (closed && this.currentBar && this.currentBar.time === bar.time) {\n // Close the bar\n this.currentBar = { ...bar, closed: true, tickCount: this.currentBar.tickCount + 1 };\n this.emit('barClose', this.currentBar);\n this.currentBar = null;\n } else if (!closed) {\n // Update forming bar\n this.currentBar = { ...bar, closed: false, tickCount: (this.currentBar?.tickCount ?? 0) + 1 };\n this.emit('bar', this.currentBar);\n } else {\n // New closed bar without a forming bar preceding it\n const aggBar: AggregatedBar = { ...bar, closed: true, tickCount: 1 };\n this.emit('barClose', aggBar);\n this.currentBar = null;\n }\n }\n\n getCurrentBar(): AggregatedBar | null {\n return this.currentBar ? { ...this.currentBar } : null;\n }\n\n getTickBuffer(): readonly RawTick[] {\n // Materialize ring into ordered array for external consumers\n const result: RawTick[] = new Array(this.ringCount);\n for (let i = 0; i < this.ringCount; i++) {\n result[i] = this.tickRing[(this.ringHead + i) % this.ringCapacity];\n }\n return result;\n }\n\n reset(): void {\n this.currentBar = null;\n this.ringHead = 0;\n this.ringCount = 0;\n }\n\n private alignToTimeframe(timestamp: number): number {\n return Math.floor(timestamp / this.timeframeMs) * this.timeframeMs;\n }\n}\n","import type { ReconnectConfig } from '@tradecanvas/commons';\nimport { DEFAULT_RECONNECT } from '@tradecanvas/commons';\nimport { Emitter } from './Emitter.js';\n\ninterface ReconnectEvents {\n attempt: { attempt: number; delay: number };\n success: void;\n giveUp: { attempts: number };\n [key: string]: unknown;\n}\n\n/**\n * Exponential backoff reconnection manager.\n *\n * Features:\n * - Exponential backoff with jitter\n * - Configurable max retries and max delay\n * - Reset on successful connection\n * - Cancellable pending reconnection\n */\nexport class ReconnectManager extends Emitter<ReconnectEvents> {\n private config: ReconnectConfig;\n private attempt = 0;\n private timer: ReturnType<typeof setTimeout> | null = null;\n private active = false;\n\n constructor(config?: Partial<ReconnectConfig>) {\n super();\n this.config = { ...DEFAULT_RECONNECT, ...config };\n }\n\n schedule(connectFn: () => void): void {\n if (!this.config.enabled || !this.active) return;\n\n this.attempt++;\n\n if (this.attempt > this.config.maxRetries) {\n this.emit('giveUp', { attempts: this.attempt - 1 });\n this.active = false;\n return;\n }\n\n const delay = this.computeDelay();\n this.emit('attempt', { attempt: this.attempt, delay });\n\n this.timer = setTimeout(() => {\n this.timer = null;\n if (this.active) connectFn();\n }, delay);\n }\n\n onConnected(): void {\n this.attempt = 0;\n this.cancel();\n this.emit('success', undefined as any);\n }\n\n start(): void {\n this.active = true;\n }\n\n stop(): void {\n this.active = false;\n this.cancel();\n this.attempt = 0;\n }\n\n cancel(): void {\n if (this.timer) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n }\n\n getAttempt(): number {\n return this.attempt;\n }\n\n isActive(): boolean {\n return this.active;\n }\n\n private computeDelay(): number {\n const base = this.config.baseDelay;\n const mult = Math.pow(this.config.backoffMultiplier, this.attempt - 1);\n const delay = Math.min(base * mult, this.config.maxDelay);\n // Add jitter (±25%)\n const jitter = delay * 0.25 * (Math.random() * 2 - 1);\n return Math.max(0, Math.round(delay + jitter));\n }\n}\n","import type { ViewportState, Theme } from '@tradecanvas/commons';\nimport { priceToY } from '../viewport/ScaleMapping.js';\nimport { PRICE_AXIS_WIDTH } from '@tradecanvas/commons';\n\n/**\n * Renders the current (last) price as a horizontal line with a badge.\n * Updates at high frequency without triggering full chart redraws.\n */\nexport class CurrentPriceLine {\n private price: number | null = null;\n private previousClose: number | null = null;\n private visible = true;\n private flashUntil = 0;\n private pricePrecision = 2;\n\n setPrice(price: number, previousClose?: number): void {\n if (this.price !== null && price !== this.price) {\n this.flashUntil = Date.now() + 300;\n }\n this.previousClose = previousClose ?? this.price ?? price;\n this.price = price;\n }\n\n setVisible(v: boolean): void {\n this.visible = v;\n }\n\n setPricePrecision(precision: number): void {\n this.pricePrecision = precision;\n }\n\n getPrice(): number | null {\n return this.price;\n }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n if (!this.visible || this.price === null) return;\n\n const y = priceToY(this.price, viewport);\n const { chartRect } = viewport;\n\n if (y < chartRect.y || y > chartRect.y + chartRect.height) return;\n\n const isUp = this.previousClose !== null ? this.price >= this.previousClose : true;\n const color = isUp ? (theme.candleUp ?? '#26A69A') : (theme.candleDown ?? '#EF5350');\n const isFlashing = Date.now() < this.flashUntil;\n\n // Dashed price line\n ctx.setLineDash([4, 3]);\n ctx.strokeStyle = color;\n ctx.lineWidth = 1;\n ctx.globalAlpha = isFlashing ? 1 : 0.7;\n ctx.beginPath();\n ctx.moveTo(chartRect.x, Math.round(y) + 0.5);\n ctx.lineTo(chartRect.x + chartRect.width, Math.round(y) + 0.5);\n ctx.stroke();\n ctx.setLineDash([]);\n ctx.globalAlpha = 1;\n\n // Price badge on axis\n const axisX = chartRect.x + chartRect.width + 1;\n const text = this.price.toFixed(this.pricePrecision);\n ctx.font = `bold 11px ${theme.font.family}`;\n const textWidth = ctx.measureText(text).width;\n const badgeWidth = Math.min(textWidth + 12, PRICE_AXIS_WIDTH - 2);\n\n ctx.fillStyle = color;\n ctx.fillRect(axisX, y - 10, badgeWidth, 20);\n\n // Arrow indicator\n const arrowX = axisX - 5;\n ctx.beginPath();\n ctx.moveTo(arrowX, y);\n ctx.lineTo(arrowX + 5, y - 5);\n ctx.lineTo(arrowX + 5, y + 5);\n ctx.closePath();\n ctx.fill();\n\n ctx.fillStyle = '#FFFFFF';\n ctx.textBaseline = 'middle';\n ctx.textAlign = 'left';\n ctx.fillText(text, axisX + 5, y);\n }\n}\n","import type {\n StreamConfig,\n ConnectionState,\n ConnectionInfo,\n DataAdapter,\n OHLCBar,\n RawTick,\n AggregatedBar,\n TimeFrame,\n} from '@tradecanvas/commons';\nimport { DEFAULT_STREAM_CONFIG, DEFAULT_RECONNECT } from '@tradecanvas/commons';\nimport { Emitter } from './Emitter.js';\nimport { TickAggregator } from './TickAggregator.js';\nimport { ReconnectManager } from './ReconnectManager.js';\nimport { CurrentPriceLine } from './CurrentPriceLine.js';\n\nexport interface StreamEvents {\n /** Historical data loaded */\n snapshot: OHLCBar[];\n /** New closed bar appended */\n barClose: AggregatedBar;\n /** Current forming bar updated */\n barUpdate: AggregatedBar;\n /** Raw tick received */\n tick: RawTick;\n /** Current price changed */\n priceChange: { price: number; previousClose: number | null };\n /** Connection state changed */\n connectionChange: ConnectionInfo;\n /** Error occurred */\n error: { message: string; code?: string };\n [key: string]: unknown;\n}\n\n/**\n * StreamManager — orchestrates data flow from adapter to chart.\n *\n * Responsibilities:\n * 1. Manages adapter lifecycle (connect, disconnect, reconnect)\n * 2. Loads historical data on connect\n * 3. Routes incoming data through TickAggregator\n * 4. Maintains current price for the price line\n * 5. Provides clean event interface for the Chart class\n *\n * Usage:\n * const stream = new StreamManager();\n * stream.on('snapshot', (bars) => chart.setData(bars));\n * stream.on('barClose', (bar) => chart.appendBar(bar));\n * stream.on('barUpdate', (bar) => chart.updateLastBar(bar));\n * stream.connect({ adapter, symbol: 'BTCUSDT', timeframe: '1m' });\n */\nexport class StreamManager extends Emitter<StreamEvents> {\n private config: StreamConfig | null = null;\n private adapter: DataAdapter | null = null;\n private aggregator: TickAggregator | null = null;\n private reconnector: ReconnectManager;\n readonly priceLine = new CurrentPriceLine();\n\n private state: ConnectionState = 'disconnected';\n private lastPrice: number | null = null;\n private previousClose: number | null = null;\n private unsubscribers: (() => void)[] = [];\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private lastMessageTime = 0;\n\n constructor() {\n super();\n this.reconnector = new ReconnectManager();\n this.wireReconnector();\n }\n\n // --- Public API ---\n\n async connect(config: StreamConfig): Promise<void> {\n // Clean up previous connection\n this.disconnect();\n\n this.config = { ...DEFAULT_STREAM_CONFIG, ...config } as StreamConfig;\n this.adapter = config.adapter;\n this.aggregator = new TickAggregator(config.timeframe);\n\n // Replace reconnector — clean up old listeners first\n this.reconnector.removeAllListeners();\n this.reconnector.stop();\n this.reconnector = new ReconnectManager(config.reconnect ?? DEFAULT_RECONNECT);\n this.wireReconnector();\n\n // Wire aggregator events -> stream events\n this.aggregator.on('bar', (bar) => {\n this.emit('barUpdate', bar);\n this.updatePrice(bar.close);\n });\n this.aggregator.on('barClose', (bar) => {\n this.previousClose = bar.close;\n this.emit('barClose', bar);\n });\n\n // Wire adapter events\n this.wireAdapter();\n\n // Start connection\n this.reconnector.start();\n await this.doConnect();\n }\n\n disconnect(): void {\n this.reconnector.stop();\n this.stopHeartbeat();\n\n for (const unsub of this.unsubscribers) unsub();\n this.unsubscribers = [];\n\n if (this.adapter) {\n this.adapter.disconnect();\n this.adapter = null;\n }\n\n this.aggregator?.reset();\n this.aggregator?.removeAllListeners();\n this.aggregator = null;\n this.config = null;\n this.lastPrice = null;\n this.previousClose = null;\n\n this.setState('disconnected');\n }\n\n /**\n * Switch symbol or timeframe without full teardown.\n * Reloads history and restarts streaming.\n */\n async switchTo(symbol: string, timeframe: TimeFrame): Promise<void> {\n if (!this.config || !this.adapter) return;\n\n this.adapter.disconnect();\n this.aggregator?.reset();\n this.aggregator?.setTimeframe(timeframe);\n this.lastPrice = null;\n this.previousClose = null;\n\n this.config.symbol = symbol;\n this.config.timeframe = timeframe;\n\n await this.doConnect();\n }\n\n getConnectionState(): ConnectionState {\n return this.state;\n }\n\n getConnectionInfo(): ConnectionInfo {\n return {\n state: this.state,\n reconnectAttempt: this.reconnector.getAttempt(),\n lastMessageTime: this.lastMessageTime,\n };\n }\n\n getLastPrice(): number | null {\n return this.lastPrice;\n }\n\n // --- Internal ---\n\n private async doConnect(): Promise<void> {\n if (!this.config || !this.adapter) return;\n\n this.setState('connecting');\n\n try {\n // 1. Load historical data\n const history = await this.adapter.fetchHistory(\n this.config.symbol,\n this.config.timeframe,\n this.config.historyLimit ?? 500,\n );\n\n if (history.length > 0) {\n this.previousClose = history[history.length - 1].close;\n this.updatePrice(history[history.length - 1].close);\n }\n\n this.emit('snapshot', history);\n\n // 2. Start streaming\n this.adapter.connect({\n symbol: this.config.symbol,\n timeframe: this.config.timeframe,\n });\n\n this.startHeartbeat();\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n this.emit('error', { message, code: 'CONNECT_FAILED' });\n this.setState('error');\n this.reconnector.schedule(() => this.doConnect());\n }\n }\n\n private wireReconnector(): void {\n this.reconnector.on('attempt', ({ attempt, delay: _delay }) => {\n this.setState('reconnecting');\n this.emit('connectionChange', {\n state: 'reconnecting',\n reconnectAttempt: attempt,\n lastMessageTime: this.lastMessageTime,\n });\n });\n this.reconnector.on('giveUp', ({ attempts }) => {\n this.setState('error');\n this.emit('error', { message: `Reconnection failed after ${attempts} attempts`, code: 'RECONNECT_EXHAUSTED' });\n });\n }\n\n private wireAdapter(): void {\n if (!this.adapter) return;\n const adapter = this.adapter;\n\n // Connection state changes\n const onConnectionChange = (e: any) => {\n const newState = e.data as ConnectionState;\n this.lastMessageTime = Date.now();\n\n if (newState === 'connected') {\n this.reconnector.onConnected();\n this.setState('connected');\n } else if (newState === 'disconnected' || newState === 'error') {\n this.reconnector.schedule(() => this.doConnect());\n }\n };\n adapter.on('connectionChange', onConnectionChange as any);\n this.unsubscribers.push(() => adapter.off('connectionChange', onConnectionChange as any));\n\n // Tick data\n const onTick = (e: any) => {\n this.lastMessageTime = Date.now();\n const tick = e.data as RawTick;\n this.emit('tick', tick);\n\n if (this.config?.aggregateTicks && this.aggregator) {\n this.aggregator.processTick(tick);\n } else {\n this.updatePrice(tick.price);\n }\n };\n adapter.on('tick', onTick as any);\n this.unsubscribers.push(() => adapter.off('tick', onTick as any));\n\n // Pre-formed bar data (most adapters provide this)\n const onBar = (e: any) => {\n this.lastMessageTime = Date.now();\n const { bar, closed } = e.data as { bar: OHLCBar; closed: boolean };\n\n if (this.aggregator) {\n this.aggregator.processBar(bar, closed);\n }\n };\n adapter.on('bar', onBar as any);\n this.unsubscribers.push(() => adapter.off('bar', onBar as any));\n\n // Error\n const onError = (e: any) => {\n this.emit('error', { message: e.data?.message ?? 'Adapter error' });\n };\n adapter.on('error', onError as any);\n this.unsubscribers.push(() => adapter.off('error', onError as any));\n }\n\n private updatePrice(price: number): void {\n if (price !== this.lastPrice) {\n this.lastPrice = price;\n this.priceLine.setPrice(price, this.previousClose ?? undefined);\n this.emit('priceChange', { price, previousClose: this.previousClose });\n }\n }\n\n private setState(state: ConnectionState): void {\n if (this.state === state) return;\n this.state = state;\n this.emit('connectionChange', {\n state,\n reconnectAttempt: this.reconnector.getAttempt(),\n lastMessageTime: this.lastMessageTime,\n });\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat();\n this.heartbeatTimer = setInterval(() => {\n const stale = Date.now() - this.lastMessageTime > 60000;\n if (stale && this.state === 'connected') {\n this.emit('error', { message: 'Heartbeat timeout', code: 'HEARTBEAT_TIMEOUT' });\n this.adapter?.disconnect();\n this.reconnector.schedule(() => this.doConnect());\n }\n }, 30000);\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n dispose(): void {\n this.disconnect();\n this.removeAllListeners();\n }\n}\n","import type { OHLCBar, DataSeries } from '@tradecanvas/commons';\nimport { Emitter } from './Emitter.js';\n\nexport type ReplayStatus = 'idle' | 'playing' | 'paused' | 'finished';\n\nexport interface ReplayBarEvent {\n bar: OHLCBar;\n index: number;\n total: number;\n}\n\nexport interface ReplayStateChangeEvent {\n status: ReplayStatus;\n index: number;\n total: number;\n}\n\nexport interface ReplayEventMap {\n bar: ReplayBarEvent;\n finished: { total: number };\n stateChange: ReplayStateChangeEvent;\n [key: string]: unknown;\n}\n\nexport interface ReplayOptions {\n /** Full historical dataset to replay through. */\n data: DataSeries;\n /** Bars emitted per second. Default 1. */\n speed?: number;\n /** Index of the first bar to emit (0-based). Default 0. */\n startIndex?: number;\n /** Auto-start when constructed. Default false. */\n autoStart?: boolean;\n}\n\n/**\n * Drives historical bars forward at a controlled speed.\n *\n * Decoupled from Chart — consumers subscribe to `bar` events and wire them\n * into a Chart (via appendBar) or a Backtester. The controller never touches\n * the chart directly, which keeps it reusable for headless analytics.\n */\nexport class ReplayController extends Emitter<ReplayEventMap> {\n private readonly data: ReadonlyArray<OHLCBar>;\n private speed: number;\n private index: number;\n private status: ReplayStatus = 'idle';\n private timer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(opts: ReplayOptions) {\n super();\n if (opts.data.length === 0) {\n throw new Error('ReplayController requires non-empty data');\n }\n this.data = opts.data;\n this.speed = Math.max(0.01, opts.speed ?? 1);\n this.index = Math.max(0, Math.min(opts.startIndex ?? 0, opts.data.length));\n\n if (opts.autoStart) this.start();\n }\n\n getStatus(): ReplayStatus {\n return this.status;\n }\n\n getIndex(): number {\n return this.index;\n }\n\n getTotal(): number {\n return this.data.length;\n }\n\n /** Bars at indices [0, index) — useful for seeding the chart before replay. */\n getPrefix(): DataSeries {\n return this.data.slice(0, this.index);\n }\n\n /** Begin emitting from current index. Idempotent if already playing. */\n start(): void {\n if (this.status === 'playing') return;\n if (this.index >= this.data.length) {\n this.transition('finished');\n return;\n }\n this.transition('playing');\n this.scheduleNext();\n }\n\n pause(): void {\n if (this.status !== 'playing') return;\n this.clearTimer();\n this.transition('paused');\n }\n\n resume(): void {\n if (this.status === 'paused') this.start();\n }\n\n stop(): void {\n this.clearTimer();\n this.index = 0;\n this.transition('idle');\n }\n\n /** Emit N bars synchronously without waiting for the timer. */\n step(n = 1): void {\n if (n <= 0) return;\n this.clearTimer();\n for (let i = 0; i < n; i++) {\n if (!this.emitNext()) return;\n }\n if (this.status !== 'finished') this.transition('paused');\n }\n\n /** Jump to a specific index without emitting bars in between. */\n seek(index: number): void {\n const clamped = Math.max(0, Math.min(index, this.data.length));\n this.clearTimer();\n this.index = clamped;\n const next: ReplayStatus = clamped >= this.data.length ? 'finished' : 'paused';\n this.transition(next);\n }\n\n setSpeed(barsPerSecond: number): void {\n this.speed = Math.max(0.01, barsPerSecond);\n if (this.status === 'playing') {\n this.clearTimer();\n this.scheduleNext();\n }\n }\n\n destroy(): void {\n this.clearTimer();\n this.removeAllListeners();\n }\n\n private scheduleNext(): void {\n const delayMs = 1000 / this.speed;\n this.timer = setTimeout(() => {\n this.timer = null;\n if (this.status !== 'playing') return;\n const more = this.emitNext();\n if (more) this.scheduleNext();\n }, delayMs);\n }\n\n private emitNext(): boolean {\n if (this.index >= this.data.length) {\n this.transition('finished');\n this.emit('finished', { total: this.data.length });\n return false;\n }\n const bar = this.data[this.index];\n const index = this.index;\n this.index++;\n this.emit('bar', { bar, index, total: this.data.length });\n if (this.index >= this.data.length) {\n this.transition('finished');\n this.emit('finished', { total: this.data.length });\n return false;\n }\n return true;\n }\n\n private clearTimer(): void {\n if (this.timer !== null) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n }\n\n private transition(next: ReplayStatus): void {\n if (this.status === next) return;\n this.status = next;\n this.emit('stateChange', {\n status: next,\n index: this.index,\n total: this.data.length,\n });\n }\n}\n","import type { OHLCBar } from '@tradecanvas/commons';\r\n\r\n/**\r\n * Binance REST `/klines` returns a 12-element array per kline.\r\n * Index map (per Binance docs):\r\n * 0 openTime, 1 open, 2 high, 3 low, 4 close, 5 volume,\r\n * 6 closeTime, 7 quoteVolume, 8 trades, 9 takerBuyBase,\r\n * 10 takerBuyQuote, 11 ignore\r\n * Numeric fields come back as strings except the timestamps.\r\n */\r\nexport type BinanceRestKline = readonly [\r\n number, // 0 openTime\r\n string, // 1 open\r\n string, // 2 high\r\n string, // 3 low\r\n string, // 4 close\r\n string, // 5 volume\r\n number, // 6 closeTime\r\n string, // 7 quoteVolume\r\n number, // 8 trades\r\n string, // 9 takerBuyBase\r\n string, // 10 takerBuyQuote\r\n string, // 11 ignore\r\n];\r\n\r\n/** Binance WS kline payload (`msg.k`). All numeric fields arrive as strings. */\r\nexport interface BinanceWsKline {\r\n t: number; // start time\r\n T: number; // close time\r\n s: string; // symbol\r\n i: string; // interval\r\n o: string; // open\r\n c: string; // close\r\n h: string; // high\r\n l: string; // low\r\n v: string; // base volume\r\n n: number; // trades\r\n x: boolean; // closed\r\n q?: string; // quote volume\r\n}\r\n\r\nexport interface BinanceWsMessage {\r\n e?: string; // event type\r\n E?: number; // event time\r\n s?: string;\r\n k?: BinanceWsKline;\r\n}\r\n\r\n/**\r\n * Validate and parse a single REST kline tuple. Returns `null` on shape mismatch\r\n * or non-finite numeric values. Pure — no fetch, no side effects — testable.\r\n */\r\nexport function parseRestKline(raw: unknown): OHLCBar | null {\r\n if (!Array.isArray(raw) || raw.length < 6) return null;\r\n const time = raw[0];\r\n if (typeof time !== 'number' || !Number.isFinite(time)) return null;\r\n\r\n const open = toFiniteNumber(raw[1]);\r\n const high = toFiniteNumber(raw[2]);\r\n const low = toFiniteNumber(raw[3]);\r\n const close = toFiniteNumber(raw[4]);\r\n const volume = toFiniteNumber(raw[5]);\r\n if (open === null || high === null || low === null || close === null || volume === null) {\r\n return null;\r\n }\r\n return { time, open, high, low, close, volume };\r\n}\r\n\r\n/**\r\n * Validate and parse the `k` payload of a WS kline message.\r\n * Returns `{ bar, closed }` or `null` if the payload is malformed.\r\n */\r\nexport function parseWsKline(\r\n raw: unknown,\r\n): { bar: OHLCBar; closed: boolean } | null {\r\n if (!isObject(raw)) return null;\r\n const time = raw.t;\r\n if (typeof time !== 'number' || !Number.isFinite(time)) return null;\r\n\r\n const open = toFiniteNumber(raw.o);\r\n const high = toFiniteNumber(raw.h);\r\n const low = toFiniteNumber(raw.l);\r\n const close = toFiniteNumber(raw.c);\r\n const volume = toFiniteNumber(raw.v);\r\n if (open === null || high === null || low === null || close === null || volume === null) {\r\n return null;\r\n }\r\n const closed = typeof raw.x === 'boolean' ? raw.x : false;\r\n return { bar: { time, open, high, low, close, volume }, closed };\r\n}\r\n\r\nfunction toFiniteNumber(value: unknown): number | null {\r\n if (typeof value === 'number') {\r\n return Number.isFinite(value) ? value : null;\r\n }\r\n if (typeof value === 'string') {\r\n const n = parseFloat(value);\r\n return Number.isFinite(n) ? n : null;\r\n }\r\n return null;\r\n}\r\n\r\nfunction isObject(value: unknown): value is Record<string, unknown> {\r\n return typeof value === 'object' && value !== null;\r\n}\r\n","import type {\r\n DataAdapter,\r\n DataAdapterConfig,\r\n DataAdapterEventType,\r\n DataAdapterListener,\r\n ConnectionState,\r\n OHLCBar,\r\n TimeFrame,\r\n} from '@tradecanvas/commons';\r\nimport { parseRestKline, parseWsKline } from './binanceTypes.js';\r\n\r\nconst TF_MAP: Record<string, string> = {\r\n '1s': '1s', '1m': '1m', '3m': '3m', '5m': '5m', '15m': '15m', '30m': '30m',\r\n '1h': '1h', '2h': '2h', '4h': '4h', '6h': '6h', '8h': '8h', '12h': '12h',\r\n '1d': '1d', '3d': '3d', '1w': '1w', '1M': '1M',\r\n};\r\n\r\n/**\r\n * Binance public API adapter (no API key required).\r\n *\r\n * Supports:\r\n * - REST klines for historical data\r\n * - WebSocket kline stream for real-time data\r\n * - Auto-reconnection via the StreamManager\r\n *\r\n * Usage:\r\n * const adapter = new BinanceAdapter();\r\n * const stream = new StreamManager();\r\n * stream.connect({ adapter, symbol: 'BTCUSDT', timeframe: '1m' });\r\n */\r\nexport class BinanceAdapter implements DataAdapter {\r\n readonly name = 'binance';\r\n\r\n private ws: WebSocket | null = null;\r\n private state: ConnectionState = 'disconnected';\r\n private listeners = new Map<DataAdapterEventType, Set<DataAdapterListener>>();\r\n private config: DataAdapterConfig | null = null;\r\n private restBase: string;\r\n private wsBase: string;\r\n\r\n constructor(options?: { restBase?: string; wsBase?: string }) {\r\n this.restBase = options?.restBase ?? 'https://api.binance.com/api/v3';\r\n this.wsBase = options?.wsBase ?? 'wss://stream.binance.com:9443/ws';\r\n }\r\n\r\n // --- DataAdapter interface ---\r\n\r\n connect(config: DataAdapterConfig): void {\r\n this.config = config;\r\n this.connectWs();\r\n }\r\n\r\n disconnect(): void {\r\n if (this.ws) {\r\n this.ws.onclose = null; // prevent reconnect trigger\r\n this.ws.close();\r\n this.ws = null;\r\n }\r\n this.setState('disconnected');\r\n }\r\n\r\n getConnectionState(): ConnectionState {\r\n return this.state;\r\n }\r\n\r\n async fetchHistory(symbol: string, timeframe: TimeFrame, limit = 500): Promise<OHLCBar[]> {\r\n const interval = TF_MAP[timeframe] ?? '15m';\r\n const url = `${this.restBase}/klines?symbol=${symbol}&interval=${interval}&limit=${limit}`;\r\n const res = await fetch(url);\r\n\r\n if (!res.ok) throw new Error(`Binance REST error: ${res.status}`);\r\n\r\n const data: unknown = await res.json();\r\n if (!Array.isArray(data)) return [];\r\n const bars: OHLCBar[] = [];\r\n for (const raw of data) {\r\n const parsed = parseRestKline(raw);\r\n if (parsed) bars.push(parsed);\r\n }\r\n return bars;\r\n }\r\n\r\n on<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void {\r\n let set = this.listeners.get(event);\r\n if (!set) {\r\n set = new Set();\r\n this.listeners.set(event, set);\r\n }\r\n set.add(listener as DataAdapterListener);\r\n }\r\n\r\n off<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void {\r\n this.listeners.get(event)?.delete(listener as DataAdapterListener);\r\n }\r\n\r\n dispose(): void {\r\n this.disconnect();\r\n this.listeners.clear();\r\n }\r\n\r\n // --- Internal ---\r\n\r\n private connectWs(): void {\r\n if (!this.config) return;\r\n\r\n const symbol = this.config.symbol.toLowerCase();\r\n const interval = TF_MAP[this.config.timeframe] ?? '15m';\r\n const stream = `${symbol}@kline_${interval}`;\r\n const url = `${this.wsBase}/${stream}`;\r\n\r\n this.setState('connecting');\r\n\r\n try {\r\n this.ws = new WebSocket(url);\r\n } catch {\r\n this.setState('error');\r\n this.emitEvent('error', { message: 'WebSocket creation failed' });\r\n this.emitEvent('connectionChange', 'error');\r\n return;\r\n }\r\n\r\n this.ws.onopen = () => {\r\n this.setState('connected');\r\n this.emitEvent('connectionChange', 'connected');\r\n };\r\n\r\n this.ws.onmessage = (event) => {\r\n let msg: unknown;\r\n try {\r\n msg = JSON.parse(typeof event.data === 'string' ? event.data : '');\r\n } catch {\r\n return;\r\n }\r\n if (\r\n typeof msg === 'object' &&\r\n msg !== null &&\r\n (msg as { e?: unknown }).e === 'kline'\r\n ) {\r\n this.handleKline((msg as { k?: unknown }).k);\r\n }\r\n };\r\n\r\n this.ws.onerror = () => {\r\n this.setState('error');\r\n this.emitEvent('error', { message: 'WebSocket error' });\r\n };\r\n\r\n this.ws.onclose = () => {\r\n this.setState('disconnected');\r\n this.emitEvent('connectionChange', 'disconnected');\r\n };\r\n }\r\n\r\n private handleKline(k: unknown): void {\r\n const parsed = parseWsKline(k);\r\n if (!parsed) return;\r\n const { bar, closed } = parsed;\r\n\r\n this.emitEvent('bar', { bar, closed });\r\n this.emitEvent('tick', {\r\n time: Date.now(),\r\n price: bar.close,\r\n volume: bar.volume,\r\n });\r\n }\r\n\r\n private setState(state: ConnectionState): void {\r\n this.state = state;\r\n }\r\n\r\n private emitEvent(type: DataAdapterEventType, data: unknown): void {\r\n const set = this.listeners.get(type);\r\n if (set) {\r\n const event = { type, data, timestamp: Date.now() };\r\n for (const listener of set) {\r\n listener(event);\r\n }\r\n }\r\n }\r\n}\r\n","import type {\n DataAdapter,\n DataAdapterConfig,\n DataAdapterEventType,\n DataAdapterListener,\n ConnectionState,\n OHLCBar,\n TimeFrame,\n} from '@tradecanvas/commons';\nimport { timeframeToMs } from '@tradecanvas/commons';\n\nexport interface MockAdapterOptions {\n /** Base price to generate data around */\n basePrice?: number;\n /** Volatility as percentage (default: 1.5) */\n volatility?: number;\n /** Tick interval in ms (default: 2000) */\n tickInterval?: number;\n /** Number of historical bars to generate */\n historySize?: number;\n /** Custom history generator */\n historyGenerator?: (symbol: string, timeframe: TimeFrame, limit: number) => OHLCBar[];\n}\n\n/**\n * Mock data adapter for testing, demos, and markets without free APIs.\n *\n * Generates realistic OHLCV data with configurable volatility.\n * Useful for:\n * - Unit/integration testing\n * - VN stock market simulation\n * - Offline development\n */\nexport class MockAdapter implements DataAdapter {\n readonly name = 'mock';\n\n private state: ConnectionState = 'disconnected';\n private listeners = new Map<DataAdapterEventType, Set<DataAdapterListener>>();\n private config: DataAdapterConfig | null = null;\n private options: MockAdapterOptions;\n private tickTimer: ReturnType<typeof setInterval> | null = null;\n private currentPrice: number;\n\n constructor(options?: MockAdapterOptions) {\n this.options = {\n basePrice: 100,\n volatility: 1.5,\n tickInterval: 2000,\n historySize: 500,\n ...options,\n };\n this.currentPrice = this.options.basePrice!;\n }\n\n connect(config: DataAdapterConfig): void {\n this.config = config;\n this.state = 'connected';\n this.emitEvent('connectionChange', 'connected');\n this.startTicking();\n }\n\n disconnect(): void {\n this.stopTicking();\n this.state = 'disconnected';\n this.emitEvent('connectionChange', 'disconnected');\n }\n\n getConnectionState(): ConnectionState {\n return this.state;\n }\n\n async fetchHistory(symbol: string, timeframe: TimeFrame, limit?: number): Promise<OHLCBar[]> {\n if (this.options.historyGenerator) {\n return this.options.historyGenerator(symbol, timeframe, limit ?? this.options.historySize!);\n }\n return this.generateHistory(timeframe, limit ?? this.options.historySize!);\n }\n\n on<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void {\n let set = this.listeners.get(event);\n if (!set) { set = new Set(); this.listeners.set(event, set); }\n set.add(listener as DataAdapterListener);\n }\n\n off<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void {\n this.listeners.get(event)?.delete(listener as DataAdapterListener);\n }\n\n dispose(): void {\n this.disconnect();\n this.listeners.clear();\n }\n\n // --- Internal ---\n\n private generateHistory(timeframe: TimeFrame, count: number): OHLCBar[] {\n const bars: OHLCBar[] = [];\n const now = Date.now();\n const intervalMs = timeframeToMs(timeframe);\n let price = this.options.basePrice!;\n const vol = this.options.volatility! / 100;\n\n for (let i = count - 1; i >= 0; i--) {\n const time = now - i * intervalMs;\n const change = (Math.random() - 0.48) * price * vol;\n const open = price;\n price += change;\n const high = Math.max(open, price) + Math.random() * price * vol * 0.3;\n const low = Math.min(open, price) - Math.random() * price * vol * 0.3;\n const volume = Math.floor(10000 + Math.random() * 100000);\n bars.push({ time, open, high, low, close: price, volume });\n }\n\n this.currentPrice = price;\n return bars;\n }\n\n private startTicking(): void {\n this.stopTicking();\n const interval = this.options.tickInterval ?? 2000;\n\n this.tickTimer = setInterval(() => {\n if (this.state !== 'connected' || !this.config) return;\n\n const vol = this.options.volatility! / 100;\n const change = (Math.random() - 0.48) * this.currentPrice * vol * 0.3;\n this.currentPrice += change;\n\n const now = Date.now();\n const intervalMs = timeframeToMs(this.config.timeframe);\n const barTime = Math.floor(now / intervalMs) * intervalMs;\n\n const bar: OHLCBar = {\n time: barTime,\n open: this.currentPrice - change,\n high: Math.max(this.currentPrice, this.currentPrice - change) + Math.abs(change) * 0.2,\n low: Math.min(this.currentPrice, this.currentPrice - change) - Math.abs(change) * 0.2,\n close: this.currentPrice,\n volume: Math.floor(100 + Math.random() * 5000),\n };\n\n // Check if bar closed (crossed timeframe boundary)\n const closed = false; // In mock, we mostly send forming bars\n\n this.emitEvent('bar', { bar, closed });\n this.emitEvent('tick', { time: now, price: this.currentPrice, volume: bar.volume });\n }, interval);\n }\n\n private stopTicking(): void {\n if (this.tickTimer) {\n clearInterval(this.tickTimer);\n this.tickTimer = null;\n }\n }\n\n private emitEvent(type: DataAdapterEventType, data: unknown): void {\n const set = this.listeners.get(type);\n if (set) {\n const event = { type, data, timestamp: Date.now() };\n for (const listener of set) listener(event);\n }\n }\n}\n","import type { ViewportState, Theme, OHLCBar, DataSeries } from '@tradecanvas/commons';\n\nexport interface LegendConfig {\n visible: boolean;\n showSymbol: boolean;\n showOHLC: boolean;\n showChange: boolean;\n showVolume: boolean;\n position: 'top-left' | 'top-right';\n fontSize: number;\n}\n\nexport const DEFAULT_LEGEND_CONFIG: LegendConfig = {\n visible: true,\n showSymbol: true,\n showOHLC: true,\n showChange: true,\n showVolume: true,\n position: 'top-left',\n fontSize: 12,\n};\n\n/**\n * Renders an OHLCV legend overlay on the chart (like TradingView top-left).\n * Shows: Symbol, O, H, L, C, Change%, Volume\n * Updates on crosshair hover or shows last bar by default.\n */\nexport class ChartLegend {\n private config: LegendConfig = { ...DEFAULT_LEGEND_CONFIG };\n private symbol = '';\n private timeframe = '';\n private hoverBar: OHLCBar | null = null;\n private indicators: { name: string; color: string; value: string }[] = [];\n private statusText: string | null = null;\n\n setConfig(config: Partial<LegendConfig>): void {\n Object.assign(this.config, config);\n }\n\n setSymbol(symbol: string): void {\n this.symbol = symbol;\n }\n\n setTimeframe(tf: string): void {\n this.timeframe = tf;\n }\n\n setChartType(_type: string): void {\n // reserved for future use\n }\n\n setHoverBar(bar: OHLCBar | null): void {\n this.hoverBar = bar;\n }\n\n setIndicatorValues(values: { name: string; color: string; value: string }[]): void {\n this.indicators = values;\n }\n\n setStatusText(text: string | null): void {\n this.statusText = text;\n }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme, data: DataSeries): void {\n if (!this.config.visible || data.length === 0) return;\n\n const bar = this.hoverBar ?? data[data.length - 1];\n const prevBar = data.length > 1 ? data[data.length - 2] : bar;\n const { chartRect } = viewport;\n const fs = this.config.fontSize;\n const isLeft = this.config.position === 'top-left';\n\n let x = isLeft ? chartRect.x + 8 : chartRect.x + chartRect.width - 8;\n let y = chartRect.y + 6;\n\n ctx.textAlign = isLeft ? 'left' : 'right';\n ctx.textBaseline = 'top';\n\n // Symbol + timeframe + chart type + status text\n if (this.config.showSymbol) {\n ctx.font = `bold ${fs + 2}px ${theme.font.family}`;\n ctx.fillStyle = theme.text;\n const symbolText = [this.symbol, this.timeframe].filter(Boolean).join(' · ');\n const displayText = this.statusText ? `${symbolText} ${this.statusText}` : symbolText;\n ctx.fillText(displayText, x, y);\n y += fs + 6;\n } else if (this.statusText) {\n ctx.font = `${fs}px ${theme.font.family}`;\n ctx.fillStyle = theme.textSecondary;\n ctx.fillText(this.statusText, x, y);\n y += fs + 4;\n }\n\n // OHLC values\n if (this.config.showOHLC) {\n ctx.font = `${fs}px ${theme.font.family}`;\n const isUp = bar.close >= bar.open;\n const fmt = (v: number) => v.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });\n\n const items = [\n { label: 'O', value: fmt(bar.open), color: theme.text },\n { label: 'H', value: fmt(bar.high), color: theme.text },\n { label: 'L', value: fmt(bar.low), color: theme.text },\n { label: 'C', value: fmt(bar.close), color: isUp ? theme.candleUp : theme.candleDown },\n ];\n\n if (this.config.showChange) {\n const change = bar.close - prevBar.close;\n const changePct = prevBar.close !== 0 ? (change / prevBar.close) * 100 : 0;\n const sign = change >= 0 ? '+' : '';\n items.push({\n label: '',\n value: `${sign}${fmt(change)} (${sign}${changePct.toFixed(2)}%)`,\n color: change >= 0 ? theme.candleUp : theme.candleDown,\n });\n }\n\n // Render inline\n let cx = x;\n if (isLeft) {\n for (const item of items) {\n if (item.label) {\n ctx.fillStyle = theme.textSecondary;\n ctx.fillText(item.label, cx, y);\n cx += ctx.measureText(item.label + ' ').width;\n }\n ctx.fillStyle = item.color;\n ctx.fillText(item.value, cx, y);\n cx += ctx.measureText(item.value + ' ').width;\n }\n } else {\n // Right-aligned: build full string and measure\n const fullText = items.map((i) => `${i.label} ${i.value}`).join(' ');\n ctx.fillStyle = theme.text;\n ctx.fillText(fullText, x, y);\n }\n y += fs + 3;\n }\n\n // Volume\n if (this.config.showVolume) {\n ctx.font = `${fs - 1}px ${theme.font.family}`;\n ctx.fillStyle = theme.textSecondary;\n const vol = bar.volume >= 1e6 ? `${(bar.volume / 1e6).toFixed(2)}M` : bar.volume >= 1e3 ? `${(bar.volume / 1e3).toFixed(2)}K` : bar.volume.toFixed(0);\n ctx.fillText(`Vol ${vol}`, x, y);\n y += fs + 2;\n }\n\n // Active indicator values\n if (this.indicators.length > 0) {\n ctx.font = `${fs - 1}px ${theme.font.family}`;\n let ix = x;\n for (const ind of this.indicators) {\n ctx.fillStyle = ind.color;\n const text = `${ind.name} ${ind.value}`;\n ctx.fillText(text, ix, y);\n ix += ctx.measureText(text + ' ').width;\n }\n }\n }\n}\n","/**\n * Captures the chart as an image by compositing all canvas layers.\n */\nexport class Screenshot {\n /**\n * Export the chart container as a PNG data URL.\n */\n static toDataURL(container: HTMLElement, background?: string): string {\n const canvases = container.querySelectorAll('canvas');\n if (canvases.length === 0) return '';\n\n const first = canvases[0];\n const width = first.width;\n const height = first.height;\n\n const compositeCanvas = document.createElement('canvas');\n compositeCanvas.width = width;\n compositeCanvas.height = height;\n const ctx = compositeCanvas.getContext('2d')!;\n\n // Background\n if (background) {\n ctx.fillStyle = background;\n ctx.fillRect(0, 0, width, height);\n }\n\n // Composite all layers in order (lowest z-index first)\n const sorted = Array.from(canvases).sort((a, b) => {\n return (parseInt(a.style.zIndex) || 0) - (parseInt(b.style.zIndex) || 0);\n });\n\n for (const canvas of sorted) {\n ctx.drawImage(canvas, 0, 0);\n }\n\n return compositeCanvas.toDataURL('image/png');\n }\n\n /**\n * Export as Blob (for file saving).\n */\n static async toBlob(container: HTMLElement, background?: string): Promise<Blob | null> {\n const dataURL = this.toDataURL(container, background);\n if (!dataURL) return null;\n\n const res = await fetch(dataURL);\n return res.blob();\n }\n\n /**\n * Trigger browser download of the chart image.\n */\n static download(container: HTMLElement, filename = 'chart.png', background?: string): void {\n const dataURL = this.toDataURL(container, background);\n if (!dataURL) return;\n\n const link = document.createElement('a');\n link.href = dataURL;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n }\n}\n","import type { ViewportState, Theme, WatermarkConfig } from '@tradecanvas/commons';\n\n/**\n * Renders a centered watermark text on the chart background.\n * Semi-transparent, non-interactive.\n */\nexport class Watermark {\n private config: WatermarkConfig | null = null;\n\n setConfig(config: WatermarkConfig | null): void {\n this.config = config;\n }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n if (!this.config?.text) return;\n\n const { chartRect } = viewport;\n const fontSize = this.config.fontSize ?? 48;\n const color = this.config.color ?? theme.textSecondary;\n\n ctx.save();\n ctx.globalAlpha = 0.07;\n ctx.font = `bold ${fontSize}px ${theme.font.family}`;\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(\n this.config.text,\n chartRect.x + chartRect.width / 2,\n chartRect.y + chartRect.height / 2,\n );\n ctx.restore();\n }\n}\n","import type { ViewportState, Theme, DataSeries } from '@tradecanvas/commons';\nimport { barIndexToX } from '../viewport/ScaleMapping.js';\n\nexport class BarCountdown {\n private visible = true;\n private timeframeMs = 0;\n\n setVisible(v: boolean): void { this.visible = v; }\n isVisible(): boolean { return this.visible; }\n\n setTimeframeMs(ms: number): void { this.timeframeMs = ms; }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme, data: DataSeries): void {\n if (!this.visible || this.timeframeMs <= 0 || data.length === 0) return;\n\n const lastBar = data[data.length - 1];\n // Handle both ms and s timestamps\n const timeMs = lastBar.time > 1e12 ? lastBar.time : lastBar.time * 1000;\n const nextBarTime = timeMs + this.timeframeMs;\n const remainingMs = nextBarTime - Date.now();\n if (remainingMs <= 0) return;\n\n const text = this.formatRemaining(remainingMs);\n\n // Position: below the last bar's X, at the bottom of the chart area (above time axis)\n const x = barIndexToX(data.length - 1, viewport);\n const y = viewport.chartRect.y + viewport.chartRect.height - 4;\n\n // Only render if X is within visible area\n if (x < viewport.chartRect.x || x > viewport.chartRect.x + viewport.chartRect.width) return;\n\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n ctx.textBaseline = 'bottom';\n ctx.textAlign = 'center';\n ctx.fillStyle = theme.textSecondary;\n ctx.fillText(text, x, y);\n }\n\n private formatRemaining(ms: number): string {\n const totalSec = Math.ceil(ms / 1000);\n const hours = Math.floor(totalSec / 3600);\n const mins = Math.floor((totalSec % 3600) / 60);\n const secs = totalSec % 60;\n if (hours > 0) {\n return `${hours}:${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;\n }\n return `${mins}:${String(secs).padStart(2, '0')}`;\n }\n}\n","import type { ViewportState, Theme, DataSeries } from '@tradecanvas/commons';\nimport { barIndexToX } from '../viewport/ScaleMapping.js';\n\nexport interface SessionBreakConfig {\n /** Whether to show session break lines */\n visible: boolean;\n /** Session open/close times as { open: 'HH:MM', close: 'HH:MM' } in exchange local time */\n sessionTimes?: { open: string; close: string };\n /** Line color override (defaults to theme.axisLine with reduced opacity) */\n color?: string;\n /** Line style: 'solid' | 'dashed' | 'dotted' */\n lineStyle?: 'solid' | 'dashed' | 'dotted';\n /** Line width (default 1) */\n lineWidth?: number;\n}\n\n/**\n * Renders vertical session break lines on the chart.\n * Detects day boundaries from bar timestamps and draws vertical separators.\n */\nexport class SessionBreaks {\n private config: SessionBreakConfig = { visible: false };\n private cachedBreaks: number[] = [];\n private lastDataLength = 0;\n\n setConfig(config: Partial<SessionBreakConfig>): void {\n Object.assign(this.config, config);\n }\n\n isVisible(): boolean {\n return this.config.visible;\n }\n\n setVisible(visible: boolean): void {\n this.config.visible = visible;\n }\n\n /**\n * Find bar indices where a new trading day begins.\n * Uses date change detection from bar timestamps.\n */\n private computeBreaks(data: DataSeries): number[] {\n if (data.length < 2) return [];\n\n // Cache: only recompute when data changes\n if (data.length === this.lastDataLength && this.cachedBreaks.length > 0) {\n return this.cachedBreaks;\n }\n\n const breaks: number[] = [];\n let prevDay = this.getDayKey(data[0].time);\n\n for (let i = 1; i < data.length; i++) {\n const day = this.getDayKey(data[i].time);\n if (day !== prevDay) {\n breaks.push(i);\n prevDay = day;\n }\n }\n\n this.lastDataLength = data.length;\n this.cachedBreaks = breaks;\n return breaks;\n }\n\n /** Get a day key from a timestamp (seconds or milliseconds) */\n private getDayKey(timestamp: number): string {\n // Auto-detect seconds vs milliseconds\n const ms = timestamp > 1e12 ? timestamp : timestamp * 1000;\n const d = new Date(ms);\n return `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;\n }\n\n render(\n ctx: CanvasRenderingContext2D,\n viewport: ViewportState,\n theme: Theme,\n data: DataSeries,\n ): void {\n if (!this.config.visible || data.length < 2) return;\n\n const breaks = this.computeBreaks(data);\n if (breaks.length === 0) return;\n\n const { chartRect } = viewport;\n const color = this.config.color ?? theme.axisLine;\n const lineWidth = this.config.lineWidth ?? 1;\n const lineStyle = this.config.lineStyle ?? 'dashed';\n\n ctx.save();\n ctx.strokeStyle = color;\n ctx.lineWidth = lineWidth;\n ctx.globalAlpha = 0.4;\n\n if (lineStyle === 'dashed') {\n ctx.setLineDash([6, 4]);\n } else if (lineStyle === 'dotted') {\n ctx.setLineDash([2, 3]);\n }\n\n ctx.beginPath();\n\n for (const barIdx of breaks) {\n const x = barIndexToX(barIdx, viewport) - (viewport.barWidth + viewport.barSpacing) / 2;\n // Only draw if visible\n if (x < chartRect.x - 1 || x > chartRect.x + chartRect.width + 1) continue;\n const px = Math.round(x) + 0.5;\n ctx.moveTo(px, chartRect.y);\n ctx.lineTo(px, chartRect.y + chartRect.height);\n }\n\n ctx.stroke();\n ctx.restore();\n }\n\n /** Invalidate cache when data changes */\n invalidateCache(): void {\n this.lastDataLength = 0;\n this.cachedBreaks = [];\n }\n}\n","import type { ViewportState, Theme } from '@tradecanvas/commons';\nimport { priceToY } from '../viewport/ScaleMapping.js';\nimport { Emitter } from '../realtime/Emitter.js';\n\nexport type AlertCondition = 'crossingUp' | 'crossingDown' | 'crossing' | 'greaterThan' | 'lessThan';\n\nexport interface PriceAlert {\n id: string;\n price: number;\n condition: AlertCondition;\n message?: string;\n triggered: boolean;\n repeating: boolean;\n}\n\ninterface AlertEvents {\n triggered: PriceAlert;\n added: PriceAlert;\n removed: string;\n [key: string]: unknown;\n}\n\nlet alertId = 1;\n\n/**\n * Manages price alerts. Renders alert lines on the chart overlay.\n * Checks each price update against configured alerts and emits 'triggered'.\n */\nexport class AlertManager extends Emitter<AlertEvents> {\n private alerts: PriceAlert[] = [];\n private lastPrice: number | null = null;\n private requestRender: (() => void) | null = null;\n private pricePrecision = 2;\n\n setRequestRender(cb: () => void): void {\n this.requestRender = cb;\n }\n\n setPricePrecision(precision: number): void {\n this.pricePrecision = precision;\n }\n\n addAlert(price: number, condition: AlertCondition = 'crossing', message?: string, repeating = false): string {\n const id = `tc_alert_${alertId++}`;\n const alert: PriceAlert = { id, price, condition, message, triggered: false, repeating };\n this.alerts.push(alert);\n this.emit('added', alert);\n this.requestRender?.();\n return id;\n }\n\n removeAlert(id: string): void {\n this.alerts = this.alerts.filter((a) => a.id !== id);\n this.emit('removed', id);\n this.requestRender?.();\n }\n\n getAlerts(): PriceAlert[] {\n return [...this.alerts];\n }\n\n clearAlerts(): void {\n this.alerts = [];\n this.requestRender?.();\n }\n\n /** Call on each price update to check alerts */\n checkPrice(price: number): void {\n if (this.lastPrice === null) {\n this.lastPrice = price;\n return;\n }\n\n for (const alert of this.alerts) {\n if (alert.triggered && !alert.repeating) continue;\n\n let triggered = false;\n switch (alert.condition) {\n case 'crossingUp':\n triggered = this.lastPrice < alert.price && price >= alert.price;\n break;\n case 'crossingDown':\n triggered = this.lastPrice > alert.price && price <= alert.price;\n break;\n case 'crossing':\n triggered = (this.lastPrice < alert.price && price >= alert.price) ||\n (this.lastPrice > alert.price && price <= alert.price);\n break;\n case 'greaterThan':\n triggered = price > alert.price;\n break;\n case 'lessThan':\n triggered = price < alert.price;\n break;\n }\n\n if (triggered) {\n alert.triggered = true;\n this.emit('triggered', { ...alert });\n }\n }\n\n this.lastPrice = price;\n }\n\n saveToStorage(key: string): void {\n try {\n const data = this.alerts.map(a => ({\n id: a.id, price: a.price, condition: a.condition,\n message: a.message, triggered: a.triggered,\n }));\n localStorage.setItem(key, JSON.stringify(data));\n } catch { /* storage unavailable or full */ }\n }\n\n loadFromStorage(key: string): void {\n try {\n const json = localStorage.getItem(key);\n if (!json) return;\n const data = JSON.parse(json);\n if (!Array.isArray(data)) return;\n for (const a of data) {\n if (a.price && a.condition && !a.triggered) {\n this.addAlert(a.price, a.condition, a.message);\n }\n }\n } catch { /* storage unavailable or corrupt data */ }\n }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n const { chartRect } = viewport;\n\n for (const alert of this.alerts) {\n const y = priceToY(alert.price, viewport);\n if (y < chartRect.y || y > chartRect.y + chartRect.height) continue;\n\n const color = alert.triggered ? '#FF9800' : '#FFD700';\n\n // Alert line\n ctx.setLineDash([2, 6]);\n ctx.strokeStyle = color;\n ctx.lineWidth = 1;\n ctx.beginPath();\n ctx.moveTo(chartRect.x, Math.round(y) + 0.5);\n ctx.lineTo(chartRect.x + chartRect.width, Math.round(y) + 0.5);\n ctx.stroke();\n ctx.setLineDash([]);\n\n // Bell icon + price label\n ctx.font = `10px ${theme.font.family}`;\n ctx.fillStyle = color;\n ctx.textBaseline = 'bottom';\n ctx.textAlign = 'right';\n const label = `🔔 ${alert.price.toFixed(this.pricePrecision)}${alert.message ? ` - ${alert.message}` : ''}`;\n ctx.fillText(label, chartRect.x + chartRect.width - 4, y - 2);\n }\n }\n}\n","import type { OHLCBar, DataSeries } from '@tradecanvas/commons';\nimport { Emitter } from '../realtime/Emitter.js';\n\nexport interface ReplayConfig {\n speed: number; // Multiplier: 1 = real-time, 2 = 2x, 0.5 = half speed\n interval: number; // Base tick interval in ms (default: 500)\n startIndex?: number; // Bar index to start from\n}\n\ninterface ReplayEvents {\n bar: { bar: OHLCBar; index: number; total: number };\n complete: void;\n stateChange: 'playing' | 'paused' | 'stopped';\n [key: string]: unknown;\n}\n\n/**\n * Replays historical data bar-by-bar for backtesting and review.\n * Feeds bars to the chart sequentially at configurable speed.\n */\nexport class ReplayManager extends Emitter<ReplayEvents> {\n private data: DataSeries = [];\n private currentIndex = 0;\n private timer: ReturnType<typeof setInterval> | null = null;\n private state: 'playing' | 'paused' | 'stopped' = 'stopped';\n private config: ReplayConfig = { speed: 1, interval: 500 };\n\n load(data: DataSeries): void {\n this.stop();\n this.data = data;\n this.currentIndex = 0;\n }\n\n play(config?: Partial<ReplayConfig>): void {\n if (this.data.length === 0) return;\n if (config) Object.assign(this.config, config);\n if (config?.startIndex !== undefined) this.currentIndex = config.startIndex;\n\n this.state = 'playing';\n this.emit('stateChange', 'playing');\n\n this.timer = setInterval(() => {\n if (this.currentIndex >= this.data.length) {\n this.stop();\n this.emit('complete', undefined as any);\n return;\n }\n\n const bar = this.data[this.currentIndex];\n this.emit('bar', { bar, index: this.currentIndex, total: this.data.length });\n this.currentIndex++;\n }, this.config.interval / this.config.speed);\n }\n\n pause(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n this.state = 'paused';\n this.emit('stateChange', 'paused');\n }\n\n resume(): void {\n if (this.state === 'paused') {\n this.play();\n }\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n this.state = 'stopped';\n this.currentIndex = 0;\n this.emit('stateChange', 'stopped');\n }\n\n seekTo(index: number): void {\n this.currentIndex = Math.max(0, Math.min(index, this.data.length - 1));\n }\n\n setSpeed(speed: number): void {\n this.config.speed = speed;\n if (this.state === 'playing') {\n this.pause();\n this.play();\n }\n }\n\n getState(): 'playing' | 'paused' | 'stopped' {\n return this.state;\n }\n\n getProgress(): { current: number; total: number; percent: number } {\n return {\n current: this.currentIndex,\n total: this.data.length,\n percent: this.data.length > 0 ? (this.currentIndex / this.data.length) * 100 : 0,\n };\n }\n\n dispose(): void {\n this.stop();\n this.removeAllListeners();\n this.data = [];\n }\n}\n","import type { ChartType, DrawingState, TradingOrder, TradingPosition, Theme } from '@tradecanvas/commons';\r\nimport type { PriceAlert } from './AlertManager.js';\r\n\r\n/**\r\n * Serializable chart state for save/load functionality.\r\n * Contains everything needed to restore a chart to its exact state.\r\n */\r\nexport interface ChartSnapshot {\r\n version: number;\r\n timestamp: number;\r\n\r\n // Chart config\r\n symbol?: string;\r\n timeframe?: string;\r\n chartType: ChartType;\r\n\r\n // Viewport\r\n viewport: {\r\n barWidth: number;\r\n barSpacing: number;\r\n offset: number;\r\n };\r\n\r\n // Visual\r\n theme?: string | Theme;\r\n locale?: string;\r\n\r\n // Indicators\r\n indicators: {\r\n id: string;\r\n instanceId: string;\r\n params: Record<string, unknown>;\r\n position?: string;\r\n }[];\r\n\r\n // Drawings (fully serializable)\r\n drawings: DrawingState[];\r\n\r\n // Trading\r\n orders: TradingOrder[];\r\n positions: TradingPosition[];\r\n\r\n // Alerts\r\n alerts: PriceAlert[];\r\n}\r\n\r\nconst CURRENT_VERSION = 1;\r\n\r\nfunction isObject(v: unknown): v is Record<string, unknown> {\r\n return typeof v === 'object' && v !== null && !Array.isArray(v);\r\n}\r\n\r\nfunction asArray(v: unknown): unknown[] {\r\n return Array.isArray(v) ? v : [];\r\n}\r\n\r\nfunction asString(v: unknown, fallback: string): string {\r\n return typeof v === 'string' ? v : fallback;\r\n}\r\n\r\nfunction asNumber(v: unknown, fallback: number): number {\r\n return typeof v === 'number' && Number.isFinite(v) ? v : fallback;\r\n}\r\n\r\nfunction validateDrawing(raw: unknown): DrawingState | null {\r\n if (!isObject(raw)) return null;\r\n if (typeof raw.id !== 'string' || typeof raw.type !== 'string') return null;\r\n if (!Array.isArray(raw.anchors) || raw.anchors.length === 0) return null;\r\n if (!isObject(raw.style)) return null;\r\n\r\n const anchors: DrawingState['anchors'] = [];\r\n for (const a of raw.anchors) {\r\n if (!isObject(a)) return null;\r\n if (typeof a.time !== 'number' || typeof a.price !== 'number') return null;\r\n if (!Number.isFinite(a.time) || !Number.isFinite(a.price)) return null;\r\n anchors.push({ time: a.time, price: a.price });\r\n }\r\n\r\n const style = raw.style;\r\n if (typeof style.color !== 'string' || typeof style.lineWidth !== 'number') {\r\n return null;\r\n }\r\n\r\n return {\r\n id: raw.id,\r\n type: raw.type as DrawingState['type'],\r\n anchors,\r\n style: style as unknown as DrawingState['style'],\r\n visible: typeof raw.visible === 'boolean' ? raw.visible : true,\r\n locked: typeof raw.locked === 'boolean' ? raw.locked : false,\r\n meta: isObject(raw.meta) ? raw.meta : undefined,\r\n };\r\n}\r\n\r\nfunction validateOrder(raw: unknown): TradingOrder | null {\r\n if (!isObject(raw)) return null;\r\n if (typeof raw.id !== 'string' || typeof raw.side !== 'string') return null;\r\n if (typeof raw.type !== 'string' || typeof raw.price !== 'number') return null;\r\n if (typeof raw.quantity !== 'number') return null;\r\n return raw as unknown as TradingOrder;\r\n}\r\n\r\nfunction validatePosition(raw: unknown): TradingPosition | null {\r\n if (!isObject(raw)) return null;\r\n if (typeof raw.id !== 'string' || typeof raw.side !== 'string') return null;\r\n if (typeof raw.entryPrice !== 'number' || typeof raw.quantity !== 'number') return null;\r\n return raw as unknown as TradingPosition;\r\n}\r\n\r\nexport function validateSnapshot(raw: unknown): ChartSnapshot {\r\n if (!isObject(raw)) {\r\n return emptySnapshot();\r\n }\r\n\r\n if (typeof raw.version === 'number' && raw.version !== CURRENT_VERSION) {\r\n console.warn(`Chart state version mismatch: ${raw.version} vs ${CURRENT_VERSION}`);\r\n }\r\n\r\n const viewport = isObject(raw.viewport) ? raw.viewport : {};\r\n\r\n const indicators: ChartSnapshot['indicators'] = [];\r\n for (const ind of asArray(raw.indicators)) {\r\n if (!isObject(ind)) continue;\r\n if (typeof ind.id !== 'string' || typeof ind.instanceId !== 'string') continue;\r\n if (!isObject(ind.params)) continue;\r\n indicators.push({\r\n id: ind.id,\r\n instanceId: ind.instanceId,\r\n params: ind.params,\r\n position: typeof ind.position === 'string' ? ind.position : undefined,\r\n });\r\n }\r\n\r\n const drawings: DrawingState[] = [];\r\n for (const d of asArray(raw.drawings)) {\r\n const v = validateDrawing(d);\r\n if (v) drawings.push(v);\r\n }\r\n\r\n const orders: TradingOrder[] = [];\r\n for (const o of asArray(raw.orders)) {\r\n const v = validateOrder(o);\r\n if (v) orders.push(v);\r\n }\r\n\r\n const positions: TradingPosition[] = [];\r\n for (const p of asArray(raw.positions)) {\r\n const v = validatePosition(p);\r\n if (v) positions.push(v);\r\n }\r\n\r\n const alerts: PriceAlert[] = [];\r\n for (const a of asArray(raw.alerts)) {\r\n if (isObject(a) && typeof a.id === 'string') alerts.push(a as unknown as PriceAlert);\r\n }\r\n\r\n return {\r\n version: typeof raw.version === 'number' ? raw.version : CURRENT_VERSION,\r\n timestamp: asNumber(raw.timestamp, Date.now()),\r\n symbol: typeof raw.symbol === 'string' ? raw.symbol : undefined,\r\n timeframe: typeof raw.timeframe === 'string' ? raw.timeframe : undefined,\r\n chartType: asString(raw.chartType, 'candlestick') as ChartType,\r\n viewport: {\r\n barWidth: asNumber(viewport.barWidth, 8),\r\n barSpacing: asNumber(viewport.barSpacing, 2),\r\n offset: asNumber(viewport.offset, 0),\r\n },\r\n theme: typeof raw.theme === 'string' ? raw.theme : undefined,\r\n locale: typeof raw.locale === 'string' ? raw.locale : undefined,\r\n indicators,\r\n drawings,\r\n orders,\r\n positions,\r\n alerts,\r\n };\r\n}\r\n\r\nfunction emptySnapshot(): ChartSnapshot {\r\n return {\r\n version: CURRENT_VERSION,\r\n timestamp: Date.now(),\r\n chartType: 'candlestick',\r\n viewport: { barWidth: 8, barSpacing: 2, offset: 0 },\r\n indicators: [],\r\n drawings: [],\r\n orders: [],\r\n positions: [],\r\n alerts: [],\r\n };\r\n}\r\n\r\nexport class ChartStateManager {\r\n /**\r\n * Capture current chart state as a serializable snapshot.\r\n */\r\n static capture(chart: {\r\n getDrawings: () => DrawingState[];\r\n getOrders?: () => TradingOrder[];\r\n getPositions?: () => TradingPosition[];\r\n getAlerts?: () => PriceAlert[];\r\n getTheme: () => Theme;\r\n getIndicators?: () => { id: string; instanceId: string; params: Record<string, unknown> }[];\r\n }, meta?: { symbol?: string; timeframe?: string; chartType?: ChartType }): ChartSnapshot {\r\n return {\r\n version: CURRENT_VERSION,\r\n timestamp: Date.now(),\r\n chartType: meta?.chartType ?? 'candlestick',\r\n symbol: meta?.symbol,\r\n timeframe: meta?.timeframe,\r\n viewport: { barWidth: 8, barSpacing: 2, offset: 0 },\r\n theme: chart.getTheme().name,\r\n indicators: chart.getIndicators?.() ?? [],\r\n drawings: chart.getDrawings(),\r\n orders: chart.getOrders?.() ?? [],\r\n positions: chart.getPositions?.() ?? [],\r\n alerts: chart.getAlerts?.() ?? [],\r\n };\r\n }\r\n\r\n /** Serialize to JSON string */\r\n static serialize(snapshot: ChartSnapshot): string {\r\n return JSON.stringify(snapshot);\r\n }\r\n\r\n /**\r\n * Deserialize from JSON string. Validates the top-level shape and filters\r\n * malformed array entries instead of trusting `JSON.parse`. Missing or\r\n * wrong-typed fields fall back to safe defaults so older saves still load.\r\n */\r\n static deserialize(json: string): ChartSnapshot {\r\n const raw: unknown = JSON.parse(json);\r\n return validateSnapshot(raw);\r\n }\r\n\r\n /** Save to localStorage */\r\n static saveToStorage(key: string, snapshot: ChartSnapshot): void {\r\n localStorage.setItem(key, this.serialize(snapshot));\r\n }\r\n\r\n /** Load from localStorage */\r\n static loadFromStorage(key: string): ChartSnapshot | null {\r\n const json = localStorage.getItem(key);\r\n return json ? this.deserialize(json) : null;\r\n }\r\n\r\n /** Download as JSON file */\r\n static downloadFile(snapshot: ChartSnapshot, filename = 'tc-chart-state.json'): void {\r\n const blob = new Blob([this.serialize(snapshot)], { type: 'application/json' });\r\n const url = URL.createObjectURL(blob);\r\n const link = document.createElement('a');\r\n link.href = url;\r\n link.download = filename;\r\n document.body.appendChild(link);\r\n link.click();\r\n document.body.removeChild(link);\r\n URL.revokeObjectURL(url);\r\n }\r\n\r\n /** Load from file (returns promise) */\r\n static loadFromFile(): Promise<ChartSnapshot> {\r\n return new Promise((resolve, reject) => {\r\n const input = document.createElement('input');\r\n input.type = 'file';\r\n input.accept = '.json';\r\n input.onchange = async () => {\r\n const file = input.files?.[0];\r\n if (!file) { reject(new Error('No file selected')); return; }\r\n const text = await file.text();\r\n resolve(this.deserialize(text));\r\n };\r\n input.click();\r\n });\r\n }\r\n}\r\n","import type { DrawingState } from '@tradecanvas/commons';\n\nexport interface UndoableAction {\n type: 'drawingCreate' | 'drawingRemove' | 'drawingModify';\n /** State before the action (null for create) */\n before: DrawingState | null;\n /** State after the action (null for remove) */\n after: DrawingState | null;\n}\n\nexport class UndoRedoManager {\n private undoStack: UndoableAction[] = [];\n private redoStack: UndoableAction[] = [];\n private maxHistory = 50;\n private onChange: (() => void) | null = null;\n\n setOnChange(cb: () => void): void {\n this.onChange = cb;\n }\n\n push(action: UndoableAction): void {\n this.undoStack.push(action);\n if (this.undoStack.length > this.maxHistory) {\n this.undoStack.shift();\n }\n // Any new action clears the redo stack\n this.redoStack.length = 0;\n this.onChange?.();\n }\n\n canUndo(): boolean {\n return this.undoStack.length > 0;\n }\n\n canRedo(): boolean {\n return this.redoStack.length > 0;\n }\n\n undo(): UndoableAction | null {\n const action = this.undoStack.pop();\n if (!action) return null;\n this.redoStack.push(action);\n this.onChange?.();\n return action;\n }\n\n redo(): UndoableAction | null {\n const action = this.redoStack.pop();\n if (!action) return null;\n this.undoStack.push(action);\n this.onChange?.();\n return action;\n }\n\n clear(): void {\n this.undoStack.length = 0;\n this.redoStack.length = 0;\n }\n\n getState(): { canUndo: boolean; canRedo: boolean; undoCount: number; redoCount: number } {\n return {\n canUndo: this.undoStack.length > 0,\n canRedo: this.redoStack.length > 0,\n undoCount: this.undoStack.length,\n redoCount: this.redoStack.length,\n };\n }\n}\n","import type { OHLCBar } from '@tradecanvas/commons';\n\nexport class DataExporter {\n static toCSV(data: ReadonlyArray<OHLCBar>): string {\n const header = 'Time,Open,High,Low,Close,Volume';\n const rows = data.map(bar => {\n const time = new Date(bar.time).toISOString();\n return `${time},${bar.open},${bar.high},${bar.low},${bar.close},${bar.volume}`;\n });\n return [header, ...rows].join('\\n');\n }\n\n static toJSON(data: ReadonlyArray<OHLCBar>): string {\n return JSON.stringify(data.map(bar => ({\n time: new Date(bar.time).toISOString(),\n open: bar.open,\n high: bar.high,\n low: bar.low,\n close: bar.close,\n volume: bar.volume,\n })), null, 2);\n }\n\n static download(content: string, filename: string, mimeType: string): void {\n const blob = new Blob([content], { type: mimeType });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n }\n}\n","import type { ViewportState, Theme, DataSeries, SignalMarker, SignalMarkerStyle } from '@tradecanvas/commons';\nimport { DEFAULT_SIGNAL_STYLE } from '@tradecanvas/commons';\nimport { priceToY, barIndexToX, timestampToBarIndex } from '../viewport/ScaleMapping.js';\nimport { Emitter } from '../realtime/Emitter.js';\n\ninterface SignalMarkerEvents {\n added: SignalMarker;\n removed: string;\n cleared: void;\n [key: string]: unknown;\n}\n\nlet markerId = 1;\n\nexport class SignalMarkerManager extends Emitter<SignalMarkerEvents> {\n private markers: SignalMarker[] = [];\n private style: SignalMarkerStyle = { ...DEFAULT_SIGNAL_STYLE };\n private requestRender: (() => void) | null = null;\n private dataGetter: (() => DataSeries) | null = null;\n\n setRequestRender(cb: () => void): void {\n this.requestRender = cb;\n }\n\n setDataGetter(getter: () => DataSeries): void {\n this.dataGetter = getter;\n }\n\n setStyle(style: Partial<SignalMarkerStyle>): void {\n this.style = { ...this.style, ...style };\n this.requestRender?.();\n }\n\n getStyle(): SignalMarkerStyle {\n return { ...this.style };\n }\n\n addMarker(marker: Omit<SignalMarker, 'id'> & { id?: string }): string {\n const id = marker.id ?? `tc_signal_${markerId++}`;\n const full: SignalMarker = { ...marker, id };\n this.markers.push(full);\n this.emit('added', full);\n this.requestRender?.();\n return id;\n }\n\n removeMarker(id: string): void {\n this.markers = this.markers.filter(m => m.id !== id);\n this.emit('removed', id);\n this.requestRender?.();\n }\n\n getMarkers(): SignalMarker[] {\n return [...this.markers];\n }\n\n clearMarkers(): void {\n this.markers = [];\n this.emit('cleared', undefined as unknown as void);\n this.requestRender?.();\n }\n\n setMarkers(markers: SignalMarker[]): void {\n this.markers = [...markers];\n this.requestRender?.();\n }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n const data = this.dataGetter?.();\n if (!data || data.length === 0 || this.markers.length === 0) return;\n\n const { chartRect, visibleRange } = viewport;\n const style = this.style;\n const arrowSize = style.arrowSize ?? 12;\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(chartRect.x, chartRect.y, chartRect.width, chartRect.height);\n ctx.clip();\n\n for (const marker of this.markers) {\n const barIdx = timestampToBarIndex(marker.time, data);\n if (barIdx < visibleRange.from - 1 || barIdx > visibleRange.to + 1) continue;\n\n const x = barIndexToX(barIdx, viewport);\n const y = priceToY(marker.price, viewport);\n\n if (x < chartRect.x - arrowSize || x > chartRect.x + chartRect.width + arrowSize) continue;\n if (y < chartRect.y - arrowSize || y > chartRect.y + chartRect.height + arrowSize) continue;\n\n const color = this.resolveColor(marker, style);\n const scaledSize = arrowSize * Math.max(0.6, Math.min(1, marker.confidence));\n\n this.renderArrow(ctx, x, y, marker.direction, scaledSize, color);\n\n if (style.showLabel && marker.label) {\n ctx.font = `10px ${theme.font.family}`;\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = marker.direction === 'long' ? 'top' : 'bottom';\n const labelY = marker.direction === 'long' ? y + scaledSize + 3 : y - scaledSize - 3;\n ctx.fillText(marker.label, x, labelY);\n }\n\n if (style.showConfidence && marker.confidence < 1) {\n ctx.font = `9px ${theme.font.family}`;\n ctx.fillStyle = color;\n ctx.globalAlpha = 0.7;\n ctx.textAlign = 'center';\n ctx.textBaseline = marker.direction === 'long' ? 'top' : 'bottom';\n const confY = marker.direction === 'long'\n ? y + scaledSize + (marker.label ? 14 : 3)\n : y - scaledSize - (marker.label ? 14 : 3);\n ctx.fillText(`${Math.round(marker.confidence * 100)}%`, x, confY);\n ctx.globalAlpha = 1;\n }\n }\n\n ctx.restore();\n }\n\n private resolveColor(marker: SignalMarker, style: SignalMarkerStyle): string {\n if (marker.color) return marker.color;\n if (style.sourceColors?.[marker.source]) return style.sourceColors[marker.source];\n switch (marker.direction) {\n case 'long': return style.longColor ?? '#26A69A';\n case 'short': return style.shortColor ?? '#EF5350';\n default: return style.neutralColor ?? '#9E9E9E';\n }\n }\n\n private renderArrow(\n ctx: CanvasRenderingContext2D,\n x: number, y: number,\n direction: string,\n size: number,\n color: string,\n ): void {\n ctx.fillStyle = color;\n ctx.beginPath();\n\n if (direction === 'long') {\n ctx.moveTo(x, y - size);\n ctx.lineTo(x - size * 0.6, y);\n ctx.lineTo(x - size * 0.2, y);\n ctx.lineTo(x - size * 0.2, y + size * 0.4);\n ctx.lineTo(x + size * 0.2, y + size * 0.4);\n ctx.lineTo(x + size * 0.2, y);\n ctx.lineTo(x + size * 0.6, y);\n } else if (direction === 'short') {\n ctx.moveTo(x, y + size);\n ctx.lineTo(x - size * 0.6, y);\n ctx.lineTo(x - size * 0.2, y);\n ctx.lineTo(x - size * 0.2, y - size * 0.4);\n ctx.lineTo(x + size * 0.2, y - size * 0.4);\n ctx.lineTo(x + size * 0.2, y);\n ctx.lineTo(x + size * 0.6, y);\n } else {\n ctx.arc(x, y, size * 0.4, 0, Math.PI * 2);\n }\n\n ctx.closePath();\n ctx.fill();\n }\n}\n","import type { ViewportState, Theme, DataSeries, TradeZone, TradeZoneStyle } from '@tradecanvas/commons';\nimport { DEFAULT_TRADE_ZONE_STYLE } from '@tradecanvas/commons';\nimport { priceToY, barIndexToX, timestampToBarIndex } from '../viewport/ScaleMapping.js';\nimport { Emitter } from '../realtime/Emitter.js';\n\ninterface TradeZoneEvents {\n added: TradeZone;\n removed: string;\n cleared: void;\n [key: string]: unknown;\n}\n\nlet zoneId = 1;\n\nexport class TradeZoneManager extends Emitter<TradeZoneEvents> {\n private zones: TradeZone[] = [];\n private style: TradeZoneStyle = { ...DEFAULT_TRADE_ZONE_STYLE };\n private requestRender: (() => void) | null = null;\n private dataGetter: (() => DataSeries) | null = null;\n private pricePrecision = 2;\n\n setRequestRender(cb: () => void): void {\n this.requestRender = cb;\n }\n\n setDataGetter(getter: () => DataSeries): void {\n this.dataGetter = getter;\n }\n\n setPricePrecision(precision: number): void {\n this.pricePrecision = precision;\n }\n\n setStyle(style: Partial<TradeZoneStyle>): void {\n this.style = { ...this.style, ...style };\n this.requestRender?.();\n }\n\n getStyle(): TradeZoneStyle {\n return { ...this.style };\n }\n\n addZone(zone: Omit<TradeZone, 'id'> & { id?: string }): string {\n const id = zone.id ?? `tc_zone_${zoneId++}`;\n const full: TradeZone = { ...zone, id };\n this.zones.push(full);\n this.emit('added', full);\n this.requestRender?.();\n return id;\n }\n\n updateZone(id: string, updates: Partial<Omit<TradeZone, 'id'>>): void {\n const idx = this.zones.findIndex(z => z.id === id);\n if (idx === -1) return;\n this.zones[idx] = { ...this.zones[idx], ...updates };\n this.requestRender?.();\n }\n\n removeZone(id: string): void {\n this.zones = this.zones.filter(z => z.id !== id);\n this.emit('removed', id);\n this.requestRender?.();\n }\n\n getZones(): TradeZone[] {\n return [...this.zones];\n }\n\n clearZones(): void {\n this.zones = [];\n this.emit('cleared', undefined as unknown as void);\n this.requestRender?.();\n }\n\n setZones(zones: TradeZone[]): void {\n this.zones = [...zones];\n this.requestRender?.();\n }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n const data = this.dataGetter?.();\n if (!data || data.length === 0 || this.zones.length === 0) return;\n\n const { chartRect } = viewport;\n const style = this.style;\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(chartRect.x, chartRect.y, chartRect.width, chartRect.height);\n ctx.clip();\n\n for (const zone of this.zones) {\n this.renderZone(ctx, zone, data, viewport, theme, style);\n }\n\n ctx.restore();\n }\n\n private renderZone(\n ctx: CanvasRenderingContext2D,\n zone: TradeZone,\n data: DataSeries,\n viewport: ViewportState,\n theme: Theme,\n style: TradeZoneStyle,\n ): void {\n const { chartRect, visibleRange } = viewport;\n\n const entryIdx = timestampToBarIndex(zone.entryTime, data);\n const exitIdx = zone.exitTime != null\n ? timestampToBarIndex(zone.exitTime, data)\n : data.length - 1;\n\n if (exitIdx < visibleRange.from || entryIdx > visibleRange.to) return;\n\n const x1 = barIndexToX(entryIdx, viewport);\n const x2 = barIndexToX(exitIdx, viewport);\n const left = Math.max(chartRect.x, Math.min(x1, x2));\n const right = Math.min(chartRect.x + chartRect.width, Math.max(x1, x2));\n if (right - left < 1) return;\n\n const entryY = priceToY(zone.entryPrice, viewport);\n const exitY = zone.exitPrice != null\n ? priceToY(zone.exitPrice, viewport)\n : priceToY(zone.entryPrice, viewport);\n\n const top = Math.min(entryY, exitY);\n const bottom = Math.max(entryY, exitY);\n const height = Math.max(bottom - top, 2);\n\n const isActive = zone.exitTime == null;\n const isProfit = zone.pnl != null ? zone.pnl >= 0 : (\n zone.direction === 'long'\n ? (zone.exitPrice ?? zone.entryPrice) >= zone.entryPrice\n : (zone.exitPrice ?? zone.entryPrice) <= zone.entryPrice\n );\n\n const fillColor = isActive\n ? (style.activeColor ?? '#2196F3')\n : isProfit\n ? (style.profitColor ?? '#26A69A')\n : (style.lossColor ?? '#EF5350');\n\n ctx.fillStyle = fillColor;\n ctx.globalAlpha = style.fillOpacity ?? 0.12;\n ctx.fillRect(left, top, right - left, height);\n ctx.globalAlpha = 1;\n\n const borderWidth = style.borderWidth ?? 1;\n ctx.strokeStyle = fillColor;\n ctx.lineWidth = borderWidth;\n\n ctx.setLineDash([]);\n ctx.beginPath();\n ctx.moveTo(left, Math.round(entryY) + 0.5);\n ctx.lineTo(right, Math.round(entryY) + 0.5);\n ctx.stroke();\n\n if (!isActive && zone.exitPrice != null) {\n ctx.setLineDash([3, 3]);\n ctx.beginPath();\n ctx.moveTo(left, Math.round(exitY) + 0.5);\n ctx.lineTo(right, Math.round(exitY) + 0.5);\n ctx.stroke();\n ctx.setLineDash([]);\n }\n\n const dirIcon = zone.direction === 'long' ? '▲' : '▼';\n ctx.font = `bold 10px ${theme.font.family}`;\n ctx.fillStyle = fillColor;\n ctx.textBaseline = 'bottom';\n ctx.textAlign = 'left';\n ctx.fillText(`${dirIcon} ${zone.entryPrice.toFixed(this.pricePrecision)}`, left + 4, entryY - 3);\n\n if (style.showPnl && !isActive && zone.pnl != null) {\n const pnlSign = zone.pnl >= 0 ? '+' : '';\n const pnlText = zone.pnlPercent != null\n ? `${pnlSign}${zone.pnl.toFixed(2)} (${pnlSign}${zone.pnlPercent.toFixed(2)}%)`\n : `${pnlSign}${zone.pnl.toFixed(2)}`;\n\n ctx.font = `bold 10px ${theme.font.family}`;\n ctx.fillStyle = fillColor;\n ctx.textBaseline = 'top';\n ctx.textAlign = 'right';\n\n const bgWidth = ctx.measureText(pnlText).width + 8;\n const bgX = right - bgWidth - 2;\n const bgY = top + 2;\n ctx.globalAlpha = 0.85;\n ctx.fillStyle = theme.background;\n ctx.fillRect(bgX, bgY, bgWidth, 14);\n ctx.globalAlpha = 1;\n ctx.fillStyle = fillColor;\n ctx.fillText(pnlText, right - 4, bgY + 1);\n }\n\n if (style.showLabel && zone.label) {\n ctx.font = `9px ${theme.font.family}`;\n ctx.fillStyle = fillColor;\n ctx.globalAlpha = 0.8;\n ctx.textBaseline = 'top';\n ctx.textAlign = 'left';\n ctx.fillText(zone.label, left + 4, entryY + 3);\n ctx.globalAlpha = 1;\n }\n }\n}\n","/**\n * Easing functions for smooth animations.\n */\nexport const Easing = {\n linear: (t: number) => t,\n easeOutCubic: (t: number) => 1 - Math.pow(1 - t, 3),\n easeOutQuart: (t: number) => 1 - Math.pow(1 - t, 4),\n easeInOutCubic: (t: number) => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2,\n easeOutExpo: (t: number) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t),\n easeOutElastic: (t: number) => {\n if (t === 0 || t === 1) return t;\n return Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * (2 * Math.PI / 3)) + 1;\n },\n spring: (t: number) => 1 - Math.pow(Math.E, -6 * t) * Math.cos(8 * t),\n};\n\nexport type EasingFn = (t: number) => number;\n\nexport interface AnimationOptions {\n duration: number;\n easing?: EasingFn;\n onUpdate: (progress: number) => void;\n onComplete?: () => void;\n}\n\n/**\n * Lightweight animation scheduler.\n * Runs multiple concurrent animations on the rAF loop.\n */\nexport class Animator {\n private animations = new Map<string, AnimationState>();\n private frameId = 0;\n private running = false;\n\n /**\n * Start a named animation. If one with the same name is running, it's replaced.\n */\n animate(name: string, opts: AnimationOptions): void {\n this.animations.set(name, {\n startTime: -1,\n duration: opts.duration,\n easing: opts.easing ?? Easing.easeOutCubic,\n onUpdate: opts.onUpdate,\n onComplete: opts.onComplete,\n });\n\n if (!this.running) {\n this.running = true;\n this.tick();\n }\n }\n\n /** Cancel a specific animation */\n cancel(name: string): void {\n this.animations.delete(name);\n if (this.animations.size === 0) this.stop();\n }\n\n /** Cancel all animations */\n cancelAll(): void {\n this.animations.clear();\n this.stop();\n }\n\n isAnimating(name?: string): boolean {\n if (name) return this.animations.has(name);\n return this.animations.size > 0;\n }\n\n private tick(): void {\n this.frameId = requestAnimationFrame((now) => {\n const toRemove: string[] = [];\n\n for (const [name, anim] of this.animations) {\n if (anim.startTime < 0) anim.startTime = now;\n\n const elapsed = now - anim.startTime;\n const t = Math.min(1, elapsed / anim.duration);\n const progress = anim.easing(t);\n\n anim.onUpdate(progress);\n\n if (t >= 1) {\n anim.onComplete?.();\n toRemove.push(name);\n }\n }\n\n for (const name of toRemove) this.animations.delete(name);\n\n if (this.animations.size > 0) {\n this.tick();\n } else {\n this.running = false;\n }\n });\n }\n\n private stop(): void {\n if (this.frameId) {\n cancelAnimationFrame(this.frameId);\n this.frameId = 0;\n }\n this.running = false;\n }\n\n dispose(): void {\n this.cancelAll();\n }\n}\n\ninterface AnimationState {\n startTime: number;\n duration: number;\n easing: EasingFn;\n onUpdate: (progress: number) => void;\n onComplete?: () => void;\n}\n","import type { Theme, ThemeName } from '@tradecanvas/commons';\nimport { DARK_THEME, LIGHT_THEME } from '@tradecanvas/commons';\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\nexport abstract class BaseFinanceChart {\n protected canvas: HTMLCanvasElement;\n protected ctx: CanvasRenderingContext2D;\n protected container: HTMLElement;\n protected theme: Theme;\n protected width = 0;\n protected height = 0;\n protected dpr = 1;\n private frameId: number | null = null;\n private resizeObserver: ResizeObserver;\n\n constructor(container: HTMLElement, theme?: ThemeName | Theme) {\n this.container = container;\n this.theme = resolveTheme(theme);\n\n this.canvas = document.createElement('canvas');\n this.canvas.style.width = '100%';\n this.canvas.style.height = '100%';\n this.canvas.style.display = 'block';\n container.appendChild(this.canvas);\n this.ctx = this.canvas.getContext('2d')!;\n\n this.dpr = window.devicePixelRatio || 1;\n this.updateSize();\n\n this.resizeObserver = new ResizeObserver(() => {\n this.updateSize();\n this.requestRender();\n });\n this.resizeObserver.observe(container);\n }\n\n private updateSize(): void {\n this.dpr = window.devicePixelRatio || 1;\n const rect = this.container.getBoundingClientRect();\n this.width = rect.width || this.container.clientWidth;\n this.height = rect.height || this.container.clientHeight;\n this.canvas.width = Math.max(1, Math.floor(this.width * this.dpr));\n this.canvas.height = Math.max(1, Math.floor(this.height * this.dpr));\n }\n\n requestRender(): void {\n if (this.frameId !== null) return;\n this.frameId = requestAnimationFrame(() => {\n this.frameId = null;\n // Ensure we have current size (may have been 0 on first mount)\n if (this.width === 0 || this.height === 0) {\n this.updateSize();\n }\n if (this.width === 0 || this.height === 0) return;\n this.ctx.save();\n this.ctx.scale(this.dpr, this.dpr);\n this.ctx.clearRect(0, 0, this.width, this.height);\n this.renderChart(this.ctx, this.width, this.height, this.theme);\n this.ctx.restore();\n });\n }\n\n protected abstract renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void;\n\n setTheme(theme: ThemeName | Theme): void {\n this.theme = resolveTheme(theme);\n this.requestRender();\n }\n\n destroy(): void {\n if (this.frameId !== null) cancelAnimationFrame(this.frameId);\n this.resizeObserver.disconnect();\n this.canvas.remove();\n }\n}\n","export class FinanceCrosshair {\n private pos: { x: number; y: number } | null = null;\n private canvas: HTMLCanvasElement;\n private onUpdate: () => void;\n\n private handleMove: (e: PointerEvent) => void;\n private handleLeave: () => void;\n\n constructor(canvas: HTMLCanvasElement, onUpdate: () => void) {\n this.canvas = canvas;\n this.onUpdate = onUpdate;\n\n this.handleMove = (e: PointerEvent) => {\n const rect = canvas.getBoundingClientRect();\n this.pos = { x: e.clientX - rect.left, y: e.clientY - rect.top };\n this.onUpdate();\n };\n this.handleLeave = () => {\n this.pos = null;\n this.onUpdate();\n };\n\n canvas.addEventListener('pointermove', this.handleMove);\n canvas.addEventListener('pointerleave', this.handleLeave);\n }\n\n getPosition(): { x: number; y: number } | null {\n return this.pos;\n }\n\n isActive(): boolean {\n return this.pos !== null;\n }\n\n drawCrosshair(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n color: string,\n ): void {\n if (!this.pos) return;\n ctx.save();\n ctx.strokeStyle = color;\n ctx.lineWidth = 0.5;\n ctx.setLineDash([4, 4]);\n // Vertical line\n ctx.beginPath();\n ctx.moveTo(this.pos.x, 0);\n ctx.lineTo(this.pos.x, height);\n ctx.stroke();\n // Horizontal line\n ctx.beginPath();\n ctx.moveTo(0, this.pos.y);\n ctx.lineTo(width, this.pos.y);\n ctx.stroke();\n ctx.restore();\n }\n\n destroy(): void {\n this.canvas.removeEventListener('pointermove', this.handleMove);\n this.canvas.removeEventListener('pointerleave', this.handleLeave);\n }\n}\n","import type { SparklineOptions, Theme } from '@tradecanvas/commons';\n\nexport function renderSparkline(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n options: SparklineOptions,\n theme: Theme,\n): void {\n const { data, mode = 'area', lineWidth = 1.5, showLastPoint = false, showMinMax = false } = options;\n if (data.length < 2 || width <= 0 || height <= 0) return;\n\n const color = options.color ?? theme.lineColor;\n const fillColor = options.fillColor ?? color;\n\n const padding = 2;\n const w = width - padding * 2;\n const h = height - padding * 2;\n\n let min = Infinity;\n let max = -Infinity;\n let minIdx = 0;\n let maxIdx = 0;\n for (let i = 0; i < data.length; i++) {\n if (data[i] < min) { min = data[i]; minIdx = i; }\n if (data[i] > max) { max = data[i]; maxIdx = i; }\n }\n const range = max - min || 1;\n\n const toX = (i: number): number => padding + (i / (data.length - 1)) * w;\n const toY = (v: number): number => padding + h - ((v - min) / range) * h;\n\n // Area fill\n if (mode === 'area') {\n const gradient = ctx.createLinearGradient(0, padding, 0, height - padding);\n gradient.addColorStop(0, fillColor + (fillColor.startsWith('#') ? '40' : ''));\n gradient.addColorStop(1, 'transparent');\n\n ctx.beginPath();\n ctx.moveTo(toX(0), toY(data[0]));\n for (let i = 1; i < data.length; i++) ctx.lineTo(toX(i), toY(data[i]));\n ctx.lineTo(toX(data.length - 1), height - padding);\n ctx.lineTo(toX(0), height - padding);\n ctx.closePath();\n ctx.fillStyle = gradient;\n ctx.fill();\n }\n\n // Line\n ctx.beginPath();\n ctx.moveTo(toX(0), toY(data[0]));\n for (let i = 1; i < data.length; i++) ctx.lineTo(toX(i), toY(data[i]));\n ctx.strokeStyle = color;\n ctx.lineWidth = lineWidth;\n ctx.lineJoin = 'round';\n ctx.stroke();\n\n // Last point dot\n if (showLastPoint) {\n const lastColor = options.lastPointColor ?? color;\n const lx = toX(data.length - 1);\n const ly = toY(data[data.length - 1]);\n ctx.beginPath();\n ctx.arc(lx, ly, 3, 0, Math.PI * 2);\n ctx.fillStyle = lastColor;\n ctx.fill();\n }\n\n // Min/max dots\n if (showMinMax) {\n const minColor = options.minPointColor ?? theme.candleDown;\n const maxColor = options.maxPointColor ?? theme.candleUp;\n // Min\n ctx.beginPath();\n ctx.arc(toX(minIdx), toY(min), 2.5, 0, Math.PI * 2);\n ctx.fillStyle = minColor;\n ctx.fill();\n // Max\n ctx.beginPath();\n ctx.arc(toX(maxIdx), toY(max), 2.5, 0, Math.PI * 2);\n ctx.fillStyle = maxColor;\n ctx.fill();\n }\n}\n","import type { DepthChartOptions, DepthLevel, Theme } from '@tradecanvas/commons';\nimport { computeTickStep } from '@tradecanvas/commons';\n\ninterface CumulativeLevel {\n price: number;\n cumulativeVolume: number;\n}\n\ninterface DepthLayout {\n left: number;\n right: number;\n top: number;\n bottom: number;\n plotWidth: number;\n plotHeight: number;\n}\n\nconst MARGIN_LEFT = 50;\nconst MARGIN_RIGHT = 60;\nconst PADDING_TB = 20;\nconst PRICE_EXTEND_FACTOR = 0.2;\n\nfunction buildCumulativeBids(bids: readonly DepthLevel[]): readonly CumulativeLevel[] {\n const sorted = [...bids].sort((a, b) => b.price - a.price);\n const result: CumulativeLevel[] = [];\n let cumVol = 0;\n for (const level of sorted) {\n cumVol += level.volume;\n result.push({ price: level.price, cumulativeVolume: cumVol });\n }\n return result;\n}\n\nfunction buildCumulativeAsks(asks: readonly DepthLevel[]): readonly CumulativeLevel[] {\n const sorted = [...asks].sort((a, b) => a.price - b.price);\n const result: CumulativeLevel[] = [];\n let cumVol = 0;\n for (const level of sorted) {\n cumVol += level.volume;\n result.push({ price: level.price, cumulativeVolume: cumVol });\n }\n return result;\n}\n\nfunction computeLayout(width: number, height: number): DepthLayout {\n return {\n left: MARGIN_LEFT,\n right: width - MARGIN_RIGHT,\n top: PADDING_TB,\n bottom: height - PADDING_TB,\n plotWidth: width - MARGIN_LEFT - MARGIN_RIGHT,\n plotHeight: height - PADDING_TB * 2,\n };\n}\n\nfunction drawBackground(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n bg: string,\n): void {\n ctx.fillStyle = bg;\n ctx.fillRect(0, 0, width, height);\n}\n\nfunction drawGrid(\n ctx: CanvasRenderingContext2D,\n layout: DepthLayout,\n priceMin: number,\n priceMax: number,\n volMax: number,\n theme: Theme,\n priceFormat: (p: number) => string,\n volumeFormat: (v: number) => string,\n): void {\n const { left, right, top, bottom, plotWidth, plotHeight } = layout;\n\n ctx.save();\n ctx.strokeStyle = theme.grid;\n ctx.lineWidth = 0.5;\n ctx.fillStyle = theme.axisLabel;\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n\n // Horizontal grid (volume)\n const volStep = computeTickStep(0, volMax, 5);\n for (let v = 0; v <= volMax; v += volStep) {\n const y = bottom - (v / volMax) * plotHeight;\n ctx.beginPath();\n ctx.moveTo(left, y);\n ctx.lineTo(right, y);\n ctx.stroke();\n ctx.textAlign = 'right';\n ctx.textBaseline = 'middle';\n ctx.fillText(volumeFormat(v), left - 4, y);\n }\n\n // Vertical grid (price)\n const priceRange = priceMax - priceMin;\n const priceStep = computeTickStep(priceMin, priceMax, 6);\n const firstTick = Math.ceil(priceMin / priceStep) * priceStep;\n for (let p = firstTick; p <= priceMax; p += priceStep) {\n const x = left + ((p - priceMin) / priceRange) * plotWidth;\n ctx.beginPath();\n ctx.moveTo(x, top);\n ctx.lineTo(x, bottom);\n ctx.stroke();\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.fillText(priceFormat(p), x, bottom + 4);\n }\n\n ctx.restore();\n}\n\nfunction drawStepArea(\n ctx: CanvasRenderingContext2D,\n levels: readonly CumulativeLevel[],\n layout: DepthLayout,\n priceMin: number,\n priceRange: number,\n volMax: number,\n fillColor: string,\n lineColor: string,\n direction: 'bid' | 'ask',\n): void {\n if (levels.length === 0) return;\n\n const { left, bottom, plotWidth, plotHeight } = layout;\n const toX = (price: number): number => left + ((price - priceMin) / priceRange) * plotWidth;\n const toY = (vol: number): number => bottom - (vol / volMax) * plotHeight;\n\n // Build step path\n ctx.beginPath();\n if (direction === 'bid') {\n // Bids go right-to-left (highest price first in the sorted array)\n ctx.moveTo(toX(levels[0].price), bottom);\n for (let i = 0; i < levels.length; i++) {\n const x = toX(levels[i].price);\n const y = toY(levels[i].cumulativeVolume);\n ctx.lineTo(x, y);\n if (i < levels.length - 1) {\n ctx.lineTo(toX(levels[i + 1].price), y);\n }\n }\n ctx.lineTo(toX(levels[levels.length - 1].price), bottom);\n } else {\n // Asks go left-to-right (lowest price first)\n ctx.moveTo(toX(levels[0].price), bottom);\n for (let i = 0; i < levels.length; i++) {\n const x = toX(levels[i].price);\n const y = toY(levels[i].cumulativeVolume);\n ctx.lineTo(x, y);\n if (i < levels.length - 1) {\n ctx.lineTo(toX(levels[i + 1].price), y);\n }\n }\n ctx.lineTo(toX(levels[levels.length - 1].price), bottom);\n }\n ctx.closePath();\n\n // Fill\n ctx.fillStyle = fillColor;\n ctx.fill();\n\n // Stroke the step line\n ctx.beginPath();\n if (direction === 'bid') {\n ctx.moveTo(toX(levels[0].price), toY(levels[0].cumulativeVolume));\n for (let i = 0; i < levels.length; i++) {\n const x = toX(levels[i].price);\n const y = toY(levels[i].cumulativeVolume);\n if (i > 0) {\n ctx.lineTo(x, toY(levels[i - 1].cumulativeVolume));\n }\n ctx.lineTo(x, y);\n }\n } else {\n ctx.moveTo(toX(levels[0].price), toY(levels[0].cumulativeVolume));\n for (let i = 1; i < levels.length; i++) {\n const prevY = toY(levels[i - 1].cumulativeVolume);\n const x = toX(levels[i].price);\n const y = toY(levels[i].cumulativeVolume);\n ctx.lineTo(x, prevY);\n ctx.lineTo(x, y);\n }\n }\n ctx.strokeStyle = lineColor;\n ctx.lineWidth = 1.5;\n ctx.stroke();\n}\n\nfunction drawMidPriceLine(\n ctx: CanvasRenderingContext2D,\n midPrice: number,\n spread: number,\n layout: DepthLayout,\n priceMin: number,\n priceRange: number,\n theme: Theme,\n showSpreadLabel: boolean,\n priceFormat: (p: number) => string,\n): void {\n const { left, top, bottom, plotWidth } = layout;\n const x = left + ((midPrice - priceMin) / priceRange) * plotWidth;\n\n ctx.save();\n ctx.strokeStyle = theme.textSecondary;\n ctx.lineWidth = 1;\n ctx.setLineDash([4, 4]);\n ctx.beginPath();\n ctx.moveTo(x, top);\n ctx.lineTo(x, bottom);\n ctx.stroke();\n ctx.restore();\n\n if (showSpreadLabel) {\n const label = `Spread: ${priceFormat(spread)}`;\n ctx.save();\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n ctx.fillStyle = theme.textSecondary;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'bottom';\n ctx.fillText(label, x, top - 2);\n ctx.restore();\n }\n}\n\nfunction drawCrosshairTooltip(\n ctx: CanvasRenderingContext2D,\n crosshairPos: { x: number; y: number },\n cumBids: readonly CumulativeLevel[],\n cumAsks: readonly CumulativeLevel[],\n layout: DepthLayout,\n priceMin: number,\n priceRange: number,\n volMax: number,\n theme: Theme,\n priceFormat: (p: number) => string,\n volumeFormat: (v: number) => string,\n): void {\n const { left, top, bottom, plotWidth, plotHeight } = layout;\n const mx = crosshairPos.x;\n\n if (mx < left || mx > layout.right) return;\n\n const price = priceMin + ((mx - left) / plotWidth) * priceRange;\n\n // Find cumulative volume at this price\n let cumVol = 0;\n let side = '';\n // Check bids (sorted descending by price)\n if (cumBids.length > 0 && price <= cumBids[0].price) {\n side = 'Bid';\n for (const level of cumBids) {\n if (price <= level.price) {\n cumVol = level.cumulativeVolume;\n } else {\n break;\n }\n }\n }\n // Check asks (sorted ascending by price)\n if (cumAsks.length > 0 && price >= cumAsks[0].price) {\n side = 'Ask';\n for (const level of cumAsks) {\n if (price >= level.price) {\n cumVol = level.cumulativeVolume;\n } else {\n break;\n }\n }\n }\n\n // Draw vertical crosshair line\n ctx.save();\n ctx.strokeStyle = theme.crosshair;\n ctx.lineWidth = 0.5;\n ctx.setLineDash([4, 4]);\n ctx.beginPath();\n ctx.moveTo(mx, top);\n ctx.lineTo(mx, bottom);\n ctx.stroke();\n\n // Draw horizontal line at volume level\n if (cumVol > 0) {\n const vy = bottom - (cumVol / volMax) * plotHeight;\n ctx.beginPath();\n ctx.moveTo(left, vy);\n ctx.lineTo(layout.right, vy);\n ctx.stroke();\n }\n ctx.restore();\n\n // Tooltip\n const lines = [\n `Price: ${priceFormat(price)}`,\n side ? `${side} Vol: ${volumeFormat(cumVol)}` : '',\n ].filter(Boolean);\n\n ctx.save();\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n const maxTextWidth = Math.max(...lines.map(l => ctx.measureText(l).width));\n const tooltipW = maxTextWidth + 16;\n const tooltipH = lines.length * (theme.font.sizeSmall + 4) + 12;\n\n let tx = mx + 10;\n let ty = crosshairPos.y - tooltipH / 2;\n if (tx + tooltipW > layout.right) tx = mx - tooltipW - 10;\n if (ty < top) ty = top;\n if (ty + tooltipH > bottom) ty = bottom - tooltipH;\n\n ctx.fillStyle = theme.axisLabelBackground;\n ctx.globalAlpha = 0.9;\n ctx.fillRect(tx, ty, tooltipW, tooltipH);\n ctx.globalAlpha = 1;\n ctx.fillStyle = theme.text;\n ctx.textBaseline = 'top';\n ctx.textAlign = 'left';\n for (let i = 0; i < lines.length; i++) {\n ctx.fillText(lines[i], tx + 8, ty + 6 + i * (theme.font.sizeSmall + 4));\n }\n ctx.restore();\n}\n\nfunction defaultPriceFormat(price: number): string {\n return price.toFixed(2);\n}\n\nfunction defaultVolumeFormat(vol: number): string {\n if (vol >= 1_000_000) return (vol / 1_000_000).toFixed(2) + 'M';\n if (vol >= 1_000) return (vol / 1_000).toFixed(1) + 'K';\n return vol.toFixed(0);\n}\n\nexport function renderDepthChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n options: DepthChartOptions,\n theme: Theme,\n crosshairPos: { x: number; y: number } | null,\n): void {\n const { data } = options;\n if (data.bids.length === 0 && data.asks.length === 0) return;\n if (width <= 0 || height <= 0) return;\n\n const bidColor = options.bidColor ?? theme.candleUp;\n const askColor = options.askColor ?? theme.candleDown;\n const bidFillColor = options.bidFillColor ?? (bidColor + '40');\n const askFillColor = options.askFillColor ?? (askColor + '40');\n const midPriceLine = options.midPriceLine !== false;\n const spreadLabel = options.spreadLabel !== false;\n const priceFormat = options.priceFormat ?? defaultPriceFormat;\n const volumeFormat = options.volumeFormat ?? defaultVolumeFormat;\n\n const cumBids = buildCumulativeBids(data.bids);\n const cumAsks = buildCumulativeAsks(data.asks);\n\n // Compute ranges\n const highestBid = cumBids.length > 0 ? cumBids[0].price : 0;\n const lowestAsk = cumAsks.length > 0 ? cumAsks[0].price : 0;\n const midPrice = cumBids.length > 0 && cumAsks.length > 0\n ? (highestBid + lowestAsk) / 2\n : highestBid || lowestAsk;\n const spread = cumAsks.length > 0 && cumBids.length > 0\n ? lowestAsk - highestBid\n : 0;\n\n const lowestBid = cumBids.length > 0 ? cumBids[cumBids.length - 1].price : midPrice;\n const highestAsk = cumAsks.length > 0 ? cumAsks[cumAsks.length - 1].price : midPrice;\n const rawRange = Math.max(midPrice - lowestBid, highestAsk - midPrice);\n const extendedRange = rawRange * (1 + PRICE_EXTEND_FACTOR);\n\n const priceMin = midPrice - extendedRange;\n const priceMax = midPrice + extendedRange;\n const priceRange = priceMax - priceMin;\n\n const maxBidVol = cumBids.length > 0 ? cumBids[cumBids.length - 1].cumulativeVolume : 0;\n const maxAskVol = cumAsks.length > 0 ? cumAsks[cumAsks.length - 1].cumulativeVolume : 0;\n const volMax = Math.max(maxBidVol, maxAskVol) || 1;\n\n const layout = computeLayout(width, height);\n\n drawBackground(ctx, width, height, theme.background);\n drawGrid(ctx, layout, priceMin, priceMax, volMax, theme, priceFormat, volumeFormat);\n\n drawStepArea(ctx, cumBids, layout, priceMin, priceRange, volMax, bidFillColor, bidColor, 'bid');\n drawStepArea(ctx, cumAsks, layout, priceMin, priceRange, volMax, askFillColor, askColor, 'ask');\n\n if (midPriceLine) {\n drawMidPriceLine(ctx, midPrice, spread, layout, priceMin, priceRange, theme, spreadLabel, priceFormat);\n }\n\n if (crosshairPos) {\n drawCrosshairTooltip(\n ctx, crosshairPos, cumBids, cumAsks,\n layout, priceMin, priceRange, volMax,\n theme, priceFormat, volumeFormat,\n );\n }\n}\n","import type { EquityCurveOptions, EquityPoint, Theme } from '@tradecanvas/commons';\nimport { computeTickStep } from '@tradecanvas/commons';\n\ninterface EquityLayout {\n left: number;\n right: number;\n top: number;\n bottom: number;\n plotWidth: number;\n plotHeight: number;\n}\n\nconst MARGIN_LEFT = 70;\nconst MARGIN_BOTTOM = 30;\nconst PADDING_RIGHT = 20;\nconst PADDING_TOP = 20;\nconst VALUE_PADDING_FACTOR = 0.05;\n\nfunction computeLayout(width: number, height: number): EquityLayout {\n return {\n left: MARGIN_LEFT,\n right: width - PADDING_RIGHT,\n top: PADDING_TOP,\n bottom: height - MARGIN_BOTTOM,\n plotWidth: width - MARGIN_LEFT - PADDING_RIGHT,\n plotHeight: height - PADDING_TOP - MARGIN_BOTTOM,\n };\n}\n\nfunction computeValueRange(\n data: readonly EquityPoint[],\n benchmark: readonly EquityPoint[] | undefined,\n): { valMin: number; valMax: number } {\n let min = Infinity;\n let max = -Infinity;\n for (const pt of data) {\n if (pt.value < min) min = pt.value;\n if (pt.value > max) max = pt.value;\n }\n if (benchmark) {\n for (const pt of benchmark) {\n if (pt.value < min) min = pt.value;\n if (pt.value > max) max = pt.value;\n }\n }\n const padding = (max - min) * VALUE_PADDING_FACTOR;\n return { valMin: min - padding, valMax: max + padding };\n}\n\nfunction buildPeakArray(data: readonly EquityPoint[]): readonly number[] {\n const peaks: number[] = [];\n let peak = -Infinity;\n for (const pt of data) {\n if (pt.value > peak) peak = pt.value;\n peaks.push(peak);\n }\n return peaks;\n}\n\nfunction selectTimeFormat(\n rangeMs: number,\n): (ts: number) => string {\n const DAY = 86_400_000;\n const YEAR = 365.25 * DAY;\n\n if (rangeMs < 7 * DAY) {\n // Show hours\n const fmt = new Intl.DateTimeFormat(undefined, { hour: '2-digit', minute: '2-digit' });\n return (ts: number) => fmt.format(new Date(ts));\n }\n if (rangeMs < YEAR) {\n // Show month/day\n const fmt = new Intl.DateTimeFormat(undefined, { month: 'short', day: 'numeric' });\n return (ts: number) => fmt.format(new Date(ts));\n }\n // Show month/year\n const fmt = new Intl.DateTimeFormat(undefined, { month: 'short', year: 'numeric' });\n return (ts: number) => fmt.format(new Date(ts));\n}\n\nfunction defaultValueFormat(val: number): string {\n if (Math.abs(val) >= 1_000_000) return (val / 1_000_000).toFixed(2) + 'M';\n if (Math.abs(val) >= 1_000) return (val / 1_000).toFixed(1) + 'K';\n return val.toFixed(2);\n}\n\nfunction drawBackground(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n bg: string,\n): void {\n ctx.fillStyle = bg;\n ctx.fillRect(0, 0, width, height);\n}\n\nfunction drawGrid(\n ctx: CanvasRenderingContext2D,\n layout: EquityLayout,\n valMin: number,\n valMax: number,\n timeMin: number,\n timeMax: number,\n theme: Theme,\n valueFormat: (v: number) => string,\n formatTime: (ts: number) => string,\n): void {\n const { left, right, top, bottom, plotWidth, plotHeight } = layout;\n\n ctx.save();\n ctx.strokeStyle = theme.grid;\n ctx.lineWidth = 0.5;\n ctx.fillStyle = theme.axisLabel;\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n\n // Value axis (left) - horizontal grid lines\n const valStep = computeTickStep(valMin, valMax, 6);\n const firstValTick = Math.ceil(valMin / valStep) * valStep;\n for (let v = firstValTick; v <= valMax; v += valStep) {\n const y = bottom - ((v - valMin) / (valMax - valMin)) * plotHeight;\n ctx.beginPath();\n ctx.moveTo(left, y);\n ctx.lineTo(right, y);\n ctx.stroke();\n ctx.textAlign = 'right';\n ctx.textBaseline = 'middle';\n ctx.fillText(valueFormat(v), left - 6, y);\n }\n\n // Time axis (bottom) - vertical grid lines\n const timeRange = timeMax - timeMin;\n const timeStep = computeTickStep(timeMin, timeMax, 6);\n const firstTimeTick = Math.ceil(timeMin / timeStep) * timeStep;\n for (let t = firstTimeTick; t <= timeMax; t += timeStep) {\n const x = left + ((t - timeMin) / timeRange) * plotWidth;\n ctx.beginPath();\n ctx.moveTo(x, top);\n ctx.lineTo(x, bottom);\n ctx.stroke();\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.fillText(formatTime(t), x, bottom + 4);\n }\n\n ctx.restore();\n}\n\nfunction drawLine(\n ctx: CanvasRenderingContext2D,\n data: readonly EquityPoint[],\n layout: EquityLayout,\n timeMin: number,\n timeRange: number,\n valMin: number,\n valRange: number,\n color: string,\n lineWidth: number,\n): void {\n if (data.length < 2) return;\n\n const { left, bottom, plotWidth, plotHeight } = layout;\n const toX = (ts: number): number => left + ((ts - timeMin) / timeRange) * plotWidth;\n const toY = (v: number): number => bottom - ((v - valMin) / valRange) * plotHeight;\n\n ctx.save();\n ctx.beginPath();\n ctx.moveTo(toX(data[0].time), toY(data[0].value));\n for (let i = 1; i < data.length; i++) {\n ctx.lineTo(toX(data[i].time), toY(data[i].value));\n }\n ctx.strokeStyle = color;\n ctx.lineWidth = lineWidth;\n ctx.lineJoin = 'round';\n ctx.stroke();\n ctx.restore();\n}\n\nfunction drawAreaFill(\n ctx: CanvasRenderingContext2D,\n data: readonly EquityPoint[],\n layout: EquityLayout,\n timeMin: number,\n timeRange: number,\n valMin: number,\n valRange: number,\n color: string,\n): void {\n if (data.length < 2) return;\n\n const { left, bottom, plotWidth, plotHeight } = layout;\n const toX = (ts: number): number => left + ((ts - timeMin) / timeRange) * plotWidth;\n const toY = (v: number): number => bottom - ((v - valMin) / valRange) * plotHeight;\n\n const gradient = ctx.createLinearGradient(0, layout.top, 0, bottom);\n gradient.addColorStop(0, color + '40');\n gradient.addColorStop(1, 'transparent');\n\n ctx.save();\n ctx.beginPath();\n ctx.moveTo(toX(data[0].time), toY(data[0].value));\n for (let i = 1; i < data.length; i++) {\n ctx.lineTo(toX(data[i].time), toY(data[i].value));\n }\n ctx.lineTo(toX(data[data.length - 1].time), bottom);\n ctx.lineTo(toX(data[0].time), bottom);\n ctx.closePath();\n ctx.fillStyle = gradient;\n ctx.fill();\n ctx.restore();\n}\n\nfunction drawDrawdown(\n ctx: CanvasRenderingContext2D,\n data: readonly EquityPoint[],\n peaks: readonly number[],\n layout: EquityLayout,\n timeMin: number,\n timeRange: number,\n valMin: number,\n valRange: number,\n drawdownColor: string,\n): void {\n if (data.length < 2) return;\n\n const { left, bottom, plotWidth, plotHeight } = layout;\n const toX = (ts: number): number => left + ((ts - timeMin) / timeRange) * plotWidth;\n const toY = (v: number): number => bottom - ((v - valMin) / valRange) * plotHeight;\n\n ctx.save();\n ctx.fillStyle = drawdownColor;\n ctx.beginPath();\n\n // Draw peak line forward\n ctx.moveTo(toX(data[0].time), toY(peaks[0]));\n for (let i = 1; i < data.length; i++) {\n ctx.lineTo(toX(data[i].time), toY(peaks[i]));\n }\n // Draw equity line backward\n for (let i = data.length - 1; i >= 0; i--) {\n ctx.lineTo(toX(data[i].time), toY(data[i].value));\n }\n ctx.closePath();\n ctx.fill();\n ctx.restore();\n}\n\nfunction drawBenchmarkLabel(\n ctx: CanvasRenderingContext2D,\n benchmark: readonly EquityPoint[],\n layout: EquityLayout,\n timeMin: number,\n timeRange: number,\n valMin: number,\n valRange: number,\n label: string,\n color: string,\n theme: Theme,\n): void {\n if (benchmark.length === 0) return;\n\n const { left, bottom, plotWidth, plotHeight } = layout;\n const last = benchmark[benchmark.length - 1];\n const x = left + ((last.time - timeMin) / timeRange) * plotWidth;\n const y = bottom - ((last.value - valMin) / valRange) * plotHeight;\n\n ctx.save();\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n ctx.fillStyle = color;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, x + 4, y);\n ctx.restore();\n}\n\nfunction drawCrosshairTooltip(\n ctx: CanvasRenderingContext2D,\n crosshairPos: { x: number; y: number },\n data: readonly EquityPoint[],\n benchmark: readonly EquityPoint[] | undefined,\n layout: EquityLayout,\n timeMin: number,\n timeRange: number,\n valMin: number,\n valRange: number,\n theme: Theme,\n formatTime: (ts: number) => string,\n valueFormat: (v: number) => string,\n): void {\n const { left, top, bottom, plotWidth, plotHeight } = layout;\n const mx = crosshairPos.x;\n\n if (mx < left || mx > layout.right) return;\n\n // Vertical crosshair line\n ctx.save();\n ctx.strokeStyle = theme.crosshair;\n ctx.lineWidth = 0.5;\n ctx.setLineDash([4, 4]);\n ctx.beginPath();\n ctx.moveTo(mx, top);\n ctx.lineTo(mx, bottom);\n ctx.stroke();\n ctx.restore();\n\n // Find closest data point\n const timeAtMouse = timeMin + ((mx - left) / plotWidth) * timeRange;\n let closestIdx = 0;\n let closestDist = Infinity;\n for (let i = 0; i < data.length; i++) {\n const dist = Math.abs(data[i].time - timeAtMouse);\n if (dist < closestDist) {\n closestDist = dist;\n closestIdx = i;\n }\n }\n\n const pt = data[closestIdx];\n const lines = [\n formatTime(pt.time),\n `Value: ${valueFormat(pt.value)}`,\n ];\n\n if (benchmark && benchmark.length > closestIdx) {\n lines.push(`Benchmark: ${valueFormat(benchmark[closestIdx].value)}`);\n }\n\n // Draw dot on equity line\n const dotX = left + ((pt.time - timeMin) / timeRange) * plotWidth;\n const dotY = bottom - ((pt.value - valMin) / valRange) * plotHeight;\n ctx.beginPath();\n ctx.arc(dotX, dotY, 3, 0, Math.PI * 2);\n ctx.fillStyle = theme.lineColor;\n ctx.fill();\n\n // Tooltip box\n ctx.save();\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n const maxTextWidth = Math.max(...lines.map(l => ctx.measureText(l).width));\n const tooltipW = maxTextWidth + 16;\n const tooltipH = lines.length * (theme.font.sizeSmall + 4) + 12;\n\n let tx = mx + 10;\n let ty = crosshairPos.y - tooltipH / 2;\n if (tx + tooltipW > layout.right) tx = mx - tooltipW - 10;\n if (ty < top) ty = top;\n if (ty + tooltipH > bottom) ty = bottom - tooltipH;\n\n ctx.fillStyle = theme.axisLabelBackground;\n ctx.globalAlpha = 0.9;\n ctx.fillRect(tx, ty, tooltipW, tooltipH);\n ctx.globalAlpha = 1;\n ctx.fillStyle = theme.text;\n ctx.textBaseline = 'top';\n ctx.textAlign = 'left';\n for (let i = 0; i < lines.length; i++) {\n ctx.fillText(lines[i], tx + 8, ty + 6 + i * (theme.font.sizeSmall + 4));\n }\n ctx.restore();\n}\n\nexport function renderEquityCurve(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n options: EquityCurveOptions,\n theme: Theme,\n crosshairPos: { x: number; y: number } | null,\n): void {\n const { data } = options;\n if (data.length < 2 || width <= 0 || height <= 0) return;\n\n const lineColor = options.lineColor ?? theme.lineColor;\n const lineWidth = options.lineWidth ?? 1.5;\n const drawdownEnabled = options.drawdown === true;\n const drawdownColor = options.drawdownColor ?? (theme.candleDown + '30');\n const fillArea = options.fillArea === true;\n const benchmark = options.benchmark;\n const benchmarkColor = options.benchmarkColor ?? theme.textSecondary;\n const benchmarkLabel = options.benchmarkLabel ?? 'Benchmark';\n const valueFormat = options.valueFormat ?? defaultValueFormat;\n\n const { valMin, valMax } = computeValueRange(data, benchmark);\n const valRange = valMax - valMin || 1;\n\n const timeMin = data[0].time;\n const timeMax = data[data.length - 1].time;\n const timeRange = timeMax - timeMin || 1;\n\n const formatTime = options.timeFormat ?? selectTimeFormat(timeRange);\n const layout = computeLayout(width, height);\n\n drawBackground(ctx, width, height, theme.background);\n drawGrid(ctx, layout, valMin, valMax, timeMin, timeMax, theme, valueFormat, formatTime);\n\n // Drawdown shading\n if (drawdownEnabled) {\n const peaks = buildPeakArray(data);\n drawDrawdown(ctx, data, peaks, layout, timeMin, timeRange, valMin, valRange, drawdownColor);\n }\n\n // Area fill under equity line\n if (fillArea) {\n drawAreaFill(ctx, data, layout, timeMin, timeRange, valMin, valRange, lineColor);\n }\n\n // Equity line\n drawLine(ctx, data, layout, timeMin, timeRange, valMin, valRange, lineColor, lineWidth);\n\n // Benchmark line\n if (benchmark && benchmark.length >= 2) {\n drawLine(ctx, benchmark, layout, timeMin, timeRange, valMin, valRange, benchmarkColor, 1);\n drawBenchmarkLabel(ctx, benchmark, layout, timeMin, timeRange, valMin, valRange, benchmarkLabel, benchmarkColor, theme);\n }\n\n // Crosshair\n if (crosshairPos) {\n drawCrosshairTooltip(\n ctx, crosshairPos, data, benchmark,\n layout, timeMin, timeRange, valMin, valRange,\n theme, formatTime, valueFormat,\n );\n }\n}\n","export interface LayoutRect {\n id: string;\n rect: { x: number; y: number; width: number; height: number };\n}\n\ninterface Bounds {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport function layoutUniformGrid(\n cells: readonly { id: string }[],\n bounds: Bounds,\n padding: number,\n): LayoutRect[] {\n if (cells.length === 0) return [];\n\n const n = cells.length;\n const cols = Math.ceil(Math.sqrt(n));\n const rows = Math.ceil(n / cols);\n\n const cellW = bounds.width / cols;\n const cellH = bounds.height / rows;\n\n const result: LayoutRect[] = [];\n for (let i = 0; i < n; i++) {\n const col = i % cols;\n const row = Math.floor(i / cols);\n result.push({\n id: cells[i].id,\n rect: {\n x: bounds.x + col * cellW + padding,\n y: bounds.y + row * cellH + padding,\n width: Math.max(0, cellW - padding * 2),\n height: Math.max(0, cellH - padding * 2),\n },\n });\n }\n\n return result;\n}\n\nfunction worstAspectRatio(\n row: readonly number[],\n sideLength: number,\n): number {\n const sumRow = row.reduce((a, b) => a + b, 0);\n if (sumRow === 0 || sideLength === 0) return Infinity;\n\n let worst = 0;\n for (const area of row) {\n const rowHeight = sumRow / sideLength;\n const cellWidth = area / rowHeight;\n const ratio = rowHeight > cellWidth\n ? rowHeight / cellWidth\n : cellWidth / rowHeight;\n if (ratio > worst) worst = ratio;\n }\n return worst;\n}\n\nfunction layoutRow(\n row: readonly number[],\n ids: readonly string[],\n bounds: Bounds,\n isWide: boolean,\n padding: number,\n results: LayoutRect[],\n): void {\n const sideLength = isWide ? bounds.height : bounds.width;\n const rowSum = row.reduce((a, b) => a + b, 0);\n const rowThickness = sideLength > 0 ? rowSum / sideLength : 0;\n\n let offset = 0;\n for (let i = 0; i < row.length; i++) {\n const cellLength = rowThickness > 0 ? row[i] / rowThickness : 0;\n\n let rect: { x: number; y: number; width: number; height: number };\n if (isWide) {\n rect = {\n x: bounds.x + padding,\n y: bounds.y + offset + padding,\n width: Math.max(0, rowThickness - padding * 2),\n height: Math.max(0, cellLength - padding * 2),\n };\n } else {\n rect = {\n x: bounds.x + offset + padding,\n y: bounds.y + padding,\n width: Math.max(0, cellLength - padding * 2),\n height: Math.max(0, rowThickness - padding * 2),\n };\n }\n\n results.push({ id: ids[i], rect });\n offset += cellLength;\n }\n}\n\nfunction squarify(\n areas: number[],\n ids: string[],\n bounds: Bounds,\n padding: number,\n results: LayoutRect[],\n): void {\n if (areas.length === 0) return;\n\n const isWide = bounds.width >= bounds.height;\n const sideLength = isWide ? bounds.height : bounds.width;\n\n if (areas.length === 1) {\n layoutRow(areas, ids, bounds, isWide, padding, results);\n return;\n }\n\n const currentRow: number[] = [];\n const currentIds: string[] = [];\n\n let i = 0;\n while (i < areas.length) {\n const testRow = [...currentRow, areas[i]];\n\n if (\n currentRow.length === 0 ||\n worstAspectRatio(testRow, sideLength) <= worstAspectRatio(currentRow, sideLength)\n ) {\n currentRow.push(areas[i]);\n currentIds.push(ids[i]);\n i++;\n } else {\n layoutRow(currentRow, currentIds, bounds, isWide, padding, results);\n const rowSum = currentRow.reduce((a, b) => a + b, 0);\n const rowThickness = sideLength > 0 ? rowSum / sideLength : 0;\n\n if (isWide) {\n bounds = {\n x: bounds.x + rowThickness,\n y: bounds.y,\n width: bounds.width - rowThickness,\n height: bounds.height,\n };\n } else {\n bounds = {\n x: bounds.x,\n y: bounds.y + rowThickness,\n width: bounds.width,\n height: bounds.height - rowThickness,\n };\n }\n\n squarify(areas.slice(i), ids.slice(i), bounds, padding, results);\n return;\n }\n }\n\n if (currentRow.length > 0) {\n layoutRow(currentRow, currentIds, bounds, isWide, padding, results);\n }\n}\n\nexport function layoutSquarifiedTreemap(\n cells: readonly { id: string; weight: number }[],\n bounds: Bounds,\n padding: number,\n): LayoutRect[] {\n if (cells.length === 0) return [];\n\n const sorted = [...cells].sort((a, b) => b.weight - a.weight);\n const totalWeight = sorted.reduce((s, c) => s + Math.max(0, c.weight), 0);\n if (totalWeight === 0) return [];\n\n const totalArea = bounds.width * bounds.height;\n const areas = sorted.map(c => (Math.max(0, c.weight) / totalWeight) * totalArea);\n const ids = sorted.map(c => c.id);\n\n const results: LayoutRect[] = [];\n squarify(areas, ids, { ...bounds }, padding, results);\n return results;\n}\n","import type { HeatmapCell, HeatmapOptions, Theme } from '@tradecanvas/commons';\nimport { lerpColor } from '@tradecanvas/commons';\nimport type { LayoutRect } from './HeatmapLayout.js';\n\nfunction defaultValueFormat(value: number): string {\n const sign = value >= 0 ? '+' : '';\n return sign + value.toFixed(2) + '%';\n}\n\nfunction defaultLabelFormat(cell: HeatmapCell): string {\n return cell.label;\n}\n\nfunction computeCellColor(\n value: number,\n colorScale: NonNullable<HeatmapOptions['colorScale']>,\n): string {\n const min = colorScale.min ?? -5;\n const max = colorScale.max ?? 5;\n\n if (value <= min) return colorScale.negative;\n if (value >= max) return colorScale.positive;\n\n if (value < 0) {\n const t = 1 - value / min;\n return lerpColor(colorScale.negative, colorScale.zero, t);\n }\n const t = value / max;\n return lerpColor(colorScale.zero, colorScale.positive, t);\n}\n\nfunction roundRect(\n ctx: CanvasRenderingContext2D,\n x: number,\n y: number,\n w: number,\n h: number,\n r: number,\n): void {\n const radius = Math.min(r, w / 2, h / 2);\n ctx.beginPath();\n ctx.moveTo(x + radius, y);\n ctx.lineTo(x + w - radius, y);\n ctx.arcTo(x + w, y, x + w, y + radius, radius);\n ctx.lineTo(x + w, y + h - radius);\n ctx.arcTo(x + w, y + h, x + w - radius, y + h, radius);\n ctx.lineTo(x + radius, y + h);\n ctx.arcTo(x, y + h, x, y + h - radius, radius);\n ctx.lineTo(x, y + radius);\n ctx.arcTo(x, y, x + radius, y, radius);\n ctx.closePath();\n}\n\nexport interface HeatmapHitResult {\n cell: HeatmapCell;\n rect: LayoutRect;\n}\n\nfunction drawCellText(\n ctx: CanvasRenderingContext2D,\n cell: HeatmapCell,\n x: number,\n y: number,\n rw: number,\n rh: number,\n theme: Theme,\n showLabels: boolean,\n showValues: boolean,\n formatLabel: (c: HeatmapCell) => string,\n formatValue: (v: number) => string,\n): void {\n if (rw < 40 || rh < 30) return;\n\n const cx = x + rw / 2;\n const cy = y + rh / 2;\n\n ctx.save();\n ctx.shadowColor = 'rgba(0,0,0,0.6)';\n ctx.shadowBlur = 2;\n ctx.fillStyle = '#FFFFFF';\n ctx.textAlign = 'center';\n\n if (showLabels) {\n const labelText = formatLabel(cell);\n const fontSize = Math.min(theme.font.sizeMedium, rw / labelText.length * 1.5, rh / 4);\n ctx.font = 'bold ' + Math.max(8, fontSize) + 'px ' + theme.font.family;\n ctx.textBaseline = showValues ? 'bottom' : 'middle';\n ctx.fillText(labelText, cx, showValues ? cy - 1 : cy, rw - 8);\n }\n\n if (showValues) {\n const valText = formatValue(cell.value);\n const valSize = Math.min(theme.font.sizeSmall, rw / valText.length * 1.5, rh / 4);\n ctx.font = Math.max(7, valSize) + 'px ' + theme.font.family;\n ctx.textBaseline = showLabels ? 'top' : 'middle';\n ctx.fillText(valText, cx, showLabels ? cy + 1 : cy, rw - 8);\n }\n\n ctx.restore();\n}\n\nfunction drawTooltip(\n ctx: CanvasRenderingContext2D,\n cell: HeatmapCell,\n crosshairPos: { x: number; y: number },\n width: number,\n height: number,\n theme: Theme,\n formatLabel: (c: HeatmapCell) => string,\n formatValue: (v: number) => string,\n): void {\n const lines = [\n formatLabel(cell),\n formatValue(cell.value),\n ];\n if (cell.meta) {\n for (const [key, val] of Object.entries(cell.meta)) {\n lines.push(key + ': ' + String(val));\n }\n }\n\n ctx.save();\n ctx.font = theme.font.sizeSmall + 'px ' + theme.font.family;\n const maxTextW = Math.max(...lines.map(l => ctx.measureText(l).width));\n const tooltipW = maxTextW + 16;\n const lineH = theme.font.sizeSmall + 4;\n const tooltipH = lines.length * lineH + 12;\n\n let tx = crosshairPos.x + 14;\n let ty = crosshairPos.y - tooltipH / 2;\n if (tx + tooltipW > width) tx = crosshairPos.x - tooltipW - 14;\n if (ty < 0) ty = 0;\n if (ty + tooltipH > height) ty = height - tooltipH;\n\n ctx.fillStyle = theme.axisLabelBackground;\n ctx.globalAlpha = 0.92;\n roundRect(ctx, tx, ty, tooltipW, tooltipH, 4);\n ctx.fill();\n ctx.globalAlpha = 1;\n ctx.fillStyle = theme.text;\n ctx.textBaseline = 'top';\n ctx.textAlign = 'left';\n for (let i = 0; i < lines.length; i++) {\n ctx.fillText(lines[i], tx + 8, ty + 6 + i * lineH);\n }\n ctx.restore();\n}\n\nexport function renderHeatmap(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n cells: readonly HeatmapCell[],\n layoutRects: readonly LayoutRect[],\n options: HeatmapOptions,\n theme: Theme,\n crosshairPos: { x: number; y: number } | null,\n): HeatmapHitResult | null {\n if (cells.length === 0 || layoutRects.length === 0 || width <= 0 || height <= 0) return null;\n\n const colorScale = options.colorScale ?? {\n negative: '#EF5350',\n zero: '#424242',\n positive: '#26A69A',\n };\n const cellRadius = options.cellRadius ?? 4;\n const showLabels = options.showLabels !== false;\n const showValues = options.showValues !== false;\n const formatValue = options.valueFormat ?? defaultValueFormat;\n const formatLabel = options.labelFormat ?? defaultLabelFormat;\n\n const cellMap = new Map<string, HeatmapCell>();\n for (const c of cells) cellMap.set(c.id, c);\n\n let hoveredId: string | null = null;\n let hitResult: HeatmapHitResult | null = null;\n\n if (crosshairPos) {\n for (const lr of layoutRects) {\n const { x, y, width: rw, height: rh } = lr.rect;\n if (\n crosshairPos.x >= x &&\n crosshairPos.x <= x + rw &&\n crosshairPos.y >= y &&\n crosshairPos.y <= y + rh\n ) {\n hoveredId = lr.id;\n const cell = cellMap.get(lr.id);\n if (cell) {\n hitResult = { cell, rect: lr };\n }\n break;\n }\n }\n }\n\n ctx.fillStyle = theme.background;\n ctx.fillRect(0, 0, width, height);\n\n for (const lr of layoutRects) {\n const cell = cellMap.get(lr.id);\n if (!cell) continue;\n\n const { x, y, width: rw, height: rh } = lr.rect;\n if (rw <= 0 || rh <= 0) continue;\n\n const bgColor = computeCellColor(cell.value, colorScale);\n roundRect(ctx, x, y, rw, rh, cellRadius);\n ctx.fillStyle = bgColor;\n ctx.fill();\n\n drawCellText(ctx, cell, x, y, rw, rh, theme, showLabels, showValues, formatLabel, formatValue);\n\n if (lr.id === hoveredId) {\n roundRect(ctx, x, y, rw, rh, cellRadius);\n ctx.strokeStyle = '#FFFFFF';\n ctx.lineWidth = 1.5;\n ctx.stroke();\n }\n }\n\n if (hitResult && crosshairPos) {\n drawTooltip(ctx, hitResult.cell, crosshairPos, width, height, theme, formatLabel, formatValue);\n }\n\n return hitResult;\n}\n","import type { Theme, WaterfallBar, WaterfallOptions } from '@tradecanvas/commons';\nimport { computeTickStep } from '@tradecanvas/commons';\n\ntype BarType = 'positive' | 'negative' | 'total' | 'subtotal';\n\ninterface WaterfallLayoutBar {\n label: string;\n value: number;\n start: number;\n end: number;\n type: BarType;\n rectX: number;\n rectY: number;\n rectW: number;\n rectH: number;\n slotX: number;\n slotW: number;\n}\n\ninterface WaterfallLayout {\n left: number;\n right: number;\n top: number;\n bottom: number;\n plotWidth: number;\n plotHeight: number;\n}\n\nconst MARGIN_LEFT = 60;\nconst MARGIN_RIGHT = 12;\nconst MARGIN_TOP = 24;\nconst MARGIN_BOTTOM = 40;\nconst DEFAULT_BAR_WIDTH_RATIO = 0.7;\nconst MIN_BAR_HEIGHT = 1;\n\nfunction resolveType(bar: WaterfallBar): BarType {\n if (bar.type) return bar.type;\n if (bar.value > 0) return 'positive';\n if (bar.value < 0) return 'negative';\n return 'subtotal';\n}\n\nfunction defaultValueFormat(v: number): string {\n const abs = Math.abs(v);\n if (abs >= 1_000_000) return (v / 1_000_000).toFixed(2) + 'M';\n if (abs >= 1_000) return (v / 1_000).toFixed(1) + 'K';\n return v.toFixed(2);\n}\n\nfunction computeLayout(width: number, height: number): WaterfallLayout {\n return {\n left: MARGIN_LEFT,\n right: width - MARGIN_RIGHT,\n top: MARGIN_TOP,\n bottom: height - MARGIN_BOTTOM,\n plotWidth: width - MARGIN_LEFT - MARGIN_RIGHT,\n plotHeight: height - MARGIN_TOP - MARGIN_BOTTOM,\n };\n}\n\nfunction buildLayoutBars(\n data: readonly WaterfallBar[],\n layout: WaterfallLayout,\n barWidthRatio: number,\n valMin: number,\n valRange: number,\n): { bars: WaterfallLayoutBar[]; cumulatives: number[] } {\n const bars: WaterfallLayoutBar[] = new Array(data.length);\n const cumulatives: number[] = new Array(data.length);\n const slotWidth = layout.plotWidth / data.length;\n const barW = slotWidth * barWidthRatio;\n const slotPadding = (slotWidth - barW) / 2;\n const { left, bottom, plotHeight } = layout;\n\n let cumulative = 0;\n for (let i = 0; i < data.length; i++) {\n const bar = data[i];\n const type = resolveType(bar);\n let start: number;\n let end: number;\n\n if (type === 'total' || type === 'subtotal') {\n start = 0;\n end = bar.value;\n cumulative = bar.value;\n } else {\n start = cumulative;\n end = cumulative + bar.value;\n cumulative = end;\n }\n\n const top = Math.min(start, end);\n const bot = Math.max(start, end);\n const topY = bottom - ((top - valMin) / valRange) * plotHeight;\n const botY = bottom - ((bot - valMin) / valRange) * plotHeight;\n const rectY = Math.min(topY, botY);\n const rectH = Math.max(Math.abs(botY - topY), MIN_BAR_HEIGHT);\n const slotX = left + i * slotWidth;\n const rectX = slotX + slotPadding;\n\n bars[i] = {\n label: bar.label,\n value: bar.value,\n start,\n end,\n type,\n rectX,\n rectY,\n rectW: barW,\n rectH,\n slotX,\n slotW: slotWidth,\n };\n cumulatives[i] = cumulative;\n }\n\n return { bars, cumulatives };\n}\n\nfunction computeValueRange(\n data: readonly WaterfallBar[],\n): { valMin: number; valMax: number } {\n if (data.length === 0) return { valMin: 0, valMax: 1 };\n\n let min = 0;\n let max = 0;\n let cumulative = 0;\n\n for (let i = 0; i < data.length; i++) {\n const bar = data[i];\n const type = resolveType(bar);\n let start: number;\n let end: number;\n\n if (type === 'total' || type === 'subtotal') {\n start = 0;\n end = bar.value;\n cumulative = bar.value;\n } else {\n start = cumulative;\n end = cumulative + bar.value;\n cumulative = end;\n }\n\n if (start < min) min = start;\n if (end < min) min = end;\n if (start > max) max = start;\n if (end > max) max = end;\n }\n\n const range = max - min || 1;\n const padding = range * 0.1;\n return { valMin: min - padding, valMax: max + padding };\n}\n\nfunction drawBackground(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n bg: string,\n): void {\n ctx.fillStyle = bg;\n ctx.fillRect(0, 0, width, height);\n}\n\nfunction drawGrid(\n ctx: CanvasRenderingContext2D,\n layout: WaterfallLayout,\n valMin: number,\n valMax: number,\n theme: Theme,\n valueFormat: (v: number) => string,\n): void {\n const { left, right, top, bottom, plotHeight } = layout;\n const valRange = valMax - valMin || 1;\n\n ctx.strokeStyle = theme.grid;\n ctx.lineWidth = 0.5;\n ctx.fillStyle = theme.axisLabel;\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n ctx.textAlign = 'right';\n ctx.textBaseline = 'middle';\n\n const step = computeTickStep(valMin, valMax, 5);\n const firstTick = Math.ceil(valMin / step) * step;\n\n // Batch horizontal grid lines\n ctx.beginPath();\n for (let v = firstTick; v <= valMax; v += step) {\n const y = Math.round(bottom - ((v - valMin) / valRange) * plotHeight) + 0.5;\n if (y < top || y > bottom) continue;\n ctx.moveTo(left, y);\n ctx.lineTo(right, y);\n }\n ctx.stroke();\n\n // Labels\n for (let v = firstTick; v <= valMax; v += step) {\n const y = bottom - ((v - valMin) / valRange) * plotHeight;\n if (y < top - 1 || y > bottom + 1) continue;\n ctx.fillText(valueFormat(v), left - 6, y);\n }\n\n // Zero baseline\n if (valMin < 0 && valMax > 0) {\n const zeroY = Math.round(bottom - ((0 - valMin) / valRange) * plotHeight) + 0.5;\n ctx.strokeStyle = theme.axisLine;\n ctx.lineWidth = 1;\n ctx.beginPath();\n ctx.moveTo(left, zeroY);\n ctx.lineTo(right, zeroY);\n ctx.stroke();\n }\n}\n\nfunction drawBars(\n ctx: CanvasRenderingContext2D,\n bars: readonly WaterfallLayoutBar[],\n colors: Record<BarType, string>,\n): void {\n // Group bars by color, draw each color group in a single fill() call.\n // This minimizes fillStyle mutations and path starts.\n const groupOrder: BarType[] = ['positive', 'negative', 'total', 'subtotal'];\n for (let g = 0; g < groupOrder.length; g++) {\n const type = groupOrder[g];\n const color = colors[type];\n let hasAny = false;\n ctx.beginPath();\n for (let i = 0; i < bars.length; i++) {\n const b = bars[i];\n if (b.type !== type) continue;\n const x = Math.round(b.rectX);\n const y = Math.round(b.rectY);\n const w = Math.round(b.rectW);\n const h = Math.round(b.rectH);\n ctx.rect(x, y, w, h);\n hasAny = true;\n }\n if (hasAny) {\n ctx.fillStyle = color;\n ctx.fill();\n }\n }\n}\n\nfunction drawConnectors(\n ctx: CanvasRenderingContext2D,\n bars: readonly WaterfallLayoutBar[],\n layout: WaterfallLayout,\n valMin: number,\n valRange: number,\n color: string,\n style: 'dashed' | 'solid' | 'none',\n): void {\n if (style === 'none' || bars.length < 2) return;\n\n const { bottom, plotHeight } = layout;\n\n ctx.strokeStyle = color;\n ctx.lineWidth = 1;\n if (style === 'dashed') {\n ctx.setLineDash([4, 4]);\n } else {\n ctx.setLineDash([]);\n }\n\n // Batch all connectors into a single path\n ctx.beginPath();\n for (let i = 0; i < bars.length - 1; i++) {\n const current = bars[i];\n const next = bars[i + 1];\n\n // Connector sits at the \"end\" of current bar (running total).\n // For total/subtotal bars, end is bar.value (absolute).\n // For gain/loss, end is the post-bar cumulative.\n const endValue = current.end;\n const y = Math.round(bottom - ((endValue - valMin) / valRange) * plotHeight) + 0.5;\n\n const x1 = Math.round(current.rectX + current.rectW);\n const x2 = Math.round(next.rectX);\n if (x2 <= x1) continue;\n\n ctx.moveTo(x1, y);\n ctx.lineTo(x2, y);\n }\n ctx.stroke();\n ctx.setLineDash([]);\n}\n\nfunction drawValueLabels(\n ctx: CanvasRenderingContext2D,\n bars: readonly WaterfallLayoutBar[],\n cumulatives: readonly number[],\n theme: Theme,\n valueFormat: (v: number) => string,\n showDelta: boolean,\n): void {\n ctx.fillStyle = theme.text;\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n ctx.textAlign = 'center';\n\n for (let i = 0; i < bars.length; i++) {\n const b = bars[i];\n let text: string;\n if (b.type === 'total' || b.type === 'subtotal') {\n text = valueFormat(b.value);\n } else if (showDelta) {\n const sign = b.value >= 0 ? '+' : '';\n text = `${sign}${valueFormat(b.value)}`;\n } else {\n text = valueFormat(cumulatives[i]);\n }\n\n const cx = b.rectX + b.rectW / 2;\n // If bar goes down (negative gain/loss), put label below\n const isDown = b.end < b.start;\n if (isDown) {\n ctx.textBaseline = 'top';\n ctx.fillText(text, cx, b.rectY + b.rectH + 4);\n } else {\n ctx.textBaseline = 'bottom';\n ctx.fillText(text, cx, b.rectY - 4);\n }\n }\n}\n\nfunction drawCategoryLabels(\n ctx: CanvasRenderingContext2D,\n bars: readonly WaterfallLayoutBar[],\n layout: WaterfallLayout,\n theme: Theme,\n labelFormat: (label: string) => string,\n): void {\n ctx.fillStyle = theme.axisLabel;\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n\n const labelY = layout.bottom + 6;\n const maxWidth = bars.length > 0 ? bars[0].slotW - 4 : 0;\n\n // Rotate if any label would overflow its slot\n let needsRotate = false;\n for (let i = 0; i < bars.length; i++) {\n const w = ctx.measureText(labelFormat(bars[i].label)).width;\n if (w > maxWidth) { needsRotate = true; break; }\n }\n\n if (!needsRotate) {\n for (let i = 0; i < bars.length; i++) {\n const b = bars[i];\n const cx = b.slotX + b.slotW / 2;\n ctx.fillText(labelFormat(b.label), cx, labelY);\n }\n return;\n }\n\n // Rotated path: save/restore once, mutate transform per label\n ctx.save();\n ctx.textAlign = 'right';\n ctx.textBaseline = 'middle';\n for (let i = 0; i < bars.length; i++) {\n const b = bars[i];\n const cx = b.slotX + b.slotW / 2;\n ctx.setTransform(1, 0, 0, 1, cx, labelY + 4);\n ctx.rotate(-Math.PI / 4);\n ctx.fillText(labelFormat(b.label), 0, 0);\n }\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.restore();\n}\n\nfunction findHitBar(\n bars: readonly WaterfallLayoutBar[],\n x: number,\n layout: WaterfallLayout,\n): number | null {\n if (x < layout.left || x > layout.right) return null;\n // Slot-based hit test (covers gaps between bars too)\n for (let i = 0; i < bars.length; i++) {\n const b = bars[i];\n if (x >= b.slotX && x <= b.slotX + b.slotW) return i;\n }\n return null;\n}\n\nfunction drawCrosshairTooltip(\n ctx: CanvasRenderingContext2D,\n bars: readonly WaterfallLayoutBar[],\n cumulatives: readonly number[],\n hitIndex: number,\n crosshairPos: { x: number; y: number },\n layout: WaterfallLayout,\n theme: Theme,\n valueFormat: (v: number) => string,\n): void {\n const bar = bars[hitIndex];\n const cumulative = cumulatives[hitIndex];\n\n // Vertical guide line across the slot center\n const cx = Math.round(bar.slotX + bar.slotW / 2) + 0.5;\n ctx.strokeStyle = theme.crosshair;\n ctx.lineWidth = 0.5;\n ctx.setLineDash([4, 4]);\n ctx.beginPath();\n ctx.moveTo(cx, layout.top);\n ctx.lineTo(cx, layout.bottom);\n ctx.stroke();\n ctx.setLineDash([]);\n\n const lines = [\n bar.label,\n `Value: ${bar.value >= 0 && (bar.type === 'positive' || bar.type === 'negative') ? '+' : ''}${valueFormat(bar.value)}`,\n `Total: ${valueFormat(cumulative)}`,\n ];\n\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n let maxTextWidth = 0;\n for (let i = 0; i < lines.length; i++) {\n const w = ctx.measureText(lines[i]).width;\n if (w > maxTextWidth) maxTextWidth = w;\n }\n const tooltipW = maxTextWidth + 16;\n const tooltipH = lines.length * (theme.font.sizeSmall + 4) + 12;\n\n let tx = crosshairPos.x + 10;\n let ty = crosshairPos.y - tooltipH / 2;\n if (tx + tooltipW > layout.right) tx = crosshairPos.x - tooltipW - 10;\n if (ty < layout.top) ty = layout.top;\n if (ty + tooltipH > layout.bottom) ty = layout.bottom - tooltipH;\n\n ctx.fillStyle = theme.axisLabelBackground;\n ctx.globalAlpha = 0.9;\n ctx.fillRect(tx, ty, tooltipW, tooltipH);\n ctx.globalAlpha = 1;\n ctx.fillStyle = theme.text;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'top';\n const lineH = theme.font.sizeSmall + 4;\n for (let i = 0; i < lines.length; i++) {\n ctx.fillText(lines[i], tx + 8, ty + 6 + i * lineH);\n }\n}\n\nexport function renderWaterfall(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n options: WaterfallOptions,\n theme: Theme,\n crosshairPos: { x: number; y: number } | null,\n): { hitBar: number | null } {\n const { data } = options;\n if (!data || data.length === 0 || width <= 0 || height <= 0) {\n return { hitBar: null };\n }\n\n const positiveColor = options.positiveColor ?? theme.candleUp;\n const negativeColor = options.negativeColor ?? theme.candleDown;\n const totalColor = options.totalColor ?? theme.lineColor;\n const subtotalColor = options.subtotalColor ?? theme.textSecondary;\n const connectorColor = options.connectorColor ?? theme.textSecondary;\n const connectorStyle = options.connectorStyle ?? 'dashed';\n const barWidthRatio = options.barWidth ?? DEFAULT_BAR_WIDTH_RATIO;\n const showValues = options.showValues !== false;\n const showDelta = options.showDelta !== false;\n const valueFormat = options.valueFormat ?? defaultValueFormat;\n const labelFormat = options.labelFormat ?? ((l: string) => l);\n\n const { valMin, valMax } = computeValueRange(data);\n const valRange = valMax - valMin || 1;\n const layout = computeLayout(width, height);\n const { bars, cumulatives } = buildLayoutBars(data, layout, barWidthRatio, valMin, valRange);\n\n drawBackground(ctx, width, height, theme.background);\n drawGrid(ctx, layout, valMin, valMax, theme, valueFormat);\n\n // Connectors first (behind bars)\n drawConnectors(ctx, bars, layout, valMin, valRange, connectorColor, connectorStyle);\n\n // Bars (batched by color)\n drawBars(ctx, bars, {\n positive: positiveColor,\n negative: negativeColor,\n total: totalColor,\n subtotal: subtotalColor,\n });\n\n if (showValues) {\n drawValueLabels(ctx, bars, cumulatives, theme, valueFormat, showDelta);\n }\n\n drawCategoryLabels(ctx, bars, layout, theme, labelFormat);\n\n // Crosshair / tooltip\n const hitBar = crosshairPos ? findHitBar(bars, crosshairPos.x, layout) : null;\n if (crosshairPos && hitBar !== null) {\n drawCrosshairTooltip(ctx, bars, cumulatives, hitBar, crosshairPos, layout, theme, valueFormat);\n }\n\n return { hitBar };\n}\n","import type { GaugeOptions, GaugeZone, Theme } from '@tradecanvas/commons';\n\nconst DEG_TO_RAD = Math.PI / 180;\nconst DEFAULT_START_DEG = 135; // bottom-left (canvas: angle measured from +x axis, clockwise)\nconst DEFAULT_END_DEG = 405; // bottom-right (135 + 270)\nconst DEFAULT_THICKNESS = 0.25;\n\ninterface GaugeGeometry {\n cx: number;\n cy: number;\n radius: number;\n innerRadius: number;\n startAngle: number;\n endAngle: number;\n angleRange: number;\n min: number;\n max: number;\n range: number;\n}\n\nfunction defaultValueFormat(v: number): string {\n const abs = Math.abs(v);\n if (abs >= 1_000_000) return (v / 1_000_000).toFixed(2) + 'M';\n if (abs >= 1_000) return (v / 1_000).toFixed(1) + 'K';\n if (Number.isInteger(v)) return v.toFixed(0);\n return v.toFixed(1);\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n if (value < min) return min;\n if (value > max) return max;\n return value;\n}\n\nfunction computeGeometry(\n width: number,\n height: number,\n options: GaugeOptions,\n): GaugeGeometry {\n const min = options.min ?? 0;\n const max = options.max ?? 100;\n const range = (max - min) || 1;\n\n const startAngle = (options.startAngle ?? DEFAULT_START_DEG) * DEG_TO_RAD;\n const endAngle = (options.endAngle ?? DEFAULT_END_DEG) * DEG_TO_RAD;\n const thicknessRatio = options.thickness ?? DEFAULT_THICKNESS;\n\n // Leave room for labels\n const margin = 24;\n const cx = width / 2;\n // Bias center down a bit so the open bottom has room for labels\n const cy = height / 2 + height * 0.05;\n const radius = Math.max(10, Math.min(width, height) / 2 - margin);\n const innerRadius = Math.max(2, radius * (1 - thicknessRatio));\n\n return {\n cx,\n cy,\n radius,\n innerRadius,\n startAngle,\n endAngle,\n angleRange: endAngle - startAngle,\n min,\n max,\n range,\n };\n}\n\nfunction valueToAngle(value: number, geo: GaugeGeometry): number {\n const t = clamp((value - geo.min) / geo.range, 0, 1);\n return geo.startAngle + geo.angleRange * t;\n}\n\nfunction drawBackground(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n bg: string,\n): void {\n ctx.fillStyle = bg;\n ctx.fillRect(0, 0, width, height);\n}\n\nfunction drawTrackArc(\n ctx: CanvasRenderingContext2D,\n geo: GaugeGeometry,\n trackColor: string,\n): void {\n ctx.beginPath();\n ctx.arc(geo.cx, geo.cy, geo.radius, geo.startAngle, geo.endAngle, false);\n ctx.arc(geo.cx, geo.cy, geo.innerRadius, geo.endAngle, geo.startAngle, true);\n ctx.closePath();\n ctx.fillStyle = trackColor;\n ctx.fill();\n}\n\nfunction drawZoneArc(\n ctx: CanvasRenderingContext2D,\n geo: GaugeGeometry,\n zone: GaugeZone,\n): void {\n const from = clamp(zone.from, geo.min, geo.max);\n const to = clamp(zone.to, geo.min, geo.max);\n if (to <= from) return;\n\n const a0 = valueToAngle(from, geo);\n const a1 = valueToAngle(to, geo);\n\n ctx.beginPath();\n ctx.arc(geo.cx, geo.cy, geo.radius, a0, a1, false);\n ctx.arc(geo.cx, geo.cy, geo.innerRadius, a1, a0, true);\n ctx.closePath();\n ctx.fillStyle = zone.color;\n ctx.fill();\n}\n\nfunction drawValueArc(\n ctx: CanvasRenderingContext2D,\n geo: GaugeGeometry,\n value: number,\n color: string,\n alpha: number,\n): void {\n const valueAngle = valueToAngle(value, geo);\n if (valueAngle <= geo.startAngle) return;\n\n ctx.globalAlpha = alpha;\n ctx.beginPath();\n ctx.arc(geo.cx, geo.cy, geo.radius, geo.startAngle, valueAngle, false);\n ctx.arc(geo.cx, geo.cy, geo.innerRadius, valueAngle, geo.startAngle, true);\n ctx.closePath();\n ctx.fillStyle = color;\n ctx.fill();\n ctx.globalAlpha = 1;\n}\n\nfunction drawNeedle(\n ctx: CanvasRenderingContext2D,\n geo: GaugeGeometry,\n value: number,\n color: string,\n): void {\n const angle = valueToAngle(value, geo);\n // Cache trig\n const cos = Math.cos(angle);\n const sin = Math.sin(angle);\n\n const tipRadius = geo.radius - 2;\n const baseRadius = geo.innerRadius * 0.25;\n\n // Needle as a narrow triangle for better presence; all in one path.\n const perpX = -sin;\n const perpY = cos;\n const baseHalf = 4;\n\n const tipX = geo.cx + cos * tipRadius;\n const tipY = geo.cy + sin * tipRadius;\n const leftX = geo.cx + perpX * baseHalf - cos * baseRadius;\n const leftY = geo.cy + perpY * baseHalf - sin * baseRadius;\n const rightX = geo.cx - perpX * baseHalf - cos * baseRadius;\n const rightY = geo.cy - perpY * baseHalf - sin * baseRadius;\n\n ctx.beginPath();\n ctx.moveTo(tipX, tipY);\n ctx.lineTo(leftX, leftY);\n ctx.lineTo(rightX, rightY);\n ctx.closePath();\n ctx.fillStyle = color;\n ctx.fill();\n\n // Center hub\n ctx.beginPath();\n ctx.arc(geo.cx, geo.cy, Math.max(4, geo.innerRadius * 0.12), 0, Math.PI * 2);\n ctx.fill();\n}\n\nfunction drawCenterLabel(\n ctx: CanvasRenderingContext2D,\n geo: GaugeGeometry,\n valueText: string,\n subtitle: string | undefined,\n theme: Theme,\n): void {\n const mainSize = Math.round(geo.innerRadius * 0.55);\n const subSize = Math.round(theme.font.sizeMedium);\n\n ctx.fillStyle = theme.text;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.font = `600 ${mainSize}px ${theme.font.family}`;\n\n const hasSubtitle = !!subtitle;\n const mainY = hasSubtitle ? geo.cy - subSize * 0.6 : geo.cy - mainSize * 0.1;\n ctx.fillText(valueText, geo.cx, mainY);\n\n if (hasSubtitle) {\n ctx.fillStyle = theme.textSecondary;\n ctx.font = `${subSize}px ${theme.font.family}`;\n ctx.fillText(subtitle!, geo.cx, geo.cy + mainSize * 0.55);\n }\n}\n\nfunction drawEndLabels(\n ctx: CanvasRenderingContext2D,\n geo: GaugeGeometry,\n valueFormat: (v: number) => string,\n theme: Theme,\n): void {\n ctx.fillStyle = theme.textSecondary;\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n\n // Min at start angle, max at end angle — positioned slightly outside the track\n const labelRadius = geo.radius + 10;\n\n const minCos = Math.cos(geo.startAngle);\n const minSin = Math.sin(geo.startAngle);\n const maxCos = Math.cos(geo.endAngle);\n const maxSin = Math.sin(geo.endAngle);\n\n const minX = geo.cx + minCos * labelRadius;\n const minY = geo.cy + minSin * labelRadius;\n const maxX = geo.cx + maxCos * labelRadius;\n const maxY = geo.cy + maxSin * labelRadius;\n\n ctx.textBaseline = 'middle';\n ctx.textAlign = minCos < -0.2 ? 'right' : minCos > 0.2 ? 'left' : 'center';\n ctx.fillText(valueFormat(geo.min), minX, minY);\n\n ctx.textAlign = maxCos < -0.2 ? 'right' : maxCos > 0.2 ? 'left' : 'center';\n ctx.fillText(valueFormat(geo.max), maxX, maxY);\n}\n\nfunction drawZoneLabels(\n ctx: CanvasRenderingContext2D,\n geo: GaugeGeometry,\n zones: readonly GaugeZone[],\n theme: Theme,\n): void {\n ctx.fillStyle = theme.textSecondary;\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n\n const labelRadius = (geo.radius + geo.innerRadius) / 2;\n\n for (let i = 0; i < zones.length; i++) {\n const zone = zones[i];\n if (!zone.label) continue;\n const mid = (clamp(zone.from, geo.min, geo.max) + clamp(zone.to, geo.min, geo.max)) / 2;\n const angle = valueToAngle(mid, geo);\n const x = geo.cx + Math.cos(angle) * labelRadius;\n const y = geo.cy + Math.sin(angle) * labelRadius;\n ctx.fillText(zone.label, x, y);\n }\n}\n\nexport function renderGauge(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n options: GaugeOptions,\n theme: Theme,\n displayValue: number,\n): void {\n if (width <= 0 || height <= 0) return;\n\n const geo = computeGeometry(width, height, options);\n const trackColor = options.trackColor ?? theme.grid;\n const needleColor = options.needleColor ?? theme.text;\n const showValue = options.showValue !== false;\n const showZoneLabels = options.showZoneLabels === true;\n const valueFormat = options.valueFormat ?? defaultValueFormat;\n\n const clampedValue = clamp(displayValue, geo.min, geo.max);\n\n drawBackground(ctx, width, height, theme.background);\n\n // 1. Track\n drawTrackArc(ctx, geo, trackColor);\n\n // 2. Zones\n const zones = options.zones;\n if (zones && zones.length > 0) {\n for (let i = 0; i < zones.length; i++) {\n drawZoneArc(ctx, geo, zones[i]);\n }\n }\n\n // 3. Value arc — subtle tint using needle color (or text color) so the filled\n // portion reads even when zones are transparent.\n drawValueArc(ctx, geo, clampedValue, needleColor, 0.12);\n\n // 4. Needle + hub\n drawNeedle(ctx, geo, clampedValue, needleColor);\n\n // 5. Center labels\n if (showValue) {\n drawCenterLabel(ctx, geo, valueFormat(clampedValue), options.label, theme);\n }\n\n // 6. Min/max labels\n drawEndLabels(ctx, geo, valueFormat, theme);\n\n // 7. Zone labels\n if (showZoneLabels && zones && zones.length > 0) {\n drawZoneLabels(ctx, geo, zones, theme);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/engine/CanvasLayer.ts","../src/engine/LayerManager.ts","../src/engine/RenderLoop.ts","../src/engine/DPRManager.ts","../src/viewport/ScaleMapping.ts","../src/engine/RenderEngine.ts","../src/viewport/Viewport.ts","../src/viewport/DataWindow.ts","../src/charts/CandlestickRenderer.ts","../src/charts/LineRenderer.ts","../src/charts/AreaRenderer.ts","../src/charts/BarRenderer.ts","../src/charts/HollowCandleRenderer.ts","../src/charts/BaselineRenderer.ts","../src/charts/RenkoRenderer.ts","../src/charts/KagiRenderer.ts","../src/charts/PointAndFigureRenderer.ts","../src/charts/VolumeCandleRenderer.ts","../src/charts/EquivolumeRenderer.ts","../src/charts/HLCAreaRenderer.ts","../src/charts/StepLineRenderer.ts","../src/charts/LineWithMarkersRenderer.ts","../src/charts/VolumeRenderer.ts","../src/charts/VolumeProfileRenderer.ts","../src/charts/CompareRenderer.ts","../src/charts/transforms/heikinAshi.ts","../src/charts/transforms/renko.ts","../src/charts/transforms/lineBreak.ts","../src/charts/transforms/kagi.ts","../src/charts/transforms/pointAndFigure.ts","../src/charts/transforms/rangeBars.ts","../src/indicators/IndicatorBase.ts","../src/indicators/IndicatorEngine.ts","../src/indicators/params.ts","../src/indicators/overlay/SMA.ts","../src/indicators/overlay/EMA.ts","../src/indicators/overlay/BollingerBands.ts","../src/indicators/overlay/VWAP.ts","../src/indicators/overlay/Ichimoku.ts","../src/indicators/overlay/ParabolicSAR.ts","../src/indicators/overlay/Supertrend.ts","../src/indicators/overlay/KeltnerChannel.ts","../src/indicators/overlay/DonchianChannel.ts","../src/indicators/overlay/PivotPoints.ts","../src/indicators/overlay/AnchoredVWAP.ts","../src/indicators/overlay/ZigZag.ts","../src/indicators/overlay/LinearRegressionChannel.ts","../src/indicators/overlay/HullMA.ts","../src/indicators/panel/AwesomeOscillator.ts","../src/indicators/panel/ChaikinOscillator.ts","../src/indicators/panel/RSI.ts","../src/indicators/panel/MACD.ts","../src/indicators/panel/Stochastic.ts","../src/indicators/panel/ATR.ts","../src/indicators/panel/ADX.ts","../src/indicators/panel/OBV.ts","../src/indicators/panel/WilliamsR.ts","../src/indicators/panel/CCI.ts","../src/indicators/panel/MFI.ts","../src/indicators/panel/Aroon.ts","../src/indicators/panel/ROC.ts","../src/indicators/panel/TSI.ts","../src/indicators/panel/CMF.ts","../src/indicators/panel/StdDev.ts","../src/indicators/panel/VolumeProfile.ts","../src/indicators/panel/AccumulationDistribution.ts","../src/indicators/panel/VROC.ts","../src/indicators/registry.ts","../src/indicators/worker/messages.ts","../src/indicators/worker/IndicatorWorkerHost.ts","../src/axis/GridRenderer.ts","../src/axis/PriceAxis.ts","../src/axis/TimeAxis.ts","../src/interaction/InteractionManager.ts","../src/interaction/PanHandler.ts","../src/interaction/ZoomHandler.ts","../src/interaction/AxisDragHandler.ts","../src/interaction/CrosshairHandler.ts","../src/interaction/KeyboardHandler.ts","../src/interaction/CrosshairTooltip.ts","../src/interaction/PinnedTooltip.ts","../src/events/EventBus.ts","../src/drawings/DrawingBase.ts","../src/drawings/DrawingManager.ts","../src/drawings/DrawingRenderer.ts","../src/drawings/tools/TrendLine.ts","../src/drawings/tools/HorizontalLine.ts","../src/drawings/tools/VerticalLine.ts","../src/drawings/tools/Ray.ts","../src/drawings/tools/ExtendedLine.ts","../src/drawings/tools/ParallelChannel.ts","../src/drawings/tools/RegressionChannel.ts","../src/drawings/tools/FibRetracement.ts","../src/drawings/tools/FibExtension.ts","../src/drawings/tools/Rectangle.ts","../src/drawings/tools/Ellipse.ts","../src/drawings/tools/Triangle.ts","../src/drawings/tools/Pitchfork.ts","../src/drawings/tools/ElliottWave.ts","../src/drawings/tools/PriceRange.ts","../src/drawings/tools/DateRange.ts","../src/drawings/tools/Measure.ts","../src/drawings/tools/TextAnnotation.ts","../src/drawings/tools/Arrow.ts","../src/drawings/tools/GannFan.ts","../src/drawings/tools/GannBox.ts","../src/drawings/tools/AnchoredVWAP.ts","../src/drawings/tools/VolumeProfileRange.ts","../src/drawings/tools/FibTimeZones.ts","../src/drawings/tools/index.ts","../src/trading/OrderRenderer.ts","../src/trading/positionFormat.ts","../src/trading/PositionRenderer.ts","../src/trading/DepthOverlay.ts","../src/trading/TradingDragHandler.ts","../src/trading/TradingContextMenu.ts","../src/trading/TradingManager.ts","../src/trading/TradingRenderer.ts","../src/realtime/Emitter.ts","../src/realtime/TickAggregator.ts","../src/realtime/ReconnectManager.ts","../src/realtime/CurrentPriceLine.ts","../src/realtime/StreamManager.ts","../src/realtime/ReplayController.ts","../src/realtime/adapters/binanceTypes.ts","../src/realtime/adapters/BinanceAdapter.ts","../src/realtime/adapters/MockAdapter.ts","../src/ui/ChartLegend.ts","../src/ui/Screenshot.ts","../src/ui/Watermark.ts","../src/ui/BarCountdown.ts","../src/ui/SessionBreaks.ts","../src/features/AlertManager.ts","../src/features/ReplayManager.ts","../src/features/ChartState.ts","../src/features/UndoRedoManager.ts","../src/features/DataExporter.ts","../src/features/SignalMarkerManager.ts","../src/features/TradeZoneManager.ts","../src/features/MeasureOverlay.ts","../src/animation/Animator.ts","../src/finance/BaseFinanceChart.ts","../src/finance/FinanceCrosshair.ts","../src/finance/SparklineRenderer.ts","../src/finance/DepthChartRenderer.ts","../src/finance/EquityCurveRenderer.ts","../src/finance/HeatmapLayout.ts","../src/finance/HeatmapRenderer.ts","../src/finance/WaterfallRenderer.ts","../src/finance/GaugeRenderer.ts"],"sourcesContent":["import type { Size } from '@tradecanvas/commons';\n\nexport class CanvasLayer {\n readonly canvas: HTMLCanvasElement;\n readonly ctx: CanvasRenderingContext2D;\n private dpr = 1;\n\n constructor(\n container: HTMLElement,\n zIndex: number,\n ) {\n this.canvas = document.createElement('canvas');\n this.canvas.style.position = 'absolute';\n this.canvas.style.top = '0';\n this.canvas.style.left = '0';\n this.canvas.style.zIndex = String(zIndex);\n this.canvas.style.pointerEvents = 'none';\n this.ctx = this.canvas.getContext('2d')!;\n container.appendChild(this.canvas);\n }\n\n resize(size: Size, dpr: number): void {\n this.dpr = dpr;\n const w = Math.round(size.width * dpr);\n const h = Math.round(size.height * dpr);\n // Only resize if dimensions changed (avoids unnecessary canvas clear)\n if (this.canvas.width !== w || this.canvas.height !== h) {\n this.canvas.width = w;\n this.canvas.height = h;\n }\n this.canvas.style.width = `${size.width}px`;\n this.canvas.style.height = `${size.height}px`;\n this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n }\n\n clear(): void {\n // Reset to identity, clear physical pixels, restore DPR transform\n this.ctx.setTransform(1, 0, 0, 1, 0, 0);\n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n this.ctx.setTransform(this.dpr, 0, 0, this.dpr, 0, 0);\n }\n\n getSize(): Size {\n return {\n width: this.canvas.width / this.dpr,\n height: this.canvas.height / this.dpr,\n };\n }\n\n destroy(): void {\n this.canvas.remove();\n }\n}\n","import type { Size } from '@tradecanvas/commons';\nimport { LayerType } from '@tradecanvas/commons';\nimport { CanvasLayer } from './CanvasLayer.js';\n\nexport class LayerManager {\n private layers = new Map<LayerType, CanvasLayer>();\n\n constructor(private container: HTMLElement) {}\n\n createLayers(): void {\n // Destroy any existing layers first to prevent duplicates\n this.destroy();\n\n for (const type of [\n LayerType.Background,\n LayerType.Main,\n LayerType.Overlay,\n LayerType.UI,\n ]) {\n this.layers.set(type, new CanvasLayer(this.container, type));\n }\n }\n\n getLayer(type: LayerType): CanvasLayer | undefined {\n return this.layers.get(type);\n }\n\n resize(size: Size, dpr: number): void {\n for (const layer of this.layers.values()) {\n layer.resize(size, dpr);\n }\n }\n\n destroy(): void {\n for (const layer of this.layers.values()) {\n layer.destroy();\n }\n this.layers.clear();\n }\n}\n","import { LayerType } from '@tradecanvas/commons';\n\nexport type RenderCallback = (dirtyLayers: ReadonlySet<LayerType>) => void;\n\nexport class RenderLoop {\n private animFrameId = 0;\n private running = false;\n private dirtyLayers = new Set<LayerType>();\n // Swap set — avoids allocation per frame\n private swapLayers = new Set<LayerType>();\n private callback: RenderCallback | null = null;\n\n setCallback(cb: RenderCallback): void {\n this.callback = cb;\n }\n\n markDirty(layer: LayerType): void {\n this.dirtyLayers.add(layer);\n if (this.running && !this.animFrameId) {\n this.scheduleFrame();\n }\n }\n\n markAllDirty(): void {\n this.dirtyLayers.add(LayerType.Background);\n this.dirtyLayers.add(LayerType.Main);\n this.dirtyLayers.add(LayerType.Overlay);\n this.dirtyLayers.add(LayerType.UI);\n if (this.running && !this.animFrameId) {\n this.scheduleFrame();\n }\n }\n\n start(): void {\n this.running = true;\n this.markAllDirty();\n }\n\n stop(): void {\n this.running = false;\n if (this.animFrameId) {\n cancelAnimationFrame(this.animFrameId);\n this.animFrameId = 0;\n }\n }\n\n private scheduleFrame(): void {\n this.animFrameId = requestAnimationFrame(() => {\n this.animFrameId = 0;\n if (!this.running || !this.callback) return;\n if (this.dirtyLayers.size > 0) {\n // Swap sets to avoid allocation — pass current dirty set, clear it via swap\n const toRender = this.dirtyLayers;\n this.dirtyLayers = this.swapLayers;\n this.callback(toRender);\n toRender.clear();\n this.swapLayers = toRender;\n }\n });\n }\n}\n","import type { Size } from '@tradecanvas/commons';\n\nexport type ResizeCallback = (size: Size, dpr: number) => void;\n\nexport class DPRManager {\n private observer: ResizeObserver | null = null;\n private callback: ResizeCallback | null = null;\n private currentDpr = 1;\n private resizeScheduled = false;\n private cachedSize: Size;\n\n constructor(private container: HTMLElement) {\n this.currentDpr = window.devicePixelRatio || 1;\n this.cachedSize = { width: container.clientWidth, height: container.clientHeight };\n }\n\n getDpr(): number {\n return this.currentDpr;\n }\n\n getContainerSize(): Size {\n return this.cachedSize;\n }\n\n /** Read live container size (bypasses cache). Use when externally triggered. */\n readContainerSize(): Size {\n const w = this.container.clientWidth;\n const h = this.container.clientHeight;\n if (w !== this.cachedSize.width || h !== this.cachedSize.height) {\n this.cachedSize = { width: w, height: h };\n }\n return this.cachedSize;\n }\n\n onResize(cb: ResizeCallback): void {\n this.callback = cb;\n this.observer = new ResizeObserver(() => {\n // Debounce via rAF — collapse multiple resize events into one per frame\n if (this.resizeScheduled) return;\n this.resizeScheduled = true;\n requestAnimationFrame(() => {\n this.resizeScheduled = false;\n this.currentDpr = window.devicePixelRatio || 1;\n const newW = this.container.clientWidth;\n const newH = this.container.clientHeight;\n // Skip if size hasn't actually changed\n if (newW === this.cachedSize.width && newH === this.cachedSize.height) return;\n this.cachedSize = { width: newW, height: newH };\n this.callback?.(this.cachedSize, this.currentDpr);\n });\n });\n this.observer.observe(this.container);\n }\n\n destroy(): void {\n this.observer?.disconnect();\n this.observer = null;\n this.callback = null;\n }\n}\n","import type { ViewportState } from '@tradecanvas/commons';\n\nexport function barIndexToX(index: number, viewport: ViewportState): number {\n const barUnit = viewport.barWidth + viewport.barSpacing;\n return index * barUnit - viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n}\n\nexport function priceToY(price: number, viewport: ViewportState): number {\n const { min, max } = viewport.priceRange;\n if (viewport.logScale && min > 0 && max > 0) {\n const logMin = Math.log(min);\n const logMax = Math.log(max);\n const logRange = logMax - logMin;\n if (logRange === 0) return viewport.chartRect.y + viewport.chartRect.height / 2;\n const ratio = (Math.log(Math.max(price, Number.EPSILON)) - logMin) / logRange;\n return viewport.chartRect.y + viewport.chartRect.height * (1 - ratio);\n }\n const range = max - min;\n if (range === 0) return viewport.chartRect.y + viewport.chartRect.height / 2;\n const ratio = (price - min) / range;\n return viewport.chartRect.y + viewport.chartRect.height * (1 - ratio);\n}\n\nexport function xToBarIndex(x: number, viewport: ViewportState): number {\n const barUnit = viewport.barWidth + viewport.barSpacing;\n return Math.round((x - viewport.chartRect.x - viewport.barWidth / 2 + viewport.offset) / barUnit);\n}\n\nexport function yToPrice(y: number, viewport: ViewportState): number {\n const { min, max } = viewport.priceRange;\n const ratio = 1 - (y - viewport.chartRect.y) / viewport.chartRect.height;\n if (viewport.logScale && min > 0 && max > 0) {\n const logMin = Math.log(min);\n const logMax = Math.log(max);\n return Math.exp(logMin + (logMax - logMin) * ratio);\n }\n return min + (max - min) * ratio;\n}\n\n/**\n * Convert a bar timestamp to its data-array index via binary search.\n * Falls back to fractional interpolation when the timestamp falls between bars.\n * Returns -1 if data is empty.\n */\nexport function timestampToBarIndex(timestamp: number, data: ReadonlyArray<{ time: number }>): number {\n if (data.length === 0) return -1;\n // Fast path: exact match at boundaries\n if (timestamp <= data[0].time) return 0;\n if (timestamp >= data[data.length - 1].time) return data.length - 1;\n // Binary search\n let lo = 0, hi = data.length - 1;\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n if (data[mid].time === timestamp) return mid;\n if (data[mid].time < timestamp) lo = mid + 1;\n else hi = mid - 1;\n }\n // lo is the insertion point; interpolate between hi and lo\n if (lo >= data.length) return data.length - 1;\n if (hi < 0) return 0;\n const tLo = data[hi].time, tHi = data[lo].time;\n const frac = tHi !== tLo ? (timestamp - tLo) / (tHi - tLo) : 0;\n return hi + frac;\n}\n\n/**\n * Resolve an anchor `time` value to a (possibly fractional) bar index in the\n * current series. When `viewport.data` is set, `time` is interpreted as a real\n * timestamp and converted via `timestampToBarIndex`. Otherwise `time` is\n * already a bar index and is returned unchanged.\n */\nexport function resolveBarIndex(time: number, viewport: ViewportState): number {\n const data = viewport.data;\n if (data && data.length > 0) {\n return timestampToBarIndex(time, data);\n }\n return time;\n}\n\n/**\n * Map an anchor `time` value to its pixel x. Works whether `time` is a\n * timestamp (when `viewport.data` is set) or a bar index (legacy callers).\n */\nexport function timeToX(time: number, viewport: ViewportState): number {\n return barIndexToX(resolveBarIndex(time, viewport), viewport);\n}\n\n/**\n * Map a pixel x back to an anchor `time` value. Returns a real timestamp when\n * `viewport.data` is set (so the value survives timeframe switches), otherwise\n * returns a bar index for legacy callers.\n */\nexport function xToTime(x: number, viewport: ViewportState): number {\n const idx = xToBarIndex(x, viewport);\n const data = viewport.data;\n if (data && data.length > 0) {\n const clamped = Math.max(0, Math.min(data.length - 1, idx));\n return data[clamped].time;\n }\n return idx;\n}\n","import { LayerType } from '@tradecanvas/commons';\nimport type { Size, ViewportState, Theme, DataSeries, Rect } from '@tradecanvas/commons';\nimport { priceToY, yToPrice, xToBarIndex, barIndexToX } from '../viewport/ScaleMapping.js';\nimport { PRICE_AXIS_WIDTH, computeTickStep, formatPrice } from '@tradecanvas/commons';\nimport { LayerManager } from './LayerManager.js';\nimport { RenderLoop } from './RenderLoop.js';\nimport { DPRManager } from './DPRManager.js';\nimport type { CanvasLayer } from './CanvasLayer.js';\nimport type { ChartRendererInterface } from '../charts/ChartRenderer.js';\nimport type { GridRenderer } from '../axis/GridRenderer.js';\nimport type { PriceAxis } from '../axis/PriceAxis.js';\nimport type { TimeAxis } from '../axis/TimeAxis.js';\nimport type { CrosshairHandler } from '../interaction/CrosshairHandler.js';\nimport type { IndicatorEngine } from '../indicators/IndicatorEngine.js';\nimport type { DrawingRenderer } from '../drawings/DrawingRenderer.js';\nimport type { TradingRenderer } from '../trading/TradingRenderer.js';\nimport type { CurrentPriceLine } from '../realtime/CurrentPriceLine.js';\nimport type { ChartLegend } from '../ui/ChartLegend.js';\nimport type { Watermark } from '../ui/Watermark.js';\nimport type { BarCountdown } from '../ui/BarCountdown.js';\nimport type { SessionBreaks } from '../ui/SessionBreaks.js';\nimport type { VolumeRenderer } from '../charts/VolumeRenderer.js';\nimport type { CompareRenderer } from '../charts/CompareRenderer.js';\nimport type { AlertManager } from '../features/AlertManager.js';\nimport type { SignalMarkerManager } from '../features/SignalMarkerManager.js';\nimport type { TradeZoneManager } from '../features/TradeZoneManager.js';\n\nexport interface PanelRenderInfo {\n instanceId: string;\n rect: Rect;\n viewport: ViewportState;\n}\n\nexport interface RenderContext {\n chartRenderer: ChartRendererInterface | null;\n gridRenderer: GridRenderer | null;\n priceAxis: PriceAxis | null;\n timeAxis: TimeAxis | null;\n crosshairHandler: CrosshairHandler | null;\n indicatorEngine: IndicatorEngine | null;\n drawingRenderer: DrawingRenderer | null;\n tradingRenderer: TradingRenderer | null;\n currentPriceLine: CurrentPriceLine | null;\n chartLegend: ChartLegend | null;\n volumeRenderer: VolumeRenderer | null;\n volumeProfile: import('../charts/VolumeProfileRenderer.js').VolumeProfileRenderer | null;\n watermark: Watermark | null;\n barCountdown: BarCountdown | null;\n sessionBreaks: SessionBreaks | null;\n compareRenderer: CompareRenderer | null;\n alertManager: AlertManager | null;\n signalMarkerManager: SignalMarkerManager | null;\n measureOverlay: import('../features/MeasureOverlay.js').MeasureOverlay | null;\n tradeZoneManager: TradeZoneManager | null;\n panels: PanelRenderInfo[];\n priceLimits?: { ceiling: number; floor: number; reference: number; colors?: { ceiling?: string; floor?: string; reference?: string } } | null;\n timeAxisY?: number;\n viewport: ViewportState;\n theme: Theme;\n data: DataSeries;\n /** BCP 47 locale for number formatting. Defaults to 'en-US' when not set. */\n numberLocale?: string;\n}\n\nexport class RenderEngine {\n readonly layerManager: LayerManager;\n readonly renderLoop: RenderLoop;\n readonly dprManager: DPRManager;\n private renderCtx: RenderContext | null = null;\n\n // Cached layer references — avoid Map lookup per frame\n private bgLayer: CanvasLayer | undefined;\n private mainLayer: CanvasLayer | undefined;\n private overlayLayer: CanvasLayer | undefined;\n private uiLayer: CanvasLayer | undefined;\n\n /**\n * Optional hook fired AFTER the canvas layers have been resized in\n * response to a container resize. The Chart class uses this to push the\n * new dimensions into its viewport + layout manager — without it, the\n * viewport keeps a stale chartRect forever and `scrollToEnd` / panning\n * compute against the wrong width.\n */\n onContainerResize: ((size: Size) => void) | null = null;\n\n constructor(container: HTMLElement) {\n this.layerManager = new LayerManager(container);\n this.renderLoop = new RenderLoop();\n this.dprManager = new DPRManager(container);\n\n this.layerManager.createLayers();\n this.cacheLayerRefs();\n\n this.renderLoop.setCallback((dirtyLayers) => this.render(dirtyLayers));\n\n this.dprManager.onResize((size, dpr) => {\n this.layerManager.resize(size, dpr);\n this.renderLoop.markAllDirty();\n // Notify the Chart so it can update viewport.chartRect + layout.\n // Without this, container resizes leave the viewport's idea of width\n // stuck at whatever it was at construction time.\n this.onContainerResize?.(size);\n });\n\n const size = this.dprManager.getContainerSize();\n const dpr = this.dprManager.getDpr();\n this.layerManager.resize(size, dpr);\n }\n\n private cacheLayerRefs(): void {\n this.bgLayer = this.layerManager.getLayer(LayerType.Background);\n this.mainLayer = this.layerManager.getLayer(LayerType.Main);\n this.overlayLayer = this.layerManager.getLayer(LayerType.Overlay);\n this.uiLayer = this.layerManager.getLayer(LayerType.UI);\n }\n\n setRenderContext(ctx: RenderContext): void {\n this.renderCtx = ctx;\n }\n\n start(): void {\n this.renderLoop.start();\n }\n\n stop(): void {\n this.renderLoop.stop();\n }\n\n requestRender(layer?: LayerType): void {\n if (layer !== undefined) {\n this.renderLoop.markDirty(layer);\n } else {\n this.renderLoop.markAllDirty();\n }\n }\n\n private render(dirtyLayers: ReadonlySet<LayerType>): void {\n const ctx = this.renderCtx;\n if (!ctx) return;\n const { viewport, theme, data } = ctx;\n const locale = ctx.numberLocale ?? 'en-US';\n\n // Skip rendering if viewport has zero dimensions\n if (viewport.chartRect.width <= 0 || viewport.chartRect.height <= 0) return;\n\n if (dirtyLayers.has(LayerType.Background) && this.bgLayer) {\n this.bgLayer.clear();\n ctx.gridRenderer?.render(this.bgLayer.ctx, viewport, theme);\n ctx.sessionBreaks?.render(this.bgLayer.ctx, viewport, theme, data);\n ctx.watermark?.render(this.bgLayer.ctx, viewport, theme);\n }\n\n if (dirtyLayers.has(LayerType.Main) && this.mainLayer) {\n this.mainLayer.clear();\n const c = this.mainLayer.ctx;\n\n // Clip main chart area\n c.save();\n c.beginPath();\n c.rect(viewport.chartRect.x, viewport.chartRect.y, viewport.chartRect.width, viewport.chartRect.height);\n c.clip();\n\n // Volume bars (drawn first, behind candles)\n ctx.volumeRenderer?.render(c, data, viewport, theme);\n ctx.volumeProfile?.render(c, data, viewport, theme);\n ctx.chartRenderer?.render(c, data, viewport, theme);\n ctx.compareRenderer?.render(c, data, viewport, theme);\n ctx.indicatorEngine?.renderOverlays(c, viewport);\n\n c.restore();\n\n // Render panel indicators in their own clipped regions\n const panels = ctx.panels;\n const indicatorEngine = ctx.indicatorEngine;\n if (indicatorEngine && panels.length > 0) {\n // Cache font string once for all panels\n const panelFont = `10px ${theme.font.family}`;\n\n // Build descriptor lookup once per frame — avoids O(n*m) .find() per panel\n const panelDescs = indicatorEngine.getPanelIndicators();\n const descMap = new Map<string, typeof panelDescs[0]>();\n for (const d of panelDescs) descMap.set(d.instanceId, d);\n\n for (const panel of panels) {\n if (panel.rect.width <= 0 || panel.rect.height <= 0) continue;\n\n c.save();\n c.beginPath();\n c.rect(panel.rect.x, panel.rect.y, panel.rect.width, panel.rect.height);\n c.clip();\n\n const PANEL_HEADER_HEIGHT = 20;\n\n // Panel background\n c.fillStyle = theme.background;\n c.fillRect(panel.rect.x, panel.rect.y, panel.rect.width, panel.rect.height);\n\n // Thick divider bar at top of panel\n c.fillStyle = theme.axisLine;\n c.fillRect(panel.rect.x, panel.rect.y, panel.rect.width, 3);\n\n // Panel indicator name in header area\n c.fillStyle = theme.textSecondary;\n c.font = panelFont;\n c.textBaseline = 'top';\n c.textAlign = 'left';\n const desc = descMap.get(panel.instanceId);\n if (desc) {\n c.fillText(desc.descriptor.name, panel.rect.x + 6, panel.rect.y + 6);\n }\n\n // Clip indicator rendering to below the header\n c.save();\n c.beginPath();\n c.rect(panel.rect.x, panel.rect.y + PANEL_HEADER_HEIGHT, panel.rect.width, panel.rect.height - PANEL_HEADER_HEIGHT);\n c.clip();\n\n indicatorEngine.renderPanel(c, panel.instanceId, panel.viewport);\n\n c.restore();\n\n c.restore();\n }\n }\n }\n\n if (dirtyLayers.has(LayerType.Overlay) && this.overlayLayer) {\n this.overlayLayer.clear();\n const c = this.overlayLayer.ctx;\n\n // Price limit lines (ceiling/floor/reference)\n if (ctx.priceLimits) {\n this.renderPriceLimits(c, viewport, theme, ctx.priceLimits);\n }\n\n ctx.tradeZoneManager?.render(c, viewport, theme);\n ctx.drawingRenderer?.render(c, viewport);\n ctx.tradingRenderer?.render(c, viewport, theme);\n ctx.signalMarkerManager?.render(c, viewport, theme);\n ctx.alertManager?.render(c, viewport, theme);\n ctx.measureOverlay?.render(c, viewport, theme);\n ctx.crosshairHandler?.render(c, viewport, theme);\n\n // Panel crosshair — draw crosshair lines in the hovered panel\n const cursorPos = ctx.crosshairHandler?.getPosition();\n if (cursorPos && ctx.panels.length > 0) {\n for (const panel of ctx.panels) {\n const pr = panel.rect;\n if (cursorPos.x >= pr.x && cursorPos.x <= pr.x + pr.width &&\n cursorPos.y >= pr.y && cursorPos.y <= pr.y + pr.height) {\n const pv = panel.viewport;\n // Vertical line (synced with main chart bar snapping)\n let cx = cursorPos.x;\n const barIdx = xToBarIndex(cx, pv);\n const snappedIdx = Math.max(0, Math.min((ctx.data?.length ?? 1) - 1, Math.round(barIdx)));\n cx = barIndexToX(snappedIdx, pv);\n\n c.save();\n c.beginPath();\n c.rect(pr.x, pr.y, pr.width, pr.height);\n c.clip();\n\n c.setLineDash([4, 4]);\n c.strokeStyle = theme.crosshair;\n c.lineWidth = 1;\n\n // Vertical\n c.beginPath();\n c.moveTo(Math.round(cx) + 0.5, pr.y);\n c.lineTo(Math.round(cx) + 0.5, pr.y + pr.height);\n c.stroke();\n\n // Horizontal\n c.beginPath();\n c.moveTo(pr.x, Math.round(cursorPos.y) + 0.5);\n c.lineTo(pr.x + pr.width, Math.round(cursorPos.y) + 0.5);\n c.stroke();\n\n c.setLineDash([]);\n c.restore();\n break;\n }\n }\n }\n }\n\n if (dirtyLayers.has(LayerType.UI) && this.uiLayer) {\n this.uiLayer.clear();\n const c = this.uiLayer.ctx;\n ctx.priceAxis?.render(c, viewport, theme);\n // Trading axis badges paint ON TOP of the regular price axis labels\n // so position entry prices and order trigger prices are always visible.\n ctx.tradingRenderer?.renderAxisBadges(c, viewport, theme);\n ctx.currentPriceLine?.render(c, viewport, theme);\n ctx.timeAxis?.render(c, viewport, theme, data, ctx.timeAxisY);\n // Crosshair axis hover pills — drawn AFTER the axes so they always\n // sit on top of the static price/time labels.\n ctx.crosshairHandler?.renderAxisLabels(c, viewport, theme, data, ctx.timeAxisY);\n ctx.chartLegend?.render(c, viewport, theme, data);\n ctx.barCountdown?.render(c, viewport, theme, data);\n\n // Panel Y-axis + crosshair value label + header values\n if (ctx.panels.length > 0) {\n const cursorPos2 = ctx.crosshairHandler?.getPosition();\n const indicatorEngine2 = ctx.indicatorEngine;\n const panelFont = `${theme.font.sizeSmall}px ${theme.font.family}`;\n\n // Build descriptor lookup once for UI layer panels\n let uiDescMap: Map<string, { instanceId: string; descriptor: any }> | undefined;\n if (indicatorEngine2) {\n const descs = indicatorEngine2.getPanelIndicators();\n uiDescMap = new Map();\n for (const d of descs) uiDescMap.set(d.instanceId, d);\n }\n\n for (const panel of ctx.panels) {\n const pv = panel.viewport;\n const pr = panel.rect;\n const { min, max } = pv.priceRange;\n const range = max - min;\n if (range <= 0 || pr.height <= 0) continue;\n\n const axisX = pr.x + pr.width;\n const insetRect = pv.chartRect; // already inset by header\n\n // --- Panel Y-axis ---\n // Axis line\n c.strokeStyle = theme.axisLine;\n c.lineWidth = 1;\n c.beginPath();\n c.moveTo(axisX + 0.5, pr.y);\n c.lineTo(axisX + 0.5, pr.y + pr.height);\n c.stroke();\n\n // Value labels\n const step = computeTickStep(min, max, 4);\n const firstVal = Math.ceil(min / step) * step;\n const precision = step < 1 ? Math.ceil(-Math.log10(step)) + 1 : step < 10 ? 1 : 0;\n\n c.font = panelFont;\n c.textBaseline = 'middle';\n c.textAlign = 'left';\n\n for (let val = firstVal; val <= max; val += step) {\n const y = priceToY(val, pv);\n if (y < insetRect.y || y > insetRect.y + insetRect.height) continue;\n // Tick mark\n c.strokeStyle = theme.axisLine;\n c.beginPath();\n c.moveTo(axisX, Math.round(y) + 0.5);\n c.lineTo(axisX + 4, Math.round(y) + 0.5);\n c.stroke();\n // Label\n c.fillStyle = theme.axisLabel;\n c.fillText(formatPrice(val, precision, locale), axisX + 6, y);\n }\n\n // --- Crosshair value badge on panel Y-axis ---\n if (cursorPos2 &&\n cursorPos2.x >= pr.x && cursorPos2.x <= pr.x + pr.width &&\n cursorPos2.y >= pr.y && cursorPos2.y <= pr.y + pr.height) {\n const hoverVal = yToPrice(cursorPos2.y, pv);\n const valText = formatPrice(hoverVal, precision, locale);\n c.font = `bold ${theme.font.sizeSmall}px ${theme.font.family}`;\n const tw = c.measureText(valText).width;\n const badgeW = Math.min(tw + 10, PRICE_AXIS_WIDTH - 2);\n\n c.fillStyle = theme.crosshair;\n c.fillRect(axisX + 1, cursorPos2.y - 9, badgeW, 18);\n c.fillStyle = theme.background;\n c.textBaseline = 'middle';\n c.textAlign = 'left';\n c.fillText(valText, axisX + 5, cursorPos2.y);\n }\n\n // --- Indicator values at crosshair bar in panel header ---\n if (cursorPos2 && indicatorEngine2) {\n const barIdx = xToBarIndex(cursorPos2.x, pv);\n const snappedIdx = Math.max(0, Math.min((data?.length ?? 1) - 1, Math.round(barIdx)));\n const output = indicatorEngine2.getOutput(panel.instanceId);\n if (output?.series && snappedIdx < output.series.length) {\n const val = output.series[snappedIdx];\n if (val) {\n const parts: string[] = [];\n for (const key in val) {\n const v = val[key];\n if (v !== undefined) parts.push(`${key}: ${v.toFixed(precision)}`);\n }\n if (parts.length > 0) {\n const desc = uiDescMap?.get(panel.instanceId);\n const nameWidth = desc ? c.measureText(desc.descriptor.name).width + 14 : 10;\n c.font = panelFont;\n c.fillStyle = theme.textSecondary;\n c.textBaseline = 'top';\n c.textAlign = 'left';\n c.fillText(parts.join(' '), pr.x + nameWidth, pr.y + 6);\n }\n }\n }\n }\n }\n }\n }\n }\n\n private renderPriceLimits(\n ctx: CanvasRenderingContext2D,\n viewport: ViewportState,\n theme: Theme,\n limits: NonNullable<RenderContext['priceLimits']>,\n ): void {\n const { chartRect } = viewport;\n const lines = [\n { price: limits.ceiling, color: limits.colors?.ceiling ?? '#FF00FF', label: 'CE' },\n { price: limits.floor, color: limits.colors?.floor ?? '#00FFFF', label: 'FL' },\n { price: limits.reference, color: limits.colors?.reference ?? '#FFD700', label: 'REF' },\n ];\n\n const boldFont = `bold 9px ${theme.font.family}`;\n const normalFont = `10px ${theme.font.family}`;\n\n for (const { price, color, label } of lines) {\n const y = priceToY(price, viewport);\n if (y < chartRect.y || y > chartRect.y + chartRect.height) continue;\n\n ctx.setLineDash([8, 4]);\n ctx.strokeStyle = color;\n ctx.lineWidth = 1;\n ctx.beginPath();\n ctx.moveTo(chartRect.x, Math.round(y) + 0.5);\n ctx.lineTo(chartRect.x + chartRect.width, Math.round(y) + 0.5);\n ctx.stroke();\n ctx.setLineDash([]);\n\n // Label\n ctx.font = boldFont;\n ctx.fillStyle = color;\n ctx.textBaseline = 'bottom';\n ctx.textAlign = 'left';\n ctx.fillText(`${label} ${price.toFixed(2)}`, chartRect.x + 4, y - 2);\n\n // Axis badge\n const axisX = chartRect.x + chartRect.width + 1;\n ctx.fillStyle = color;\n ctx.fillRect(axisX, y - 7, PRICE_AXIS_WIDTH - 2, 14);\n ctx.fillStyle = '#000';\n ctx.font = normalFont;\n ctx.textBaseline = 'middle';\n ctx.textAlign = 'left';\n ctx.fillText(price.toFixed(2), axisX + 4, y);\n }\n }\n\n destroy(): void {\n this.renderLoop.stop();\n this.dprManager.destroy();\n this.layerManager.destroy();\n }\n}\n","import type { ViewportState, Rect, DataSeries } from '@tradecanvas/commons';\nimport { clamp, computePriceRange } from '@tradecanvas/commons';\nimport { DEFAULT_BAR_WIDTH, DEFAULT_BAR_SPACING, PRICE_AXIS_WIDTH, TIME_AXIS_HEIGHT } from '@tradecanvas/commons';\n\nexport class Viewport {\n private state: ViewportState;\n private dataLength = 0;\n private minBarWidth: number;\n private maxBarWidth: number;\n private rightMarginBars: number;\n\n constructor(\n containerWidth: number,\n containerHeight: number,\n minBarWidth = 2,\n maxBarWidth = 30,\n rightMarginBars = 5,\n ) {\n this.minBarWidth = minBarWidth;\n this.maxBarWidth = maxBarWidth;\n this.rightMarginBars = rightMarginBars;\n const chartRect = this.computeChartRect(containerWidth, containerHeight);\n this.state = {\n visibleRange: { from: 0, to: 0 },\n priceRange: { min: 0, max: 1 },\n barWidth: DEFAULT_BAR_WIDTH,\n barSpacing: DEFAULT_BAR_SPACING,\n offset: 0,\n chartRect,\n };\n }\n\n /** Returns a snapshot (deep copy). Safe to store/pass. */\n getState(): ViewportState {\n return {\n visibleRange: { ...this.state.visibleRange },\n priceRange: { ...this.state.priceRange },\n barWidth: this.state.barWidth,\n barSpacing: this.state.barSpacing,\n offset: this.state.offset,\n chartRect: { ...this.state.chartRect },\n logScale: this.state.logScale,\n };\n }\n\n setLogScale(enabled: boolean): void {\n this.state.logScale = enabled;\n }\n\n isLogScale(): boolean {\n return this.state.logScale ?? false;\n }\n\n setRightMargin(bars: number): void {\n this.rightMarginBars = bars;\n }\n\n private computeChartRect(width: number, height: number): Rect {\n return {\n x: 0,\n y: 0,\n width: Math.max(0, width - PRICE_AXIS_WIDTH),\n height: Math.max(0, height - TIME_AXIS_HEIGHT),\n };\n }\n\n resize(width: number, height: number): void {\n this.state.chartRect = this.computeChartRect(width, height);\n this.clampOffset();\n }\n\n setChartRect(rect: Rect): void {\n this.state.chartRect = {\n x: rect.x,\n y: rect.y,\n width: Math.max(0, rect.width),\n height: Math.max(0, rect.height),\n };\n this.clampOffset();\n this.updateVisibleRange();\n }\n\n updateData(data: DataSeries, autoScale: boolean): void {\n this.dataLength = data.length;\n if (this.dataLength === 0) return;\n\n this.clampOffset();\n this.updateVisibleRange();\n\n if (autoScale) {\n this.state.priceRange = computePriceRange(\n data,\n this.state.visibleRange.from,\n Math.min(this.state.visibleRange.to, this.dataLength - 1),\n 0.08, // 8% padding for more breathing room\n );\n }\n }\n\n setPriceRange(min: number, max: number): void {\n this.state.priceRange = { min, max };\n }\n\n /**\n * Multiply the visible price range by `factor` around its midpoint.\n * `factor > 1` expands (zooms out vertically), `< 1` compresses.\n * Used by drag-on-price-axis scaling.\n */\n scalePriceRange(factor: number): void {\n if (!Number.isFinite(factor) || factor <= 0) return;\n const { min, max } = this.state.priceRange;\n const mid = (min + max) / 2;\n const half = (max - min) / 2;\n const newHalf = Math.max(half * factor, 1e-9);\n this.state.priceRange = { min: mid - newHalf, max: mid + newHalf };\n }\n\n scrollBy(deltaPixels: number): void {\n this.state.offset += deltaPixels;\n this.clampOffset();\n this.updateVisibleRange();\n }\n\n /** Returns true if the viewport is scrolled to show the latest bars. */\n isAtEnd(): boolean {\n const barUnit = this.state.barWidth + this.state.barSpacing;\n const rightMarginPx = this.rightMarginBars * barUnit;\n const totalWidth = this.dataLength * barUnit;\n // Natural \"scrolled to end\" offset — may be negative when data is shorter\n // than the viewport (right-aligned with empty space on the left).\n const endOffset = totalWidth - this.state.chartRect.width + rightMarginPx;\n return this.state.offset >= endOffset - barUnit * 2;\n }\n\n scrollToEnd(): void {\n const barUnit = this.state.barWidth + this.state.barSpacing;\n const rightMarginPx = this.rightMarginBars * barUnit;\n const totalWidth = this.dataLength * barUnit;\n // Position last bar with rightMargin breathing room from the right edge.\n // For short data this offset is negative — that's intentional. It puts\n // the bars on the right side of the viewport with empty space on the\n // left, matching TradingView's behaviour for sparse charts.\n this.state.offset = totalWidth - this.state.chartRect.width + rightMarginPx;\n this.updateVisibleRange();\n }\n\n zoom(delta: number, centerX: number): void {\n const oldBarWidth = this.state.barWidth;\n const newBarWidth = clamp(\n oldBarWidth * (1 + delta),\n this.minBarWidth,\n this.maxBarWidth,\n );\n if (newBarWidth === oldBarWidth) return;\n\n const barUnit = this.state.barWidth + this.state.barSpacing;\n const centerBarIndex = (this.state.offset + centerX) / barUnit;\n\n this.state.barWidth = newBarWidth;\n const newBarUnit = newBarWidth + this.state.barSpacing;\n this.state.offset = centerBarIndex * newBarUnit - centerX;\n\n this.clampOffset();\n this.updateVisibleRange();\n }\n\n private clampOffset(): void {\n if (this.state.chartRect.width <= 0) return;\n const barUnit = this.state.barWidth + this.state.barSpacing;\n const totalWidth = this.dataLength * barUnit;\n const rightMarginPx = this.rightMarginBars * barUnit;\n\n // Natural \"scrolled to end\" offset — last bar `rightMarginPx` from the\n // right edge of the chart area. Positive when data overflows the\n // viewport, negative when data is shorter than the viewport.\n const endOffset = totalWidth - this.state.chartRect.width + rightMarginPx;\n\n let minOffset: number;\n let maxOffset: number;\n\n if (endOffset > 0) {\n // Long data: user can pan left to history or scroll right to the end.\n // Allow a half-viewport of \"empty space on the left\" past offset 0\n // for breathing room when looking at the oldest bars.\n minOffset = -(this.state.chartRect.width * 0.5);\n maxOffset = endOffset;\n } else {\n // Short data: lock the viewport to the right-aligned position. There's\n // nothing to scroll to — all bars fit, with empty space on the left.\n // TradingView does this same lock for sparse charts.\n minOffset = endOffset;\n maxOffset = endOffset;\n }\n\n this.state.offset = clamp(this.state.offset, minOffset, maxOffset);\n }\n\n private updateVisibleRange(): void {\n const barUnit = this.state.barWidth + this.state.barSpacing;\n if (barUnit <= 0 || this.state.chartRect.width <= 0) return;\n const from = Math.floor(this.state.offset / barUnit);\n const visibleBars = Math.ceil(this.state.chartRect.width / barUnit) + 1;\n const to = Math.min(from + visibleBars, this.dataLength - 1);\n this.state.visibleRange = { from: Math.max(0, from), to: Math.max(0, to) };\n }\n}\n","import type { DataSeries, ViewportState } from '@tradecanvas/commons';\nimport { sliceVisibleData } from '@tradecanvas/commons';\n\nexport function getVisibleData(data: DataSeries, viewport: ViewportState): DataSeries {\n return sliceVisibleData(data, viewport.visibleRange.from, viewport.visibleRange.to);\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\nexport class CandlestickRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n const barWidth = viewport.barWidth;\n const halfBar = barWidth / 2;\n\n // Pre-compute coordinate conversion constants (avoid function call overhead per bar)\n const barUnit = barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + halfBar;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n const chartY = viewport.chartRect.y;\n const chartH = viewport.chartRect.height;\n const priceScale = chartH / priceRange;\n\n // Inline coordinate conversions\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n // Batch: collect up/down wicks and bodies into Path2D objects — single draw call per color\n const upWickPath = new Path2D();\n const downWickPath = new Path2D();\n const upBodyPath = new Path2D();\n const downBodyPath = new Path2D();\n\n for (let i = from; i <= to && i < data.length; i++) {\n const bar = data[i];\n const x = toX(i);\n const highY = toY(bar.high);\n const lowY = toY(bar.low);\n const openY = toY(bar.open);\n const closeY = toY(bar.close);\n const isUp = bar.close >= bar.open;\n\n // Wick\n const wickPath = isUp ? upWickPath : downWickPath;\n wickPath.moveTo(x, highY);\n wickPath.lineTo(x, lowY);\n\n // Body\n const bodyTop = isUp ? closeY : openY;\n const bodyHeight = Math.max(Math.abs(closeY - openY), 1);\n const bodyPath = isUp ? upBodyPath : downBodyPath;\n bodyPath.rect(x - halfBar, bodyTop, barWidth, bodyHeight);\n }\n\n // Draw all up wicks\n ctx.strokeStyle = theme.candleUpWick;\n ctx.lineWidth = 1;\n ctx.stroke(upWickPath);\n\n // Draw all down wicks\n ctx.strokeStyle = theme.candleDownWick;\n ctx.stroke(downWickPath);\n\n // Draw all up bodies\n ctx.fillStyle = theme.candleUp;\n ctx.fill(upBodyPath);\n\n // Draw all down bodies\n ctx.fillStyle = theme.candleDown;\n ctx.fill(downBodyPath);\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\nexport class LineRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n if (from > to || data.length === 0) return;\n\n // Pre-compute constants\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n\n ctx.beginPath();\n ctx.strokeStyle = theme.lineColor;\n ctx.lineWidth = 2;\n ctx.lineJoin = 'round';\n\n let started = false;\n for (let i = from; i <= to && i < data.length; i++) {\n const x = i * barUnit + offsetX;\n const y = chartY + (max - data[i].close) * priceScale;\n if (!started) { ctx.moveTo(x, y); started = true; }\n else ctx.lineTo(x, y);\n }\n ctx.stroke();\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\nexport class AreaRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n if (from > to || data.length === 0) return;\n\n // Pre-compute constants\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n const chartY = viewport.chartRect.y;\n const chartH = viewport.chartRect.height;\n const priceScale = chartH / priceRange;\n const bottomY = chartY + chartH;\n\n // Build path in single pass\n const firstX = from * barUnit + offsetX;\n const firstY = chartY + (max - data[from].close) * priceScale;\n\n // Fill\n const gradient = ctx.createLinearGradient(0, chartY, 0, bottomY);\n gradient.addColorStop(0, theme.areaTopColor);\n gradient.addColorStop(1, theme.areaBottomColor);\n\n ctx.beginPath();\n ctx.moveTo(firstX, bottomY);\n ctx.lineTo(firstX, firstY);\n\n let lastX = firstX;\n for (let i = from + 1; i <= to && i < data.length; i++) {\n lastX = i * barUnit + offsetX;\n ctx.lineTo(lastX, chartY + (max - data[i].close) * priceScale);\n }\n\n ctx.lineTo(lastX, bottomY);\n ctx.closePath();\n ctx.fillStyle = gradient;\n ctx.fill();\n\n // Line on top\n ctx.beginPath();\n ctx.strokeStyle = theme.lineColor;\n ctx.lineWidth = 2;\n ctx.lineJoin = 'round';\n ctx.moveTo(firstX, firstY);\n for (let i = from + 1; i <= to && i < data.length; i++) {\n ctx.lineTo(i * barUnit + offsetX, chartY + (max - data[i].close) * priceScale);\n }\n ctx.stroke();\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\nexport class BarRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n const barWidth = viewport.barWidth;\n const halfBar = barWidth / 2;\n\n // Pre-compute constants\n const barUnit = barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + halfBar;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n // Batch by color using Path2D\n const upPath = new Path2D();\n const downPath = new Path2D();\n\n for (let i = from; i <= to && i < data.length; i++) {\n const bar = data[i];\n const x = toX(i);\n const isUp = bar.close >= bar.open;\n const path = isUp ? upPath : downPath;\n\n const highY = toY(bar.high);\n const lowY = toY(bar.low);\n const openY = toY(bar.open);\n const closeY = toY(bar.close);\n\n // Vertical line (high to low)\n path.moveTo(x, highY);\n path.lineTo(x, lowY);\n // Open tick (left)\n path.moveTo(x - halfBar, openY);\n path.lineTo(x, openY);\n // Close tick (right)\n path.moveTo(x, closeY);\n path.lineTo(x + halfBar, closeY);\n }\n\n ctx.lineWidth = 1;\n ctx.strokeStyle = theme.candleUp;\n ctx.stroke(upPath);\n ctx.strokeStyle = theme.candleDown;\n ctx.stroke(downPath);\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\n/**\n * Hollow Candle: filled body when close < open (bearish), hollow when close >= open (bullish).\n * Color based on close vs previous close (not open).\n */\nexport class HollowCandleRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n const barWidth = viewport.barWidth;\n const halfBar = barWidth / 2;\n\n // Pre-compute coordinate conversion constants\n const barUnit = barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + halfBar;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n // Path2D objects batched by color and type\n const upWickPath = new Path2D();\n const downWickPath = new Path2D();\n const upHollowRects: { x: number; y: number; w: number; h: number }[] = [];\n const downHollowRects: { x: number; y: number; w: number; h: number }[] = [];\n const upFilledPath = new Path2D();\n const downFilledPath = new Path2D();\n\n for (let i = from; i <= to && i < data.length; i++) {\n const bar = data[i];\n const x = toX(i);\n const isBullish = bar.close >= bar.open;\n const isRising = i === 0 || bar.close >= data[i - 1].close;\n\n const highY = toY(bar.high);\n const lowY = toY(bar.low);\n const openY = toY(bar.open);\n const closeY = toY(bar.close);\n const bodyTop = Math.min(openY, closeY);\n const bodyHeight = Math.max(Math.abs(closeY - openY), 1);\n\n // Wick\n const wickPath = isRising ? upWickPath : downWickPath;\n wickPath.moveTo(x, highY);\n wickPath.lineTo(x, lowY);\n\n if (isBullish) {\n // Hollow body - collect rects for strokeRect batching\n const rects = isRising ? upHollowRects : downHollowRects;\n rects.push({ x: x - halfBar, y: bodyTop, w: barWidth, h: bodyHeight });\n } else {\n // Filled body\n const fillPath = isRising ? upFilledPath : downFilledPath;\n fillPath.rect(x - halfBar, bodyTop, barWidth, bodyHeight);\n }\n }\n\n // Draw wicks (lineWidth = 1)\n ctx.lineWidth = 1;\n ctx.strokeStyle = theme.candleUp;\n ctx.stroke(upWickPath);\n ctx.strokeStyle = theme.candleDown;\n ctx.stroke(downWickPath);\n\n // Draw filled bodies\n ctx.fillStyle = theme.candleUp;\n ctx.fill(upFilledPath);\n ctx.fillStyle = theme.candleDown;\n ctx.fill(downFilledPath);\n\n // Draw hollow bodies (strokeRect - must iterate but no per-bar beginPath/stroke)\n ctx.lineWidth = 1.5;\n ctx.strokeStyle = theme.candleUp;\n for (const r of upHollowRects) {\n ctx.strokeRect(r.x, r.y, r.w, r.h);\n }\n ctx.strokeStyle = theme.candleDown;\n for (const r of downHollowRects) {\n ctx.strokeRect(r.x, r.y, r.w, r.h);\n }\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\n/**\n * Baseline chart: line chart split at a baseline price.\n * Above baseline = green (bullish), below = red (bearish).\n * Fill with gradient on each side.\n */\nexport class BaselineRenderer implements ChartRendererInterface {\n private baselinePrice: number | null = null;\n\n setBaseline(price: number): void {\n this.baselinePrice = price;\n }\n\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n if (from > to || data.length === 0) return;\n\n const barWidth = viewport.barWidth;\n const halfBar = barWidth / 2;\n\n // Pre-compute coordinate conversion constants\n const barUnit = barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + halfBar;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n // Auto-detect baseline as average of visible range if not set\n const baseline = this.baselinePrice ?? this.computeBaseline(data, from, to);\n const baselineY = toY(baseline);\n const { chartRect } = viewport;\n\n // Collect points using pre-computed conversions\n const xs: number[] = [];\n const ys: number[] = [];\n for (let i = from; i <= to && i < data.length; i++) {\n xs.push(toX(i));\n ys.push(toY(data[i].close));\n }\n if (xs.length < 2) return;\n\n const lastIdx = xs.length - 1;\n\n // Fill above baseline (bullish) using Path2D\n ctx.save();\n const clipAbove = new Path2D();\n clipAbove.rect(chartRect.x, chartRect.y, chartRect.width, baselineY - chartRect.y);\n ctx.clip(clipAbove);\n\n const fillAbovePath = new Path2D();\n fillAbovePath.moveTo(xs[0], baselineY);\n for (let i = 0; i <= lastIdx; i++) fillAbovePath.lineTo(xs[i], ys[i]);\n fillAbovePath.lineTo(xs[lastIdx], baselineY);\n fillAbovePath.closePath();\n ctx.fillStyle = `${theme.candleUp}20`;\n ctx.fill(fillAbovePath);\n ctx.restore();\n\n // Fill below baseline (bearish) using Path2D\n ctx.save();\n const clipBelow = new Path2D();\n clipBelow.rect(chartRect.x, baselineY, chartRect.width, chartRect.y + chartRect.height - baselineY);\n ctx.clip(clipBelow);\n\n const fillBelowPath = new Path2D();\n fillBelowPath.moveTo(xs[0], baselineY);\n for (let i = 0; i <= lastIdx; i++) fillBelowPath.lineTo(xs[i], ys[i]);\n fillBelowPath.lineTo(xs[lastIdx], baselineY);\n fillBelowPath.closePath();\n ctx.fillStyle = `${theme.candleDown}20`;\n ctx.fill(fillBelowPath);\n ctx.restore();\n\n // Line segments batched by color using Path2D\n const abovePath = new Path2D();\n const belowPath = new Path2D();\n for (let i = 1; i <= lastIdx; i++) {\n const path = ys[i] <= baselineY ? abovePath : belowPath;\n path.moveTo(xs[i - 1], ys[i - 1]);\n path.lineTo(xs[i], ys[i]);\n }\n ctx.lineWidth = 2;\n ctx.strokeStyle = theme.candleUp;\n ctx.stroke(abovePath);\n ctx.strokeStyle = theme.candleDown;\n ctx.stroke(belowPath);\n\n // Baseline dashed line\n ctx.setLineDash([6, 4]);\n ctx.strokeStyle = theme.textSecondary;\n ctx.lineWidth = 1;\n const baselinePath = new Path2D();\n baselinePath.moveTo(chartRect.x, baselineY);\n baselinePath.lineTo(chartRect.x + chartRect.width, baselineY);\n ctx.stroke(baselinePath);\n ctx.setLineDash([]);\n }\n\n private computeBaseline(data: DataSeries, from: number, to: number): number {\n let sum = 0;\n let count = 0;\n for (let i = from; i <= to && i < data.length; i++) {\n sum += data[i].close;\n count++;\n }\n return count > 0 ? sum / count : 0;\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\n/**\n * Renders Renko bricks. Data should already be transformed via toRenko().\n * Each brick is a solid colored rectangle (no wicks).\n */\nexport class RenkoRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n const barWidth = viewport.barWidth;\n const halfBar = barWidth / 2;\n\n // Pre-compute coordinate conversion constants\n const barUnit = barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + halfBar;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n // Batch fills and strokes by color using Path2D\n const upFillPath = new Path2D();\n const downFillPath = new Path2D();\n const upStrokePath = new Path2D();\n const downStrokePath = new Path2D();\n\n for (let i = from; i <= to && i < data.length; i++) {\n const bar = data[i];\n const x = toX(i);\n const isUp = bar.close >= bar.open;\n\n const topY = toY(Math.max(bar.open, bar.close));\n const bottomY = toY(Math.min(bar.open, bar.close));\n const height = Math.max(bottomY - topY, 1);\n\n const rectX = x - halfBar;\n if (isUp) {\n upFillPath.rect(rectX, topY, barWidth, height);\n upStrokePath.rect(rectX, topY, barWidth, height);\n } else {\n downFillPath.rect(rectX, topY, barWidth, height);\n downStrokePath.rect(rectX, topY, barWidth, height);\n }\n }\n\n // Draw all fills then all strokes, grouped by color\n ctx.fillStyle = theme.candleUp;\n ctx.fill(upFillPath);\n ctx.fillStyle = theme.candleDown;\n ctx.fill(downFillPath);\n\n ctx.lineWidth = 1;\n ctx.strokeStyle = theme.candleUp;\n ctx.stroke(upStrokePath);\n ctx.strokeStyle = theme.candleDown;\n ctx.stroke(downStrokePath);\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\n/**\n * Renders Kagi lines. Data should already be transformed via toKagi().\n * Thick lines (yang) for up, thin lines (yin) for down.\n */\nexport class KagiRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n const barWidth = viewport.barWidth;\n const halfBar = barWidth / 2;\n\n // Pre-compute coordinate conversion constants\n const barUnit = barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + halfBar;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n // Batch paths by direction: yang (up/thick) and yin (down/thin)\n const yangPath = new Path2D();\n const yinPath = new Path2D();\n\n for (let i = from; i <= to && i < data.length; i++) {\n const bar = data[i];\n const x = toX(i);\n const isUp = bar.close >= bar.open;\n\n const topY = toY(bar.high);\n const bottomY = toY(bar.low);\n\n // Vertical line\n const path = isUp ? yangPath : yinPath;\n path.moveTo(x, topY);\n path.lineTo(x, bottomY);\n\n // Horizontal connector to next bar\n if (i < to && i + 1 < data.length) {\n const nextX = toX(i + 1);\n const connectY = isUp ? bottomY : topY;\n path.moveTo(x, connectY);\n path.lineTo(nextX, connectY);\n }\n }\n\n // Draw yang (up) lines - thick\n ctx.strokeStyle = theme.candleUp;\n ctx.lineWidth = 3;\n ctx.stroke(yangPath);\n\n // Draw yin (down) lines - thin\n ctx.strokeStyle = theme.candleDown;\n ctx.lineWidth = 1;\n ctx.stroke(yinPath);\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\n/**\n * Renders Point & Figure chart. Data should be transformed via toPointAndFigure().\n * X for up columns, O for down columns.\n */\nexport class PointAndFigureRenderer implements ChartRendererInterface {\n private boxSize = 1;\n\n setBoxSize(size: number): void {\n this.boxSize = size;\n }\n\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n const barWidth = viewport.barWidth;\n const halfBar = barWidth / 2;\n\n // Pre-compute coordinate conversion constants\n const barUnit = barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + halfBar;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n const boxPixelHeight = Math.abs(this.boxSize * priceScale);\n const symbolSize = Math.min(halfBar * 0.8, boxPixelHeight * 0.8);\n const s = symbolSize * 0.5;\n\n // Batch X strokes and O strokes into separate Path2D objects\n const xPath = new Path2D();\n const oPath = new Path2D();\n\n for (let i = from; i <= to && i < data.length; i++) {\n const bar = data[i];\n const x = toX(i);\n const isX = bar.close >= bar.open; // X column (up)\n\n const topPrice = bar.high;\n const bottomPrice = bar.low;\n const numBoxes = Math.max(1, Math.round((topPrice - bottomPrice) / this.boxSize));\n\n for (let j = 0; j < numBoxes; j++) {\n const price = bottomPrice + (j + 0.5) * this.boxSize;\n const y = toY(price);\n\n if (isX) {\n // Draw X into path\n xPath.moveTo(x - s, y - s);\n xPath.lineTo(x + s, y + s);\n xPath.moveTo(x + s, y - s);\n xPath.lineTo(x - s, y + s);\n } else {\n // Draw O into path\n oPath.moveTo(x + s, y);\n oPath.arc(x, y, s, 0, Math.PI * 2);\n }\n }\n }\n\n // Stroke all X symbols at once\n ctx.lineWidth = 1.5;\n ctx.strokeStyle = theme.candleUp;\n ctx.stroke(xPath);\n\n // Stroke all O symbols at once\n ctx.strokeStyle = theme.candleDown;\n ctx.stroke(oPath);\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\nexport class VolumeCandleRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0 || from > to || data.length === 0) return;\n\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n const maxBarWidth = viewport.barWidth;\n\n let maxVolume = 0;\n for (let i = from; i <= to && i < data.length; i++) {\n if (data[i].volume > maxVolume) maxVolume = data[i].volume;\n }\n if (maxVolume === 0) maxVolume = 1;\n\n const upWickPath = new Path2D();\n const downWickPath = new Path2D();\n const upBodyPath = new Path2D();\n const downBodyPath = new Path2D();\n\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n for (let i = from; i <= to && i < data.length; i++) {\n const bar = data[i];\n const x = toX(i);\n const highY = toY(bar.high);\n const lowY = toY(bar.low);\n const openY = toY(bar.open);\n const closeY = toY(bar.close);\n const isUp = bar.close >= bar.open;\n\n const volRatio = Math.max(0.2, bar.volume / maxVolume);\n const w = maxBarWidth * volRatio;\n const halfW = w / 2;\n\n const wickPath = isUp ? upWickPath : downWickPath;\n wickPath.moveTo(x, highY);\n wickPath.lineTo(x, lowY);\n\n const bodyTop = isUp ? closeY : openY;\n const bodyHeight = Math.max(Math.abs(closeY - openY), 1);\n const bodyPath = isUp ? upBodyPath : downBodyPath;\n bodyPath.rect(x - halfW, bodyTop, w, bodyHeight);\n }\n\n ctx.strokeStyle = theme.candleUpWick;\n ctx.lineWidth = 1;\n ctx.stroke(upWickPath);\n\n ctx.strokeStyle = theme.candleDownWick;\n ctx.stroke(downWickPath);\n\n ctx.fillStyle = theme.candleUp;\n ctx.fill(upBodyPath);\n\n ctx.fillStyle = theme.candleDown;\n ctx.fill(downBodyPath);\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\n/**\n * Equivolume (Richard Arms) — boxes spanning the full high/low range with\n * width proportional to volume share. Color tracks close vs previous close\n * (not open/close), which is the classical convention.\n */\nexport class EquivolumeRenderer implements ChartRendererInterface {\n render(\n ctx: CanvasRenderingContext2D,\n data: DataSeries,\n viewport: ViewportState,\n theme: Theme,\n ): void {\n const { from, to } = viewport.visibleRange;\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0 || from > to || data.length === 0) return;\n\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n const maxBoxWidth = viewport.barWidth;\n\n let maxVolume = 0;\n for (let i = from; i <= to && i < data.length; i++) {\n if (data[i].volume > maxVolume) maxVolume = data[i].volume;\n }\n if (maxVolume === 0) maxVolume = 1;\n\n const upBodyPath = new Path2D();\n const downBodyPath = new Path2D();\n const upEdgePath = new Path2D();\n const downEdgePath = new Path2D();\n\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n for (let i = from; i <= to && i < data.length; i++) {\n const bar = data[i];\n const prev = i > 0 ? data[i - 1] : bar;\n const x = toX(i);\n const highY = toY(bar.high);\n const lowY = toY(bar.low);\n const isUp = bar.close >= prev.close;\n\n const volRatio = Math.max(0.15, bar.volume / maxVolume);\n const w = maxBoxWidth * volRatio;\n const halfW = w / 2;\n const height = Math.max(lowY - highY, 1);\n\n const bodyPath = isUp ? upBodyPath : downBodyPath;\n const edgePath = isUp ? upEdgePath : downEdgePath;\n bodyPath.rect(x - halfW, highY, w, height);\n edgePath.rect(x - halfW, highY, w, height);\n }\n\n ctx.fillStyle = withAlpha(theme.candleUp, 0.55);\n ctx.fill(upBodyPath);\n ctx.fillStyle = withAlpha(theme.candleDown, 0.55);\n ctx.fill(downBodyPath);\n\n ctx.lineWidth = 1;\n ctx.strokeStyle = theme.candleUpWick;\n ctx.stroke(upEdgePath);\n ctx.strokeStyle = theme.candleDownWick;\n ctx.stroke(downEdgePath);\n }\n}\n\nfunction withAlpha(color: string, alpha: number): string {\n if (color.startsWith('#')) {\n const a = Math.round(Math.max(0, Math.min(1, alpha)) * 255)\n .toString(16)\n .padStart(2, '0');\n if (color.length === 7) return `${color}${a}`;\n if (color.length === 9) return `${color.slice(0, 7)}${a}`;\n }\n return color;\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\nexport class HLCAreaRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n if (from > to || data.length === 0) return;\n\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n const highPoints: { x: number; y: number }[] = [];\n const lowPoints: { x: number; y: number }[] = [];\n\n for (let i = from; i <= to && i < data.length; i++) {\n const x = toX(i);\n highPoints.push({ x, y: toY(data[i].high) });\n lowPoints.push({ x, y: toY(data[i].low) });\n }\n\n if (highPoints.length === 0) return;\n\n const gradient = ctx.createLinearGradient(0, chartY, 0, chartY + viewport.chartRect.height);\n gradient.addColorStop(0, theme.areaTopColor);\n gradient.addColorStop(1, theme.areaBottomColor);\n\n ctx.beginPath();\n ctx.moveTo(highPoints[0].x, highPoints[0].y);\n for (let i = 1; i < highPoints.length; i++) {\n ctx.lineTo(highPoints[i].x, highPoints[i].y);\n }\n for (let i = lowPoints.length - 1; i >= 0; i--) {\n ctx.lineTo(lowPoints[i].x, lowPoints[i].y);\n }\n ctx.closePath();\n ctx.fillStyle = gradient;\n ctx.fill();\n\n ctx.beginPath();\n ctx.strokeStyle = theme.lineColor;\n ctx.lineWidth = 2;\n ctx.lineJoin = 'round';\n for (let i = from; i <= to && i < data.length; i++) {\n const x = toX(i);\n const y = toY(data[i].close);\n if (i === from) ctx.moveTo(x, y);\n else ctx.lineTo(x, y);\n }\n ctx.stroke();\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\nexport class StepLineRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n if (from > to || data.length === 0) return;\n\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n ctx.beginPath();\n ctx.strokeStyle = theme.lineColor;\n ctx.lineWidth = 2;\n ctx.lineJoin = 'miter';\n\n let prevY = 0;\n for (let i = from; i <= to && i < data.length; i++) {\n const x = toX(i);\n const y = toY(data[i].close);\n if (i === from) {\n ctx.moveTo(x, y);\n } else {\n ctx.lineTo(x, prevY);\n ctx.lineTo(x, y);\n }\n prevY = y;\n }\n ctx.stroke();\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport type { ChartRendererInterface } from './ChartRenderer.js';\n\nexport class LineWithMarkersRenderer implements ChartRendererInterface {\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n const { from, to } = viewport.visibleRange;\n if (from > to || data.length === 0) return;\n\n const { min, max } = viewport.priceRange;\n const priceRange = max - min;\n if (priceRange === 0) return;\n\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n const chartY = viewport.chartRect.y;\n const priceScale = viewport.chartRect.height / priceRange;\n\n const toX = (i: number) => i * barUnit + offsetX;\n const toY = (price: number) => chartY + (max - price) * priceScale;\n\n ctx.beginPath();\n ctx.strokeStyle = theme.lineColor;\n ctx.lineWidth = 2;\n ctx.lineJoin = 'round';\n\n const points: { x: number; y: number }[] = [];\n\n for (let i = from; i <= to && i < data.length; i++) {\n const x = toX(i);\n const y = toY(data[i].close);\n points.push({ x, y });\n if (i === from) ctx.moveTo(x, y);\n else ctx.lineTo(x, y);\n }\n ctx.stroke();\n\n const markerRadius = Math.max(2, Math.min(4, viewport.barWidth * 0.3));\n const markerPath = new Path2D();\n for (const { x, y } of points) {\n markerPath.moveTo(x + markerRadius, y);\n markerPath.arc(x, y, markerRadius, 0, Math.PI * 2);\n }\n\n ctx.fillStyle = theme.lineColor;\n ctx.fill(markerPath);\n\n ctx.strokeStyle = theme.background;\n ctx.lineWidth = 1;\n ctx.stroke(markerPath);\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\n\n/**\n * Renders volume histogram bars at the bottom of the main chart area.\n * Semi-transparent, colored by candle direction.\n * Height proportional to volume, occupying bottom 15-25% of chart.\n */\nexport class VolumeRenderer {\n private visible = true;\n private heightRatio = 0.2; // 20% of chart height\n\n setVisible(v: boolean): void { this.visible = v; }\n setHeightRatio(r: number): void { this.heightRatio = Math.max(0.05, Math.min(0.5, r)); }\n\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n if (!this.visible || data.length === 0) return;\n\n const { from, to } = viewport.visibleRange;\n const { chartRect } = viewport;\n const barWidth = viewport.barWidth;\n const halfBar = barWidth / 2;\n\n // Pre-compute constants\n const barUnit = barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + chartRect.x + halfBar;\n\n // Find max volume in visible range\n let maxVol = 0;\n for (let i = from; i <= to && i < data.length; i++) {\n if (data[i].volume > maxVol) maxVol = data[i].volume;\n }\n if (maxVol === 0) return;\n\n const volumeAreaHeight = chartRect.height * this.heightRatio;\n const volumeBottom = chartRect.y + chartRect.height;\n const volScale = volumeAreaHeight / maxVol;\n\n // Batch by color\n const upPath = new Path2D();\n const downPath = new Path2D();\n\n for (let i = from; i <= to && i < data.length; i++) {\n const bar = data[i];\n const x = i * barUnit + offsetX;\n const barHeight = bar.volume * volScale;\n const path = bar.close >= bar.open ? upPath : downPath;\n path.rect(x - halfBar, volumeBottom - barHeight, barWidth, barHeight);\n }\n\n ctx.globalAlpha = 0.35;\n ctx.fillStyle = theme.candleUp;\n ctx.fill(upPath);\n ctx.fillStyle = theme.candleDown;\n ctx.fill(downPath);\n ctx.globalAlpha = 1;\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\n\n/**\n * Volume Profile — horizontal histogram of traded volume bucketed by price.\n *\n * Distributes each bar's volume across the price range it covered (low → high)\n * using a simple uniform distribution. The result is a side histogram pinned\n * to the right edge of the chart that shows where the market spent the most\n * volume — the \"value area\" and \"point of control\" come from this shape.\n *\n * Tradeoffs (intentional):\n * - Uniform low→high allocation, not VWAP-weighted. Cheaper to compute and\n * close enough for visual reading at chart-zoom scales.\n * - Buckets are computed against the *visible price range*, so the profile\n * rebins on pan/zoom — what you see is always relative to the current\n * viewport.\n * - No look-ahead: only bars currently inside `visibleRange` contribute.\n */\nexport class VolumeProfileRenderer {\n private visible = false;\n /** Number of horizontal buckets the visible price range is split into. */\n private buckets = 48;\n /** Profile width as a fraction of chart width. 0.18 ≈ 18%. */\n private widthRatio = 0.18;\n /** Opacity of the histogram bars. */\n private opacity = 0.32;\n /** Highlight the highest-volume bucket (point of control). */\n private highlightPoC = true;\n\n setVisible(v: boolean): void { this.visible = v; }\n isVisible(): boolean { return this.visible; }\n setBuckets(n: number): void { this.buckets = Math.max(8, Math.min(200, Math.floor(n))); }\n setWidthRatio(r: number): void { this.widthRatio = Math.max(0.05, Math.min(0.5, r)); }\n setOpacity(o: number): void { this.opacity = Math.max(0.05, Math.min(1, o)); }\n setHighlightPoC(enabled: boolean): void { this.highlightPoC = enabled; }\n\n render(ctx: CanvasRenderingContext2D, data: DataSeries, viewport: ViewportState, theme: Theme): void {\n if (!this.visible || data.length === 0) return;\n\n const { from, to } = viewport.visibleRange;\n const { chartRect, priceRange } = viewport;\n const priceSpan = priceRange.max - priceRange.min;\n if (priceSpan <= 0) return;\n\n const buckets = new Float64Array(this.buckets);\n let upBuckets = new Float64Array(this.buckets);\n let downBuckets = new Float64Array(this.buckets);\n\n for (let i = from; i <= to && i < data.length; i++) {\n const bar = data[i];\n if (bar.volume <= 0) continue;\n const lo = Math.max(bar.low, priceRange.min);\n const hi = Math.min(bar.high, priceRange.max);\n if (hi <= lo) continue;\n\n // Uniformly spread the bar's volume across the bucket(s) it covers.\n const loFrac = (lo - priceRange.min) / priceSpan;\n const hiFrac = (hi - priceRange.min) / priceSpan;\n const loBucket = Math.max(0, Math.floor(loFrac * this.buckets));\n const hiBucket = Math.min(this.buckets - 1, Math.floor(hiFrac * this.buckets));\n const span = Math.max(1, hiBucket - loBucket + 1);\n const perBucket = bar.volume / span;\n const isUp = bar.close >= bar.open;\n\n for (let b = loBucket; b <= hiBucket; b++) {\n buckets[b] += perBucket;\n if (isUp) upBuckets[b] += perBucket;\n else downBuckets[b] += perBucket;\n }\n }\n\n let maxBucket = 0;\n let pocIndex = -1;\n for (let b = 0; b < buckets.length; b++) {\n if (buckets[b] > maxBucket) {\n maxBucket = buckets[b];\n pocIndex = b;\n }\n }\n if (maxBucket === 0) return;\n\n const profileWidth = chartRect.width * this.widthRatio;\n const profileRight = chartRect.x + chartRect.width;\n const bucketHeight = chartRect.height / this.buckets;\n const inv = 1 / maxBucket;\n\n ctx.save();\n ctx.globalAlpha = this.opacity;\n\n // Draw stacked up/down per bucket. Each bucket: [low price row] → up at\n // bottom, down on top. Right-aligned, growing leftward.\n for (let b = 0; b < this.buckets; b++) {\n const total = buckets[b];\n if (total === 0) continue;\n\n const y = chartRect.y + chartRect.height - (b + 1) * bucketHeight;\n const totalW = (total * inv) * profileWidth;\n const upW = (upBuckets[b] * inv) * profileWidth;\n const downW = (downBuckets[b] * inv) * profileWidth;\n\n // Layered: green block first, red stacks on top of it horizontally.\n if (upW > 0) {\n ctx.fillStyle = theme.candleUp;\n ctx.fillRect(profileRight - upW, y + 0.5, upW, bucketHeight - 1);\n }\n if (downW > 0) {\n ctx.fillStyle = theme.candleDown;\n ctx.fillRect(profileRight - totalW, y + 0.5, downW, bucketHeight - 1);\n }\n\n // Point of control — overlay a thin outline + brighter alpha so it\n // pops as the high-volume bucket.\n if (this.highlightPoC && b === pocIndex) {\n ctx.globalAlpha = 1;\n ctx.strokeStyle = theme.crosshair;\n ctx.lineWidth = 1;\n ctx.setLineDash([3, 2]);\n ctx.beginPath();\n ctx.moveTo(chartRect.x, y + bucketHeight / 2 + 0.5);\n ctx.lineTo(profileRight - totalW - 2, y + bucketHeight / 2 + 0.5);\n ctx.stroke();\n ctx.setLineDash([]);\n ctx.globalAlpha = this.opacity;\n }\n }\n\n ctx.restore();\n // Silence \"unused\" linter chatter on dev rebuilds — these arrays escape\n // the closure intentionally; we keep them as separate references for\n // future per-direction extensions (e.g., delta volume profile).\n void upBuckets; void downBuckets;\n }\n}\n","import type { DataSeries, ViewportState, Theme } from '@tradecanvas/commons';\nimport { barIndexToX, priceToY } from '../viewport/ScaleMapping.js';\n\nexport interface CompareSymbol {\n id: string;\n label: string;\n data: DataSeries;\n color: string;\n lineWidth?: number;\n visible: boolean;\n}\n\n/**\n * Renders comparison overlays on the main chart.\n * Each compare symbol is normalized to percentage change from the first visible bar,\n * then mapped onto the main chart's price axis.\n */\nexport class CompareRenderer {\n private symbols = new Map<string, CompareSymbol>();\n private mode: 'percent' | 'absolute' = 'percent';\n\n setMode(mode: 'percent' | 'absolute'): void {\n this.mode = mode;\n }\n\n addSymbol(symbol: CompareSymbol): void {\n this.symbols.set(symbol.id, symbol);\n }\n\n removeSymbol(id: string): void {\n this.symbols.delete(id);\n }\n\n setSymbolData(id: string, data: DataSeries): void {\n const sym = this.symbols.get(id);\n if (sym) sym.data = data;\n }\n\n setSymbolVisible(id: string, visible: boolean): void {\n const sym = this.symbols.get(id);\n if (sym) sym.visible = visible;\n }\n\n getSymbols(): CompareSymbol[] {\n return Array.from(this.symbols.values());\n }\n\n clear(): void {\n this.symbols.clear();\n }\n\n render(\n ctx: CanvasRenderingContext2D,\n mainData: DataSeries,\n viewport: ViewportState,\n theme: Theme,\n ): void {\n if (this.symbols.size === 0 || mainData.length === 0) return;\n\n const { chartRect } = viewport;\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(chartRect.x, chartRect.y, chartRect.width, chartRect.height);\n ctx.clip();\n\n for (const sym of this.symbols.values()) {\n if (!sym.visible || sym.data.length === 0) continue;\n this.renderSymbol(ctx, sym, mainData, viewport, theme);\n }\n\n ctx.restore();\n }\n\n private renderSymbol(\n ctx: CanvasRenderingContext2D,\n sym: CompareSymbol,\n mainData: DataSeries,\n viewport: ViewportState,\n _theme: Theme,\n ): void {\n const { chartRect } = viewport;\n\n // Find the first visible bar index for the main data\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const firstVisibleIdx = Math.max(0, Math.floor(viewport.offset / barUnit));\n\n if (firstVisibleIdx >= mainData.length || firstVisibleIdx >= sym.data.length) return;\n\n const mainBase = mainData[firstVisibleIdx].close;\n const symBase = sym.data[firstVisibleIdx].close;\n\n if (mainBase === 0 || symBase === 0) return;\n\n ctx.strokeStyle = sym.color;\n ctx.lineWidth = sym.lineWidth ?? 1.5;\n ctx.lineJoin = 'round';\n ctx.beginPath();\n\n let started = false;\n const lastIdx = Math.min(mainData.length, sym.data.length);\n\n for (let i = firstVisibleIdx; i < lastIdx; i++) {\n const x = barIndexToX(i, viewport);\n if (x < chartRect.x - barUnit) continue;\n if (x > chartRect.x + chartRect.width + barUnit) break;\n\n let y: number;\n if (this.mode === 'percent') {\n // Percentage change from base, mapped to main chart's price scale\n const pctChange = (sym.data[i].close - symBase) / symBase;\n const mappedPrice = mainBase * (1 + pctChange);\n y = priceToY(mappedPrice, viewport);\n } else {\n y = priceToY(sym.data[i].close, viewport);\n }\n\n if (!started) {\n ctx.moveTo(x, y);\n started = true;\n } else {\n ctx.lineTo(x, y);\n }\n }\n\n ctx.stroke();\n\n // Draw label\n if (started) {\n const labelIdx = Math.min(firstVisibleIdx + 2, lastIdx - 1);\n const labelX = barIndexToX(labelIdx, viewport) + 4;\n let labelY: number;\n if (this.mode === 'percent') {\n const pct = (sym.data[labelIdx].close - symBase) / symBase;\n labelY = priceToY(mainBase * (1 + pct), viewport) - 4;\n } else {\n labelY = priceToY(sym.data[labelIdx].close, viewport) - 4;\n }\n ctx.fillStyle = sym.color;\n ctx.font = `bold 10px sans-serif`;\n ctx.textBaseline = 'bottom';\n ctx.textAlign = 'left';\n ctx.fillText(sym.label, labelX, labelY);\n }\n }\n}\n","import type { OHLCBar, DataSeries } from '@tradecanvas/commons';\n\n/**\n * Transform OHLC data to Heikin Ashi.\n * HA Close = (O+H+L+C) / 4\n * HA Open = (prev HA Open + prev HA Close) / 2\n * HA High = max(H, HA Open, HA Close)\n * HA Low = min(L, HA Open, HA Close)\n */\nexport function toHeikinAshi(data: DataSeries): DataSeries {\n if (data.length === 0) return [];\n\n const result: OHLCBar[] = [];\n let prevOpen = data[0].open;\n let prevClose = (data[0].open + data[0].high + data[0].low + data[0].close) / 4;\n\n for (let i = 0; i < data.length; i++) {\n const bar = data[i];\n const haClose = (bar.open + bar.high + bar.low + bar.close) / 4;\n const haOpen = i === 0 ? bar.open : (prevOpen + prevClose) / 2;\n const haHigh = Math.max(bar.high, haOpen, haClose);\n const haLow = Math.min(bar.low, haOpen, haClose);\n\n result.push({\n time: bar.time,\n open: haOpen,\n high: haHigh,\n low: haLow,\n close: haClose,\n volume: bar.volume,\n });\n\n prevOpen = haOpen;\n prevClose = haClose;\n }\n\n return result;\n}\n","import type { OHLCBar, DataSeries } from '@tradecanvas/commons';\n\nexport interface RenkoConfig {\n brickSize: number; // Price change per brick\n useATR?: boolean; // Auto-calculate brick size from ATR\n atrPeriod?: number; // Default: 14\n}\n\n/**\n * Transform OHLC data to Renko bricks.\n * Each brick represents a fixed price movement.\n * No time axis — bricks form only when price moves by brickSize.\n */\nexport function toRenko(data: DataSeries, config: RenkoConfig): DataSeries {\n if (data.length === 0) return [];\n\n let brickSize = config.brickSize;\n if (config.useATR && data.length > (config.atrPeriod ?? 14)) {\n brickSize = computeATRBrickSize(data, config.atrPeriod ?? 14);\n }\n if (brickSize <= 0) brickSize = 1;\n\n const bricks: OHLCBar[] = [];\n let lastClose = Math.round(data[0].close / brickSize) * brickSize;\n let lastTime = data[0].time;\n\n for (let i = 1; i < data.length; i++) {\n const price = data[i].close;\n const diff = price - lastClose;\n const numBricks = Math.floor(Math.abs(diff) / brickSize);\n\n if (numBricks >= 1) {\n const direction = diff > 0 ? 1 : -1;\n for (let j = 0; j < numBricks; j++) {\n const open = lastClose;\n lastClose += direction * brickSize;\n bricks.push({\n time: lastTime++, // Increment for ordering\n open,\n high: Math.max(open, lastClose),\n low: Math.min(open, lastClose),\n close: lastClose,\n volume: data[i].volume / numBricks,\n });\n }\n }\n }\n\n return bricks;\n}\n\nfunction computeATRBrickSize(data: DataSeries, period: number): number {\n let atr = 0;\n for (let i = 1; i <= Math.min(period, data.length - 1); i++) {\n const tr = Math.max(\n data[i].high - data[i].low,\n Math.abs(data[i].high - data[i - 1].close),\n Math.abs(data[i].low - data[i - 1].close),\n );\n atr += tr;\n }\n return atr / period;\n}\n","import type { OHLCBar, DataSeries } from '@tradecanvas/commons';\n\n/**\n * Three Line Break chart.\n * A new line is drawn only when the closing price exceeds the high or low\n * of the prior N lines (default: 3).\n */\nexport function toLineBreak(data: DataSeries, lineCount = 3): DataSeries {\n if (data.length === 0) return [];\n\n const lines: OHLCBar[] = [];\n let idx = 0;\n\n // First line\n lines.push({\n time: idx++,\n open: data[0].open,\n high: Math.max(data[0].open, data[0].close),\n low: Math.min(data[0].open, data[0].close),\n close: data[0].close,\n volume: data[0].volume,\n });\n\n for (let i = 1; i < data.length; i++) {\n const price = data[i].close;\n const lastLine = lines[lines.length - 1];\n const isUp = lastLine.close >= lastLine.open;\n\n // Look back N lines for reversal detection\n const lookback = Math.min(lineCount, lines.length);\n let highestHigh = -Infinity;\n let lowestLow = Infinity;\n for (let j = lines.length - lookback; j < lines.length; j++) {\n highestHigh = Math.max(highestHigh, lines[j].high);\n lowestLow = Math.min(lowestLow, lines[j].low);\n }\n\n if (isUp && price > lastLine.close) {\n // Continuation up\n lines.push({\n time: idx++,\n open: lastLine.close,\n high: price,\n low: lastLine.close,\n close: price,\n volume: data[i].volume,\n });\n } else if (!isUp && price < lastLine.close) {\n // Continuation down\n lines.push({\n time: idx++,\n open: lastLine.close,\n high: lastLine.close,\n low: price,\n close: price,\n volume: data[i].volume,\n });\n } else if (isUp && price < lowestLow) {\n // Reversal down\n lines.push({\n time: idx++,\n open: lastLine.close,\n high: lastLine.close,\n low: price,\n close: price,\n volume: data[i].volume,\n });\n } else if (!isUp && price > highestHigh) {\n // Reversal up\n lines.push({\n time: idx++,\n open: lastLine.close,\n high: price,\n low: lastLine.close,\n close: price,\n volume: data[i].volume,\n });\n }\n }\n\n return lines;\n}\n","import type { OHLCBar, DataSeries } from '@tradecanvas/commons';\n\n/**\n * Kagi chart.\n * Changes direction when price reverses by the reversal amount.\n * Thick lines (yang) for uptrends, thin lines (yin) for downtrends.\n */\nexport function toKagi(data: DataSeries, reversalPercent = 4): DataSeries {\n if (data.length < 2) return data.slice();\n\n const lines: OHLCBar[] = [];\n let direction = data[1].close >= data[0].close ? 1 : -1;\n let high = data[0].close;\n let low = data[0].close;\n let lineStart = data[0].close;\n let idx = 0;\n\n for (let i = 1; i < data.length; i++) {\n const price = data[i].close;\n const reversal = lineStart * (reversalPercent / 100);\n\n if (direction === 1) {\n if (price > high) high = price;\n if (high - price >= reversal) {\n // Finish up line, start down\n lines.push({\n time: idx++,\n open: lineStart,\n high,\n low: lineStart,\n close: high,\n volume: data[i].volume,\n });\n direction = -1;\n lineStart = high;\n low = price;\n high = price;\n }\n } else {\n if (price < low) low = price;\n if (price - low >= reversal) {\n // Finish down line, start up\n lines.push({\n time: idx++,\n open: lineStart,\n high: lineStart,\n low,\n close: low,\n volume: data[i].volume,\n });\n direction = 1;\n lineStart = low;\n high = price;\n low = price;\n }\n }\n }\n\n // Close final line\n if (direction === 1) {\n lines.push({ time: idx, open: lineStart, high, low: lineStart, close: high, volume: 0 });\n } else {\n lines.push({ time: idx, open: lineStart, high: lineStart, low, close: low, volume: 0 });\n }\n\n return lines;\n}\n","import type { OHLCBar, DataSeries } from '@tradecanvas/commons';\n\n/**\n * Point & Figure chart.\n * X columns for rising prices, O columns for falling prices.\n * Reversal requires N boxes (default: 3) in the opposite direction.\n */\nexport function toPointAndFigure(data: DataSeries, boxSize: number, reversalBoxes = 3): DataSeries {\n if (data.length === 0 || boxSize <= 0) return [];\n\n const columns: OHLCBar[] = [];\n let direction = 0; // 1 = X (up), -1 = O (down)\n let colHigh = 0;\n let colLow = 0;\n let idx = 0;\n\n // Initialize\n const startPrice = Math.round(data[0].close / boxSize) * boxSize;\n colHigh = startPrice;\n colLow = startPrice;\n direction = 1;\n\n for (let i = 1; i < data.length; i++) {\n const price = data[i].close;\n const roundedPrice = Math.round(price / boxSize) * boxSize;\n\n if (direction === 1) {\n if (roundedPrice > colHigh) {\n colHigh = roundedPrice;\n } else if (colHigh - roundedPrice >= boxSize * reversalBoxes) {\n // Close X column, start O column\n columns.push({\n time: idx++,\n open: colLow,\n high: colHigh,\n low: colLow,\n close: colHigh, // X = up\n volume: data[i].volume,\n });\n direction = -1;\n colLow = roundedPrice;\n colHigh = colHigh - boxSize;\n }\n } else {\n if (roundedPrice < colLow) {\n colLow = roundedPrice;\n } else if (roundedPrice - colLow >= boxSize * reversalBoxes) {\n // Close O column, start X column\n columns.push({\n time: idx++,\n open: colHigh,\n high: colHigh,\n low: colLow,\n close: colLow, // O = down\n volume: data[i].volume,\n });\n direction = 1;\n colHigh = roundedPrice;\n colLow = colLow + boxSize;\n }\n }\n }\n\n // Close final column\n columns.push({\n time: idx,\n open: direction === 1 ? colLow : colHigh,\n high: colHigh,\n low: colLow,\n close: direction === 1 ? colHigh : colLow,\n volume: 0,\n });\n\n return columns;\n}\n","import type { OHLCBar, DataSeries } from '@tradecanvas/commons';\r\n\r\nexport interface RangeBarsConfig {\r\n /** Price distance per range bar. Each bar is closed when (high - low) >= rangeSize. */\r\n rangeSize: number;\r\n}\r\n\r\n/**\r\n * Transform OHLC data into fixed-range bars. Each bar's price range\r\n * (high - low) is capped at `rangeSize`; a new bar starts as soon as the cap\r\n * is met. Like Renko, range bars have no time axis — emitted timestamps are\r\n * monotonically incremented to preserve ordering for the renderer.\r\n *\r\n * Approximation: input is OHLC, not tick-level. We replay each bar's\r\n * extremes in the order implied by its candle direction (up bar:\r\n * low→high→close; down bar: high→low→close) which is the standard\r\n * approach for OHLC-derived range bars.\r\n */\r\nexport function toRangeBars(data: DataSeries, config: RangeBarsConfig): DataSeries {\r\n if (data.length === 0 || config.rangeSize <= 0) return [];\r\n\r\n const out: OHLCBar[] = [];\r\n let timeCursor = data[0].time;\r\n\r\n let openPrice = data[0].open;\r\n let curHigh = openPrice;\r\n let curLow = openPrice;\r\n let curVolume = 0;\r\n\r\n const pushExtreme = (price: number, vol: number) => {\r\n if (price > curHigh) curHigh = price;\r\n if (price < curLow) curLow = price;\r\n curVolume += vol;\r\n\r\n while (curHigh - curLow >= config.rangeSize) {\r\n const upward = price >= openPrice;\r\n const closePrice = upward\r\n ? openPrice + config.rangeSize\r\n : openPrice - config.rangeSize;\r\n out.push({\r\n time: timeCursor++,\r\n open: openPrice,\r\n high: upward ? closePrice : openPrice,\r\n low: upward ? openPrice : closePrice,\r\n close: closePrice,\r\n volume: curVolume,\r\n });\r\n openPrice = closePrice;\r\n curHigh = closePrice;\r\n curLow = closePrice;\r\n curVolume = 0;\r\n }\r\n };\r\n\r\n for (const bar of data) {\r\n const isUp = bar.close >= bar.open;\r\n const order = isUp ? [bar.low, bar.high, bar.close] : [bar.high, bar.low, bar.close];\r\n const volPer = bar.volume / order.length;\r\n for (const px of order) pushExtreme(px, volPer);\r\n }\r\n\r\n return out;\r\n}\r\n","import type {\n IndicatorPlugin,\n IndicatorDescriptor,\n IndicatorConfig,\n IndicatorOutput,\n ResolvedIndicatorStyle,\n DataSeries,\n ViewportState,\n Point,\n} from '@tradecanvas/commons';\nimport { barIndexToX, priceToY } from '../viewport/ScaleMapping.js';\n\nexport abstract class IndicatorBase implements IndicatorPlugin {\n abstract descriptor: IndicatorDescriptor;\n abstract calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput;\n abstract render(\n ctx: CanvasRenderingContext2D,\n output: IndicatorOutput,\n viewport: ViewportState,\n style: ResolvedIndicatorStyle,\n ): void;\n\n protected drawLine(\n ctx: CanvasRenderingContext2D,\n points: Point[],\n color: string,\n lineWidth: number,\n ): void {\n if (points.length < 2) return;\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = lineWidth;\n ctx.lineJoin = 'round';\n ctx.moveTo(points[0].x, points[0].y);\n for (let i = 1; i < points.length; i++) {\n ctx.lineTo(points[i].x, points[i].y);\n }\n ctx.stroke();\n }\n\n protected drawBand(\n ctx: CanvasRenderingContext2D,\n upper: Point[],\n lower: Point[],\n fillColor: string,\n ): void {\n if (upper.length < 2 || lower.length < 2) return;\n ctx.beginPath();\n ctx.moveTo(upper[0].x, upper[0].y);\n for (let i = 1; i < upper.length; i++) {\n ctx.lineTo(upper[i].x, upper[i].y);\n }\n for (let i = lower.length - 1; i >= 0; i--) {\n ctx.lineTo(lower[i].x, lower[i].y);\n }\n ctx.closePath();\n ctx.fillStyle = fillColor;\n ctx.fill();\n }\n\n protected drawHistogram(\n ctx: CanvasRenderingContext2D,\n data: { x: number; y: number; baseY: number; color: string }[],\n barWidth: number,\n ): void {\n const halfBar = barWidth / 2;\n for (const bar of data) {\n ctx.fillStyle = bar.color;\n const top = Math.min(bar.y, bar.baseY);\n const height = Math.abs(bar.y - bar.baseY);\n ctx.fillRect(bar.x - halfBar, top, barWidth, Math.max(height, 1));\n }\n }\n\n protected valuesToPoints(\n output: IndicatorOutput,\n key: string,\n data: DataSeries,\n viewport: ViewportState,\n ): Point[] {\n const points: Point[] = [];\n const { from, to } = viewport.visibleRange;\n for (let i = from; i <= to && i < data.length; i++) {\n const val = output.values.get(data[i].time);\n if (val && val[key] !== undefined) {\n points.push({\n x: barIndexToX(i, viewport),\n y: priceToY(val[key]!, viewport),\n });\n }\n }\n return points;\n }\n}\n","import type {\n IndicatorPlugin,\n IndicatorConfig,\n IndicatorOutput,\n IndicatorDescriptor,\n ResolvedIndicatorStyle,\n DataSeries,\n ViewportState,\n} from '@tradecanvas/commons';\n\ninterface IndicatorInstance {\n plugin: IndicatorPlugin;\n config: IndicatorConfig;\n output: IndicatorOutput | null;\n style: ResolvedIndicatorStyle;\n}\n\nlet nextId = 1;\n\nexport class IndicatorEngine {\n private registry = new Map<string, IndicatorPlugin>();\n private instances = new Map<string, IndicatorInstance>();\n\n register(plugin: IndicatorPlugin): void {\n this.registry.set(plugin.descriptor.id, plugin);\n }\n\n getAvailableIndicators(): IndicatorDescriptor[] {\n return Array.from(this.registry.values()).map((p) => p.descriptor);\n }\n\n addIndicator(\n id: string,\n params: Record<string, number | string | boolean> = {},\n data?: DataSeries,\n ): string {\n const plugin = this.registry.get(id);\n if (!plugin) throw new Error(`Unknown indicator: ${id}`);\n\n const instanceId = `tc_${id}_${nextId++}`;\n const config: IndicatorConfig = {\n id,\n instanceId,\n params: { ...plugin.descriptor.defaultConfig, ...params } as Record<string, number | string | boolean>,\n visible: true,\n };\n\n const defaultColors = ['#2196F3', '#FF9800', '#4CAF50', '#E91E63', '#9C27B0'];\n const style: ResolvedIndicatorStyle = {\n colors: config.style?.colors ?? defaultColors,\n lineWidths: config.style?.lineWidths ?? [1.5],\n opacity: config.style?.opacity ?? 1,\n };\n\n const instance: IndicatorInstance = { plugin, config, output: null, style };\n\n if (data) {\n instance.output = plugin.calculate(data, config);\n }\n\n this.instances.set(instanceId, instance);\n return instanceId;\n }\n\n removeIndicator(instanceId: string): void {\n this.instances.delete(instanceId);\n }\n\n updateIndicator(instanceId: string, params: Record<string, number | string | boolean>, data?: DataSeries): void {\n const instance = this.instances.get(instanceId);\n if (!instance) return;\n Object.assign(instance.config.params, params);\n if (data) {\n instance.output = instance.plugin.calculate(data, instance.config);\n }\n }\n\n recalculateAll(data: DataSeries): void {\n for (const instance of this.instances.values()) {\n instance.output = instance.plugin.calculate(data, instance.config);\n }\n }\n\n getOutput(instanceId: string): IndicatorOutput | null {\n return this.instances.get(instanceId)?.output ?? null;\n }\n\n renderOverlays(ctx: CanvasRenderingContext2D, viewport: ViewportState): void {\n for (const instance of this.instances.values()) {\n if (!instance.output || !instance.config.visible) continue;\n if (instance.plugin.descriptor.placement !== 'overlay') continue;\n instance.plugin.render(ctx, instance.output, viewport, instance.style);\n }\n }\n\n renderPanel(\n ctx: CanvasRenderingContext2D,\n instanceId: string,\n viewport: ViewportState,\n ): void {\n const instance = this.instances.get(instanceId);\n if (!instance?.output || !instance.config.visible) return;\n instance.plugin.render(ctx, instance.output, viewport, instance.style);\n }\n\n /** Get config for an active indicator instance */\n getIndicatorConfig(instanceId: string): IndicatorConfig | null {\n return this.instances.get(instanceId)?.config ?? null;\n }\n\n /** Get descriptor for an active indicator instance */\n getIndicatorDescriptor(instanceId: string): IndicatorDescriptor | null {\n return this.instances.get(instanceId)?.plugin.descriptor ?? null;\n }\n\n /** List all active indicator instances with their current config */\n getActiveIndicators(): { instanceId: string; id: string; params: Record<string, unknown>; descriptor: IndicatorDescriptor }[] {\n const result: { instanceId: string; id: string; params: Record<string, unknown>; descriptor: IndicatorDescriptor }[] = [];\n for (const [instanceId, instance] of this.instances) {\n result.push({\n instanceId,\n id: instance.config.id,\n params: { ...instance.config.params },\n descriptor: instance.plugin.descriptor,\n });\n }\n return result;\n }\n\n /** Update indicator style (colors, line widths) at runtime */\n updateIndicatorStyle(instanceId: string, style: Partial<ResolvedIndicatorStyle>): void {\n const instance = this.instances.get(instanceId);\n if (!instance) return;\n Object.assign(instance.style, style);\n }\n\n /** Compute the min/max of all visible overlay indicator values within a bar index range. */\n getOverlayPriceRange(from: number, to: number): { min: number; max: number } | null {\n let gMin = Infinity;\n let gMax = -Infinity;\n\n for (const instance of this.instances.values()) {\n if (!instance.output || !instance.config.visible) continue;\n if (instance.plugin.descriptor.placement !== 'overlay') continue;\n\n let idx = 0;\n for (const [, val] of instance.output.values) {\n if (idx >= from && idx <= to) {\n for (const key in val) {\n const v = val[key];\n if (v !== undefined && isFinite(v)) {\n if (v < gMin) gMin = v;\n if (v > gMax) gMax = v;\n }\n }\n }\n idx++;\n }\n }\n\n if (gMin === Infinity) return null;\n return { min: gMin, max: gMax };\n }\n\n getPanelIndicators(): { instanceId: string; descriptor: IndicatorDescriptor }[] {\n const result: { instanceId: string; descriptor: IndicatorDescriptor }[] = [];\n for (const [id, instance] of this.instances) {\n if (instance.plugin.descriptor.placement === 'panel') {\n result.push({ instanceId: id, descriptor: instance.plugin.descriptor });\n }\n }\n return result;\n }\n}\n","import type { IndicatorConfig } from '@tradecanvas/commons';\r\n\r\n/**\r\n * Safely read a numeric indicator parameter. Falls back to `defaultValue` when\r\n * the param is missing or cannot be coerced to a finite number. Replaces ad-hoc\r\n * `config.params.foo as number` casts that silently propagate NaN.\r\n */\r\nexport function getNumberParam(\r\n config: IndicatorConfig,\r\n key: string,\r\n defaultValue: number,\r\n): number {\r\n const raw = config.params[key];\r\n if (typeof raw === 'number' && Number.isFinite(raw)) return raw;\r\n if (typeof raw === 'string') {\r\n const parsed = Number(raw);\r\n if (Number.isFinite(parsed)) return parsed;\r\n }\r\n return defaultValue;\r\n}\r\n\r\n/** Same as getNumberParam, but clamps to >= min and rounds to int. */\r\nexport function getIntParam(\r\n config: IndicatorConfig,\r\n key: string,\r\n defaultValue: number,\r\n min = 1,\r\n): number {\r\n const v = getNumberParam(config, key, defaultValue);\r\n return Math.max(min, Math.floor(v));\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class SMAIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'sma',\r\n name: 'Simple Moving Average',\r\n placement: 'overlay' as const,\r\n defaultConfig: { period: 20 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 20, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n let sum = 0;\r\n for (let i = 0; i < data.length; i++) {\r\n sum += data[i].close;\r\n if (i >= period) sum -= data[i - period].close;\r\n if (i >= period - 1) {\r\n const val: IndicatorValue = { value: sum / period };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.value === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = priceToY(val.value, viewport);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class EMAIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'ema',\r\n name: 'Exponential Moving Average',\r\n placement: 'overlay' as const,\r\n defaultConfig: { period: 20 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 20, 1);\r\n const multiplier = 2 / (period + 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n let ema = 0;\r\n for (let i = 0; i < data.length; i++) {\r\n if (i < period - 1) {\r\n ema += data[i].close;\r\n continue;\r\n }\r\n if (i === period - 1) {\r\n ema = (ema + data[i].close) / period;\r\n } else {\r\n ema = (data[i].close - ema) * multiplier + ema;\r\n }\r\n const val: IndicatorValue = { value: ema };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.value === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = priceToY(val.value, viewport);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam, getNumberParam } from '../params.js';\r\nimport { withAlpha } from '@tradecanvas/commons';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class BollingerBandsIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'bb',\r\n name: 'Bollinger Bands',\r\n placement: 'overlay' as const,\r\n defaultConfig: { period: 20, stdDev: 2 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 20, 1);\r\n const stdDevMult = getNumberParam(config, 'stdDev', 2);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n // Running sum and sum-of-squares for O(n) calculation\r\n let sum = 0;\r\n let sumSq = 0;\r\n\r\n for (let i = 0; i < data.length; i++) {\r\n const c = data[i].close;\r\n sum += c;\r\n sumSq += c * c;\r\n\r\n if (i >= period) {\r\n const old = data[i - period].close;\r\n sum -= old;\r\n sumSq -= old * old;\r\n }\r\n\r\n if (i >= period - 1) {\r\n const sma = sum / period;\r\n // variance = E[x²] - (E[x])²\r\n const variance = sumSq / period - sma * sma;\r\n const stdDev = Math.sqrt(Math.max(0, variance));\r\n\r\n const val: IndicatorValue = {\r\n middle: sma,\r\n upper: sma + stdDevMult * stdDev,\r\n lower: sma - stdDevMult * stdDev,\r\n };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n // Build point arrays in a single pass — reuse arrays via length reset\r\n let count = 0;\r\n const maxPts = to - from + 1;\r\n const upperXs = new Float64Array(maxPts);\r\n const upperYs = new Float64Array(maxPts);\r\n const middleXs = new Float64Array(maxPts);\r\n const middleYs = new Float64Array(maxPts);\r\n const lowerXs = new Float64Array(maxPts);\r\n const lowerYs = new Float64Array(maxPts);\r\n\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.upper === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n upperXs[count] = x; upperYs[count] = priceToY(val.upper!, viewport);\r\n middleXs[count] = x; middleYs[count] = priceToY(val.middle!, viewport);\r\n lowerXs[count] = x; lowerYs[count] = priceToY(val.lower!, viewport);\r\n count++;\r\n }\r\n\r\n if (count < 2) return;\r\n\r\n // Band fill\r\n ctx.beginPath();\r\n ctx.moveTo(upperXs[0], upperYs[0]);\r\n for (let i = 1; i < count; i++) ctx.lineTo(upperXs[i], upperYs[i]);\r\n for (let i = count - 1; i >= 0; i--) ctx.lineTo(lowerXs[i], lowerYs[i]);\r\n ctx.closePath();\r\n ctx.fillStyle = withAlpha(style.colors[0], 0.1);\r\n ctx.fill();\r\n\r\n // Upper line\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n ctx.moveTo(upperXs[0], upperYs[0]);\r\n for (let i = 1; i < count; i++) ctx.lineTo(upperXs[i], upperYs[i]);\r\n ctx.stroke();\r\n\r\n // Middle line\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[1] ?? style.colors[0];\r\n ctx.moveTo(middleXs[0], middleYs[0]);\r\n for (let i = 1; i < count; i++) ctx.lineTo(middleXs[i], middleYs[i]);\r\n ctx.stroke();\r\n\r\n // Lower line\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.moveTo(lowerXs[0], lowerYs[0]);\r\n for (let i = 1; i < count; i++) ctx.lineTo(lowerXs[i], lowerYs[i]);\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\nimport { IndicatorBase } from '../IndicatorBase.js';\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\n\nexport class VWAPIndicator extends IndicatorBase {\n descriptor = {\n id: 'vwap',\n name: 'Volume Weighted Average Price',\n placement: 'overlay' as const,\n defaultConfig: {},\n };\n\n calculate(data: DataSeries, _config: IndicatorConfig): IndicatorOutput {\n const values = new Map<number, IndicatorValue>();\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\n let cumulativeVolume = 0;\n let cumulativeVolumePrice = 0;\n\n for (let i = 0; i < data.length; i++) {\n const typicalPrice = (data[i].high + data[i].low + data[i].close) / 3;\n cumulativeVolume += data[i].volume;\n cumulativeVolumePrice += typicalPrice * data[i].volume;\n if (cumulativeVolume > 0) {\n const val: IndicatorValue = { value: cumulativeVolumePrice / cumulativeVolume };\n values.set(data[i].time, val);\n series[i] = val;\n }\n }\n return { values, series };\n }\n\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\n const series = output.series;\n if (!series) return;\n const { from, to } = viewport.visibleRange;\n\n ctx.beginPath();\n ctx.strokeStyle = style.colors[0];\n ctx.lineWidth = style.lineWidths[0];\n ctx.lineJoin = 'round';\n\n let started = false;\n for (let i = from; i <= to && i < series.length; i++) {\n const val = series[i];\n if (!val || val.value === undefined) continue;\n const x = barIndexToX(i, viewport);\n const y = priceToY(val.value, viewport);\n if (!started) { ctx.moveTo(x, y); started = true; }\n else ctx.lineTo(x, y);\n }\n ctx.stroke();\n }\n}\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { withAlpha } from '@tradecanvas/commons';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class IchimokuIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'ichimoku',\r\n name: 'Ichimoku Cloud',\r\n placement: 'overlay' as const,\r\n defaultConfig: { tenkan: 9, kijun: 26, senkou: 52, displacement: 26 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const tenkanPeriod = getIntParam(config, 'tenkan', 9, 1);\r\n const kijunPeriod = getIntParam(config, 'kijun', 26, 1);\r\n const senkouBPeriod = getIntParam(config, 'senkou', 52, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n // Precompute rolling high/low for each period using deque-style sliding window\r\n const rollingHL = (period: number): { highs: Float64Array; lows: Float64Array } => {\r\n const highs = new Float64Array(data.length);\r\n const lows = new Float64Array(data.length);\r\n for (let i = 0; i < data.length; i++) {\r\n let high = -Infinity;\r\n let low = Infinity;\r\n const start = Math.max(0, i - period + 1);\r\n for (let j = start; j <= i; j++) {\r\n if (data[j].high > high) high = data[j].high;\r\n if (data[j].low < low) low = data[j].low;\r\n }\r\n highs[i] = high;\r\n lows[i] = low;\r\n }\r\n return { highs, lows };\r\n };\r\n\r\n const tenkanHL = rollingHL(tenkanPeriod);\r\n const kijunHL = rollingHL(kijunPeriod);\r\n const senkouBHL = rollingHL(senkouBPeriod);\r\n\r\n for (let i = 0; i < data.length; i++) {\r\n const val: IndicatorValue = {};\r\n\r\n if (i >= tenkanPeriod - 1) {\r\n val.tenkan = (tenkanHL.highs[i] + tenkanHL.lows[i]) / 2;\r\n }\r\n if (i >= kijunPeriod - 1) {\r\n val.kijun = (kijunHL.highs[i] + kijunHL.lows[i]) / 2;\r\n }\r\n if (val.tenkan !== undefined && val.kijun !== undefined) {\r\n val.senkouA = (val.tenkan + val.kijun) / 2;\r\n }\r\n if (i >= senkouBPeriod - 1) {\r\n val.senkouB = (senkouBHL.highs[i] + senkouBHL.lows[i]) / 2;\r\n }\r\n if (i >= kijunPeriod - 1) {\r\n val.chikou = data[i].close;\r\n }\r\n\r\n if (val.tenkan !== undefined || val.kijun !== undefined || val.senkouA !== undefined || val.senkouB !== undefined) {\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n // Single pass to collect points using typed arrays\r\n const maxPts = to - from + 1;\r\n const tenkanXs = new Float64Array(maxPts); const tenkanYs = new Float64Array(maxPts); let tenkanN = 0;\r\n const kijunXs = new Float64Array(maxPts); const kijunYs = new Float64Array(maxPts); let kijunN = 0;\r\n const senkouAXs = new Float64Array(maxPts); const senkouAYs = new Float64Array(maxPts); let senkouAN = 0;\r\n const senkouBXs = new Float64Array(maxPts); const senkouBYs = new Float64Array(maxPts); let senkouBN = 0;\r\n\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val) continue;\r\n const x = barIndexToX(i, viewport);\r\n if (val.tenkan !== undefined) { tenkanXs[tenkanN] = x; tenkanYs[tenkanN] = priceToY(val.tenkan, viewport); tenkanN++; }\r\n if (val.kijun !== undefined) { kijunXs[kijunN] = x; kijunYs[kijunN] = priceToY(val.kijun, viewport); kijunN++; }\r\n if (val.senkouA !== undefined) { senkouAXs[senkouAN] = x; senkouAYs[senkouAN] = priceToY(val.senkouA, viewport); senkouAN++; }\r\n if (val.senkouB !== undefined) { senkouBXs[senkouBN] = x; senkouBYs[senkouBN] = priceToY(val.senkouB, viewport); senkouBN++; }\r\n }\r\n\r\n // Cloud fill\r\n if (senkouAN > 1 && senkouBN > 1) {\r\n const n = Math.min(senkouAN, senkouBN);\r\n ctx.beginPath();\r\n ctx.moveTo(senkouAXs[0], senkouAYs[0]);\r\n for (let i = 1; i < n; i++) ctx.lineTo(senkouAXs[i], senkouAYs[i]);\r\n for (let i = n - 1; i >= 0; i--) ctx.lineTo(senkouBXs[i], senkouBYs[i]);\r\n ctx.closePath();\r\n ctx.fillStyle = withAlpha(style.colors[2] ?? '#26A69A', 0.15);\r\n ctx.fill();\r\n }\r\n\r\n // Lines — set state once per line\r\n const drawTypedLine = (xs: Float64Array, ys: Float64Array, n: number, color: string, lw: number) => {\r\n if (n < 2) return;\r\n ctx.beginPath();\r\n ctx.strokeStyle = color;\r\n ctx.lineWidth = lw;\r\n ctx.lineJoin = 'round';\r\n ctx.moveTo(xs[0], ys[0]);\r\n for (let i = 1; i < n; i++) ctx.lineTo(xs[i], ys[i]);\r\n ctx.stroke();\r\n };\r\n\r\n drawTypedLine(tenkanXs, tenkanYs, tenkanN, style.colors[0], style.lineWidths[0]);\r\n drawTypedLine(kijunXs, kijunYs, kijunN, style.colors[1] ?? '#FF9800', style.lineWidths[0]);\r\n drawTypedLine(senkouAXs, senkouAYs, senkouAN, style.colors[2] ?? '#26A69A', 1);\r\n drawTypedLine(senkouBXs, senkouBYs, senkouBN, style.colors[3] ?? '#EF5350', 1);\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getNumberParam } from '../params.js';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class ParabolicSARIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'psar',\r\n name: 'Parabolic SAR',\r\n placement: 'overlay' as const,\r\n defaultConfig: { step: 0.02, max: 0.2 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const stepVal = getNumberParam(config, 'step', 0.02);\r\n const maxVal = getNumberParam(config, 'max', 0.2);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n if (data.length < 2) return { values, series };\r\n\r\n let isUpTrend = data[1].close > data[0].close;\r\n let af = stepVal;\r\n let ep = isUpTrend ? data[0].high : data[0].low;\r\n let sar = isUpTrend ? data[0].low : data[0].high;\r\n\r\n const val0: IndicatorValue = { value: sar, trend: isUpTrend ? 1 : -1 };\r\n values.set(data[0].time, val0);\r\n series[0] = val0;\r\n\r\n for (let i = 1; i < data.length; i++) {\r\n const prevSar = sar;\r\n sar = prevSar + af * (ep - prevSar);\r\n\r\n if (isUpTrend) {\r\n sar = Math.min(sar, data[i - 1].low);\r\n if (i >= 2) sar = Math.min(sar, data[i - 2].low);\r\n\r\n if (data[i].low < sar) {\r\n isUpTrend = false;\r\n sar = ep;\r\n ep = data[i].low;\r\n af = stepVal;\r\n } else {\r\n if (data[i].high > ep) {\r\n ep = data[i].high;\r\n af = Math.min(af + stepVal, maxVal);\r\n }\r\n }\r\n } else {\r\n sar = Math.max(sar, data[i - 1].high);\r\n if (i >= 2) sar = Math.max(sar, data[i - 2].high);\r\n\r\n if (data[i].high > sar) {\r\n isUpTrend = true;\r\n sar = ep;\r\n ep = data[i].high;\r\n af = stepVal;\r\n } else {\r\n if (data[i].low < ep) {\r\n ep = data[i].low;\r\n af = Math.min(af + stepVal, maxVal);\r\n }\r\n }\r\n }\r\n\r\n const val: IndicatorValue = { value: sar, trend: isUpTrend ? 1 : -1 };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n const dotRadius = Math.max(1.5, viewport.barWidth * 0.15);\r\n\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.value === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = priceToY(val.value, viewport);\r\n ctx.beginPath();\r\n ctx.arc(x, y, dotRadius, 0, Math.PI * 2);\r\n ctx.fillStyle = val.trend === 1 ? (style.colors[0]) : (style.colors[1] ?? '#EF5350');\r\n ctx.fill();\r\n }\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam, getNumberParam } from '../params.js';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class SupertrendIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'supertrend',\r\n name: 'Supertrend',\r\n placement: 'overlay' as const,\r\n defaultConfig: { period: 10, multiplier: 3 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 10, 1);\r\n const multiplier = getNumberParam(config, 'multiplier', 3);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n if (data.length < period) return { values, series };\r\n\r\n // ATR\r\n const trueRanges: number[] = [data[0].high - data[0].low];\r\n for (let i = 1; i < data.length; i++) {\r\n trueRanges.push(Math.max(\r\n data[i].high - data[i].low,\r\n Math.abs(data[i].high - data[i - 1].close),\r\n Math.abs(data[i].low - data[i - 1].close),\r\n ));\r\n }\r\n\r\n let atr = 0;\r\n for (let i = 0; i < period; i++) atr += trueRanges[i];\r\n atr /= period;\r\n\r\n let upperBand = 0, lowerBand = 0;\r\n let prevUpperBand = 0, prevLowerBand = 0;\r\n let supertrend = 0;\r\n let prevSupertrend = 0;\r\n let direction = 1;\r\n\r\n for (let i = period - 1; i < data.length; i++) {\r\n if (i > period - 1) {\r\n atr = (atr * (period - 1) + trueRanges[i]) / period;\r\n }\r\n\r\n const hl2 = (data[i].high + data[i].low) / 2;\r\n const basicUpper = hl2 + multiplier * atr;\r\n const basicLower = hl2 - multiplier * atr;\r\n\r\n upperBand = (basicUpper < prevUpperBand || data[i - 1].close > prevUpperBand) ? basicUpper : prevUpperBand;\r\n lowerBand = (basicLower > prevLowerBand || data[i - 1].close < prevLowerBand) ? basicLower : prevLowerBand;\r\n\r\n if (prevSupertrend === prevUpperBand) {\r\n supertrend = data[i].close <= upperBand ? upperBand : lowerBand;\r\n } else {\r\n supertrend = data[i].close >= lowerBand ? lowerBand : upperBand;\r\n }\r\n\r\n direction = supertrend === lowerBand ? 1 : -1;\r\n\r\n const val: IndicatorValue = { value: supertrend, trend: direction };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n\r\n prevUpperBand = upperBand;\r\n prevLowerBand = lowerBand;\r\n prevSupertrend = supertrend;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n const upColor = style.colors[0];\r\n const downColor = style.colors[1] ?? '#EF5350';\r\n\r\n // Draw segments per trend direction\r\n let prevX = 0, prevY = 0, prevTrend = 0;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.value === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = priceToY(val.value, viewport);\r\n const trend = val.trend ?? 1;\r\n\r\n if (prevTrend !== 0) {\r\n ctx.beginPath();\r\n ctx.strokeStyle = trend === 1 ? upColor : downColor;\r\n ctx.lineWidth = style.lineWidths[0] + 0.5;\r\n ctx.moveTo(prevX, prevY);\r\n ctx.lineTo(x, y);\r\n ctx.stroke();\r\n }\r\n\r\n prevX = x;\r\n prevY = y;\r\n prevTrend = trend;\r\n }\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam, getNumberParam } from '../params.js';\r\nimport { withAlpha } from '@tradecanvas/commons';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class KeltnerChannelIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'keltner',\r\n name: 'Keltner Channel',\r\n placement: 'overlay' as const,\r\n defaultConfig: { emaPeriod: 20, atrPeriod: 10, multiplier: 1.5 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const emaPeriod = getIntParam(config, 'emaPeriod', 20, 1);\r\n const atrPeriod = getIntParam(config, 'atrPeriod', 10, 1);\r\n const mult = getNumberParam(config, 'multiplier', 1.5);\r\n const values = new Map<number, IndicatorValue>();\r\n if (data.length < Math.max(emaPeriod, atrPeriod)) return { values };\r\n\r\n // EMA of close\r\n const emaMult = 2 / (emaPeriod + 1);\r\n let ema = data[0].close;\r\n const emaArr: number[] = [ema];\r\n for (let i = 1; i < data.length; i++) {\r\n ema = (data[i].close - ema) * emaMult + ema;\r\n emaArr.push(ema);\r\n }\r\n\r\n // ATR\r\n const trArr: number[] = [data[0].high - data[0].low];\r\n for (let i = 1; i < data.length; i++) {\r\n trArr.push(Math.max(\r\n data[i].high - data[i].low,\r\n Math.abs(data[i].high - data[i - 1].close),\r\n Math.abs(data[i].low - data[i - 1].close),\r\n ));\r\n }\r\n\r\n let atr = 0;\r\n for (let i = 0; i < atrPeriod; i++) atr += trArr[i];\r\n atr /= atrPeriod;\r\n\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n const start = Math.max(emaPeriod, atrPeriod) - 1;\r\n for (let i = start; i < data.length; i++) {\r\n if (i > start) {\r\n atr = (atr * (atrPeriod - 1) + trArr[i]) / atrPeriod;\r\n }\r\n const val: IndicatorValue = {\r\n middle: emaArr[i],\r\n upper: emaArr[i] + mult * atr,\r\n lower: emaArr[i] - mult * atr,\r\n };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n const upperPts: { x: number; y: number }[] = [];\r\n const middlePts: { x: number; y: number }[] = [];\r\n const lowerPts: { x: number; y: number }[] = [];\r\n\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val) continue;\r\n const x = barIndexToX(i, viewport);\r\n if (val.upper !== undefined) upperPts.push({ x, y: priceToY(val.upper, viewport) });\r\n if (val.middle !== undefined) middlePts.push({ x, y: priceToY(val.middle, viewport) });\r\n if (val.lower !== undefined) lowerPts.push({ x, y: priceToY(val.lower, viewport) });\r\n }\r\n\r\n this.drawBand(ctx, upperPts, lowerPts, withAlpha(style.colors[0], 0.08));\r\n this.drawLine(ctx, upperPts, style.colors[0], style.lineWidths[0]);\r\n this.drawLine(ctx, middlePts, style.colors[1] ?? style.colors[0], style.lineWidths[0]);\r\n this.drawLine(ctx, lowerPts, style.colors[0], style.lineWidths[0]);\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { withAlpha } from '@tradecanvas/commons';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class DonchianChannelIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'donchian',\r\n name: 'Donchian Channel',\r\n placement: 'overlay' as const,\r\n defaultConfig: { period: 20 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 20, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n for (let i = period - 1; i < data.length; i++) {\r\n let high = -Infinity, low = Infinity;\r\n for (let j = i - period + 1; j <= i; j++) {\r\n if (data[j].high > high) high = data[j].high;\r\n if (data[j].low < low) low = data[j].low;\r\n }\r\n const val: IndicatorValue = {\r\n upper: high,\r\n middle: (high + low) / 2,\r\n lower: low,\r\n };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n const upperPts: { x: number; y: number }[] = [];\r\n const middlePts: { x: number; y: number }[] = [];\r\n const lowerPts: { x: number; y: number }[] = [];\r\n\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val) continue;\r\n const x = barIndexToX(i, viewport);\r\n if (val.upper !== undefined) upperPts.push({ x, y: priceToY(val.upper, viewport) });\r\n if (val.middle !== undefined) middlePts.push({ x, y: priceToY(val.middle, viewport) });\r\n if (val.lower !== undefined) lowerPts.push({ x, y: priceToY(val.lower, viewport) });\r\n }\r\n\r\n this.drawBand(ctx, upperPts, lowerPts, withAlpha(style.colors[0], 0.08));\r\n this.drawLine(ctx, upperPts, style.colors[0], style.lineWidths[0]);\r\n this.drawLine(ctx, middlePts, style.colors[1] ?? '#787B86', 1);\r\n this.drawLine(ctx, lowerPts, style.colors[0], style.lineWidths[0]);\r\n }\r\n}\r\n","import type {\r\n DataSeries,\r\n IndicatorConfig,\r\n IndicatorOutput,\r\n IndicatorValue,\r\n ResolvedIndicatorStyle,\r\n ViewportState,\r\n} from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\nconst LEVEL_KEYS = ['s3', 's2', 's1', 'pp', 'r1', 'r2', 'r3'] as const;\r\ntype LevelKey = (typeof LEVEL_KEYS)[number];\r\n\r\nexport class PivotPointsIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'pivots',\r\n name: 'Pivot Points (Classic)',\r\n placement: 'overlay' as const,\r\n defaultConfig: { lookback: 24 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const lookback = getIntParam(config, 'lookback', 24, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n if (data.length <= lookback) return { values, series };\r\n\r\n for (let i = lookback; i < data.length; i++) {\r\n let high = -Infinity;\r\n let low = Infinity;\r\n for (let j = i - lookback; j < i; j++) {\r\n if (data[j].high > high) high = data[j].high;\r\n if (data[j].low < low) low = data[j].low;\r\n }\r\n const close = data[i - 1].close;\r\n const pp = (high + low + close) / 3;\r\n const range = high - low;\r\n const val: IndicatorValue = {\r\n pp,\r\n r1: 2 * pp - low,\r\n s1: 2 * pp - high,\r\n r2: pp + range,\r\n s2: pp - range,\r\n r3: high + 2 * (pp - low),\r\n s3: low - 2 * (high - pp),\r\n };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(\r\n ctx: CanvasRenderingContext2D,\r\n output: IndicatorOutput,\r\n viewport: ViewportState,\r\n style: ResolvedIndicatorStyle,\r\n ): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n const ppColor = style.colors[0];\r\n const rColor = style.colors[1] ?? '#EF5350';\r\n const sColor = style.colors[2] ?? '#26A69A';\r\n const lineWidth = style.lineWidths[0];\r\n\r\n const colorFor = (key: LevelKey): string => {\r\n if (key === 'pp') return ppColor;\r\n return key.startsWith('r') ? rColor : sColor;\r\n };\r\n\r\n for (const key of LEVEL_KEYS) {\r\n ctx.beginPath();\r\n ctx.strokeStyle = colorFor(key);\r\n ctx.lineWidth = key === 'pp' ? lineWidth : Math.max(1, lineWidth - 1);\r\n if (key !== 'pp') ctx.setLineDash([4, 3]);\r\n\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n const v = val?.[key];\r\n if (v === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = priceToY(v, viewport);\r\n if (!started) {\r\n ctx.moveTo(x, y);\r\n started = true;\r\n } else {\r\n ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n ctx.setLineDash([]);\r\n }\r\n }\r\n}\r\n","import type {\r\n DataSeries,\r\n IndicatorConfig,\r\n IndicatorOutput,\r\n IndicatorValue,\r\n ResolvedIndicatorStyle,\r\n ViewportState,\r\n} from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getNumberParam } from '../params.js';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\n/**\r\n * Anchored VWAP — VWAP that resets at a chosen anchor.\r\n * Anchor is provided as a unix-ms timestamp via params.anchorTime.\r\n * If anchorTime is missing or precedes the dataset, behaves like regular VWAP.\r\n */\r\nexport class AnchoredVWAPIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'avwap',\r\n name: 'Anchored VWAP',\r\n placement: 'overlay' as const,\r\n defaultConfig: { anchorTime: 0 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const anchorTime = getNumberParam(config, 'anchorTime', 0);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n let anchorIdx = 0;\r\n if (anchorTime > 0) {\r\n anchorIdx = data.findIndex((b) => b.time >= anchorTime);\r\n if (anchorIdx < 0) return { values, series };\r\n }\r\n\r\n let cumVol = 0;\r\n let cumVolPrice = 0;\r\n for (let i = anchorIdx; i < data.length; i++) {\r\n const typical = (data[i].high + data[i].low + data[i].close) / 3;\r\n cumVol += data[i].volume;\r\n cumVolPrice += typical * data[i].volume;\r\n if (cumVol > 0) {\r\n const val: IndicatorValue = { value: cumVolPrice / cumVol };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(\r\n ctx: CanvasRenderingContext2D,\r\n output: IndicatorOutput,\r\n viewport: ViewportState,\r\n style: ResolvedIndicatorStyle,\r\n ): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.value === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = priceToY(val.value, viewport);\r\n if (!started) {\r\n ctx.moveTo(x, y);\r\n started = true;\r\n } else {\r\n ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type {\r\n DataSeries,\r\n IndicatorConfig,\r\n IndicatorOutput,\r\n IndicatorValue,\r\n ResolvedIndicatorStyle,\r\n ViewportState,\r\n} from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getNumberParam } from '../params.js';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\n/**\r\n * ZigZag — connects swing highs/lows that exceed a percentage move threshold.\r\n * Pivots are written to series[i].pivot (price) when bar i is a confirmed swing.\r\n * meta.pivots holds the ordered list of pivot bar indices for fast rendering.\r\n */\r\nexport class ZigZagIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'zigzag',\r\n name: 'ZigZag',\r\n placement: 'overlay' as const,\r\n defaultConfig: { deviation: 5 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const devPct = Math.max(0.01, getNumberParam(config, 'deviation', 5)) / 100;\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n if (data.length < 2) return { values, series, meta: { pivots: [] } };\r\n\r\n const pivots: { idx: number; price: number; type: 'high' | 'low' }[] = [];\r\n let direction: 'up' | 'down' | null = null;\r\n let lastPivotIdx = 0;\r\n let lastPivotPrice = data[0].close;\r\n\r\n for (let i = 1; i < data.length; i++) {\r\n const high = data[i].high;\r\n const low = data[i].low;\r\n\r\n if (direction === null) {\r\n if (high >= lastPivotPrice * (1 + devPct)) {\r\n pivots.push({ idx: lastPivotIdx, price: lastPivotPrice, type: 'low' });\r\n direction = 'up';\r\n lastPivotIdx = i;\r\n lastPivotPrice = high;\r\n } else if (low <= lastPivotPrice * (1 - devPct)) {\r\n pivots.push({ idx: lastPivotIdx, price: lastPivotPrice, type: 'high' });\r\n direction = 'down';\r\n lastPivotIdx = i;\r\n lastPivotPrice = low;\r\n }\r\n continue;\r\n }\r\n\r\n if (direction === 'up') {\r\n if (high > lastPivotPrice) {\r\n lastPivotIdx = i;\r\n lastPivotPrice = high;\r\n } else if (low <= lastPivotPrice * (1 - devPct)) {\r\n pivots.push({ idx: lastPivotIdx, price: lastPivotPrice, type: 'high' });\r\n direction = 'down';\r\n lastPivotIdx = i;\r\n lastPivotPrice = low;\r\n }\r\n } else {\r\n if (low < lastPivotPrice) {\r\n lastPivotIdx = i;\r\n lastPivotPrice = low;\r\n } else if (high >= lastPivotPrice * (1 + devPct)) {\r\n pivots.push({ idx: lastPivotIdx, price: lastPivotPrice, type: 'low' });\r\n direction = 'up';\r\n lastPivotIdx = i;\r\n lastPivotPrice = high;\r\n }\r\n }\r\n }\r\n\r\n pivots.push({\r\n idx: lastPivotIdx,\r\n price: lastPivotPrice,\r\n type: direction === 'up' ? 'high' : 'low',\r\n });\r\n\r\n for (const p of pivots) {\r\n const val: IndicatorValue = { pivot: p.price };\r\n values.set(data[p.idx].time, val);\r\n series[p.idx] = val;\r\n }\r\n\r\n return { values, series, meta: { pivots } };\r\n }\r\n\r\n render(\r\n ctx: CanvasRenderingContext2D,\r\n output: IndicatorOutput,\r\n viewport: ViewportState,\r\n style: ResolvedIndicatorStyle,\r\n ): void {\r\n const pivots = output.meta?.pivots as\r\n | { idx: number; price: number }[]\r\n | undefined;\r\n if (!pivots || pivots.length < 2) return;\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n\r\n for (let k = 0; k < pivots.length; k++) {\r\n const p = pivots[k];\r\n const x = barIndexToX(p.idx, viewport);\r\n const y = priceToY(p.price, viewport);\r\n if (k === 0) ctx.moveTo(x, y);\r\n else ctx.lineTo(x, y);\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type {\r\n DataSeries,\r\n IndicatorConfig,\r\n IndicatorOutput,\r\n IndicatorValue,\r\n ResolvedIndicatorStyle,\r\n ViewportState,\r\n} from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam, getNumberParam } from '../params.js';\r\nimport { withAlpha } from '@tradecanvas/commons';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\n\r\n/**\r\n * Linear Regression Channel — fits a least-squares line over the trailing `period` closes\r\n * and offsets it by `stdDev` standard deviations of residuals to form upper/lower bands.\r\n */\r\nexport class LinearRegressionChannelIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'lrc',\r\n name: 'Linear Regression Channel',\r\n placement: 'overlay' as const,\r\n defaultConfig: { period: 100, stdDev: 2 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 100, 2);\r\n const dev = getNumberParam(config, 'stdDev', 2);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n if (data.length < period) return { values, series };\r\n\r\n for (let i = period - 1; i < data.length; i++) {\r\n const start = i - period + 1;\r\n let sumX = 0;\r\n let sumY = 0;\r\n let sumXY = 0;\r\n let sumXX = 0;\r\n for (let k = 0; k < period; k++) {\r\n const x = k;\r\n const y = data[start + k].close;\r\n sumX += x;\r\n sumY += y;\r\n sumXY += x * y;\r\n sumXX += x * x;\r\n }\r\n const denom = period * sumXX - sumX * sumX;\r\n if (denom === 0) continue;\r\n const slope = (period * sumXY - sumX * sumY) / denom;\r\n const intercept = (sumY - slope * sumX) / period;\r\n\r\n let sse = 0;\r\n for (let k = 0; k < period; k++) {\r\n const fitted = slope * k + intercept;\r\n const resid = data[start + k].close - fitted;\r\n sse += resid * resid;\r\n }\r\n const sd = Math.sqrt(sse / period);\r\n const mid = slope * (period - 1) + intercept;\r\n const val: IndicatorValue = {\r\n middle: mid,\r\n upper: mid + dev * sd,\r\n lower: mid - dev * sd,\r\n slope,\r\n };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(\r\n ctx: CanvasRenderingContext2D,\r\n output: IndicatorOutput,\r\n viewport: ViewportState,\r\n style: ResolvedIndicatorStyle,\r\n ): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n const upperPts: { x: number; y: number }[] = [];\r\n const middlePts: { x: number; y: number }[] = [];\r\n const lowerPts: { x: number; y: number }[] = [];\r\n\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val) continue;\r\n const x = barIndexToX(i, viewport);\r\n if (val.middle !== undefined) middlePts.push({ x, y: priceToY(val.middle, viewport) });\r\n if (val.upper !== undefined) upperPts.push({ x, y: priceToY(val.upper, viewport) });\r\n if (val.lower !== undefined) lowerPts.push({ x, y: priceToY(val.lower, viewport) });\r\n }\r\n\r\n this.drawBand(ctx, upperPts, lowerPts, withAlpha(style.colors[0], 0.08));\r\n this.drawLine(ctx, upperPts, style.colors[0], style.lineWidths[0]);\r\n this.drawLine(ctx, middlePts, style.colors[1] ?? style.colors[0], style.lineWidths[0]);\r\n this.drawLine(ctx, lowerPts, style.colors[0], style.lineWidths[0]);\r\n }\r\n}\r\n","import type {\r\n DataSeries,\r\n IndicatorConfig,\r\n IndicatorOutput,\r\n IndicatorValue,\r\n ResolvedIndicatorStyle,\r\n ViewportState,\r\n} from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { barIndexToX, priceToY } from '../../viewport/ScaleMapping.js';\r\nimport { getIntParam } from '../params.js';\r\n\r\n/**\r\n * Hull Moving Average — HMA(n) = WMA( 2*WMA(close, n/2) - WMA(close, n), sqrt(n) )\r\n * Designed to reduce lag while preserving smoothness.\r\n */\r\nexport class HullMAIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'hma',\r\n name: 'Hull Moving Average',\r\n placement: 'overlay' as const,\r\n defaultConfig: { period: 21 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 21, 2);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n if (data.length < period) return { values, series };\r\n\r\n const closes = data.map((b) => b.close);\r\n const halfPeriod = Math.max(2, Math.floor(period / 2));\r\n const sqrtPeriod = Math.max(2, Math.floor(Math.sqrt(period)));\r\n\r\n const wmaFull = wma(closes, period);\r\n const wmaHalf = wma(closes, halfPeriod);\r\n const diff = closes.map((_, i) =>\r\n wmaFull[i] === null || wmaHalf[i] === null ? null : 2 * (wmaHalf[i] as number) - (wmaFull[i] as number),\r\n );\r\n const hma = wmaNullable(diff, sqrtPeriod);\r\n\r\n for (let i = 0; i < data.length; i++) {\r\n if (hma[i] === null) continue;\r\n const val: IndicatorValue = { value: hma[i] as number };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(\r\n ctx: CanvasRenderingContext2D,\r\n output: IndicatorOutput,\r\n viewport: ViewportState,\r\n style: ResolvedIndicatorStyle,\r\n ): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.value === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = priceToY(val.value, viewport);\r\n if (!started) {\r\n ctx.moveTo(x, y);\r\n started = true;\r\n } else {\r\n ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n\r\nfunction wma(data: number[], period: number): (number | null)[] {\r\n const out: (number | null)[] = new Array(data.length).fill(null);\r\n if (data.length < period) return out;\r\n const denom = (period * (period + 1)) / 2;\r\n for (let i = period - 1; i < data.length; i++) {\r\n let sum = 0;\r\n for (let k = 0; k < period; k++) {\r\n sum += data[i - k] * (period - k);\r\n }\r\n out[i] = sum / denom;\r\n }\r\n return out;\r\n}\r\n\r\nfunction wmaNullable(data: (number | null)[], period: number): (number | null)[] {\r\n const out: (number | null)[] = new Array(data.length).fill(null);\r\n const denom = (period * (period + 1)) / 2;\r\n for (let i = period - 1; i < data.length; i++) {\r\n let sum = 0;\r\n let ok = true;\r\n for (let k = 0; k < period; k++) {\r\n const v = data[i - k];\r\n if (v === null) {\r\n ok = false;\r\n break;\r\n }\r\n sum += v * (period - k);\r\n }\r\n if (ok) out[i] = sum / denom;\r\n }\r\n return out;\r\n}\r\n","import type {\r\n DataSeries,\r\n IndicatorConfig,\r\n IndicatorOutput,\r\n IndicatorValue,\r\n ResolvedIndicatorStyle,\r\n ViewportState,\r\n} from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class AwesomeOscillatorIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'ao',\r\n name: 'Awesome Oscillator',\r\n placement: 'panel' as const,\r\n defaultConfig: { fast: 5, slow: 34 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const fast = getIntParam(config, 'fast', 5, 1);\r\n const slow = getIntParam(config, 'slow', 34, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n if (data.length < slow) return { values, series };\r\n\r\n const median: number[] = new Array(data.length);\r\n for (let i = 0; i < data.length; i++) {\r\n median[i] = (data[i].high + data[i].low) / 2;\r\n }\r\n\r\n let fastSum = 0;\r\n let slowSum = 0;\r\n let prevAo: number | undefined;\r\n for (let i = 0; i < data.length; i++) {\r\n slowSum += median[i];\r\n if (i >= slow) slowSum -= median[i - slow];\r\n fastSum += median[i];\r\n if (i >= fast) fastSum -= median[i - fast];\r\n\r\n if (i >= slow - 1) {\r\n const ao = fastSum / fast - slowSum / slow;\r\n const up = prevAo === undefined ? true : ao >= prevAo;\r\n const val: IndicatorValue = { value: ao, up: up ? 1 : 0 };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n prevAo = ao;\r\n }\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(\r\n ctx: CanvasRenderingContext2D,\r\n output: IndicatorOutput,\r\n viewport: ViewportState,\r\n style: ResolvedIndicatorStyle,\r\n ): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n let minVal = Infinity;\r\n let maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const v = series[i]?.value;\r\n if (v === undefined) continue;\r\n if (v < minVal) minVal = v;\r\n if (v > maxVal) maxVal = v;\r\n }\r\n if (minVal === Infinity) return;\r\n const absMax = Math.max(Math.abs(minVal), Math.abs(maxVal)) || 1;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v + absMax) / (2 * absMax));\r\n const zeroY = toY(0);\r\n const halfBar = viewport.barWidth / 2;\r\n\r\n const upColor = style.colors[0] ?? '#26A69A';\r\n const downColor = style.colors[1] ?? '#EF5350';\r\n\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.value === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n const top = Math.min(y, zeroY);\r\n const h = Math.max(Math.abs(y - zeroY), 1);\r\n ctx.fillStyle = val.up ? upColor : downColor;\r\n ctx.fillRect(x - halfBar, top, viewport.barWidth, h);\r\n }\r\n }\r\n}\r\n","import type {\r\n DataSeries,\r\n IndicatorConfig,\r\n IndicatorOutput,\r\n IndicatorValue,\r\n ResolvedIndicatorStyle,\r\n ViewportState,\r\n} from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\nimport { getIntParam } from '../params.js';\r\n\r\n/**\r\n * Chaikin Oscillator = EMA(ADL, fast) - EMA(ADL, slow)\r\n * where ADL = cumulative Σ Money Flow Volume,\r\n * and Money Flow Volume = ((close - low) - (high - close)) / (high - low) * volume.\r\n */\r\nexport class ChaikinOscillatorIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'chaikinOsc',\r\n name: 'Chaikin Oscillator',\r\n placement: 'panel' as const,\r\n defaultConfig: { fast: 3, slow: 10 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const fast = getIntParam(config, 'fast', 3, 1);\r\n const slow = getIntParam(config, 'slow', 10, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n if (data.length < slow) return { values, series };\r\n\r\n const fastMult = 2 / (fast + 1);\r\n const slowMult = 2 / (slow + 1);\r\n\r\n let adl = 0;\r\n let emaFast = 0;\r\n let emaSlow = 0;\r\n\r\n for (let i = 0; i < data.length; i++) {\r\n const { high, low, close, volume } = data[i];\r\n const range = high - low;\r\n const mfm = range === 0 ? 0 : ((close - low) - (high - close)) / range;\r\n adl += mfm * volume;\r\n\r\n if (i === 0) {\r\n emaFast = adl;\r\n emaSlow = adl;\r\n } else {\r\n emaFast = (adl - emaFast) * fastMult + emaFast;\r\n emaSlow = (adl - emaSlow) * slowMult + emaSlow;\r\n }\r\n\r\n if (i >= slow - 1) {\r\n const osc = emaFast - emaSlow;\r\n const val: IndicatorValue = { value: osc, adl };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(\r\n ctx: CanvasRenderingContext2D,\r\n output: IndicatorOutput,\r\n viewport: ViewportState,\r\n style: ResolvedIndicatorStyle,\r\n ): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n let minVal = Infinity;\r\n let maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const v = series[i]?.value;\r\n if (v === undefined) continue;\r\n if (v < minVal) minVal = v;\r\n if (v > maxVal) maxVal = v;\r\n }\r\n if (minVal === Infinity) return;\r\n const absMax = Math.max(Math.abs(minVal), Math.abs(maxVal)) || 1;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v + absMax) / (2 * absMax));\r\n const zeroY = toY(0);\r\n const halfBar = viewport.barWidth / 2;\r\n\r\n const upColor = style.colors[0] ?? '#26A69A';\r\n const downColor = style.colors[1] ?? '#EF5350';\r\n\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.value === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n const top = Math.min(y, zeroY);\r\n const h = Math.max(Math.abs(y - zeroY), 1);\r\n ctx.fillStyle = val.value >= 0 ? upColor : downColor;\r\n ctx.fillRect(x - halfBar, top, viewport.barWidth, h);\r\n }\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class RSIIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'rsi',\r\n name: 'Relative Strength Index',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 14 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 14, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n if (data.length < period + 1) return { values, series };\r\n\r\n let avgGain = 0;\r\n let avgLoss = 0;\r\n\r\n for (let i = 1; i <= period; i++) {\r\n const change = data[i].close - data[i - 1].close;\r\n if (change > 0) avgGain += change;\r\n else avgLoss -= change;\r\n }\r\n avgGain /= period;\r\n avgLoss /= period;\r\n\r\n const rsi = avgLoss === 0 ? 100 : 100 - 100 / (1 + avgGain / avgLoss);\r\n const val0: IndicatorValue = { value: rsi };\r\n values.set(data[period].time, val0);\r\n series[period] = val0;\r\n\r\n for (let i = period + 1; i < data.length; i++) {\r\n const change = data[i].close - data[i - 1].close;\r\n const gain = change > 0 ? change : 0;\r\n const loss = change < 0 ? -change : 0;\r\n avgGain = (avgGain * (period - 1) + gain) / period;\r\n avgLoss = (avgLoss * (period - 1) + loss) / period;\r\n const rs = avgLoss === 0 ? 100 : 100 - 100 / (1 + avgGain / avgLoss);\r\n const val: IndicatorValue = { value: rs };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n const toY = (val: number) => chartRect.y + chartRect.height * (1 - val / 100);\r\n\r\n // Overbought/oversold levels — single path\r\n ctx.strokeStyle = style.colors[1] ?? '#787B86';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n ctx.beginPath();\r\n for (const level of [30, 70]) {\r\n const y = toY(level);\r\n ctx.moveTo(chartRect.x, y);\r\n ctx.lineTo(chartRect.x + chartRect.width, y);\r\n }\r\n ctx.stroke();\r\n ctx.setLineDash([]);\r\n\r\n // RSI line\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val.value === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class MACDIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'macd',\r\n name: 'MACD',\r\n placement: 'panel' as const,\r\n defaultConfig: { fast: 12, slow: 26, signal: 9 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const fast = getIntParam(config, 'fast', 12, 1);\r\n const slow = getIntParam(config, 'slow', 26, 1);\r\n const signalPeriod = getIntParam(config, 'signal', 9, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n if (data.length < slow) return { values, series };\r\n\r\n // Compute EMA incrementally without storing full arrays\r\n const fastMult = 2 / (fast + 1);\r\n const slowMult = 2 / (slow + 1);\r\n const signalMult = 2 / (signalPeriod + 1);\r\n\r\n let fastEma = data[0].close;\r\n let slowEma = data[0].close;\r\n let sig = 0;\r\n let sigStarted = false;\r\n\r\n for (let i = 0; i < data.length; i++) {\r\n const c = data[i].close;\r\n if (i === 0) { fastEma = c; slowEma = c; }\r\n else { fastEma = (c - fastEma) * fastMult + fastEma; slowEma = (c - slowEma) * slowMult + slowEma; }\r\n\r\n if (i >= slow - 1) {\r\n const macd = fastEma - slowEma;\r\n if (!sigStarted) { sig = macd; sigStarted = true; }\r\n else { sig = (macd - sig) * signalMult + sig; }\r\n const histogram = macd - sig;\r\n const val: IndicatorValue = { macd, signal: sig, histogram };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n // Find range for scaling — single pass\r\n let minVal = Infinity;\r\n let maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val) continue;\r\n if (val.macd !== undefined) { if (val.macd < minVal) minVal = val.macd; if (val.macd > maxVal) maxVal = val.macd; }\r\n if (val.signal !== undefined) { if (val.signal < minVal) minVal = val.signal; if (val.signal > maxVal) maxVal = val.signal; }\r\n if (val.histogram !== undefined) { if (val.histogram < minVal) minVal = val.histogram; if (val.histogram > maxVal) maxVal = val.histogram; }\r\n }\r\n if (minVal === Infinity) return;\r\n const range = maxVal - minVal || 1;\r\n\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - minVal) / range);\r\n const zeroY = toY(0);\r\n const halfBar = viewport.barWidth / 2;\r\n\r\n // Single pass: histogram + collect MACD/signal points\r\n const posColor = style.colors[2] ?? '#26A69A';\r\n const negColor = style.colors[3] ?? '#EF5350';\r\n const macdColor = style.colors[0];\r\n const signalColor = style.colors[1] ?? '#FF9800';\r\n\r\n // Histogram — batch by color: two paths\r\n ctx.beginPath();\r\n const posPath = new Path2D();\r\n const negPath = new Path2D();\r\n\r\n let macdStarted = false;\r\n let sigStarted = false;\r\n const macdPath = new Path2D();\r\n const sigPath = new Path2D();\r\n\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val) continue;\r\n const x = barIndexToX(i, viewport);\r\n\r\n if (val.histogram !== undefined) {\r\n const y = toY(val.histogram);\r\n const top = Math.min(y, zeroY);\r\n const h = Math.max(Math.abs(y - zeroY), 1);\r\n if (val.histogram >= 0) posPath.rect(x - halfBar, top, viewport.barWidth, h);\r\n else negPath.rect(x - halfBar, top, viewport.barWidth, h);\r\n }\r\n\r\n if (val.macd !== undefined) {\r\n const y = toY(val.macd);\r\n if (!macdStarted) { macdPath.moveTo(x, y); macdStarted = true; }\r\n else macdPath.lineTo(x, y);\r\n }\r\n if (val.signal !== undefined) {\r\n const y = toY(val.signal);\r\n if (!sigStarted) { sigPath.moveTo(x, y); sigStarted = true; }\r\n else sigPath.lineTo(x, y);\r\n }\r\n }\r\n\r\n // Draw histogram\r\n ctx.fillStyle = posColor;\r\n ctx.fill(posPath);\r\n ctx.fillStyle = negColor;\r\n ctx.fill(negPath);\r\n\r\n // Draw lines\r\n ctx.strokeStyle = macdColor;\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n ctx.stroke(macdPath);\r\n\r\n ctx.strokeStyle = signalColor;\r\n ctx.stroke(sigPath);\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class StochasticIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'stochastic',\r\n name: 'Stochastic Oscillator',\r\n placement: 'panel' as const,\r\n defaultConfig: { kPeriod: 14, dPeriod: 3, smooth: 3 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const kPeriod = getIntParam(config, 'kPeriod', 14, 1);\r\n const dPeriod = getIntParam(config, 'dPeriod', 3, 1);\r\n const smooth = getIntParam(config, 'smooth', 3, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n if (data.length < kPeriod) return { values, series };\r\n\r\n // Raw %K\r\n const rawK: number[] = [];\r\n for (let i = 0; i < data.length; i++) {\r\n if (i < kPeriod - 1) { rawK.push(0); continue; }\r\n let high = -Infinity;\r\n let low = Infinity;\r\n for (let j = i - kPeriod + 1; j <= i; j++) {\r\n if (data[j].high > high) high = data[j].high;\r\n if (data[j].low < low) low = data[j].low;\r\n }\r\n rawK.push(high === low ? 50 : ((data[i].close - low) / (high - low)) * 100);\r\n }\r\n\r\n // Smoothed %K (SMA of raw %K)\r\n const kValues: number[] = [];\r\n for (let i = 0; i < rawK.length; i++) {\r\n if (i < kPeriod - 1 + smooth - 1) { kValues.push(0); continue; }\r\n let sum = 0;\r\n for (let j = i - smooth + 1; j <= i; j++) sum += rawK[j];\r\n kValues.push(sum / smooth);\r\n }\r\n\r\n // %D (SMA of %K)\r\n const startIdx = kPeriod - 1 + smooth - 1;\r\n for (let i = startIdx; i < kValues.length; i++) {\r\n const val: IndicatorValue = { k: kValues[i] };\r\n if (i >= startIdx + dPeriod - 1) {\r\n let sum = 0;\r\n for (let j = i - dPeriod + 1; j <= i; j++) sum += kValues[j];\r\n val.d = sum / dPeriod;\r\n }\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n const toY = (val: number) => chartRect.y + chartRect.height * (1 - val / 100);\r\n\r\n // Levels\r\n ctx.strokeStyle = style.colors[2] ?? '#787B86';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n for (const level of [20, 80]) {\r\n const y = toY(level);\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, y);\r\n ctx.lineTo(chartRect.x + chartRect.width, y);\r\n ctx.stroke();\r\n }\r\n ctx.setLineDash([]);\r\n\r\n // %K line\r\n const drawLine = (key: string, color: string) => {\r\n ctx.beginPath();\r\n ctx.strokeStyle = color;\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val[key] === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val[key]!);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n ctx.stroke();\r\n };\r\n\r\n drawLine('k', style.colors[0]);\r\n drawLine('d', style.colors[1] ?? '#FF9800');\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class ATRIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'atr',\r\n name: 'Average True Range',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 14 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 14, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n if (data.length < 2) return { values, series };\r\n\r\n const trueRanges: number[] = [data[0].high - data[0].low];\r\n for (let i = 1; i < data.length; i++) {\r\n const tr = Math.max(\r\n data[i].high - data[i].low,\r\n Math.abs(data[i].high - data[i - 1].close),\r\n Math.abs(data[i].low - data[i - 1].close),\r\n );\r\n trueRanges.push(tr);\r\n }\r\n\r\n let atr = 0;\r\n for (let i = 0; i < period; i++) atr += trueRanges[i];\r\n atr /= period;\r\n const val0: IndicatorValue = { value: atr };\r\n values.set(data[period - 1].time, val0);\r\n series[period - 1] = val0;\r\n\r\n for (let i = period; i < data.length; i++) {\r\n atr = (atr * (period - 1) + trueRanges[i]) / period;\r\n const val: IndicatorValue = { value: atr };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n let minVal = Infinity;\r\n let maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n minVal = Math.min(minVal, val.value);\r\n maxVal = Math.max(maxVal, val.value);\r\n }\r\n }\r\n if (minVal === Infinity) return;\r\n const range = maxVal - minVal || 1;\r\n const padding = range * 0.1;\r\n const adjMin = minVal - padding;\r\n const adjMax = maxVal + padding;\r\n const adjRange = adjMax - adjMin;\r\n\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - adjMin) / adjRange);\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class ADXIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'adx',\r\n name: 'Average Directional Index',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 14 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 14, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n if (data.length < period * 2) return { values, series };\r\n\r\n const trArr: number[] = [];\r\n const plusDM: number[] = [];\r\n const minusDM: number[] = [];\r\n\r\n for (let i = 1; i < data.length; i++) {\r\n const tr = Math.max(\r\n data[i].high - data[i].low,\r\n Math.abs(data[i].high - data[i - 1].close),\r\n Math.abs(data[i].low - data[i - 1].close),\r\n );\r\n trArr.push(tr);\r\n\r\n const upMove = data[i].high - data[i - 1].high;\r\n const downMove = data[i - 1].low - data[i].low;\r\n plusDM.push(upMove > downMove && upMove > 0 ? upMove : 0);\r\n minusDM.push(downMove > upMove && downMove > 0 ? downMove : 0);\r\n }\r\n\r\n // Smoothed values\r\n let smoothTR = 0;\r\n let smoothPlusDM = 0;\r\n let smoothMinusDM = 0;\r\n for (let i = 0; i < period; i++) {\r\n smoothTR += trArr[i];\r\n smoothPlusDM += plusDM[i];\r\n smoothMinusDM += minusDM[i];\r\n }\r\n\r\n const dxValues: number[] = [];\r\n\r\n for (let i = period; i < trArr.length; i++) {\r\n if (i > period) {\r\n smoothTR = smoothTR - smoothTR / period + trArr[i];\r\n smoothPlusDM = smoothPlusDM - smoothPlusDM / period + plusDM[i];\r\n smoothMinusDM = smoothMinusDM - smoothMinusDM / period + minusDM[i];\r\n }\r\n\r\n const plusDI = smoothTR !== 0 ? (smoothPlusDM / smoothTR) * 100 : 0;\r\n const minusDI = smoothTR !== 0 ? (smoothMinusDM / smoothTR) * 100 : 0;\r\n const diSum = plusDI + minusDI;\r\n const dx = diSum !== 0 ? Math.abs(plusDI - minusDI) / diSum * 100 : 0;\r\n dxValues.push(dx);\r\n\r\n const dataIdx = i + 1;\r\n const val: IndicatorValue = { plusDI, minusDI, dx };\r\n values.set(data[dataIdx].time, val);\r\n series[dataIdx] = val;\r\n }\r\n\r\n // ADX = smoothed DX\r\n if (dxValues.length >= period) {\r\n let adx = 0;\r\n for (let i = 0; i < period; i++) adx += dxValues[i];\r\n adx /= period;\r\n\r\n const startDataIdx = period * 2;\r\n if (startDataIdx < data.length) {\r\n const existing = values.get(data[startDataIdx].time);\r\n if (existing) existing.adx = adx;\r\n if (series[startDataIdx]) series[startDataIdx]!.adx = adx;\r\n }\r\n\r\n for (let i = period; i < dxValues.length; i++) {\r\n adx = (adx * (period - 1) + dxValues[i]) / period;\r\n const dataIdx = i + period + 1;\r\n if (dataIdx < data.length) {\r\n const existing = values.get(data[dataIdx].time);\r\n if (existing) existing.adx = adx;\r\n if (series[dataIdx]) series[dataIdx]!.adx = adx;\r\n }\r\n }\r\n }\r\n\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n const toY = (val: number) => chartRect.y + chartRect.height * (1 - val / 100);\r\n\r\n const drawLine = (key: string, color: string) => {\r\n ctx.beginPath();\r\n ctx.strokeStyle = color;\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val[key] === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val[key]!);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n ctx.stroke();\r\n };\r\n\r\n drawLine('adx', style.colors[0]);\r\n drawLine('plusDI', style.colors[1] ?? '#26A69A');\r\n drawLine('minusDI', style.colors[2] ?? '#EF5350');\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\nimport { IndicatorBase } from '../IndicatorBase.js';\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\n\nexport class OBVIndicator extends IndicatorBase {\n descriptor = {\n id: 'obv',\n name: 'On Balance Volume',\n placement: 'panel' as const,\n defaultConfig: {},\n };\n\n calculate(data: DataSeries, _config: IndicatorConfig): IndicatorOutput {\n const values = new Map<number, IndicatorValue>();\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\n if (data.length === 0) return { values, series };\n\n let obv = 0;\n const val0: IndicatorValue = { value: obv };\n values.set(data[0].time, val0);\n series[0] = val0;\n\n for (let i = 1; i < data.length; i++) {\n if (data[i].close > data[i - 1].close) obv += data[i].volume;\n else if (data[i].close < data[i - 1].close) obv -= data[i].volume;\n const val: IndicatorValue = { value: obv };\n values.set(data[i].time, val);\n series[i] = val;\n }\n return { values, series };\n }\n\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\n const series = output.series;\n if (!series) return;\n const { chartRect } = viewport;\n const { from, to } = viewport.visibleRange;\n\n let minVal = Infinity;\n let maxVal = -Infinity;\n for (let i = from; i <= to && i < series.length; i++) {\n const val = series[i];\n if (val && val.value !== undefined) {\n minVal = Math.min(minVal, val.value);\n maxVal = Math.max(maxVal, val.value);\n }\n }\n if (minVal === Infinity) return;\n const range = maxVal - minVal || 1;\n const padding = range * 0.1;\n const adjMin = minVal - padding;\n const adjRange = (maxVal + padding) - adjMin;\n\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - adjMin) / adjRange);\n\n ctx.beginPath();\n ctx.strokeStyle = style.colors[0];\n ctx.lineWidth = style.lineWidths[0];\n ctx.lineJoin = 'round';\n\n let started = false;\n for (let i = from; i <= to && i < series.length; i++) {\n const val = series[i];\n if (val && val.value !== undefined) {\n const x = barIndexToX(i, viewport);\n const y = toY(val.value);\n if (!started) { ctx.moveTo(x, y); started = true; }\n else ctx.lineTo(x, y);\n }\n }\n ctx.stroke();\n }\n}\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class WilliamsRIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'williamsR',\r\n name: 'Williams %R',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 14 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 14, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n for (let i = period - 1; i < data.length; i++) {\r\n let highestHigh = -Infinity;\r\n let lowestLow = Infinity;\r\n for (let j = i - period + 1; j <= i; j++) {\r\n if (data[j].high > highestHigh) highestHigh = data[j].high;\r\n if (data[j].low < lowestLow) lowestLow = data[j].low;\r\n }\r\n const wr = highestHigh === lowestLow ? -50 : ((highestHigh - data[i].close) / (highestHigh - lowestLow)) * -100;\r\n const val: IndicatorValue = { value: wr };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v + 100) / 100);\r\n\r\n // Levels at -20 and -80\r\n ctx.strokeStyle = style.colors[1] ?? '#787B86';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n for (const level of [-20, -80]) {\r\n const y = toY(level);\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, y);\r\n ctx.lineTo(chartRect.x + chartRect.width, y);\r\n ctx.stroke();\r\n }\r\n ctx.setLineDash([]);\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class CCIIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'cci',\r\n name: 'Commodity Channel Index',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 20 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 20, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n for (let i = period - 1; i < data.length; i++) {\r\n let sumTP = 0;\r\n for (let j = i - period + 1; j <= i; j++) {\r\n sumTP += (data[j].high + data[j].low + data[j].close) / 3;\r\n }\r\n const meanTP = sumTP / period;\r\n let sumDev = 0;\r\n for (let j = i - period + 1; j <= i; j++) {\r\n const tp = (data[j].high + data[j].low + data[j].close) / 3;\r\n sumDev += Math.abs(tp - meanTP);\r\n }\r\n const meanDev = sumDev / period;\r\n const tp = (data[i].high + data[i].low + data[i].close) / 3;\r\n const cci = meanDev === 0 ? 0 : (tp - meanTP) / (0.015 * meanDev);\r\n const val: IndicatorValue = { value: cci };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n let minVal = Infinity, maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n minVal = Math.min(minVal, val.value);\r\n maxVal = Math.max(maxVal, val.value);\r\n }\r\n }\r\n if (minVal === Infinity) return;\r\n const range = maxVal - minVal || 1;\r\n const pad = range * 0.1;\r\n const adjMin = minVal - pad, adjMax = maxVal + pad, adjRange = adjMax - adjMin;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - adjMin) / adjRange);\r\n\r\n // Levels at +100, 0, -100\r\n ctx.strokeStyle = style.colors[1] ?? '#787B86';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n for (const level of [-100, 0, 100]) {\r\n if (level >= adjMin && level <= adjMax) {\r\n const y = toY(level);\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, y);\r\n ctx.lineTo(chartRect.x + chartRect.width, y);\r\n ctx.stroke();\r\n }\r\n }\r\n ctx.setLineDash([]);\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class MFIIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'mfi',\r\n name: 'Money Flow Index',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 14 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 14, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n if (data.length < period + 1) return { values, series };\r\n\r\n const typicalPrices = data.map((b) => (b.high + b.low + b.close) / 3);\r\n const rawMF = typicalPrices.map((tp, i) => tp * data[i].volume);\r\n\r\n for (let i = period; i < data.length; i++) {\r\n let posFlow = 0, negFlow = 0;\r\n for (let j = i - period + 1; j <= i; j++) {\r\n if (typicalPrices[j] > typicalPrices[j - 1]) posFlow += rawMF[j];\r\n else if (typicalPrices[j] < typicalPrices[j - 1]) negFlow += rawMF[j];\r\n }\r\n const mfi = negFlow === 0 ? 100 : 100 - 100 / (1 + posFlow / negFlow);\r\n const val: IndicatorValue = { value: mfi };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - v / 100);\r\n\r\n ctx.strokeStyle = style.colors[1] ?? '#787B86';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n for (const level of [20, 80]) {\r\n const y = toY(level);\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, y);\r\n ctx.lineTo(chartRect.x + chartRect.width, y);\r\n ctx.stroke();\r\n }\r\n ctx.setLineDash([]);\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class AroonIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'aroon',\r\n name: 'Aroon',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 25 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 25, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n for (let i = period; i < data.length; i++) {\r\n let highIdx = 0, lowIdx = 0;\r\n let high = -Infinity, low = Infinity;\r\n for (let j = 0; j <= period; j++) {\r\n const k = i - period + j;\r\n if (data[k].high > high) { high = data[k].high; highIdx = j; }\r\n if (data[k].low < low) { low = data[k].low; lowIdx = j; }\r\n }\r\n const val: IndicatorValue = {\r\n up: (highIdx / period) * 100,\r\n down: (lowIdx / period) * 100,\r\n };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - v / 100);\r\n\r\n const drawLine = (key: string, color: string) => {\r\n ctx.beginPath();\r\n ctx.strokeStyle = color;\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val[key] === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val[key]!);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n ctx.stroke();\r\n };\r\n\r\n drawLine('up', style.colors[0]);\r\n drawLine('down', style.colors[1] ?? '#EF5350');\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class ROCIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'roc',\r\n name: 'Rate of Change',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 12 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 12, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n for (let i = period; i < data.length; i++) {\r\n const prev = data[i - period].close;\r\n const roc = prev === 0 ? 0 : ((data[i].close - prev) / prev) * 100;\r\n const val: IndicatorValue = { value: roc };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n let minVal = Infinity, maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n minVal = Math.min(minVal, val.value);\r\n maxVal = Math.max(maxVal, val.value);\r\n }\r\n }\r\n if (minVal === Infinity) return;\r\n const range = maxVal - minVal || 1;\r\n const pad = range * 0.1;\r\n const adjMin = minVal - pad, adjMax = maxVal + pad, adjRange = adjMax - adjMin;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - adjMin) / adjRange);\r\n\r\n // Zero line\r\n if (0 >= adjMin && 0 <= adjMax) {\r\n ctx.strokeStyle = style.colors[1] ?? '#787B86';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n const y = toY(0);\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, y);\r\n ctx.lineTo(chartRect.x + chartRect.width, y);\r\n ctx.stroke();\r\n ctx.setLineDash([]);\r\n }\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class TSIIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'tsi',\r\n name: 'True Strength Index',\r\n placement: 'panel' as const,\r\n defaultConfig: { longPeriod: 25, shortPeriod: 13, signalPeriod: 7 },\r\n };\r\n\r\n private emaSmooth(values: number[], period: number): number[] {\r\n const mult = 2 / (period + 1);\r\n const result: number[] = [values[0]];\r\n for (let i = 1; i < values.length; i++) {\r\n result.push((values[i] - result[i - 1]) * mult + result[i - 1]);\r\n }\r\n return result;\r\n }\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const longP = getIntParam(config, 'longPeriod', 25, 1);\r\n const shortP = getIntParam(config, 'shortPeriod', 13, 1);\r\n const sigP = getIntParam(config, 'signalPeriod', 7, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n if (data.length < 2) return { values, series };\r\n\r\n const momentum: number[] = [];\r\n const absMomentum: number[] = [];\r\n for (let i = 1; i < data.length; i++) {\r\n const m = data[i].close - data[i - 1].close;\r\n momentum.push(m);\r\n absMomentum.push(Math.abs(m));\r\n }\r\n\r\n const smoothMom = this.emaSmooth(this.emaSmooth(momentum, longP), shortP);\r\n const smoothAbsMom = this.emaSmooth(this.emaSmooth(absMomentum, longP), shortP);\r\n\r\n const tsiValues: number[] = [];\r\n for (let i = 0; i < smoothMom.length; i++) {\r\n tsiValues.push(smoothAbsMom[i] === 0 ? 0 : (smoothMom[i] / smoothAbsMom[i]) * 100);\r\n }\r\n\r\n const signalLine = this.emaSmooth(tsiValues, sigP);\r\n\r\n for (let i = 0; i < tsiValues.length; i++) {\r\n const dataIdx = i + 1;\r\n if (dataIdx < data.length) {\r\n const val: IndicatorValue = {\r\n tsi: tsiValues[i],\r\n signal: signalLine[i],\r\n };\r\n values.set(data[dataIdx].time, val);\r\n series[dataIdx] = val;\r\n }\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n let minVal = Infinity, maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val) continue;\r\n if (val.tsi !== undefined) { minVal = Math.min(minVal, val.tsi); maxVal = Math.max(maxVal, val.tsi); }\r\n if (val.signal !== undefined) { minVal = Math.min(minVal, val.signal); maxVal = Math.max(maxVal, val.signal); }\r\n }\r\n if (minVal === Infinity) return;\r\n const range = maxVal - minVal || 1;\r\n const pad = range * 0.1;\r\n const adjMin = minVal - pad, adjMax = maxVal + pad, adjRange = adjMax - adjMin;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - adjMin) / adjRange);\r\n\r\n // Zero line\r\n if (0 >= adjMin && 0 <= adjMax) {\r\n ctx.strokeStyle = '#787B86';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, toY(0));\r\n ctx.lineTo(chartRect.x + chartRect.width, toY(0));\r\n ctx.stroke();\r\n ctx.setLineDash([]);\r\n }\r\n\r\n const drawLine = (key: string, color: string) => {\r\n ctx.beginPath();\r\n ctx.strokeStyle = color;\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (!val || val[key] === undefined) continue;\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val[key]!);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n ctx.stroke();\r\n };\r\n\r\n drawLine('tsi', style.colors[0]);\r\n drawLine('signal', style.colors[1] ?? '#FF9800');\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class CMFIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'cmf',\r\n name: 'Chaikin Money Flow',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 20 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 20, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n for (let i = period - 1; i < data.length; i++) {\r\n let mfvSum = 0, volSum = 0;\r\n for (let j = i - period + 1; j <= i; j++) {\r\n const hl = data[j].high - data[j].low;\r\n const mfm = hl === 0 ? 0 : ((data[j].close - data[j].low) - (data[j].high - data[j].close)) / hl;\r\n mfvSum += mfm * data[j].volume;\r\n volSum += data[j].volume;\r\n }\r\n const val: IndicatorValue = { value: volSum === 0 ? 0 : mfvSum / volSum };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n let minVal = Infinity, maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n minVal = Math.min(minVal, val.value);\r\n maxVal = Math.max(maxVal, val.value);\r\n }\r\n }\r\n if (minVal === Infinity) return;\r\n const range = maxVal - minVal || 1;\r\n const pad = range * 0.1;\r\n const adjMin = minVal - pad, adjMax = maxVal + pad, adjRange = adjMax - adjMin;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - adjMin) / adjRange);\r\n\r\n // Zero line\r\n if (0 >= adjMin && 0 <= adjMax) {\r\n ctx.strokeStyle = '#787B86';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, toY(0));\r\n ctx.lineTo(chartRect.x + chartRect.width, toY(0));\r\n ctx.stroke();\r\n ctx.setLineDash([]);\r\n }\r\n\r\n // Histogram bars\r\n const halfBar = viewport.barWidth / 2;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n const zeroY = toY(0);\r\n ctx.fillStyle = val.value >= 0 ? (style.colors[0]) : (style.colors[1] ?? '#EF5350');\r\n const top = Math.min(y, zeroY);\r\n ctx.fillRect(x - halfBar, top, viewport.barWidth, Math.max(Math.abs(y - zeroY), 1));\r\n }\r\n }\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class StdDevIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'stddev',\r\n name: 'Standard Deviation',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 20 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 20, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n for (let i = period - 1; i < data.length; i++) {\r\n let sum = 0;\r\n for (let j = i - period + 1; j <= i; j++) sum += data[j].close;\r\n const mean = sum / period;\r\n let variance = 0;\r\n for (let j = i - period + 1; j <= i; j++) {\r\n const d = data[j].close - mean;\r\n variance += d * d;\r\n }\r\n const val: IndicatorValue = { value: Math.sqrt(variance / period) };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n let minVal = Infinity, maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n minVal = Math.min(minVal, val.value);\r\n maxVal = Math.max(maxVal, val.value);\r\n }\r\n }\r\n if (minVal === Infinity) return;\r\n const range = maxVal - minVal || 1;\r\n const pad = range * 0.1;\r\n const adjMin = minVal - pad, adjRange = (maxVal + pad) - adjMin;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - adjMin) / adjRange);\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\n\r\nexport class VolumeProfileIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'volumeProfile',\r\n name: 'Volume Profile',\r\n placement: 'panel' as const,\r\n defaultConfig: { rows: 24 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const rows = getIntParam(config, 'rows', 24, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n if (data.length === 0) return { values, series };\r\n\r\n let minPrice = Infinity, maxPrice = -Infinity;\r\n for (const bar of data) {\r\n if (bar.low < minPrice) minPrice = bar.low;\r\n if (bar.high > maxPrice) maxPrice = bar.high;\r\n }\r\n\r\n const range = maxPrice - minPrice || 1;\r\n const rowHeight = range / rows;\r\n const bins = new Array(rows).fill(0);\r\n\r\n for (const bar of data) {\r\n const typicalPrice = (bar.high + bar.low + bar.close) / 3;\r\n const bin = Math.min(rows - 1, Math.floor((typicalPrice - minPrice) / rowHeight));\r\n bins[bin] += bar.volume;\r\n }\r\n\r\n // Store bins as values keyed by a synthetic timestamp (row index)\r\n for (let i = 0; i < rows; i++) {\r\n const price = minPrice + (i + 0.5) * rowHeight;\r\n values.set(i, { price, volume: bins[i], rowIndex: i });\r\n }\r\n\r\n return {\r\n values,\r\n series,\r\n meta: { minPrice, maxPrice, rows, rowHeight, bins, maxVolume: Math.max(...bins) },\r\n };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const { chartRect } = viewport;\r\n const meta = output.meta as { minPrice: number; maxPrice: number; rows: number; rowHeight: number; bins: number[]; maxVolume: number } | undefined;\r\n if (!meta || meta.maxVolume === 0) return;\r\n\r\n const { minPrice, rows, rowHeight, bins, maxVolume } = meta;\r\n const barHeight = chartRect.height / rows;\r\n const maxBarWidth = chartRect.width * 0.3;\r\n\r\n for (let i = 0; i < rows; i++) {\r\n const price = minPrice + (i + 0.5) * rowHeight;\r\n const ratio = (price - viewport.priceRange.min) / (viewport.priceRange.max - viewport.priceRange.min);\r\n const y = chartRect.y + chartRect.height * (1 - ratio);\r\n const width = (bins[i] / maxVolume) * maxBarWidth;\r\n\r\n ctx.fillStyle = bins[i] > maxVolume * 0.7\r\n ? (style.colors[1] ?? 'rgba(255, 152, 0, 0.5)')\r\n : (style.colors[0] ?? 'rgba(33, 150, 243, 0.3)');\r\n ctx.fillRect(chartRect.x, y - barHeight / 2, width, Math.max(barHeight - 1, 1));\r\n }\r\n }\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\nimport { IndicatorBase } from '../IndicatorBase.js';\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\n\nexport class AccumulationDistributionIndicator extends IndicatorBase {\n descriptor = {\n id: 'ad',\n name: 'Accumulation/Distribution',\n placement: 'panel' as const,\n defaultConfig: {},\n };\n\n calculate(data: DataSeries, _config: IndicatorConfig): IndicatorOutput {\n const values = new Map<number, IndicatorValue>();\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\n if (data.length === 0) return { values, series };\n\n let ad = 0;\n for (let i = 0; i < data.length; i++) {\n const hl = data[i].high - data[i].low;\n const mfm = hl === 0 ? 0 : ((data[i].close - data[i].low) - (data[i].high - data[i].close)) / hl;\n ad += mfm * data[i].volume;\n const val: IndicatorValue = { value: ad };\n values.set(data[i].time, val);\n series[i] = val;\n }\n return { values, series };\n }\n\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\n const series = output.series;\n if (!series) return;\n const { chartRect } = viewport;\n const { from, to } = viewport.visibleRange;\n\n let minVal = Infinity, maxVal = -Infinity;\n for (let i = from; i <= to && i < series.length; i++) {\n const val = series[i];\n if (val && val.value !== undefined) {\n minVal = Math.min(minVal, val.value);\n maxVal = Math.max(maxVal, val.value);\n }\n }\n if (minVal === Infinity) return;\n const range = maxVal - minVal || 1;\n const pad = range * 0.1;\n const adjMin = minVal - pad, adjRange = (maxVal + pad) - adjMin;\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - adjMin) / adjRange);\n\n ctx.beginPath();\n ctx.strokeStyle = style.colors[0];\n ctx.lineWidth = style.lineWidths[0];\n ctx.lineJoin = 'round';\n let started = false;\n for (let i = from; i <= to && i < series.length; i++) {\n const val = series[i];\n if (val && val.value !== undefined) {\n const x = barIndexToX(i, viewport);\n const y = toY(val.value);\n if (!started) { ctx.moveTo(x, y); started = true; }\n else ctx.lineTo(x, y);\n }\n }\n ctx.stroke();\n }\n}\n","import type { DataSeries, IndicatorConfig, IndicatorOutput, IndicatorValue, ResolvedIndicatorStyle, ViewportState } from '@tradecanvas/commons';\r\nimport { IndicatorBase } from '../IndicatorBase.js';\r\nimport { getIntParam } from '../params.js';\r\nimport { barIndexToX } from '../../viewport/ScaleMapping.js';\r\n\r\nexport class VROCIndicator extends IndicatorBase {\r\n descriptor = {\r\n id: 'vroc',\r\n name: 'Volume Rate of Change',\r\n placement: 'panel' as const,\r\n defaultConfig: { period: 14 },\r\n };\r\n\r\n calculate(data: DataSeries, config: IndicatorConfig): IndicatorOutput {\r\n const period = getIntParam(config, 'period', 14, 1);\r\n const values = new Map<number, IndicatorValue>();\r\n const series: (IndicatorValue | null)[] = new Array(data.length).fill(null);\r\n\r\n for (let i = period; i < data.length; i++) {\r\n const prev = data[i - period].volume;\r\n const vroc = prev === 0 ? 0 : ((data[i].volume - prev) / prev) * 100;\r\n const val: IndicatorValue = { value: vroc };\r\n values.set(data[i].time, val);\r\n series[i] = val;\r\n }\r\n return { values, series };\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, output: IndicatorOutput, viewport: ViewportState, style: ResolvedIndicatorStyle): void {\r\n const series = output.series;\r\n if (!series) return;\r\n const { chartRect } = viewport;\r\n const { from, to } = viewport.visibleRange;\r\n\r\n let minVal = Infinity, maxVal = -Infinity;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n minVal = Math.min(minVal, val.value);\r\n maxVal = Math.max(maxVal, val.value);\r\n }\r\n }\r\n if (minVal === Infinity) return;\r\n const range = maxVal - minVal || 1;\r\n const pad = range * 0.1;\r\n const adjMin = minVal - pad, adjMax = maxVal + pad, adjRange = adjMax - adjMin;\r\n const toY = (v: number) => chartRect.y + chartRect.height * (1 - (v - adjMin) / adjRange);\r\n\r\n // Zero line\r\n if (0 >= adjMin && 0 <= adjMax) {\r\n ctx.strokeStyle = '#787B86';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, toY(0));\r\n ctx.lineTo(chartRect.x + chartRect.width, toY(0));\r\n ctx.stroke();\r\n ctx.setLineDash([]);\r\n }\r\n\r\n ctx.beginPath();\r\n ctx.strokeStyle = style.colors[0];\r\n ctx.lineWidth = style.lineWidths[0];\r\n ctx.lineJoin = 'round';\r\n let started = false;\r\n for (let i = from; i <= to && i < series.length; i++) {\r\n const val = series[i];\r\n if (val && val.value !== undefined) {\r\n const x = barIndexToX(i, viewport);\r\n const y = toY(val.value);\r\n if (!started) { ctx.moveTo(x, y); started = true; }\r\n else ctx.lineTo(x, y);\r\n }\r\n }\r\n ctx.stroke();\r\n }\r\n}\r\n","import type { IndicatorEngine } from './IndicatorEngine.js';\r\n// Overlays\r\nimport { SMAIndicator } from './overlay/SMA.js';\r\nimport { EMAIndicator } from './overlay/EMA.js';\r\nimport { BollingerBandsIndicator } from './overlay/BollingerBands.js';\r\nimport { VWAPIndicator } from './overlay/VWAP.js';\r\nimport { IchimokuIndicator } from './overlay/Ichimoku.js';\r\nimport { ParabolicSARIndicator } from './overlay/ParabolicSAR.js';\r\nimport { SupertrendIndicator } from './overlay/Supertrend.js';\r\nimport { KeltnerChannelIndicator } from './overlay/KeltnerChannel.js';\r\nimport { DonchianChannelIndicator } from './overlay/DonchianChannel.js';\r\nimport { PivotPointsIndicator } from './overlay/PivotPoints.js';\r\nimport { AnchoredVWAPIndicator } from './overlay/AnchoredVWAP.js';\r\nimport { ZigZagIndicator } from './overlay/ZigZag.js';\r\nimport { LinearRegressionChannelIndicator } from './overlay/LinearRegressionChannel.js';\r\nimport { HullMAIndicator } from './overlay/HullMA.js';\r\nimport { AwesomeOscillatorIndicator } from './panel/AwesomeOscillator.js';\r\nimport { ChaikinOscillatorIndicator } from './panel/ChaikinOscillator.js';\r\n// Panels\r\nimport { RSIIndicator } from './panel/RSI.js';\r\nimport { MACDIndicator } from './panel/MACD.js';\r\nimport { StochasticIndicator } from './panel/Stochastic.js';\r\nimport { ATRIndicator } from './panel/ATR.js';\r\nimport { ADXIndicator } from './panel/ADX.js';\r\nimport { OBVIndicator } from './panel/OBV.js';\r\nimport { WilliamsRIndicator } from './panel/WilliamsR.js';\r\nimport { CCIIndicator } from './panel/CCI.js';\r\nimport { MFIIndicator } from './panel/MFI.js';\r\nimport { AroonIndicator } from './panel/Aroon.js';\r\nimport { ROCIndicator } from './panel/ROC.js';\r\nimport { TSIIndicator } from './panel/TSI.js';\r\nimport { CMFIndicator } from './panel/CMF.js';\r\nimport { StdDevIndicator } from './panel/StdDev.js';\r\nimport { VolumeProfileIndicator } from './panel/VolumeProfile.js';\r\nimport { AccumulationDistributionIndicator } from './panel/AccumulationDistribution.js';\r\nimport { VROCIndicator } from './panel/VROC.js';\r\n\r\nexport function registerBuiltInIndicators(engine: IndicatorEngine): void {\r\n // Overlays\r\n engine.register(new SMAIndicator());\r\n engine.register(new EMAIndicator());\r\n engine.register(new BollingerBandsIndicator());\r\n engine.register(new VWAPIndicator());\r\n engine.register(new IchimokuIndicator());\r\n engine.register(new ParabolicSARIndicator());\r\n engine.register(new SupertrendIndicator());\r\n engine.register(new KeltnerChannelIndicator());\r\n engine.register(new DonchianChannelIndicator());\r\n engine.register(new PivotPointsIndicator());\r\n engine.register(new AnchoredVWAPIndicator());\r\n engine.register(new ZigZagIndicator());\r\n engine.register(new LinearRegressionChannelIndicator());\r\n engine.register(new HullMAIndicator());\r\n // Panels\r\n engine.register(new RSIIndicator());\r\n engine.register(new MACDIndicator());\r\n engine.register(new StochasticIndicator());\r\n engine.register(new ATRIndicator());\r\n engine.register(new ADXIndicator());\r\n engine.register(new OBVIndicator());\r\n engine.register(new WilliamsRIndicator());\r\n engine.register(new CCIIndicator());\r\n engine.register(new MFIIndicator());\r\n engine.register(new AroonIndicator());\r\n engine.register(new ROCIndicator());\r\n engine.register(new TSIIndicator());\r\n engine.register(new CMFIndicator());\r\n engine.register(new StdDevIndicator());\r\n engine.register(new VolumeProfileIndicator());\r\n engine.register(new AccumulationDistributionIndicator());\r\n engine.register(new VROCIndicator());\r\n engine.register(new AwesomeOscillatorIndicator());\r\n engine.register(new ChaikinOscillatorIndicator());\r\n}\r\n","import type { DataSeries, IndicatorConfig, IndicatorOutput } from '@tradecanvas/commons';\r\n\r\n/** Request sent from main thread → worker. */\r\nexport type IndicatorWorkerRequest =\r\n | {\r\n type: 'calculate';\r\n requestId: number;\r\n indicatorId: string;\r\n config: IndicatorConfig;\r\n data: DataSeries;\r\n }\r\n | { type: 'ping'; requestId: number };\r\n\r\n/** Response posted from worker → main thread. */\r\nexport type IndicatorWorkerResponse =\r\n | { type: 'result'; requestId: number; output: IndicatorOutput }\r\n | { type: 'pong'; requestId: number }\r\n | { type: 'error'; requestId: number; message: string };\r\n\r\nexport function isWorkerResponse(value: unknown): value is IndicatorWorkerResponse {\r\n if (typeof value !== 'object' || value === null) return false;\r\n const v = value as { type?: unknown; requestId?: unknown };\r\n if (typeof v.requestId !== 'number') return false;\r\n return v.type === 'result' || v.type === 'pong' || v.type === 'error';\r\n}\r\n","import type {\r\n DataSeries,\r\n IndicatorConfig,\r\n IndicatorOutput,\r\n IndicatorPlugin,\r\n} from '@tradecanvas/commons';\r\nimport { isWorkerResponse } from './messages.js';\r\nimport type { IndicatorWorkerRequest, IndicatorWorkerResponse } from './messages.js';\r\n\r\n/**\r\n * A minimal worker shape — easier to mock than the full DOM `Worker`.\r\n * Real `Worker` instances satisfy this interface; tests can pass a stub.\r\n */\r\nexport interface WorkerLike {\r\n postMessage(msg: unknown): void;\r\n addEventListener(\r\n type: 'message' | 'error' | 'messageerror',\r\n listener: (ev: MessageEvent | ErrorEvent) => void,\r\n ): void;\r\n removeEventListener(\r\n type: 'message' | 'error' | 'messageerror',\r\n listener: (ev: MessageEvent | ErrorEvent) => void,\r\n ): void;\r\n terminate(): void;\r\n}\r\n\r\ninterface PendingRequest {\r\n resolve: (output: IndicatorOutput) => void;\r\n reject: (err: Error) => void;\r\n timer: ReturnType<typeof setTimeout> | null;\r\n}\r\n\r\nexport interface IndicatorWorkerHostOptions {\r\n /** Synchronous fallback registry. Used when no worker is provided. */\r\n fallbackPlugins?: Map<string, IndicatorPlugin>;\r\n /** Per-request timeout in ms. Default 30s. Set to 0 to disable. */\r\n timeoutMs?: number;\r\n}\r\n\r\n/**\r\n * Main-thread façade for indicator calculations. When a `Worker` is provided,\r\n * `calculate()` posts the request and resolves with the worker's response.\r\n * Without a worker, it falls back to synchronous calculation against\r\n * `fallbackPlugins` — useful for SSR, tests, or as a safety net.\r\n *\r\n * Render is intentionally NOT routed through the worker because it needs\r\n * `CanvasRenderingContext2D`. This class only offloads `calculate()`.\r\n */\r\nexport class IndicatorWorkerHost {\r\n private worker: WorkerLike | null;\r\n private fallbackPlugins: Map<string, IndicatorPlugin>;\r\n private timeoutMs: number;\r\n private nextRequestId = 1;\r\n private pending = new Map<number, PendingRequest>();\r\n private messageHandler: (ev: MessageEvent | ErrorEvent) => void;\r\n\r\n constructor(worker: WorkerLike | null, options: IndicatorWorkerHostOptions = {}) {\r\n this.worker = worker;\r\n this.fallbackPlugins = options.fallbackPlugins ?? new Map();\r\n this.timeoutMs = options.timeoutMs ?? 30_000;\r\n this.messageHandler = (ev) => this.handleMessage(ev);\r\n if (this.worker) {\r\n this.worker.addEventListener('message', this.messageHandler);\r\n this.worker.addEventListener('error', this.messageHandler);\r\n }\r\n }\r\n\r\n /** True when a worker is attached. False means calls run synchronously. */\r\n hasWorker(): boolean {\r\n return this.worker !== null;\r\n }\r\n\r\n registerFallbackPlugin(plugin: IndicatorPlugin): void {\r\n this.fallbackPlugins.set(plugin.descriptor.id, plugin);\r\n }\r\n\r\n /**\r\n * Compute an indicator output. Routes through the worker when present,\r\n * otherwise calls the fallback plugin synchronously.\r\n */\r\n async calculate(\r\n indicatorId: string,\r\n config: IndicatorConfig,\r\n data: DataSeries,\r\n ): Promise<IndicatorOutput> {\r\n if (!this.worker) {\r\n const plugin = this.fallbackPlugins.get(indicatorId);\r\n if (!plugin) throw new Error(`Unknown indicator: ${indicatorId}`);\r\n return plugin.calculate(data, config);\r\n }\r\n\r\n const requestId = this.nextRequestId++;\r\n const req: IndicatorWorkerRequest = {\r\n type: 'calculate',\r\n requestId,\r\n indicatorId,\r\n config,\r\n data,\r\n };\r\n\r\n return new Promise<IndicatorOutput>((resolve, reject) => {\r\n const entry: PendingRequest = { resolve, reject, timer: null };\r\n if (this.timeoutMs > 0) {\r\n entry.timer = setTimeout(() => {\r\n this.pending.delete(requestId);\r\n reject(new Error(`Indicator worker timeout (${this.timeoutMs}ms): ${indicatorId}`));\r\n }, this.timeoutMs);\r\n }\r\n this.pending.set(requestId, entry);\r\n this.worker!.postMessage(req);\r\n });\r\n }\r\n\r\n /** Issue a ping; resolves when the worker responds. Useful for health checks. */\r\n ping(): Promise<void> {\r\n if (!this.worker) return Promise.resolve();\r\n const requestId = this.nextRequestId++;\r\n return new Promise<void>((resolve, reject) => {\r\n const entry: PendingRequest = {\r\n resolve: () => resolve(),\r\n reject,\r\n timer:\r\n this.timeoutMs > 0\r\n ? setTimeout(() => {\r\n this.pending.delete(requestId);\r\n reject(new Error('Indicator worker ping timeout'));\r\n }, this.timeoutMs)\r\n : null,\r\n };\r\n this.pending.set(requestId, entry);\r\n this.worker!.postMessage({ type: 'ping', requestId });\r\n });\r\n }\r\n\r\n terminate(): void {\r\n if (this.worker) {\r\n this.worker.removeEventListener('message', this.messageHandler);\r\n this.worker.removeEventListener('error', this.messageHandler);\r\n this.worker.terminate();\r\n this.worker = null;\r\n }\r\n for (const entry of this.pending.values()) {\r\n if (entry.timer) clearTimeout(entry.timer);\r\n entry.reject(new Error('Indicator worker terminated'));\r\n }\r\n this.pending.clear();\r\n }\r\n\r\n private handleMessage(ev: MessageEvent | ErrorEvent): void {\r\n const data = (ev as MessageEvent).data;\r\n if (data !== undefined) {\r\n if (!isWorkerResponse(data)) return;\r\n this.dispatchResponse(data);\r\n return;\r\n }\r\n\r\n // No data field → treat as an error event. Reject all pending requests.\r\n const message = (ev as ErrorEvent).message ?? 'Indicator worker error';\r\n for (const [id, entry] of this.pending) {\r\n if (entry.timer) clearTimeout(entry.timer);\r\n entry.reject(new Error(message));\r\n this.pending.delete(id);\r\n }\r\n }\r\n\r\n private dispatchResponse(res: IndicatorWorkerResponse): void {\r\n const entry = this.pending.get(res.requestId);\r\n if (!entry) return;\r\n this.pending.delete(res.requestId);\r\n if (entry.timer) clearTimeout(entry.timer);\r\n\r\n if (res.type === 'error') {\r\n entry.reject(new Error(res.message));\r\n return;\r\n }\r\n if (res.type === 'pong') {\r\n entry.resolve(undefined as unknown as IndicatorOutput);\r\n return;\r\n }\r\n entry.resolve(res.output);\r\n }\r\n}\r\n","import type { ViewportState, Theme } from '@tradecanvas/commons';\nimport { computeTickStep } from '@tradecanvas/commons';\n\nexport class GridRenderer {\n private visible = true;\n\n setVisible(v: boolean): void { this.visible = v; }\n isVisible(): boolean { return this.visible; }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n if (!this.visible) return;\n const { chartRect, priceRange } = viewport;\n ctx.strokeStyle = theme.grid;\n ctx.lineWidth = 1;\n\n const range = priceRange.max - priceRange.min;\n if (range <= 0) return;\n const invRange = 1 / range;\n\n // Single path for all grid lines — one stroke call\n ctx.beginPath();\n\n // Horizontal grid lines (price levels)\n const priceStep = computeTickStep(priceRange.min, priceRange.max, 8);\n const firstPrice = Math.ceil(priceRange.min / priceStep) * priceStep;\n for (let price = firstPrice; price <= priceRange.max; price += priceStep) {\n const y = Math.round(chartRect.y + chartRect.height * (1 - (price - priceRange.min) * invRange)) + 0.5;\n ctx.moveTo(chartRect.x, y);\n ctx.lineTo(chartRect.x + chartRect.width, y);\n }\n\n // Vertical grid lines (time intervals)\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const barsPerGrid = Math.max(1, Math.ceil(80 / barUnit));\n const { from, to } = viewport.visibleRange;\n const offsetX = -viewport.offset + chartRect.x + viewport.barWidth / 2;\n for (let i = from; i <= to; i++) {\n if (i % barsPerGrid !== 0) continue;\n const x = Math.round(i * barUnit + offsetX) + 0.5;\n ctx.moveTo(x, chartRect.y);\n ctx.lineTo(x, chartRect.y + chartRect.height);\n }\n\n ctx.stroke();\n }\n}\n","import type { ViewportState, Theme } from '@tradecanvas/commons';\nimport { computeTickStep, formatPrice, PRICE_AXIS_WIDTH } from '@tradecanvas/commons';\n\nexport class PriceAxis {\n private locale = 'en-US';\n\n setLocale(locale: string): void {\n this.locale = locale;\n }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n const { chartRect, priceRange } = viewport;\n const axisX = chartRect.x + chartRect.width;\n const range = priceRange.max - priceRange.min;\n if (range <= 0) return;\n const invRange = 1 / range;\n\n // Subtle vertical divider — single pixel, less assertive than a solid axis\n // line. Looks closer to TradingView's premium feel.\n ctx.strokeStyle = theme.axisLine;\n ctx.lineWidth = 1;\n ctx.globalAlpha = 0.65;\n ctx.beginPath();\n ctx.moveTo(axisX + 0.5, chartRect.y);\n ctx.lineTo(axisX + 0.5, chartRect.y + chartRect.height);\n ctx.stroke();\n ctx.globalAlpha = 1;\n\n // Compute labels\n const step = computeTickStep(priceRange.min, priceRange.max, 8);\n const firstPrice = Math.ceil(priceRange.min / step) * step;\n const precision = step < 1 ? Math.ceil(-Math.log10(step)) + 1 : 2;\n const font = `500 ${theme.font.sizeSmall}px ${theme.font.family}`;\n\n // Collect label positions\n const labels: { y: number; text: string }[] = [];\n for (let price = firstPrice; price <= priceRange.max; price += step) {\n const y = chartRect.y + chartRect.height * (1 - (price - priceRange.min) * invRange);\n labels.push({ y, text: formatPrice(price, precision, this.locale) });\n }\n\n ctx.font = font;\n ctx.textBaseline = 'middle';\n ctx.textAlign = 'left';\n\n // Tiny tick marks (3px notch) — gives the axis structure without the heavy\n // background rectangles that the previous implementation drew per label.\n ctx.strokeStyle = theme.axisLine;\n ctx.globalAlpha = 0.45;\n ctx.beginPath();\n for (const { y } of labels) {\n ctx.moveTo(axisX + 1, y + 0.5);\n ctx.lineTo(axisX + 4, y + 0.5);\n }\n ctx.stroke();\n ctx.globalAlpha = 1;\n\n // Text labels — single fillStyle pass.\n ctx.fillStyle = theme.axisLabel;\n for (const { y, text } of labels) {\n ctx.fillText(text, axisX + 8, y);\n }\n void PRICE_AXIS_WIDTH;\n }\n}\n","import type { ViewportState, Theme, DataSeries } from '@tradecanvas/commons';\n\n// Reusable Date object — avoid allocation per bar\nconst _date = new Date();\nconst _pad2 = (n: number) => n < 10 ? '0' + n : '' + n;\n\n// Detect user's UTC offset once\nconst UTC_OFFSET_MIN = new Date().getTimezoneOffset();\nconst UTC_OFFSET_H = -UTC_OFFSET_MIN / 60;\nconst TZ_LABEL = `UTC${UTC_OFFSET_H >= 0 ? '+' : ''}${UTC_OFFSET_H}`;\n\nexport class TimeAxis {\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme, data: DataSeries, axisYOverride?: number): void {\n const { chartRect } = viewport;\n const axisY = axisYOverride ?? (chartRect.y + chartRect.height);\n\n // Subtle horizontal divider\n ctx.strokeStyle = theme.axisLine;\n ctx.lineWidth = 1;\n ctx.globalAlpha = 0.65;\n ctx.beginPath();\n ctx.moveTo(chartRect.x, axisY + 0.5);\n ctx.lineTo(chartRect.x + chartRect.width, axisY + 0.5);\n ctx.stroke();\n ctx.globalAlpha = 1;\n\n // Time labels\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const minLabelSpacing = 80;\n const barsPerLabel = Math.max(1, Math.ceil(minLabelSpacing / barUnit));\n const { from, to } = viewport.visibleRange;\n const offsetX = -viewport.offset + chartRect.x + viewport.barWidth / 2;\n\n ctx.font = `500 ${theme.font.sizeSmall}px ${theme.font.family}`;\n ctx.textBaseline = 'top';\n ctx.textAlign = 'center';\n ctx.fillStyle = theme.axisLabel;\n\n // Detect timeframe from bar spacing (approximate)\n let prevDay = -1;\n\n for (let i = from; i <= to && i < data.length; i++) {\n if (i % barsPerLabel !== 0) continue;\n const x = i * barUnit + offsetX;\n\n // Handle both milliseconds and seconds timestamps\n const rawTime = data[i].time;\n const timeMs = rawTime > 1e12 ? rawTime : rawTime * 1000;\n _date.setTime(timeMs);\n\n const day = _date.getDate();\n const month = _date.getMonth() + 1;\n const hours = _date.getHours();\n const minutes = _date.getMinutes();\n\n // Smart format: show date on day change, time otherwise\n let label: string;\n if (day !== prevDay) {\n label = `${month}/${day}`;\n prevDay = day;\n } else {\n label = `${_pad2(hours)}:${_pad2(minutes)}`;\n }\n\n ctx.fillText(label, x, axisY + 7);\n }\n\n // ─── Timezone indicator (bottom-right, like TradingView) ───\n const tzX = chartRect.x + chartRect.width - 4;\n const tzY = axisY + 7;\n ctx.font = `500 ${theme.font.sizeSmall - 1}px ${theme.font.family}`;\n ctx.textAlign = 'right';\n ctx.textBaseline = 'top';\n ctx.globalAlpha = 0.75;\n ctx.fillStyle = theme.textSecondary;\n ctx.fillText(TZ_LABEL, tzX, tzY);\n ctx.globalAlpha = 1;\n }\n}\n","import type { Point, ViewportState } from '@tradecanvas/commons';\nimport type { PanHandler } from './PanHandler.js';\nimport type { ZoomHandler } from './ZoomHandler.js';\nimport type { CrosshairHandler } from './CrosshairHandler.js';\nimport type { AxisDragHandler } from './AxisDragHandler.js';\nimport type { DrawingManager } from '../drawings/DrawingManager.js';\nimport type { TradingManager } from '../trading/TradingManager.js';\n\nexport class InteractionManager {\n private panHandler: PanHandler | null = null;\n private zoomHandler: ZoomHandler | null = null;\n private crosshairHandler: CrosshairHandler | null = null;\n private axisDragHandler: AxisDragHandler | null = null;\n private axisViewportGetter: (() => ViewportState) | null = null;\n private onAxisDoubleClick: ((axis: 'price' | 'time') => void) | null = null;\n private measureHandlers: {\n begin: (pos: Point) => void;\n move: (pos: Point) => void;\n end: () => void;\n } | null = null;\n private measuring = false;\n private onAltClick: ((pos: Point) => void) | null = null;\n private onEscape: (() => void) | null = null;\n private drawingManager: DrawingManager | null = null;\n private tradingManager: TradingManager | null = null;\n private viewportGetter: (() => ViewportState) | null = null;\n private onOverlayDirty: (() => void) | null = null;\n private boundHandlers: (() => void)[] = [];\n\n // Touch state\n private lastTouchDist = 0;\n private lastTouchMid: Point = { x: 0, y: 0 };\n private touchActive = false;\n\n // Cached bounding rect — avoid a layout read per mousemove.\n // Invalidated on pointerdown, window resize, and explicit calls.\n private cachedRect: DOMRect | null = null;\n\n constructor(private element: HTMLElement) {}\n\n setOverlayDirtyCallback(cb: () => void): void { this.onOverlayDirty = cb; }\n\n setPanHandler(handler: PanHandler): void { this.panHandler = handler; }\n setZoomHandler(handler: ZoomHandler): void { this.zoomHandler = handler; }\n setCrosshairHandler(handler: CrosshairHandler): void { this.crosshairHandler = handler; }\n\n /**\n * Enable drag-to-scale on the price + time axis regions. The viewport getter\n * lets us hit-test the chartRect on every pointer event (cheap), so this\n * picks up panel/layout changes for free.\n */\n /**\n * Shift-drag measure tool. The handlers are simple position callbacks; the\n * Chart converts pos → bar index + price internally.\n */\n /**\n * Alt/Option+click on the chart area. Used by the pinned-tooltip feature\n * so the gesture doesn't collide with drawing tools (plain click) or with\n * the trading context menu (right-click).\n */\n setAltClickHandler(handler: (pos: Point) => void): void {\n this.onAltClick = handler;\n }\n\n /** Wire an `Escape` keydown to the host — used to unpin tooltips, etc. */\n setEscapeHandler(handler: () => void): void {\n this.onEscape = handler;\n }\n\n setMeasureHandlers(handlers: {\n begin: (pos: Point) => void;\n move: (pos: Point) => void;\n end: () => void;\n }): void {\n this.measureHandlers = handlers;\n }\n\n setAxisDragHandler(\n handler: AxisDragHandler,\n viewportGetter: () => ViewportState,\n onDoubleClick?: (axis: 'price' | 'time') => void,\n ): void {\n this.axisDragHandler = handler;\n this.axisViewportGetter = viewportGetter;\n this.onAxisDoubleClick = onDoubleClick ?? null;\n }\n\n setDrawingManager(manager: DrawingManager, viewportGetter: () => ViewportState): void {\n this.drawingManager = manager;\n this.viewportGetter = viewportGetter;\n }\n\n setTradingManager(manager: TradingManager, viewportGetter: () => ViewportState): void {\n this.tradingManager = manager;\n this.viewportGetter = viewportGetter;\n }\n\n attach(): void {\n const getVP = () => this.viewportGetter?.() ?? null;\n\n // Axis hit-test: returns 'price' if pointer is in the right-side price\n // axis strip, 'time' if in the bottom time-axis strip, null otherwise.\n const hitAxis = (pos: Point): 'price' | 'time' | null => {\n const vp = this.axisViewportGetter?.();\n if (!vp) return null;\n const r = vp.chartRect;\n // Bottom strip wins if we're in the corner — clicking the corner is\n // ambiguous, but bottom is the rarer / less-disruptive default.\n if (pos.y > r.y + r.height) return 'time';\n if (pos.x > r.x + r.width) return 'price';\n return null;\n };\n\n // --- Mouse events ---\n const onMouseDown = (e: MouseEvent) => {\n // Cheap refresh point — ensures the rect is current for the\n // interaction that follows (drag, pan, draw, etc.).\n this.invalidateRect();\n const pos = this.getMousePos(e);\n const vp = getVP();\n\n // Axis drag has priority — clicking the price/time strip should never\n // start drawing or open the trading menu.\n const axis = hitAxis(pos);\n if (axis && this.axisDragHandler) {\n this.axisDragHandler.begin(axis, pos);\n return;\n }\n\n // Shift-drag measure tool — bypasses pan/draw/trade. Tracked separately\n // because the gesture spans mousedown→mouseup and crosshair should be\n // suppressed while measuring.\n if (e.shiftKey && this.measureHandlers) {\n this.measuring = true;\n this.measureHandlers.begin(pos);\n this.onOverlayDirty?.();\n return;\n }\n\n // Alt/Option-click pins the OHLC tooltip at the hovered bar. Pure\n // discrete action, doesn't enter any drag state.\n if (e.altKey && this.onAltClick) {\n this.onAltClick(pos);\n return;\n }\n\n if (this.tradingManager && vp && this.tradingManager.onPointerDown(pos, vp)) return;\n if (this.drawingManager && vp && this.drawingManager.onPointerDown(pos, vp)) return;\n this.panHandler?.onPointerDown(pos);\n };\n\n const onMouseMove = (e: MouseEvent) => {\n const pos = this.getMousePos(e);\n const vp = getVP();\n\n // Axis drag in progress — owns the gesture exclusively.\n if (this.axisDragHandler?.isActive()) {\n this.axisDragHandler.move(pos);\n return;\n }\n\n if (this.measuring && this.measureHandlers) {\n this.measureHandlers.move(pos);\n this.onOverlayDirty?.();\n return;\n }\n\n // Hover cursor over axis strips (only when nothing else is happening).\n const axisHover = hitAxis(pos);\n if (axisHover === 'price') {\n this.element.style.cursor = 'ns-resize';\n } else if (axisHover === 'time') {\n this.element.style.cursor = 'ew-resize';\n } else if (this.element.style.cursor === 'ns-resize' || this.element.style.cursor === 'ew-resize') {\n this.element.style.cursor = '';\n }\n\n if (this.tradingManager && vp && this.tradingManager.onPointerMove(pos, vp)) {\n this.crosshairHandler?.onPointerMove(pos);\n this.onOverlayDirty?.();\n return;\n }\n if (this.drawingManager && vp && this.drawingManager.onPointerMove(pos, vp)) {\n this.crosshairHandler?.onPointerMove(pos);\n this.onOverlayDirty?.();\n return;\n }\n this.panHandler?.onPointerMove(pos);\n this.crosshairHandler?.onPointerMove(pos);\n this.onOverlayDirty?.();\n };\n\n const onMouseUp = () => {\n if (this.axisDragHandler?.isActive()) {\n this.axisDragHandler.end();\n return;\n }\n if (this.measuring && this.measureHandlers) {\n this.measuring = false;\n this.measureHandlers.end();\n this.onOverlayDirty?.();\n return;\n }\n if (this.tradingManager?.onPointerUp()) return;\n if (this.drawingManager?.onPointerUp()) return;\n this.panHandler?.onPointerUp();\n };\n\n const onDblClick = (e: MouseEvent) => {\n const pos = this.getMousePos(e);\n const axis = hitAxis(pos);\n if (axis && this.onAxisDoubleClick) {\n this.onAxisDoubleClick(axis);\n }\n };\n\n const onMouseLeave = () => {\n this.panHandler?.onPointerUp();\n this.drawingManager?.onPointerUp();\n this.tradingManager?.onPointerUp();\n this.crosshairHandler?.onPointerLeave();\n this.onOverlayDirty?.();\n };\n\n const onWheel = (e: WheelEvent) => {\n e.preventDefault();\n const pos = this.getMousePos(e);\n this.zoomHandler?.onWheel(e.deltaY, pos);\n };\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && this.onEscape) {\n this.onEscape();\n }\n if (this.drawingManager?.onKeyDown(e.key, e.ctrlKey || e.metaKey)) e.preventDefault();\n };\n\n const onContextMenu = (e: MouseEvent) => {\n const vp = getVP();\n if (!this.tradingManager || !vp) return;\n const shown = this.tradingManager.onContextMenu(this.getMousePos(e), vp);\n // Only suppress the native menu when the trading context menu actually\n // opened — otherwise users with trading disabled lose right-click entirely.\n if (shown) e.preventDefault();\n };\n\n // --- Touch events ---\n const onTouchStart = (e: TouchEvent) => {\n e.preventDefault();\n this.invalidateRect();\n if (e.touches.length === 1) {\n // Single finger: pan\n const pos = this.getTouchPos(e.touches[0]);\n this.panHandler?.onPointerDown(pos);\n this.crosshairHandler?.onPointerMove(pos);\n this.touchActive = true;\n } else if (e.touches.length === 2) {\n // Two fingers: start pinch-to-zoom\n this.panHandler?.onPointerUp(); // Stop panning\n this.lastTouchDist = this.getTouchDistance(e.touches[0], e.touches[1]);\n this.lastTouchMid = this.getTouchMidpoint(e.touches[0], e.touches[1]);\n this.touchActive = true;\n }\n };\n\n const onTouchMove = (e: TouchEvent) => {\n e.preventDefault();\n if (e.touches.length === 1 && this.touchActive) {\n const pos = this.getTouchPos(e.touches[0]);\n this.panHandler?.onPointerMove(pos);\n this.crosshairHandler?.onPointerMove(pos);\n } else if (e.touches.length === 2) {\n const dist = this.getTouchDistance(e.touches[0], e.touches[1]);\n const mid = this.getTouchMidpoint(e.touches[0], e.touches[1]);\n\n // Pinch zoom\n if (this.lastTouchDist > 0) {\n const scale = dist / this.lastTouchDist;\n const delta = (scale - 1) * 0.5; // Dampen\n this.zoomHandler?.onWheel(-delta * 100, mid);\n }\n\n // Two-finger pan\n const dx = this.lastTouchMid.x - mid.x;\n if (Math.abs(dx) > 1) {\n this.panHandler?.onPointerDown(this.lastTouchMid);\n this.panHandler?.onPointerMove(mid);\n }\n\n this.lastTouchDist = dist;\n this.lastTouchMid = mid;\n }\n this.onOverlayDirty?.();\n };\n\n const onTouchEnd = (e: TouchEvent) => {\n if (e.touches.length === 0) {\n this.panHandler?.onPointerUp();\n this.crosshairHandler?.onPointerLeave();\n this.touchActive = false;\n this.lastTouchDist = 0;\n } else if (e.touches.length === 1) {\n // Went from 2 fingers to 1: restart pan\n const pos = this.getTouchPos(e.touches[0]);\n this.panHandler?.onPointerDown(pos);\n }\n };\n\n const onWindowResize = () => this.invalidateRect();\n const onElementScroll = () => this.invalidateRect();\n\n // Attach all — mouseup on document so we catch it even if cursor leaves the chart\n this.element.addEventListener('mousedown', onMouseDown);\n this.element.addEventListener('mousemove', onMouseMove);\n document.addEventListener('mouseup', onMouseUp);\n this.element.addEventListener('mouseleave', onMouseLeave);\n this.element.addEventListener('dblclick', onDblClick);\n this.element.addEventListener('wheel', onWheel, { passive: false });\n this.element.addEventListener('contextmenu', onContextMenu);\n this.element.addEventListener('touchstart', onTouchStart, { passive: false });\n this.element.addEventListener('touchmove', onTouchMove, { passive: false });\n this.element.addEventListener('touchend', onTouchEnd);\n document.addEventListener('keydown', onKeyDown);\n window.addEventListener('resize', onWindowResize);\n this.element.addEventListener('scroll', onElementScroll, { passive: true });\n\n this.boundHandlers.push(\n () => this.element.removeEventListener('mousedown', onMouseDown),\n () => this.element.removeEventListener('mousemove', onMouseMove),\n () => document.removeEventListener('mouseup', onMouseUp),\n () => this.element.removeEventListener('mouseleave', onMouseLeave),\n () => this.element.removeEventListener('dblclick', onDblClick),\n () => this.element.removeEventListener('wheel', onWheel),\n () => this.element.removeEventListener('contextmenu', onContextMenu),\n () => this.element.removeEventListener('touchstart', onTouchStart),\n () => this.element.removeEventListener('touchmove', onTouchMove),\n () => this.element.removeEventListener('touchend', onTouchEnd),\n () => document.removeEventListener('keydown', onKeyDown),\n () => window.removeEventListener('resize', onWindowResize),\n () => this.element.removeEventListener('scroll', onElementScroll),\n );\n }\n\n detach(): void {\n for (const remove of this.boundHandlers) remove();\n this.boundHandlers = [];\n this.cachedRect = null;\n }\n\n /** Force the cached bounding rect to be re-read on next access. */\n invalidateRect(): void {\n this.cachedRect = null;\n }\n\n private getRect(): DOMRect {\n if (!this.cachedRect) {\n this.cachedRect = this.element.getBoundingClientRect();\n }\n return this.cachedRect;\n }\n\n private getMousePos(e: MouseEvent): Point {\n const rect = this.getRect();\n return { x: e.clientX - rect.left, y: e.clientY - rect.top };\n }\n\n private getTouchPos(touch: Touch): Point {\n const rect = this.getRect();\n return { x: touch.clientX - rect.left, y: touch.clientY - rect.top };\n }\n\n private getTouchDistance(a: Touch, b: Touch): number {\n return Math.hypot(b.clientX - a.clientX, b.clientY - a.clientY);\n }\n\n private getTouchMidpoint(a: Touch, b: Touch): Point {\n const rect = this.getRect();\n return {\n x: (a.clientX + b.clientX) / 2 - rect.left,\n y: (a.clientY + b.clientY) / 2 - rect.top,\n };\n }\n}\n","import type { Point } from '@tradecanvas/commons';\n\nexport type PanCallback = (deltaX: number) => void;\n\n/**\n * Handles drag-to-pan with momentum/inertia scrolling.\n * On release, velocity decays smoothly over ~500ms.\n */\nexport class PanHandler {\n private dragging = false;\n private lastX = 0;\n private lastTime = 0;\n private velocity = 0;\n private momentumId = 0;\n private callback: PanCallback;\n private friction = 0.92;\n\n constructor(callback: PanCallback) {\n this.callback = callback;\n }\n\n onPointerDown(pos: Point): void {\n this.dragging = true;\n this.lastX = pos.x;\n this.lastTime = Date.now();\n this.velocity = 0;\n this.stopMomentum();\n }\n\n onPointerMove(pos: Point): void {\n if (!this.dragging) return;\n const now = Date.now();\n const delta = this.lastX - pos.x;\n const dt = now - this.lastTime;\n\n // Track velocity (pixels per ms)\n if (dt > 0) {\n this.velocity = delta / dt;\n }\n\n this.lastX = pos.x;\n this.lastTime = now;\n this.callback(delta);\n }\n\n onPointerUp(): void {\n if (!this.dragging) return;\n this.dragging = false;\n\n // Start momentum if flick was fast enough\n if (Math.abs(this.velocity) > 0.1) {\n this.startMomentum();\n }\n }\n\n private startMomentum(): void {\n this.stopMomentum();\n let v = this.velocity * 16; // Convert to pixels per frame (~16ms)\n\n const tick = () => {\n v *= this.friction;\n if (Math.abs(v) < 0.5) {\n this.momentumId = 0;\n return;\n }\n this.callback(v);\n this.momentumId = requestAnimationFrame(tick);\n };\n\n this.momentumId = requestAnimationFrame(tick);\n }\n\n private stopMomentum(): void {\n if (this.momentumId) {\n cancelAnimationFrame(this.momentumId);\n this.momentumId = 0;\n }\n }\n}\n","import type { Point } from '@tradecanvas/commons';\n\nexport type ZoomCallback = (delta: number, centerX: number) => void;\n\n/**\n * Coalesces rapid wheel events into a single callback per animation frame.\n * Accumulates delta across all wheel events within a frame, then fires once.\n */\nexport class ZoomHandler {\n private callback: ZoomCallback;\n private sensitivity: number;\n\n // rAF coalescing state\n private pendingDelta = 0;\n private pendingCenterX = 0;\n private rafId = 0;\n\n constructor(callback: ZoomCallback, sensitivity = 0.001) {\n this.callback = callback;\n this.sensitivity = sensitivity;\n }\n\n onWheel(deltaY: number, pos: Point): void {\n this.pendingDelta += -deltaY * this.sensitivity;\n this.pendingCenterX = pos.x;\n\n if (!this.rafId) {\n this.rafId = requestAnimationFrame(() => {\n this.rafId = 0;\n const delta = this.pendingDelta;\n const cx = this.pendingCenterX;\n this.pendingDelta = 0;\n this.callback(delta, cx);\n });\n }\n }\n\n dispose(): void {\n if (this.rafId) {\n cancelAnimationFrame(this.rafId);\n this.rafId = 0;\n }\n }\n}\n","import type { Point } from '@tradecanvas/commons';\n\nexport type AxisScaleCallback = (factor: number) => void;\nexport type AxisResetCallback = () => void;\n\n/**\n * Drag-to-scale handler for price + time axes (TradingView style).\n *\n * Price axis: drag down compresses (factor > 1, expand price range);\n * drag up expands (factor < 1, compress price range).\n * Time axis: drag right compresses (zoom out);\n * drag left expands (zoom in).\n *\n * Sensitivity is logarithmic so the gesture feels natural and stays bounded\n * regardless of drag distance. A small drag threshold (~3px) avoids treating\n * stray clicks as drags so `dblclick` keeps working for axis reset.\n */\nexport class AxisDragHandler {\n private dragging = false;\n private axis: 'price' | 'time' | null = null;\n private startPos: Point = { x: 0, y: 0 };\n private lastPos: Point = { x: 0, y: 0 };\n private moved = false;\n private readonly threshold = 3;\n private readonly sensitivity = 0.005;\n\n constructor(\n private onPriceScale: AxisScaleCallback,\n private onTimeScale: AxisScaleCallback,\n ) {}\n\n begin(axis: 'price' | 'time', pos: Point): void {\n this.dragging = true;\n this.axis = axis;\n this.startPos = pos;\n this.lastPos = pos;\n this.moved = false;\n }\n\n move(pos: Point): boolean {\n if (!this.dragging || !this.axis) return false;\n const dx = pos.x - this.startPos.x;\n const dy = pos.y - this.startPos.y;\n if (!this.moved && Math.hypot(dx, dy) < this.threshold) return false;\n this.moved = true;\n\n if (this.axis === 'price') {\n const delta = pos.y - this.lastPos.y;\n // drag DOWN (positive delta) → factor > 1 → range grows → chart visually\n // compresses (each price is closer to mid → bars look smaller vertically)\n const factor = Math.exp(delta * this.sensitivity);\n this.onPriceScale(factor);\n } else {\n const delta = pos.x - this.lastPos.x;\n // drag RIGHT (positive delta) → zoom out (factor > 1 expands range)\n const factor = Math.exp(delta * this.sensitivity);\n this.onTimeScale(factor);\n }\n\n this.lastPos = pos;\n return true;\n }\n\n end(): boolean {\n const consumed = this.dragging && this.moved;\n this.dragging = false;\n this.axis = null;\n this.moved = false;\n return consumed;\n }\n\n isActive(): boolean {\n return this.dragging;\n }\n}\n","import type { Point, ViewportState, Theme, DataSeries } from '@tradecanvas/commons';\nimport { formatPrice } from '@tradecanvas/commons';\nimport { xToBarIndex, yToPrice, barIndexToX } from '../viewport/ScaleMapping.js';\n\nexport type CrosshairCallback = (barIndex: number | null, point: Point | null) => void;\n\nexport type CrosshairMode = 'normal' | 'magnet' | 'hidden';\n\nexport class CrosshairHandler {\n private position: Point | null = null;\n private callback: CrosshairCallback | null = null;\n private data: DataSeries = [];\n private magnetMode = true;\n private mode: CrosshairMode = 'magnet';\n private pricePrecision = 2;\n private locale = 'en-US';\n\n // Deferred callback state — avoid calling during render\n private pendingBarIndex: number | null = null;\n private pendingPoint: Point | null = null;\n private callbackScheduled = false;\n private lastCallbackBarIndex = -1;\n\n setCallback(cb: CrosshairCallback): void {\n this.callback = cb;\n }\n\n setData(data: DataSeries): void {\n this.data = data;\n }\n\n setMagnetMode(enabled: boolean): void {\n this.magnetMode = enabled;\n this.mode = enabled ? 'magnet' : 'normal';\n }\n\n setMode(mode: CrosshairMode): void {\n this.mode = mode;\n this.magnetMode = mode === 'magnet';\n }\n\n getMode(): CrosshairMode {\n return this.mode;\n }\n\n setPricePrecision(precision: number): void {\n this.pricePrecision = precision;\n }\n\n setLocale(locale: string): void {\n this.locale = locale;\n }\n\n getPosition(): Point | null {\n return this.position;\n }\n\n onPointerMove(pos: Point): void {\n this.position = pos;\n }\n\n onPointerLeave(): void {\n this.position = null;\n this.pendingBarIndex = null;\n this.pendingPoint = null;\n this.lastCallbackBarIndex = -1;\n this.flushCallback(null, null);\n }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n if (!this.position || this.mode === 'hidden') return;\n const { chartRect } = viewport;\n let { x, y } = this.position;\n\n if (x < chartRect.x || x > chartRect.x + chartRect.width) return;\n if (y < chartRect.y || y > chartRect.y + chartRect.height) return;\n\n let barIndex = xToBarIndex(x, viewport);\n barIndex = Math.max(0, Math.min(this.data.length - 1, barIndex));\n\n if (this.magnetMode && barIndex >= 0 && barIndex < this.data.length) {\n x = barIndexToX(barIndex, viewport);\n }\n\n // Defer callback — only fire if bar changed, and fire AFTER render via microtask\n if (barIndex !== this.lastCallbackBarIndex) {\n this.pendingBarIndex = barIndex;\n this.pendingPoint = { x, y };\n this.lastCallbackBarIndex = barIndex;\n this.scheduleCallback();\n }\n\n // Subtle \"hovered bar\" tint — a translucent column behind the crosshair\n // so users have unambiguous visual feedback about which bar they're\n // sitting on. Especially helpful in dense candle charts.\n if (this.magnetMode && barIndex >= 0 && barIndex < this.data.length) {\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const halfUnit = barUnit / 2;\n ctx.fillStyle = theme.crosshair;\n ctx.globalAlpha = 0.08;\n ctx.fillRect(x - halfUnit, chartRect.y, barUnit, chartRect.height);\n ctx.globalAlpha = 1;\n }\n\n // Draw crosshair lines — minimal work, no DOM, no allocations\n ctx.setLineDash([4, 4]);\n ctx.strokeStyle = theme.crosshair;\n ctx.lineWidth = 1;\n\n ctx.beginPath();\n ctx.moveTo(Math.round(x) + 0.5, chartRect.y);\n ctx.lineTo(Math.round(x) + 0.5, chartRect.y + chartRect.height);\n ctx.stroke();\n\n ctx.beginPath();\n ctx.moveTo(chartRect.x, Math.round(y) + 0.5);\n ctx.lineTo(chartRect.x + chartRect.width, Math.round(y) + 0.5);\n ctx.stroke();\n\n ctx.setLineDash([]);\n }\n\n /**\n * Render the axis hover labels — price pill on the right, time pill on the\n * bottom. Called on the UI pass (after the axes) so the badges always sit\n * on top of the static axis labels. TradingView-style with a small notch.\n *\n * `timeAxisY` lets the host place the bottom label at the actual time axis\n * baseline (which moves when bottom panels are open).\n */\n renderAxisLabels(\n ctx: CanvasRenderingContext2D,\n viewport: ViewportState,\n theme: Theme,\n data: DataSeries,\n timeAxisY?: number,\n ): void {\n if (!this.position || this.mode === 'hidden') return;\n const { chartRect } = viewport;\n let { x, y } = this.position;\n if (x < chartRect.x || x > chartRect.x + chartRect.width) return;\n if (y < chartRect.y || y > chartRect.y + chartRect.height) return;\n\n let barIndex = xToBarIndex(x, viewport);\n barIndex = Math.max(0, Math.min(data.length - 1, barIndex));\n if (this.magnetMode && barIndex >= 0 && barIndex < data.length) {\n x = barIndexToX(barIndex, viewport);\n }\n\n const font = `600 ${theme.font.sizeSmall}px ${theme.font.family}`;\n\n // ── Price pill (right axis) ──\n const price = yToPrice(y, viewport);\n const priceText = formatPrice(price, this.pricePrecision, this.locale);\n const priceAxisX = chartRect.x + chartRect.width;\n drawAxisPill(ctx, {\n text: priceText,\n anchorX: priceAxisX,\n anchorY: y,\n orientation: 'right',\n bg: theme.text,\n fg: theme.background,\n font,\n });\n\n // ── Time pill (bottom axis) ──\n if (barIndex >= 0 && barIndex < data.length) {\n const timeText = formatBarTime(data[barIndex].time);\n const axisY = timeAxisY ?? (chartRect.y + chartRect.height);\n drawAxisPill(ctx, {\n text: timeText,\n anchorX: x,\n anchorY: axisY,\n orientation: 'bottom',\n bg: theme.text,\n fg: theme.background,\n font,\n });\n }\n }\n\n /** Fire callback outside of render frame via microtask */\n private scheduleCallback(): void {\n if (this.callbackScheduled) return;\n this.callbackScheduled = true;\n queueMicrotask(() => {\n this.callbackScheduled = false;\n this.flushCallback(this.pendingBarIndex, this.pendingPoint);\n });\n }\n\n private flushCallback(barIndex: number | null, point: Point | null): void {\n this.callback?.(barIndex, point);\n }\n}\n\ninterface AxisPillOptions {\n text: string;\n anchorX: number;\n anchorY: number;\n orientation: 'right' | 'bottom';\n bg: string;\n fg: string;\n font: string;\n}\n\n/**\n * TradingView-style axis hover pill. A rectangle with a small triangular\n * notch pointing toward the crosshair line, painted in inverted theme\n * colors so it always pops against the axis strip.\n */\nfunction drawAxisPill(ctx: CanvasRenderingContext2D, opts: AxisPillOptions): void {\n ctx.save();\n ctx.font = opts.font;\n const padX = 8;\n const padY = 4;\n const notch = 5;\n const textW = Math.ceil(ctx.measureText(opts.text).width);\n const w = textW + padX * 2;\n const h = 20 + padY * 0;\n\n if (opts.orientation === 'right') {\n const x = opts.anchorX + notch;\n const y = opts.anchorY - h / 2;\n ctx.beginPath();\n ctx.moveTo(opts.anchorX, opts.anchorY);\n ctx.lineTo(x, opts.anchorY - notch);\n ctx.lineTo(x, y);\n ctx.lineTo(x + w, y);\n ctx.lineTo(x + w, y + h);\n ctx.lineTo(x, y + h);\n ctx.lineTo(x, opts.anchorY + notch);\n ctx.closePath();\n ctx.fillStyle = opts.bg;\n ctx.fill();\n\n ctx.fillStyle = opts.fg;\n ctx.textBaseline = 'middle';\n ctx.textAlign = 'left';\n ctx.fillText(opts.text, x + padX, opts.anchorY);\n } else {\n const x = opts.anchorX - w / 2;\n const y = opts.anchorY + notch;\n ctx.beginPath();\n ctx.moveTo(opts.anchorX, opts.anchorY);\n ctx.lineTo(opts.anchorX + notch, y);\n ctx.lineTo(x + w, y);\n ctx.lineTo(x + w, y + h);\n ctx.lineTo(x, y + h);\n ctx.lineTo(x, y);\n ctx.lineTo(opts.anchorX - notch, y);\n ctx.closePath();\n ctx.fillStyle = opts.bg;\n ctx.fill();\n\n ctx.fillStyle = opts.fg;\n ctx.textBaseline = 'middle';\n ctx.textAlign = 'center';\n ctx.fillText(opts.text, opts.anchorX, y + h / 2);\n }\n ctx.restore();\n}\n\nfunction formatBarTime(rawTime: number): string {\n const ms = rawTime > 1e12 ? rawTime : rawTime * 1000;\n const d = new Date(ms);\n const m = d.getMonth() + 1;\n const day = d.getDate();\n const h = d.getHours();\n const mm = d.getMinutes();\n return `${m}/${day} ${h < 10 ? '0' + h : h}:${mm < 10 ? '0' + mm : mm}`;\n}\n","/**\n * Keyboard navigation for chart.\n * Arrow keys: navigate bars. +/-: zoom. Home/End: jump to start/end.\n * Shift+Arrow: fast navigation (10 bars). Double-click: fit content.\n */\nexport interface KeyboardCallbacks {\n scrollBars: (count: number) => void;\n zoom: (delta: number) => void;\n goToStart: () => void;\n goToEnd: () => void;\n fitContent: () => void;\n}\n\nexport class KeyboardHandler {\n private callbacks: KeyboardCallbacks;\n private enabled = true;\n\n constructor(callbacks: KeyboardCallbacks) {\n this.callbacks = callbacks;\n }\n\n setEnabled(v: boolean): void {\n this.enabled = v;\n }\n\n handleKey(e: KeyboardEvent): boolean {\n if (!this.enabled) return false;\n\n const shift = e.shiftKey;\n const step = shift ? 10 : 1;\n\n switch (e.key) {\n case 'ArrowLeft':\n this.callbacks.scrollBars(-step);\n return true;\n case 'ArrowRight':\n this.callbacks.scrollBars(step);\n return true;\n case 'ArrowUp':\n case '+':\n case '=':\n this.callbacks.zoom(0.1);\n return true;\n case 'ArrowDown':\n case '-':\n this.callbacks.zoom(-0.1);\n return true;\n case 'Home':\n this.callbacks.goToStart();\n return true;\n case 'End':\n this.callbacks.goToEnd();\n return true;\n case ' ':\n this.callbacks.fitContent();\n return true;\n default:\n return false;\n }\n }\n}\n","import type { OHLCBar, Theme, Point } from '@tradecanvas/commons';\n\n/**\n * High-performance floating tooltip.\n * Pre-builds DOM structure once, updates only textContent on hover.\n * No innerHTML, no offsetWidth reads, no layout thrashing.\n */\nexport class CrosshairTooltip {\n private el: HTMLElement | null = null;\n private visible = false;\n\n // Pre-built child nodes — updated via textContent (no reflow)\n private timeEl!: HTMLElement;\n private openEl!: HTMLElement;\n private highEl!: HTMLElement;\n private lowEl!: HTMLElement;\n private closeEl!: HTMLElement;\n private changeEl!: HTMLElement;\n private volEl!: HTMLElement;\n\n // Cached dimensions (measured once, avoids offsetWidth reads)\n private measuredWidth = 155;\n private measuredHeight = 95;\n private measured = false;\n\n create(container: HTMLElement): void {\n if (this.el) return;\n\n this.el = document.createElement('div');\n Object.assign(this.el.style, {\n position: 'absolute',\n display: 'none',\n padding: '6px 10px',\n borderRadius: '4px',\n fontSize: '11px',\n fontFamily: '-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,sans-serif',\n lineHeight: '1.5',\n pointerEvents: 'none',\n zIndex: '100',\n whiteSpace: 'nowrap',\n willChange: 'transform', // GPU layer for smooth repositioning\n });\n\n // Pre-build structure with reusable spans\n this.timeEl = this.addLine(this.el);\n const row1 = this.addLine(this.el);\n const row2 = this.addLine(this.el);\n this.changeEl = this.addLine(this.el);\n this.volEl = this.addLine(this.el);\n\n // O/H in row1, L/C in row2\n row1.append(this.label('O '), this.openEl = this.val(), this.label(' H '), this.highEl = this.val());\n row2.append(this.label('L '), this.lowEl = this.val(), this.label(' C '), this.closeEl = this.val());\n\n container.appendChild(this.el);\n }\n\n show(pos: Point, bar: OHLCBar, theme: Theme, containerRect: { width: number; height: number }): void {\n if (!this.el) return;\n\n const isUp = bar.close >= bar.open;\n const color = isUp ? theme.candleUp : theme.candleDown;\n\n // Fast number formatting (avoid toLocaleString)\n const fmt = (v: number) => v.toFixed(2);\n\n // Update text only (no DOM structure changes, no reflow)\n const d = new Date(bar.time);\n this.timeEl.textContent = `${d.getMonth() + 1}/${d.getDate()} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`;\n this.timeEl.style.color = theme.textSecondary;\n\n this.openEl.textContent = fmt(bar.open);\n this.highEl.textContent = fmt(bar.high);\n this.lowEl.textContent = fmt(bar.low);\n this.closeEl.textContent = fmt(bar.close);\n\n this.openEl.style.color = color;\n this.highEl.style.color = color;\n this.lowEl.style.color = color;\n this.closeEl.style.color = color;\n\n const change = bar.close - bar.open;\n const pct = bar.open !== 0 ? (change / bar.open * 100) : 0;\n const sign = change >= 0 ? '+' : '';\n this.changeEl.textContent = `${sign}${fmt(change)} (${sign}${pct.toFixed(2)}%)`;\n this.changeEl.style.color = color;\n\n const v = bar.volume;\n this.volEl.textContent = `Vol ${v >= 1e6 ? (v / 1e6).toFixed(1) + 'M' : v >= 1e3 ? (v / 1e3).toFixed(1) + 'K' : v.toFixed(0)}`;\n this.volEl.style.color = theme.textSecondary;\n\n // Style — use theme tokens with alpha overlay\n // Detect dark vs light theme by parsing the background luminance\n const isDark = isDarkColor(theme.background);\n this.el.style.background = isDark\n ? withAlpha(theme.background, 0.95)\n : withAlpha(theme.background, 0.97);\n this.el.style.border = `1px solid ${theme.axisLine}`;\n this.el.style.boxShadow = isDark\n ? '0 4px 12px rgba(0,0,0,0.5)'\n : '0 4px 12px rgba(0,0,0,0.15)';\n this.el.style.color = theme.text;\n // Backdrop blur for depth (optional, browser-dependent)\n this.el.style.backdropFilter = 'blur(8px)';\n\n // Measure once after first show\n if (!this.measured && this.visible) {\n this.measuredWidth = this.el.offsetWidth;\n this.measuredHeight = this.el.offsetHeight;\n this.measured = true;\n }\n\n // Position using transform (no layout trigger, GPU-composited)\n let x = pos.x + 16;\n let y = pos.y - 40;\n if (x + this.measuredWidth > containerRect.width - 80) x = pos.x - this.measuredWidth - 16;\n if (y < 4) y = 4;\n if (y + this.measuredHeight > containerRect.height) y = containerRect.height - this.measuredHeight - 4;\n\n this.el.style.transform = `translate(${Math.round(x)}px, ${Math.round(y)}px)`;\n this.el.style.left = '0';\n this.el.style.top = '0';\n\n if (!this.visible) {\n this.el.style.display = 'block';\n this.visible = true;\n }\n }\n\n hide(): void {\n if (this.el && this.visible) {\n this.el.style.display = 'none';\n this.visible = false;\n }\n }\n\n isVisible(): boolean {\n return this.visible;\n }\n\n destroy(): void {\n this.el?.remove();\n this.el = null;\n this.visible = false;\n this.measured = false;\n }\n\n private addLine(parent: HTMLElement): HTMLElement {\n const div = document.createElement('div');\n parent.appendChild(div);\n return div;\n }\n\n private label(text: string): HTMLSpanElement {\n const span = document.createElement('span');\n span.textContent = text;\n span.style.opacity = '0.6';\n return span;\n }\n\n private val(): HTMLSpanElement {\n return document.createElement('span');\n }\n}\n\n/** Detect if a hex/rgb color is dark (luminance < 0.5) */\nfunction isDarkColor(color: string): boolean {\n // Parse hex like #0f1729 or #fff\n if (color.startsWith('#')) {\n const hex = color.slice(1);\n const full = hex.length === 3\n ? hex.split('').map(c => c + c).join('')\n : hex.slice(0, 6);\n const r = parseInt(full.slice(0, 2), 16);\n const g = parseInt(full.slice(2, 4), 16);\n const b = parseInt(full.slice(4, 6), 16);\n // Relative luminance approximation (sRGB)\n const luma = (0.299 * r + 0.587 * g + 0.114 * b) / 255;\n return luma < 0.5;\n }\n // Parse rgb(r, g, b) or rgba(r, g, b, a)\n const m = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (m) {\n const r = parseInt(m[1]), g = parseInt(m[2]), b = parseInt(m[3]);\n const luma = (0.299 * r + 0.587 * g + 0.114 * b) / 255;\n return luma < 0.5;\n }\n return true; // assume dark if unknown\n}\n\n/** Add alpha to a hex color */\nfunction withAlpha(color: string, alpha: number): string {\n if (color.startsWith('#')) {\n const hex = color.slice(1);\n const full = hex.length === 3\n ? hex.split('').map(c => c + c).join('')\n : hex.slice(0, 6);\n const r = parseInt(full.slice(0, 2), 16);\n const g = parseInt(full.slice(2, 4), 16);\n const b = parseInt(full.slice(4, 6), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n }\n return color;\n}\n","import type { OHLCBar, Theme, ViewportState } from '@tradecanvas/commons';\nimport { barIndexToX, priceToY } from '../viewport/ScaleMapping.js';\n\n/**\n * Pinned OHLC tooltip — a second DOM tooltip anchored to a specific bar index.\n *\n * Designed to work alongside the live `CrosshairTooltip`: user pins bar A\n * (Alt+click), then hovers bar B → the live tooltip shows bar B, the pinned\n * tooltip stays on bar A, and the delta strip on the pinned tooltip shows\n * price / time / bar-count differences between the two.\n *\n * Implementation notes:\n * - DOM rather than canvas so the same styling pipeline as the live\n * tooltip is reused (and text remains selectable for screen readers).\n * - Positioning is driven externally via `reposition()` so the Chart can\n * batch it inside its sync loop instead of paying for a per-frame DOM\n * read.\n * - Uses `transform: translate(...)` for repositioning to stay on the\n * compositor layer.\n */\nexport class PinnedTooltip {\n private el: HTMLElement | null = null;\n private deltaEl: HTMLElement | null = null;\n private timeEl: HTMLElement | null = null;\n private ohlcEl: HTMLElement | null = null;\n private pinnedBar: OHLCBar | null = null;\n private pinnedIndex = -1;\n\n create(container: HTMLElement): void {\n if (this.el) return;\n this.el = document.createElement('div');\n Object.assign(this.el.style, {\n position: 'absolute',\n display: 'none',\n padding: '6px 10px',\n borderRadius: '4px',\n fontSize: '11px',\n fontFamily: '-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,sans-serif',\n lineHeight: '1.5',\n pointerEvents: 'auto',\n cursor: 'pointer',\n zIndex: '99',\n whiteSpace: 'nowrap',\n willChange: 'transform',\n });\n\n this.timeEl = document.createElement('div');\n this.ohlcEl = document.createElement('div');\n this.deltaEl = document.createElement('div');\n this.deltaEl.style.marginTop = '4px';\n this.deltaEl.style.paddingTop = '4px';\n this.deltaEl.style.borderTop = '1px solid currentColor';\n this.deltaEl.style.opacity = '0.85';\n this.deltaEl.style.fontVariantNumeric = 'tabular-nums';\n\n this.el.appendChild(this.timeEl);\n this.el.appendChild(this.ohlcEl);\n this.el.appendChild(this.deltaEl);\n\n // Small \"pin\" badge so the user knows what they're looking at.\n const pinBadge = document.createElement('div');\n pinBadge.textContent = '📌 pinned';\n pinBadge.style.fontSize = '9px';\n pinBadge.style.opacity = '0.6';\n pinBadge.style.marginBottom = '2px';\n pinBadge.style.letterSpacing = '0.04em';\n pinBadge.style.textTransform = 'uppercase';\n this.el.insertBefore(pinBadge, this.timeEl);\n\n container.appendChild(this.el);\n }\n\n pin(bar: OHLCBar, barIndex: number, theme: Theme): void {\n if (!this.el || !this.timeEl || !this.ohlcEl) return;\n this.pinnedBar = bar;\n this.pinnedIndex = barIndex;\n\n const isUp = bar.close >= bar.open;\n const color = isUp ? theme.candleUp : theme.candleDown;\n\n const d = new Date(bar.time > 1e12 ? bar.time : bar.time * 1000);\n this.timeEl.textContent = `${d.getMonth() + 1}/${d.getDate()} ${pad(d.getHours())}:${pad(d.getMinutes())}`;\n this.timeEl.style.color = theme.textSecondary;\n\n this.ohlcEl.innerHTML = `\n <span style=\"opacity:.6\">O </span><span style=\"color:${color}\">${fmt(bar.open)}</span>\n <span style=\"opacity:.6\"> H </span><span style=\"color:${color}\">${fmt(bar.high)}</span>\n <span style=\"opacity:.6\"> L </span><span style=\"color:${color}\">${fmt(bar.low)}</span>\n <span style=\"opacity:.6\"> C </span><span style=\"color:${color}\">${fmt(bar.close)}</span>\n `;\n\n const isDark = isDarkColor(theme.background);\n this.el.style.background = withAlpha(theme.background, isDark ? 0.96 : 0.97);\n this.el.style.border = `1px solid ${color}`;\n this.el.style.boxShadow = isDark\n ? '0 4px 12px rgba(0,0,0,0.55)'\n : '0 4px 12px rgba(0,0,0,0.18)';\n this.el.style.color = theme.text;\n this.el.style.backdropFilter = 'blur(8px)';\n\n this.el.style.display = 'block';\n }\n\n unpin(): void {\n this.pinnedBar = null;\n this.pinnedIndex = -1;\n if (this.el) this.el.style.display = 'none';\n }\n\n isPinned(): boolean {\n return this.pinnedBar !== null;\n }\n\n getPinnedIndex(): number {\n return this.pinnedIndex;\n }\n\n /**\n * Reposition the tooltip at the pinned bar's screen X, and refresh the\n * delta strip against the bar currently under the crosshair. Called by\n * the Chart on every viewport sync (cheap — only DOM writes).\n */\n reposition(viewport: ViewportState, hoverBar: OHLCBar | null, hoverIndex: number | null, theme: Theme): void {\n if (!this.el || !this.pinnedBar) return;\n\n const x = barIndexToX(this.pinnedIndex, viewport);\n const y = priceToY(this.pinnedBar.close, viewport);\n\n // Clip to chart bounds — if the pinned bar is scrolled out of view, fade.\n const r = viewport.chartRect;\n const inView = x >= r.x - 4 && x <= r.x + r.width + 4;\n this.el.style.opacity = inView ? '1' : '0.35';\n\n const left = Math.max(r.x, Math.min(r.x + r.width - 180, x + 8));\n const top = Math.max(r.y, Math.min(r.y + r.height - 90, y - 64));\n this.el.style.transform = `translate(${Math.round(left)}px, ${Math.round(top)}px)`;\n this.el.style.left = '0';\n this.el.style.top = '0';\n\n if (this.deltaEl) {\n if (hoverBar && hoverIndex !== null && hoverIndex !== this.pinnedIndex) {\n const priceΔ = hoverBar.close - this.pinnedBar.close;\n const pct = this.pinnedBar.close !== 0 ? (priceΔ / this.pinnedBar.close) * 100 : 0;\n const sign = priceΔ > 0 ? '+' : priceΔ < 0 ? '−' : '';\n const barΔ = hoverIndex - this.pinnedIndex;\n const direction = priceΔ >= 0 ? theme.candleUp : theme.candleDown;\n this.deltaEl.style.color = direction;\n this.deltaEl.innerHTML = `Δ ${sign}${fmt(Math.abs(priceΔ))} <span style=\"opacity:.7\">(${sign}${Math.abs(pct).toFixed(2)}%)</span> · ${barΔ > 0 ? '+' : ''}${barΔ} bars`;\n this.deltaEl.style.display = 'block';\n } else {\n this.deltaEl.style.display = 'none';\n }\n }\n }\n\n destroy(): void {\n this.el?.remove();\n this.el = null;\n this.deltaEl = null;\n this.timeEl = null;\n this.ohlcEl = null;\n this.pinnedBar = null;\n this.pinnedIndex = -1;\n }\n}\n\nfunction fmt(v: number): string {\n return v.toFixed(2);\n}\n\nfunction pad(n: number): string {\n return n < 10 ? '0' + n : '' + n;\n}\n\nfunction isDarkColor(color: string): boolean {\n if (color.startsWith('#')) {\n const hex = color.slice(1);\n const full = hex.length === 3 ? hex.split('').map(c => c + c).join('') : hex.slice(0, 6);\n const r = parseInt(full.slice(0, 2), 16);\n const g = parseInt(full.slice(2, 4), 16);\n const b = parseInt(full.slice(4, 6), 16);\n return (0.299 * r + 0.587 * g + 0.114 * b) / 255 < 0.5;\n }\n return true;\n}\n\nfunction withAlpha(color: string, alpha: number): string {\n if (color.startsWith('#')) {\n const hex = color.slice(1);\n const full = hex.length === 3 ? hex.split('').map(c => c + c).join('') : hex.slice(0, 6);\n const r = parseInt(full.slice(0, 2), 16);\n const g = parseInt(full.slice(2, 4), 16);\n const b = parseInt(full.slice(4, 6), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n }\n return color;\n}\n","import type { ChartEventType, ChartEvent, TauriBridgeOptions } from '@tradecanvas/commons';\n\ntype Listener = (event: ChartEvent) => void;\n\ndeclare global {\n interface Window {\n __TAURI__?: {\n event: {\n emit(event: string, payload: unknown): Promise<void>;\n };\n };\n }\n}\n\nexport class EventBus {\n private listeners = new Map<ChartEventType, Set<Listener>>();\n private tauriBridge: TauriBridgeOptions | null = null;\n\n on(type: ChartEventType, listener: Listener): void {\n let set = this.listeners.get(type);\n if (!set) {\n set = new Set();\n this.listeners.set(type, set);\n }\n set.add(listener);\n }\n\n off(type: ChartEventType, listener: Listener): void {\n this.listeners.get(type)?.delete(listener);\n }\n\n emit(type: ChartEventType, payload: unknown): void {\n const event: ChartEvent = {\n type,\n timestamp: Date.now(),\n payload,\n };\n\n const set = this.listeners.get(type);\n if (set) {\n for (const listener of set) {\n listener(event);\n }\n }\n\n if (this.tauriBridge?.enabled && window.__TAURI__) {\n const prefix = this.tauriBridge.eventPrefix ?? 'tc-chart';\n window.__TAURI__.event.emit(`${prefix}:${type}`, event).catch(() => {});\n }\n }\n\n enableTauriBridge(options: TauriBridgeOptions): void {\n this.tauriBridge = options;\n }\n\n disableTauriBridge(): void {\n this.tauriBridge = null;\n }\n\n destroy(): void {\n this.listeners.clear();\n this.tauriBridge = null;\n }\n}\n","import type {\n DrawingPlugin,\n DrawingDescriptor,\n DrawingState,\n DrawingStyle,\n Point,\n ViewportState,\n AnchorPoint,\n} from '@tradecanvas/commons';\nimport { priceToY, timeToX, xToTime, yToPrice } from '../viewport/ScaleMapping.js';\n\nexport abstract class DrawingBase implements DrawingPlugin {\n abstract descriptor: DrawingDescriptor;\n\n abstract render(\n ctx: CanvasRenderingContext2D,\n state: DrawingState,\n viewport: ViewportState,\n selected: boolean,\n ): void;\n\n abstract hitTest(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): boolean;\n\n hitTestAnchor(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): number {\n for (let i = 0; i < state.anchors.length; i++) {\n const px = this.anchorToPixel(state.anchors[i], viewport);\n const dist = Math.hypot(point.x - px.x, point.y - px.y);\n if (dist <= tolerance) return i;\n }\n return -1;\n }\n\n protected anchorToPixel(anchor: AnchorPoint, viewport: ViewportState): Point {\n const x = timeToX(anchor.time, viewport);\n const y = priceToY(anchor.price, viewport);\n return { x, y };\n }\n\n protected pixelToAnchor(point: Point, viewport: ViewportState): AnchorPoint {\n const time = xToTime(point.x, viewport);\n const price = yToPrice(point.y, viewport);\n return { time, price };\n }\n\n protected applyLineStyle(ctx: CanvasRenderingContext2D, style: DrawingStyle): void {\n ctx.strokeStyle = style.color;\n ctx.lineWidth = style.lineWidth;\n switch (style.lineStyle) {\n case 'dashed': ctx.setLineDash([6, 4]); break;\n case 'dotted': ctx.setLineDash([2, 2]); break;\n default: ctx.setLineDash([]); break;\n }\n }\n\n protected resetLineStyle(ctx: CanvasRenderingContext2D): void {\n ctx.setLineDash([]);\n }\n\n protected renderAnchorHandles(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState): void {\n const size = 4;\n ctx.fillStyle = '#FFFFFF';\n ctx.strokeStyle = state.style.color;\n ctx.lineWidth = 1;\n for (const anchor of state.anchors) {\n const p = this.anchorToPixel(anchor, viewport);\n ctx.fillRect(p.x - size, p.y - size, size * 2, size * 2);\n ctx.strokeRect(p.x - size, p.y - size, size * 2, size * 2);\n }\n }\n\n protected distanceToLine(point: Point, p1: Point, p2: Point): number {\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const lenSq = dx * dx + dy * dy;\n if (lenSq === 0) return Math.hypot(point.x - p1.x, point.y - p1.y);\n let t = ((point.x - p1.x) * dx + (point.y - p1.y) * dy) / lenSq;\n t = Math.max(0, Math.min(1, t));\n const projX = p1.x + t * dx;\n const projY = p1.y + t * dy;\n return Math.hypot(point.x - projX, point.y - projY);\n }\n\n protected distanceToInfiniteLine(point: Point, p1: Point, p2: Point): number {\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const len = Math.hypot(dx, dy);\n if (len === 0) return Math.hypot(point.x - p1.x, point.y - p1.y);\n return Math.abs(dx * (p1.y - point.y) - dy * (p1.x - point.x)) / len;\n }\n}\n","import type {\n DrawingPlugin,\n DrawingState,\n DrawingToolType,\n DrawingStyle,\n Point,\n ViewportState,\n OHLCBar,\n} from '@tradecanvas/commons';\nimport { timestampToBarIndex, xToTime, yToPrice } from '../viewport/ScaleMapping.js';\nimport type { UndoRedoManager } from '../features/UndoRedoManager.js';\n\ntype DrawingEventCallback = (event: string, data: unknown) => void;\n\nexport type DrawingInteractionState = 'idle' | 'creating' | 'selected' | 'moving' | 'resizing';\nexport type MagnetMode = 'none' | 'magnet';\n\nlet nextDrawingId = 1;\n\n/**\n * Shallow clone tailored for DrawingState. Avoids `structuredClone` in hot\n * paths (drag, resize, duplicate) where the well-known shape lets us spread\n * much faster than the structured-clone algorithm.\n */\nfunction cloneDrawing(d: DrawingState): DrawingState {\n return {\n ...d,\n anchors: d.anchors.map((a) => ({ ...a })),\n style: { ...d.style },\n meta: d.meta ? { ...d.meta } : undefined,\n };\n}\n\nexport class DrawingManager {\n private registry = new Map<DrawingToolType, DrawingPlugin>();\n private drawings: DrawingState[] = [];\n private state: DrawingInteractionState = 'idle';\n private activeTool: DrawingToolType | null = null;\n private activeStyle: DrawingStyle = {\n color: '#2196F3',\n lineWidth: 1,\n lineStyle: 'solid',\n fillColor: 'rgba(33, 150, 243, 0.1)',\n fillOpacity: 0.1,\n fontSize: 12,\n };\n private creatingDrawing: DrawingState | null = null;\n private committedAnchors = 0; // how many anchors have been clicked (not preview)\n private previewAnchor: { time: number; price: number } | null = null;\n private selectedDrawingId: string | null = null;\n private dragAnchorIndex = -1;\n private dragStartPoint: Point | null = null;\n private dragStartAnchors: { time: number; price: number }[] = [];\n private dragBeforeState: DrawingState | null = null;\n private eventCallback: DrawingEventCallback | null = null;\n private requestRender: (() => void) | null = null;\n private undoRedo: UndoRedoManager | null = null;\n private magnetMode: MagnetMode = 'none';\n private dataGetter: (() => OHLCBar[]) | null = null;\n private displayDataGetter: (() => OHLCBar[]) | null = null;\n\n register(plugin: DrawingPlugin): void {\n this.registry.set(plugin.descriptor.type, plugin);\n }\n\n setEventCallback(cb: DrawingEventCallback): void {\n this.eventCallback = cb;\n }\n\n setRequestRender(cb: () => void): void {\n this.requestRender = cb;\n }\n\n setUndoRedoManager(mgr: UndoRedoManager): void {\n this.undoRedo = mgr;\n }\n\n setMagnetMode(mode: MagnetMode): void {\n this.magnetMode = mode;\n }\n\n getMagnetMode(): MagnetMode {\n return this.magnetMode;\n }\n\n setDataGetter(getter: () => OHLCBar[]): void {\n this.dataGetter = getter;\n }\n\n /** Set a separate getter for display data (e.g. Heikin Ashi transformed). Used by magnet snap. */\n setDisplayDataGetter(getter: () => OHLCBar[]): void {\n this.displayDataGetter = getter;\n }\n\n // --- Magnet snap ---\n\n /**\n * Snap an in-progress anchor to the closest OHLC value of the underlying\n * bar. `time` is interpreted as a timestamp when `viewport.data` is set\n * (the modern, recommended mode) or as a bar index otherwise. The returned\n * `time` matches the input convention so the caller doesn't need to know.\n */\n private snapToOHLC(time: number, price: number, viewport?: ViewportState): { time: number; price: number } {\n if (this.magnetMode === 'none' || !this.dataGetter) {\n return { time, price };\n }\n // Use display data for magnet snap (matches what's visually rendered, e.g. Heikin Ashi)\n const data = this.displayDataGetter?.() ?? this.dataGetter();\n if (data.length === 0) return { time, price };\n\n const useTimestamps = !!(viewport?.data && viewport.data.length > 0);\n const idx = Math.max(\n 0,\n Math.min(\n data.length - 1,\n Math.round(useTimestamps ? timestampToBarIndex(time, data) : time),\n ),\n );\n const bar = data[idx];\n\n // Find closest OHLC value\n const candidates = [bar.open, bar.high, bar.low, bar.close];\n let closest = candidates[0];\n let minDist = Math.abs(price - closest);\n for (let i = 1; i < candidates.length; i++) {\n const d = Math.abs(price - candidates[i]);\n if (d < minDist) { minDist = d; closest = candidates[i]; }\n }\n\n // Only snap if within a reasonable pixel distance (magnet radius)\n if (viewport) {\n const pxPerPrice = viewport.chartRect.height / (viewport.priceRange.max - viewport.priceRange.min || 1);\n const distPx = minDist * pxPerPrice;\n if (distPx > 30) {\n // Too far — don't snap, use the raw input position (bar-aligned).\n return { time: useTimestamps ? bar.time : idx, price };\n }\n }\n\n return { time: useTimestamps ? bar.time : idx, price: closest };\n }\n\n // --- Undo / Redo ---\n\n undo(): boolean {\n if (!this.undoRedo) return false;\n const action = this.undoRedo.undo();\n if (!action) return false;\n this.applyUndoAction(action);\n return true;\n }\n\n redo(): boolean {\n if (!this.undoRedo) return false;\n const action = this.undoRedo.redo();\n if (!action) return false;\n this.applyRedoAction(action);\n return true;\n }\n\n private applyUndoAction(action: import('../features/UndoRedoManager.js').UndoableAction): void {\n switch (action.type) {\n case 'drawingCreate':\n // Undo create = remove\n if (action.after) {\n this.drawings = this.drawings.filter(d => d.id !== action.after!.id);\n }\n break;\n case 'drawingRemove':\n // Undo remove = restore\n if (action.before) {\n this.drawings.push(action.before);\n }\n break;\n case 'drawingModify':\n // Undo modify = restore before state\n if (action.before) {\n const idx = this.drawings.findIndex(d => d.id === action.before!.id);\n if (idx >= 0) this.drawings[idx] = structuredClone(action.before);\n }\n break;\n }\n this.selectedDrawingId = null;\n this.state = 'idle';\n this.requestRender?.();\n }\n\n private applyRedoAction(action: import('../features/UndoRedoManager.js').UndoableAction): void {\n switch (action.type) {\n case 'drawingCreate':\n // Redo create = add again\n if (action.after) {\n this.drawings.push(structuredClone(action.after));\n }\n break;\n case 'drawingRemove':\n // Redo remove = remove again\n if (action.before) {\n this.drawings = this.drawings.filter(d => d.id !== action.before!.id);\n }\n break;\n case 'drawingModify':\n // Redo modify = apply after state\n if (action.after) {\n const idx = this.drawings.findIndex(d => d.id === action.after!.id);\n if (idx >= 0) this.drawings[idx] = structuredClone(action.after);\n }\n break;\n }\n this.selectedDrawingId = null;\n this.state = 'idle';\n this.requestRender?.();\n }\n\n // --- Bulk operations (TradingView-like) ---\n\n lockAllDrawings(): void {\n for (const d of this.drawings) d.locked = true;\n this.requestRender?.();\n }\n\n unlockAllDrawings(): void {\n for (const d of this.drawings) d.locked = false;\n this.requestRender?.();\n }\n\n hideAllDrawings(): void {\n for (const d of this.drawings) d.visible = false;\n this.selectedDrawingId = null;\n this.state = 'idle';\n this.requestRender?.();\n }\n\n showAllDrawings(): void {\n for (const d of this.drawings) d.visible = true;\n this.requestRender?.();\n }\n\n // --- Tool selection ---\n\n setActiveTool(type: DrawingToolType | null): void {\n this.activeTool = type;\n this.state = type ? 'creating' : 'idle';\n this.creatingDrawing = null;\n this.committedAnchors = 0;\n this.previewAnchor = null;\n }\n\n getActiveTool(): DrawingToolType | null {\n return this.activeTool;\n }\n\n setStyle(style: Partial<DrawingStyle>): void {\n Object.assign(this.activeStyle, style);\n }\n\n // --- Pointer events (returns true if consumed) ---\n\n onPointerDown(pos: Point, viewport: ViewportState): boolean {\n if (this.state === 'creating' && this.activeTool) {\n return this.handleCreationClick(pos, viewport);\n }\n\n if (this.state === 'idle' || this.state === 'selected') {\n return this.handleSelectionClick(pos, viewport);\n }\n\n return false;\n }\n\n onPointerMove(pos: Point, viewport: ViewportState): boolean {\n if (this.state === 'creating' && this.creatingDrawing) {\n const plugin = this.registry.get(this.creatingDrawing.type);\n if (plugin && this.committedAnchors < plugin.descriptor.requiredAnchors) {\n const rawTime = xToTime(pos.x, viewport);\n const rawPrice = yToPrice(pos.y, viewport);\n this.previewAnchor = this.snapToOHLC(rawTime, rawPrice, viewport);\n this.requestRender?.();\n return true;\n }\n }\n\n if (this.state === 'moving' && this.selectedDrawingId && this.dragStartPoint) {\n return this.handleMove(pos, viewport);\n }\n\n if (this.state === 'resizing' && this.selectedDrawingId && this.dragAnchorIndex >= 0) {\n return this.handleResize(pos, viewport);\n }\n\n return false;\n }\n\n onPointerUp(): boolean {\n if (this.state === 'moving' || this.state === 'resizing') {\n // Record undo for the completed move/resize\n if (this.dragBeforeState && this.selectedDrawingId) {\n const drawing = this.drawings.find(d => d.id === this.selectedDrawingId);\n if (drawing) {\n this.undoRedo?.push({\n type: 'drawingModify',\n before: this.dragBeforeState,\n after: cloneDrawing(drawing),\n });\n }\n }\n this.state = 'selected';\n this.dragStartPoint = null;\n this.dragStartAnchors = [];\n this.dragAnchorIndex = -1;\n this.dragBeforeState = null;\n return true;\n }\n return false;\n }\n\n onKeyDown(key: string, ctrlKey = false): boolean {\n // Ctrl+D to duplicate selected drawing\n if (ctrlKey && (key === 'd' || key === 'D')) {\n if (this.state === 'selected' && this.selectedDrawingId) {\n if (this.duplicateDrawing(this.selectedDrawingId)) return true;\n }\n }\n\n // Ctrl+Z / Ctrl+Y for undo/redo\n if (ctrlKey && (key === 'z' || key === 'Z')) {\n if (this.undo()) { return true; }\n }\n if (ctrlKey && (key === 'y' || key === 'Y')) {\n if (this.redo()) { return true; }\n }\n\n if (key === 'Escape') {\n if (this.state === 'creating') {\n this.setActiveTool(null);\n this.requestRender?.();\n return true;\n }\n if (this.state === 'selected') {\n this.selectedDrawingId = null;\n this.state = 'idle';\n this.requestRender?.();\n return true;\n }\n }\n if (key === 'Delete' || key === 'Backspace') {\n if (this.state === 'selected' && this.selectedDrawingId) {\n const drawing = this.drawings.find(d => d.id === this.selectedDrawingId);\n if (drawing?.locked) return false; // Can't delete locked drawings\n this.removeDrawing(this.selectedDrawingId);\n this.selectedDrawingId = null;\n this.state = 'idle';\n this.requestRender?.();\n return true;\n }\n }\n return false;\n }\n\n // --- Drawing CRUD ---\n\n getDrawings(): DrawingState[] {\n return this.drawings;\n }\n\n setDrawings(states: DrawingState[]): void {\n this.drawings = this.upgradeLegacyAnchors(states);\n this.requestRender?.();\n }\n\n /**\n * Auto-migrate legacy bar-index anchors to real timestamps when data is\n * available. Heuristic: anchors with `time < 1e9` are treated as bar indices\n * (timestamps in seconds are > 1e9 for any date after 2001-09-09), and\n * upgraded by looking up the corresponding bar's timestamp. Anchors that\n * already look like timestamps are passed through untouched. Idempotent.\n */\n private upgradeLegacyAnchors(states: DrawingState[]): DrawingState[] {\n const data = this.dataGetter?.();\n if (!data || data.length === 0) return states;\n const TIMESTAMP_THRESHOLD = 1e9;\n return states.map(d => ({\n ...d,\n anchors: d.anchors.map(a => {\n if (a.time >= TIMESTAMP_THRESHOLD) return a;\n const idx = Math.max(0, Math.min(data.length - 1, Math.round(a.time)));\n return { ...a, time: data[idx].time };\n }),\n }));\n }\n\n removeDrawing(id: string): void {\n const removed = this.drawings.find(d => d.id === id);\n this.drawings = this.drawings.filter((d) => d.id !== id);\n if (removed) {\n this.undoRedo?.push({\n type: 'drawingRemove',\n before: structuredClone(removed),\n after: null,\n });\n }\n this.eventCallback?.('drawingRemove', { id });\n this.requestRender?.();\n }\n\n duplicateDrawing(id: string): string | null {\n const drawing = this.drawings.find(d => d.id === id);\n if (!drawing) return null;\n\n const newDrawing: DrawingState = structuredClone(drawing);\n newDrawing.id = `tc_drawing_${nextDrawingId++}`;\n // Offset by 3 bars so the copy is visually distinct. When anchors are\n // timestamps, \"3 bars\" means 3 × median bar interval in the current\n // series; when anchors are bar indices (legacy / no data), it's literal.\n const timeOffset = this.computeBarOffsetTime(3);\n newDrawing.anchors = newDrawing.anchors.map(a => ({\n ...a,\n time: a.time + timeOffset,\n }));\n newDrawing.locked = false;\n\n this.drawings.push(newDrawing);\n this.undoRedo?.push({\n type: 'drawingCreate',\n before: null,\n after: structuredClone(newDrawing),\n });\n this.selectedDrawingId = newDrawing.id;\n this.state = 'selected';\n this.eventCallback?.('drawingCreate', { drawing: newDrawing });\n this.requestRender?.();\n return newDrawing.id;\n }\n\n clearDrawings(): void {\n this.drawings = [];\n this.selectedDrawingId = null;\n this.state = 'idle';\n this.requestRender?.();\n }\n\n getSelectedDrawingId(): string | null {\n return this.selectedDrawingId;\n }\n\n // --- Render ---\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState): void {\n // Clip to chart area so drawings don't bleed into axis areas\n ctx.save();\n ctx.beginPath();\n ctx.rect(viewport.chartRect.x, viewport.chartRect.y, viewport.chartRect.width, viewport.chartRect.height);\n ctx.clip();\n\n for (const drawing of this.drawings) {\n if (!drawing.visible) continue;\n const plugin = this.registry.get(drawing.type);\n if (!plugin) continue;\n const isSelected = drawing.id === this.selectedDrawingId;\n plugin.render(ctx, drawing, viewport, isSelected);\n }\n\n // Render drawing being created (with preview anchor)\n if (this.creatingDrawing && this.committedAnchors > 0) {\n const plugin = this.registry.get(this.creatingDrawing.type);\n if (plugin) {\n // Build preview state: committed anchors + optional preview anchor\n const previewState: DrawingState = {\n ...this.creatingDrawing,\n anchors: this.previewAnchor\n ? [...this.creatingDrawing.anchors, this.previewAnchor]\n : [...this.creatingDrawing.anchors],\n };\n plugin.render(ctx, previewState, viewport, false);\n }\n }\n\n ctx.restore();\n }\n\n // --- Internal ---\n\n /**\n * Compute the offset (in anchor-time units) equivalent to `n` bars.\n * When the viewport carries data and anchors are timestamps, this is\n * `n × median bar interval`; otherwise it's just `n` (bar-index mode).\n */\n private computeBarOffsetTime(n: number): number {\n const data = this.dataGetter?.();\n if (!data || data.length < 2) return n;\n // Only meaningful in timestamp mode — detect via data presence.\n // Use median of the last few intervals to be robust against gaps.\n const sampleStart = Math.max(0, data.length - 20);\n const intervals: number[] = [];\n for (let i = sampleStart + 1; i < data.length; i++) {\n intervals.push(data[i].time - data[i - 1].time);\n }\n if (intervals.length === 0) return n;\n intervals.sort((a, b) => a - b);\n const median = intervals[Math.floor(intervals.length / 2)];\n return n * median;\n }\n\n private handleCreationClick(pos: Point, viewport: ViewportState): boolean {\n if (!this.activeTool) return false;\n const plugin = this.registry.get(this.activeTool);\n if (!plugin) return false;\n\n const rawTime = xToTime(pos.x, viewport);\n const rawPrice = yToPrice(pos.y, viewport);\n const anchor = this.snapToOHLC(rawTime, rawPrice, viewport);\n\n if (!this.creatingDrawing) {\n // First click: start creation\n this.creatingDrawing = {\n id: `tc_drawing_${nextDrawingId++}`,\n type: this.activeTool,\n anchors: [anchor],\n style: { ...this.activeStyle },\n visible: true,\n locked: false,\n };\n this.committedAnchors = 1;\n this.previewAnchor = null;\n\n if (plugin.descriptor.requiredAnchors === 1) {\n this.finalizeCreation();\n }\n this.requestRender?.();\n return true;\n }\n\n // Subsequent click: commit the anchor\n this.creatingDrawing.anchors.push(anchor);\n this.committedAnchors++;\n this.previewAnchor = null;\n\n if (this.committedAnchors >= plugin.descriptor.requiredAnchors) {\n this.finalizeCreation();\n }\n\n this.requestRender?.();\n return true;\n }\n\n private finalizeCreation(): void {\n if (!this.creatingDrawing) return;\n this.drawings.push(this.creatingDrawing);\n this.selectedDrawingId = this.creatingDrawing.id;\n // Record undo action\n this.undoRedo?.push({\n type: 'drawingCreate',\n before: null,\n after: structuredClone(this.creatingDrawing),\n });\n this.eventCallback?.('drawingCreate', { drawing: this.creatingDrawing });\n this.creatingDrawing = null;\n this.committedAnchors = 0;\n this.previewAnchor = null;\n this.activeTool = null;\n this.state = 'selected';\n }\n\n private handleSelectionClick(pos: Point, viewport: ViewportState): boolean {\n const tolerance = 8;\n\n // If already selected, check for anchor drag\n if (this.selectedDrawingId) {\n const drawing = this.drawings.find((d) => d.id === this.selectedDrawingId);\n if (drawing && !drawing.locked) {\n const plugin = this.registry.get(drawing.type);\n if (plugin) {\n const anchorIdx = plugin.hitTestAnchor(pos, drawing, viewport, tolerance);\n if (anchorIdx >= 0) {\n this.state = 'resizing';\n this.dragAnchorIndex = anchorIdx;\n this.dragStartPoint = pos;\n this.dragBeforeState = cloneDrawing(drawing);\n return true;\n }\n if (plugin.hitTest(pos, drawing, viewport, tolerance)) {\n this.state = 'moving';\n this.dragStartPoint = pos;\n this.dragStartAnchors = drawing.anchors.map((a) => ({ ...a }));\n this.dragBeforeState = cloneDrawing(drawing);\n return true;\n }\n }\n }\n }\n\n // Try to select a drawing\n for (let i = this.drawings.length - 1; i >= 0; i--) {\n const drawing = this.drawings[i];\n if (!drawing.visible) continue;\n const plugin = this.registry.get(drawing.type);\n if (!plugin) continue;\n if (plugin.hitTest(pos, drawing, viewport, tolerance)) {\n this.selectedDrawingId = drawing.id;\n this.state = 'selected';\n this.requestRender?.();\n return true;\n }\n }\n\n // Clicked empty space — deselect\n if (this.selectedDrawingId) {\n this.selectedDrawingId = null;\n this.state = 'idle';\n this.requestRender?.();\n }\n return false;\n }\n\n private handleMove(pos: Point, viewport: ViewportState): boolean {\n const drawing = this.drawings.find((d) => d.id === this.selectedDrawingId);\n if (!drawing || !this.dragStartPoint) return false;\n\n // Translate by anchor-time delta. In timestamp mode this is a wall-clock\n // seconds difference; in bar-index mode it's a bar-count difference —\n // `xToTime` returns whichever unit the viewport is set up for.\n const dTime = xToTime(pos.x, viewport) - xToTime(this.dragStartPoint.x, viewport);\n const dPrice = yToPrice(pos.y, viewport) - yToPrice(this.dragStartPoint.y, viewport);\n\n drawing.anchors = this.dragStartAnchors.map((a) => ({\n time: a.time + dTime,\n price: a.price + dPrice,\n }));\n\n this.requestRender?.();\n return true;\n }\n\n private handleResize(pos: Point, viewport: ViewportState): boolean {\n const drawing = this.drawings.find((d) => d.id === this.selectedDrawingId);\n if (!drawing || this.dragAnchorIndex < 0) return false;\n\n drawing.anchors[this.dragAnchorIndex] = {\n time: xToTime(pos.x, viewport),\n price: yToPrice(pos.y, viewport),\n };\n\n this.requestRender?.();\n return true;\n }\n}\n","import type { ViewportState } from '@tradecanvas/commons';\nimport type { DrawingManager } from './DrawingManager.js';\n\nexport class DrawingRenderer {\n constructor(private manager: DrawingManager) {}\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState): void {\n this.manager.render(ctx, viewport);\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class TrendLineTool extends DrawingBase {\n descriptor = { type: 'trendLine' as const, name: 'Trend Line', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p2.x, p2.y);\n ctx.stroke();\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n return this.distanceToLine(point, p1, p2) <= tolerance;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\nimport { priceToY } from '../../viewport/ScaleMapping.js';\n\nexport class HorizontalLineTool extends DrawingBase {\n descriptor = { type: 'horizontalLine' as const, name: 'Horizontal Line', requiredAnchors: 1 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 1) return;\n const y = priceToY(state.anchors[0].price, viewport);\n const { chartRect } = viewport;\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(chartRect.x, y);\n ctx.lineTo(chartRect.x + chartRect.width, y);\n ctx.stroke();\n this.resetLineStyle(ctx);\n\n // Price label\n ctx.fillStyle = state.style.color;\n ctx.font = '11px sans-serif';\n ctx.textBaseline = 'bottom';\n ctx.fillText(state.anchors[0].price.toFixed(2), chartRect.x + 4, y - 3);\n\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 1) return false;\n const y = priceToY(state.anchors[0].price, viewport);\n return Math.abs(point.y - y) <= tolerance && point.x >= viewport.chartRect.x && point.x <= viewport.chartRect.x + viewport.chartRect.width;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class VerticalLineTool extends DrawingBase {\n descriptor = { type: 'verticalLine' as const, name: 'Vertical Line', requiredAnchors: 1 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 1) return;\n const p = this.anchorToPixel(state.anchors[0], viewport);\n const { chartRect } = viewport;\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(p.x, chartRect.y);\n ctx.lineTo(p.x, chartRect.y + chartRect.height);\n ctx.stroke();\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 1) return false;\n const p = this.anchorToPixel(state.anchors[0], viewport);\n const { chartRect } = viewport;\n return Math.abs(point.x - p.x) <= tolerance &&\n point.y >= chartRect.y && point.y <= chartRect.y + chartRect.height;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class RayTool extends DrawingBase {\n descriptor = { type: 'ray' as const, name: 'Ray', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const { chartRect } = viewport;\n\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const len = Math.hypot(dx, dy);\n if (len === 0) return;\n\n // Extend to chart edge\n const maxDist = Math.hypot(chartRect.width, chartRect.height) * 2;\n const endX = p1.x + (dx / len) * maxDist;\n const endY = p1.y + (dy / len) * maxDist;\n\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(endX, endY);\n ctx.stroke();\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n // Only test in the ray direction (from p1 toward p2)\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const t = ((point.x - p1.x) * dx + (point.y - p1.y) * dy) / (dx * dx + dy * dy);\n if (t < 0) return false;\n return this.distanceToInfiniteLine(point, p1, p2) <= tolerance;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class ExtendedLineTool extends DrawingBase {\n descriptor = { type: 'extendedLine' as const, name: 'Extended Line', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const { chartRect } = viewport;\n\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const len = Math.hypot(dx, dy);\n if (len === 0) return;\n\n const maxDist = Math.hypot(chartRect.width, chartRect.height) * 2;\n const startX = p1.x - (dx / len) * maxDist;\n const startY = p1.y - (dy / len) * maxDist;\n const endX = p1.x + (dx / len) * maxDist;\n const endY = p1.y + (dy / len) * maxDist;\n\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(startX, startY);\n ctx.lineTo(endX, endY);\n ctx.stroke();\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n return this.distanceToInfiniteLine(point, p1, p2) <= tolerance;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class ParallelChannelTool extends DrawingBase {\n descriptor = { type: 'parallelChannel' as const, name: 'Parallel Channel', requiredAnchors: 3 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p2.x, p2.y);\n ctx.stroke();\n\n if (state.anchors.length >= 3) {\n const p3 = this.anchorToPixel(state.anchors[2], viewport);\n // Perpendicular offset from baseline (p1→p2)\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const len = Math.hypot(dx, dy) || 1;\n const nx = -dy / len;\n const ny = dx / len;\n const perpDist = (p3.x - p1.x) * nx + (p3.y - p1.y) * ny;\n const p1b = { x: p1.x + nx * perpDist, y: p1.y + ny * perpDist };\n const p2b = { x: p2.x + nx * perpDist, y: p2.y + ny * perpDist };\n\n ctx.beginPath();\n ctx.moveTo(p1b.x, p1b.y);\n ctx.lineTo(p2b.x, p2b.y);\n ctx.stroke();\n\n // Fill between\n if (state.style.fillColor) {\n ctx.fillStyle = state.style.fillColor;\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p2.x, p2.y);\n ctx.lineTo(p2b.x, p2b.y);\n ctx.lineTo(p1b.x, p1b.y);\n ctx.closePath();\n ctx.fill();\n }\n }\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n if (this.distanceToLine(point, p1, p2) <= tolerance) return true;\n if (state.anchors.length >= 3) {\n const p3 = this.anchorToPixel(state.anchors[2], viewport);\n // Perpendicular offset from baseline (p1→p2)\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const len = Math.hypot(dx, dy) || 1;\n const nx = -dy / len;\n const ny = dx / len;\n const perpDist = (p3.x - p1.x) * nx + (p3.y - p1.y) * ny;\n const p1b = { x: p1.x + nx * perpDist, y: p1.y + ny * perpDist };\n const p2b = { x: p2.x + nx * perpDist, y: p2.y + ny * perpDist };\n if (this.distanceToLine(point, p1b, p2b) <= tolerance) return true;\n }\n return false;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class RegressionChannelTool extends DrawingBase {\n descriptor = { type: 'regressionChannel' as const, name: 'Regression Channel', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n\n // Draw center line\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p2.x, p2.y);\n ctx.stroke();\n\n // Draw parallel channel lines (fixed offset)\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const len = Math.hypot(dx, dy);\n if (len === 0) { this.resetLineStyle(ctx); return; }\n // Channel width scales with line length (20% of length, min 10px, max 100px)\n const channelOffset = Math.max(10, Math.min(len * 0.2, 100));\n const nx = -dy / len * channelOffset;\n const ny = dx / len * channelOffset;\n\n ctx.setLineDash([4, 4]);\n ctx.beginPath();\n ctx.moveTo(p1.x + nx, p1.y + ny);\n ctx.lineTo(p2.x + nx, p2.y + ny);\n ctx.stroke();\n ctx.beginPath();\n ctx.moveTo(p1.x - nx, p1.y - ny);\n ctx.lineTo(p2.x - nx, p2.y - ny);\n ctx.stroke();\n\n if (state.style.fillColor) {\n ctx.fillStyle = state.style.fillColor;\n ctx.beginPath();\n ctx.moveTo(p1.x + nx, p1.y + ny);\n ctx.lineTo(p2.x + nx, p2.y + ny);\n ctx.lineTo(p2.x - nx, p2.y - ny);\n ctx.lineTo(p1.x - nx, p1.y - ny);\n ctx.closePath();\n ctx.fill();\n }\n\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const len = Math.hypot(p2.x - p1.x, p2.y - p1.y);\n const channelOffset = Math.max(10, Math.min(len * 0.2, 100));\n return this.distanceToLine(point, p1, p2) <= tolerance + channelOffset;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\nimport { priceToY } from '../../viewport/ScaleMapping.js';\n\nconst FIB_LEVELS = [0, 0.236, 0.382, 0.5, 0.618, 0.786, 1];\n\nexport class FibRetracementTool extends DrawingBase {\n descriptor = { type: 'fibRetracement' as const, name: 'Fibonacci Retracement', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const { chartRect } = viewport;\n const priceHigh = state.anchors[0].price;\n const priceLow = state.anchors[1].price;\n const priceRange = priceHigh - priceLow;\n\n ctx.font = '11px sans-serif';\n ctx.textBaseline = 'middle';\n\n for (const level of FIB_LEVELS) {\n const price = priceLow + priceRange * (1 - level);\n const y = priceToY(price, viewport);\n\n this.applyLineStyle(ctx, state.style);\n ctx.globalAlpha = level === 0 || level === 1 ? 1 : 0.7;\n ctx.beginPath();\n ctx.moveTo(chartRect.x, y);\n ctx.lineTo(chartRect.x + chartRect.width, y);\n ctx.stroke();\n\n // Label\n ctx.fillStyle = state.style.color;\n ctx.textAlign = 'left';\n ctx.fillText(`${(level * 100).toFixed(1)}% (${price.toFixed(2)})`, chartRect.x + 4, y - 2);\n }\n\n ctx.globalAlpha = 1;\n\n // Fill between levels\n if (state.style.fillColor) {\n for (let i = 0; i < FIB_LEVELS.length - 1; i++) {\n const priceA = priceLow + priceRange * (1 - FIB_LEVELS[i]);\n const priceB = priceLow + priceRange * (1 - FIB_LEVELS[i + 1]);\n const yA = priceToY(priceA, viewport);\n const yB = priceToY(priceB, viewport);\n ctx.fillStyle = state.style.fillColor;\n ctx.globalAlpha = 0.05 + i * 0.02;\n ctx.fillRect(chartRect.x, Math.min(yA, yB), chartRect.width, Math.abs(yB - yA));\n }\n ctx.globalAlpha = 1;\n }\n\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const { chartRect } = viewport;\n if (point.x < chartRect.x - tolerance || point.x > chartRect.x + chartRect.width + tolerance) return false;\n const priceHigh = state.anchors[0].price;\n const priceLow = state.anchors[1].price;\n const priceRange = priceHigh - priceLow;\n for (const level of FIB_LEVELS) {\n const price = priceLow + priceRange * (1 - level);\n const y = priceToY(price, viewport);\n if (Math.abs(point.y - y) <= tolerance) return true;\n }\n return false;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\nimport { priceToY } from '../../viewport/ScaleMapping.js';\n\nconst EXT_LEVELS = [0, 0.618, 1, 1.618, 2, 2.618, 3.618, 4.236];\n\nexport class FibExtensionTool extends DrawingBase {\n descriptor = { type: 'fibExtension' as const, name: 'Fibonacci Extension', requiredAnchors: 3 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 3) {\n if (state.anchors.length === 2) {\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p2.x, p2.y);\n ctx.stroke();\n this.resetLineStyle(ctx);\n }\n return;\n }\n\n const { chartRect } = viewport;\n const priceA = state.anchors[0].price;\n const priceB = state.anchors[1].price;\n const priceC = state.anchors[2].price;\n const swing = priceA - priceB;\n\n ctx.font = '11px sans-serif';\n ctx.textBaseline = 'middle';\n ctx.textAlign = 'left';\n\n for (const level of EXT_LEVELS) {\n const price = priceC + swing * level;\n const y = priceToY(price, viewport);\n\n this.applyLineStyle(ctx, state.style);\n ctx.globalAlpha = level === 0 || level === 1 ? 1 : 0.6;\n ctx.beginPath();\n ctx.moveTo(chartRect.x, y);\n ctx.lineTo(chartRect.x + chartRect.width, y);\n ctx.stroke();\n\n ctx.fillStyle = state.style.color;\n ctx.fillText(`${(level * 100).toFixed(1)}%`, chartRect.x + 4, y - 2);\n }\n\n ctx.globalAlpha = 1;\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 3) return false;\n const { chartRect } = viewport;\n if (point.x < chartRect.x - tolerance || point.x > chartRect.x + chartRect.width + tolerance) return false;\n const swing = state.anchors[0].price - state.anchors[1].price;\n for (const level of EXT_LEVELS) {\n const price = state.anchors[2].price + swing * level;\n const y = priceToY(price, viewport);\n if (Math.abs(point.y - y) <= tolerance) return true;\n }\n return false;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class RectangleTool extends DrawingBase {\n descriptor = { type: 'rectangle' as const, name: 'Rectangle', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const x = Math.min(p1.x, p2.x), y = Math.min(p1.y, p2.y);\n const w = Math.abs(p2.x - p1.x), h = Math.abs(p2.y - p1.y);\n\n if (state.style.fillColor) {\n ctx.fillStyle = state.style.fillColor;\n ctx.fillRect(x, y, w, h);\n }\n this.applyLineStyle(ctx, state.style);\n ctx.strokeRect(x, y, w, h);\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const x1 = Math.min(p1.x, p2.x) - tolerance, y1 = Math.min(p1.y, p2.y) - tolerance;\n const x2 = Math.max(p1.x, p2.x) + tolerance, y2 = Math.max(p1.y, p2.y) + tolerance;\n if (point.x < x1 || point.x > x2 || point.y < y1 || point.y > y2) return false;\n // Check if near border\n const ix1 = Math.min(p1.x, p2.x) + tolerance, iy1 = Math.min(p1.y, p2.y) + tolerance;\n const ix2 = Math.max(p1.x, p2.x) - tolerance, iy2 = Math.max(p1.y, p2.y) - tolerance;\n return !(point.x > ix1 && point.x < ix2 && point.y > iy1 && point.y < iy2) || !!state.style.fillColor;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class EllipseTool extends DrawingBase {\n descriptor = { type: 'ellipse' as const, name: 'Ellipse', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const cx = (p1.x + p2.x) / 2, cy = (p1.y + p2.y) / 2;\n const rx = Math.abs(p2.x - p1.x) / 2, ry = Math.abs(p2.y - p1.y) / 2;\n\n ctx.beginPath();\n ctx.ellipse(cx, cy, Math.max(rx, 1), Math.max(ry, 1), 0, 0, Math.PI * 2);\n if (state.style.fillColor) {\n ctx.fillStyle = state.style.fillColor;\n ctx.fill();\n }\n this.applyLineStyle(ctx, state.style);\n ctx.stroke();\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const cx = (p1.x + p2.x) / 2, cy = (p1.y + p2.y) / 2;\n const rx = Math.max(Math.abs(p2.x - p1.x) / 2, 1);\n const ry = Math.max(Math.abs(p2.y - p1.y) / 2, 1);\n const dx = (point.x - cx) / rx, dy = (point.y - cy) / ry;\n const dist = Math.sqrt(dx * dx + dy * dy);\n // Normalized tolerance: tolerance pixels mapped to ellipse-normalized space\n const normTol = tolerance / Math.max(Math.min(rx, ry), 4);\n // Hit if within the stroke band around the ellipse edge (dist ≈ 1)\n return state.style.fillColor ? dist <= 1 + normTol : Math.abs(dist - 1) <= normTol;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class TriangleTool extends DrawingBase {\n descriptor = { type: 'triangle' as const, name: 'Triangle', requiredAnchors: 3 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 3) {\n if (state.anchors.length === 2) {\n const a = this.anchorToPixel(state.anchors[0], viewport);\n const b = this.anchorToPixel(state.anchors[1], viewport);\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(a.x, a.y);\n ctx.lineTo(b.x, b.y);\n ctx.stroke();\n this.resetLineStyle(ctx);\n }\n return;\n }\n const pts = state.anchors.map((a) => this.anchorToPixel(a, viewport));\n\n ctx.beginPath();\n ctx.moveTo(pts[0].x, pts[0].y);\n ctx.lineTo(pts[1].x, pts[1].y);\n ctx.lineTo(pts[2].x, pts[2].y);\n ctx.closePath();\n\n if (state.style.fillColor) {\n ctx.fillStyle = state.style.fillColor;\n ctx.fill();\n }\n this.applyLineStyle(ctx, state.style);\n ctx.stroke();\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 3) return false;\n const pts = state.anchors.map((a) => this.anchorToPixel(a, viewport));\n // Check if near edges\n for (let i = 0; i < 3; i++) {\n const j = (i + 1) % 3;\n if (this.distanceToLine(point, pts[i], pts[j]) <= tolerance) return true;\n }\n return false;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class PitchforkTool extends DrawingBase {\n descriptor = { type: 'pitchfork' as const, name: \"Andrews' Pitchfork\", requiredAnchors: 3 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 3) {\n if (state.anchors.length === 2) {\n const a = this.anchorToPixel(state.anchors[0], viewport);\n const b = this.anchorToPixel(state.anchors[1], viewport);\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(a.x, a.y);\n ctx.lineTo(b.x, b.y);\n ctx.stroke();\n this.resetLineStyle(ctx);\n }\n return;\n }\n\n const p0 = this.anchorToPixel(state.anchors[0], viewport);\n const p1 = this.anchorToPixel(state.anchors[1], viewport);\n const p2 = this.anchorToPixel(state.anchors[2], viewport);\n const mid = { x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2 };\n\n // Median line (from p0 through midpoint of p1-p2)\n const dx = mid.x - p0.x, dy = mid.y - p0.y;\n const len = Math.hypot(dx, dy) || 1;\n const ext = Math.hypot(viewport.chartRect.width, viewport.chartRect.height);\n const endX = p0.x + (dx / len) * ext;\n const endY = p0.y + (dy / len) * ext;\n\n this.applyLineStyle(ctx, state.style);\n\n // Median line\n ctx.beginPath();\n ctx.moveTo(p0.x, p0.y);\n ctx.lineTo(endX, endY);\n ctx.stroke();\n\n // Upper prong (from p1 parallel to median)\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p1.x + (dx / len) * ext, p1.y + (dy / len) * ext);\n ctx.stroke();\n\n // Lower prong (from p2 parallel to median)\n ctx.beginPath();\n ctx.moveTo(p2.x, p2.y);\n ctx.lineTo(p2.x + (dx / len) * ext, p2.y + (dy / len) * ext);\n ctx.stroke();\n\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 3) return false;\n const p0 = this.anchorToPixel(state.anchors[0], viewport);\n const p1 = this.anchorToPixel(state.anchors[1], viewport);\n const p2 = this.anchorToPixel(state.anchors[2], viewport);\n const mid = { x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2 };\n if (this.distanceToInfiniteLine(point, p0, mid) <= tolerance) return true;\n const dx = mid.x - p0.x, dy = mid.y - p0.y;\n const p1end = { x: p1.x + dx, y: p1.y + dy };\n const p2end = { x: p2.x + dx, y: p2.y + dy };\n if (this.distanceToInfiniteLine(point, p1, p1end) <= tolerance) return true;\n if (this.distanceToInfiniteLine(point, p2, p2end) <= tolerance) return true;\n return false;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nconst WAVE_LABELS = ['1', '2', '3', '4', '5', 'A', 'B', 'C'];\n\nexport class ElliottWaveTool extends DrawingBase {\n descriptor = { type: 'elliottWave' as const, name: 'Elliott Wave', requiredAnchors: 8 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const pts = state.anchors.map((a) => this.anchorToPixel(a, viewport));\n\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) {\n ctx.lineTo(pts[i].x, pts[i].y);\n }\n ctx.stroke();\n this.resetLineStyle(ctx);\n\n // Labels\n ctx.font = 'bold 12px sans-serif';\n ctx.fillStyle = state.style.color;\n ctx.textAlign = 'center';\n for (let i = 0; i < pts.length && i < WAVE_LABELS.length; i++) {\n const offsetY = i % 2 === 0 ? -12 : 12;\n ctx.textBaseline = offsetY < 0 ? 'bottom' : 'top';\n ctx.fillText(WAVE_LABELS[i], pts[i].x, pts[i].y + offsetY);\n }\n\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const pts = state.anchors.map((a) => this.anchorToPixel(a, viewport));\n for (let i = 0; i < pts.length - 1; i++) {\n if (this.distanceToLine(point, pts[i], pts[i + 1]) <= tolerance) return true;\n }\n return false;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class PriceRangeTool extends DrawingBase {\n descriptor = { type: 'priceRange' as const, name: 'Price Range', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const x = Math.min(p1.x, p2.x), w = Math.abs(p2.x - p1.x);\n const top = Math.min(p1.y, p2.y), h = Math.abs(p2.y - p1.y);\n\n // Fill\n const isUp = state.anchors[1].price > state.anchors[0].price;\n ctx.fillStyle = isUp ? 'rgba(38, 166, 154, 0.15)' : 'rgba(239, 83, 80, 0.15)';\n ctx.fillRect(x, top, w, h);\n\n this.applyLineStyle(ctx, state.style);\n ctx.strokeRect(x, top, w, h);\n this.resetLineStyle(ctx);\n\n // Label\n const priceDiff = state.anchors[1].price - state.anchors[0].price;\n const pctChange = state.anchors[0].price !== 0 ? (priceDiff / state.anchors[0].price * 100) : 0;\n const label = `${priceDiff >= 0 ? '+' : ''}${priceDiff.toFixed(2)} (${pctChange >= 0 ? '+' : ''}${pctChange.toFixed(2)}%)`;\n\n ctx.font = '12px sans-serif';\n ctx.fillStyle = isUp ? '#26A69A' : '#EF5350';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, x + w / 2, top + h / 2);\n\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const x1 = Math.min(p1.x, p2.x), x2 = Math.max(p1.x, p2.x);\n const y1 = Math.min(p1.y, p2.y), y2 = Math.max(p1.y, p2.y);\n return point.x >= x1 - tolerance && point.x <= x2 + tolerance && point.y >= y1 - tolerance && point.y <= y2 + tolerance;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\nimport { resolveBarIndex } from '../../viewport/ScaleMapping.js';\n\nexport class DateRangeTool extends DrawingBase {\n descriptor = { type: 'dateRange' as const, name: 'Date Range', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const { chartRect } = viewport;\n const x1 = Math.min(p1.x, p2.x), x2 = Math.max(p1.x, p2.x);\n\n ctx.fillStyle = 'rgba(33, 150, 243, 0.08)';\n ctx.fillRect(x1, chartRect.y, x2 - x1, chartRect.height);\n\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(x1, chartRect.y);\n ctx.lineTo(x1, chartRect.y + chartRect.height);\n ctx.stroke();\n ctx.beginPath();\n ctx.moveTo(x2, chartRect.y);\n ctx.lineTo(x2, chartRect.y + chartRect.height);\n ctx.stroke();\n this.resetLineStyle(ctx);\n\n // Bars count — compute via resolved bar indices so the label reflects the\n // actual span on the current timeframe (anchor.time may be a timestamp).\n const idx0 = resolveBarIndex(state.anchors[0].time, viewport);\n const idx1 = resolveBarIndex(state.anchors[1].time, viewport);\n const bars = Math.max(0, Math.round(Math.abs(idx1 - idx0)));\n ctx.font = '12px sans-serif';\n ctx.fillStyle = state.style.color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.fillText(`${bars} bars`, (x1 + x2) / 2, chartRect.y + 4);\n\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const { chartRect } = viewport;\n const x1 = Math.min(p1.x, p2.x), x2 = Math.max(p1.x, p2.x);\n return point.x >= x1 - tolerance && point.x <= x2 + tolerance &&\n point.y >= chartRect.y && point.y <= chartRect.y + chartRect.height;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\nimport { resolveBarIndex } from '../../viewport/ScaleMapping.js';\n\nexport class MeasureTool extends DrawingBase {\n descriptor = { type: 'measure' as const, name: 'Measure', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n\n // Dotted line from p1 to p2\n this.applyLineStyle(ctx, state.style);\n ctx.setLineDash([4, 4]); // Always dashed for measure\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p2.x, p2.y);\n ctx.stroke();\n this.resetLineStyle(ctx);\n\n // Info label — resolve bar indices so the bar count is correct even when\n // anchor.time is a real timestamp (timestamp mode is the new default).\n const priceDiff = state.anchors[1].price - state.anchors[0].price;\n const idx0 = resolveBarIndex(state.anchors[0].time, viewport);\n const idx1 = resolveBarIndex(state.anchors[1].time, viewport);\n const barsDiff = Math.max(0, Math.round(Math.abs(idx1 - idx0)));\n const pctChange = state.anchors[0].price !== 0 ? (priceDiff / state.anchors[0].price * 100) : 0;\n\n const lines = [\n `Price: ${priceDiff >= 0 ? '+' : ''}${priceDiff.toFixed(2)} (${pctChange >= 0 ? '+' : ''}${pctChange.toFixed(2)}%)`,\n `Bars: ${barsDiff}`,\n ];\n\n const midX = (p1.x + p2.x) / 2;\n const midY = (p1.y + p2.y) / 2;\n\n ctx.font = '11px sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'bottom';\n\n // Background\n const maxWidth = Math.max(...lines.map((l) => ctx.measureText(l).width));\n ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';\n ctx.fillRect(midX - maxWidth / 2 - 6, midY - lines.length * 14 - 4, maxWidth + 12, lines.length * 14 + 8);\n\n ctx.fillStyle = '#FFFFFF';\n for (let i = 0; i < lines.length; i++) {\n ctx.fillText(lines[i], midX, midY - (lines.length - 1 - i) * 14);\n }\n\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n return this.distanceToLine(point, p1, p2) <= tolerance;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\r\nimport { DrawingBase } from '../DrawingBase.js';\r\n\r\n/**\r\n * Pull annotation text from `style.text`, then `meta.text`, then a literal default.\r\n * Pure helper — exported so it can be unit-tested without a canvas.\r\n */\r\nexport function resolveAnnotationText(state: DrawingState, fallback = 'Text'): string {\r\n if (typeof state.style.text === 'string' && state.style.text.length > 0) {\r\n return state.style.text;\r\n }\r\n const metaText = state.meta?.text;\r\n if (typeof metaText === 'string' && metaText.length > 0) return metaText;\r\n return fallback;\r\n}\r\n\r\nexport class TextAnnotationTool extends DrawingBase {\r\n descriptor = { type: 'text' as const, name: 'Text', requiredAnchors: 1 };\r\n\r\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\r\n if (state.anchors.length < 1) return;\r\n const p = this.anchorToPixel(state.anchors[0], viewport);\r\n const text = resolveAnnotationText(state);\r\n const fontSize = state.style.fontSize || 14;\r\n\r\n ctx.font = `${fontSize}px sans-serif`;\r\n ctx.fillStyle = state.style.color;\r\n ctx.textAlign = 'left';\r\n ctx.textBaseline = 'top';\r\n\r\n if (selected) {\r\n const metrics = ctx.measureText(text);\r\n ctx.strokeStyle = state.style.color;\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([3, 3]);\r\n ctx.strokeRect(p.x - 2, p.y - 2, metrics.width + 4, fontSize + 4);\r\n ctx.setLineDash([]);\r\n }\r\n\r\n ctx.fillText(text, p.x, p.y);\r\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\r\n }\r\n\r\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\r\n if (state.anchors.length < 1) return false;\r\n const p = this.anchorToPixel(state.anchors[0], viewport);\r\n const fontSize = state.style.fontSize || 14;\r\n const textWidth = 80; // approximate\r\n return point.x >= p.x - tolerance && point.x <= p.x + textWidth + tolerance && point.y >= p.y - tolerance && point.y <= p.y + fontSize + tolerance;\r\n }\r\n}\r\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\nexport class ArrowTool extends DrawingBase {\n descriptor = { type: 'arrow' as const, name: 'Arrow', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n\n this.applyLineStyle(ctx, state.style);\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p2.x, p2.y);\n ctx.stroke();\n\n // Arrowhead\n const angle = Math.atan2(p2.y - p1.y, p2.x - p1.x);\n const headLen = 12;\n ctx.beginPath();\n ctx.moveTo(p2.x, p2.y);\n ctx.lineTo(p2.x - headLen * Math.cos(angle - Math.PI / 6), p2.y - headLen * Math.sin(angle - Math.PI / 6));\n ctx.lineTo(p2.x - headLen * Math.cos(angle + Math.PI / 6), p2.y - headLen * Math.sin(angle + Math.PI / 6));\n ctx.closePath();\n ctx.fillStyle = state.style.color;\n ctx.fill();\n\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n return this.distanceToLine(point, p1, p2) <= tolerance;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\n/**\n * Gann Fan drawing tool.\n * Two anchors define the 1x1 angle (45°). Additional ratio lines fan out\n * from the first anchor: 1x1, 1x2, 2x1, 1x3, 3x1, 1x4, 4x1, 1x8, 8x1.\n */\n\nconst GANN_RATIOS = [\n { label: '8x1', ratio: 8 },\n { label: '4x1', ratio: 4 },\n { label: '3x1', ratio: 3 },\n { label: '2x1', ratio: 2 },\n { label: '1x1', ratio: 1 },\n { label: '1x2', ratio: 0.5 },\n { label: '1x3', ratio: 1 / 3 },\n { label: '1x4', ratio: 0.25 },\n { label: '1x8', ratio: 0.125 },\n];\n\nexport class GannFanTool extends DrawingBase {\n descriptor = { type: 'gannFan' as const, name: 'Gann Fan', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n\n // The 1x1 line goes from p1 to p2. We use it to compute the unit scale.\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n\n if (Math.abs(dx) < 1) return;\n\n // The unit price-per-bar in pixel space is defined by the 1x1 angle\n const unitSlope = dy / dx;\n const direction = dx > 0 ? 1 : -1;\n const { chartRect } = viewport;\n const extendX = direction > 0\n ? chartRect.x + chartRect.width\n : chartRect.x;\n\n this.applyLineStyle(ctx, state.style);\n\n for (const { label, ratio } of GANN_RATIOS) {\n const slope = unitSlope * ratio;\n const farX = extendX;\n const farY = p1.y + slope * (farX - p1.x);\n\n ctx.globalAlpha = ratio === 1 ? 1 : 0.5;\n ctx.lineWidth = ratio === 1 ? state.style.lineWidth : Math.max(0.5, state.style.lineWidth * 0.7);\n\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(farX, farY);\n ctx.stroke();\n\n // Label at the end\n const labelX = farX - direction * 4;\n const labelY = farY;\n if (labelY > chartRect.y && labelY < chartRect.y + chartRect.height) {\n ctx.globalAlpha = 0.7;\n ctx.fillStyle = state.style.color;\n ctx.font = '9px sans-serif';\n ctx.textAlign = direction > 0 ? 'right' : 'left';\n ctx.textBaseline = 'bottom';\n ctx.fillText(label, labelX, labelY - 2);\n }\n }\n\n ctx.globalAlpha = 1;\n this.resetLineStyle(ctx);\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n\n if (Math.abs(dx) < 1) return false;\n\n const unitSlope = dy / dx;\n const direction = dx > 0 ? 1 : -1;\n const { chartRect } = viewport;\n const extendX = direction > 0\n ? chartRect.x + chartRect.width\n : chartRect.x;\n\n for (const { ratio } of GANN_RATIOS) {\n const slope = unitSlope * ratio;\n const farX = extendX;\n const farY = p1.y + slope * (farX - p1.x);\n const dist = this.distanceToLine(point, p1, { x: farX, y: farY });\n if (dist <= tolerance) return true;\n }\n return false;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\n\n/**\n * Gann Box drawing tool.\n * Two anchors define a rectangular region. The box is subdivided by\n * Gann angles (diagonal lines) and horizontal/vertical price/time divisions.\n */\n\nconst DIVISIONS = [0, 0.25, 0.333, 0.5, 0.667, 0.75, 1];\n\nexport class GannBoxTool extends DrawingBase {\n descriptor = { type: 'gannBox' as const, name: 'Gann Box', requiredAnchors: 2 };\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2) return;\n\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n\n const left = Math.min(p1.x, p2.x);\n const right = Math.max(p1.x, p2.x);\n const top = Math.min(p1.y, p2.y);\n const bottom = Math.max(p1.y, p2.y);\n const w = right - left;\n const h = bottom - top;\n\n if (w < 2 || h < 2) return;\n\n this.applyLineStyle(ctx, state.style);\n\n // Outer rectangle\n ctx.strokeRect(left, top, w, h);\n\n // Horizontal divisions\n ctx.save();\n ctx.globalAlpha = 0.35;\n for (const d of DIVISIONS) {\n if (d === 0 || d === 1) continue;\n const y = top + h * d;\n ctx.beginPath();\n ctx.moveTo(left, y);\n ctx.lineTo(right, y);\n ctx.stroke();\n }\n\n // Vertical divisions\n for (const d of DIVISIONS) {\n if (d === 0 || d === 1) continue;\n const x = left + w * d;\n ctx.beginPath();\n ctx.moveTo(x, top);\n ctx.lineTo(x, bottom);\n ctx.stroke();\n }\n\n // Diagonal lines (Gann angles)\n ctx.globalAlpha = 0.5;\n ctx.setLineDash([4, 3]);\n\n // Main diagonal\n ctx.beginPath();\n ctx.moveTo(left, top);\n ctx.lineTo(right, bottom);\n ctx.stroke();\n\n // Anti-diagonal\n ctx.beginPath();\n ctx.moveTo(right, top);\n ctx.lineTo(left, bottom);\n ctx.stroke();\n\n ctx.restore();\n this.resetLineStyle(ctx);\n\n // Labels for divisions\n ctx.fillStyle = state.style.color;\n ctx.font = '8px sans-serif';\n ctx.globalAlpha = 0.6;\n ctx.textBaseline = 'bottom';\n ctx.textAlign = 'right';\n for (const d of DIVISIONS) {\n if (d === 0 || d === 1) continue;\n const y = top + h * d;\n ctx.fillText(`${(d * 100).toFixed(0)}%`, left - 3, y);\n }\n ctx.globalAlpha = 1;\n\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n\n const left = Math.min(p1.x, p2.x);\n const right = Math.max(p1.x, p2.x);\n const top = Math.min(p1.y, p2.y);\n const bottom = Math.max(p1.y, p2.y);\n\n // Check outer edges\n if (Math.abs(point.x - left) <= tolerance && point.y >= top - tolerance && point.y <= bottom + tolerance) return true;\n if (Math.abs(point.x - right) <= tolerance && point.y >= top - tolerance && point.y <= bottom + tolerance) return true;\n if (Math.abs(point.y - top) <= tolerance && point.x >= left - tolerance && point.x <= right + tolerance) return true;\n if (Math.abs(point.y - bottom) <= tolerance && point.x >= left - tolerance && point.x <= right + tolerance) return true;\n\n // Check diagonals\n const dist1 = this.distanceToLine(point, { x: left, y: top }, { x: right, y: bottom });\n if (dist1 <= tolerance) return true;\n const dist2 = this.distanceToLine(point, { x: right, y: top }, { x: left, y: bottom });\n if (dist2 <= tolerance) return true;\n\n return false;\n }\n}\n","import type { DrawingState, Point, ViewportState, DataSeries } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\nimport { barIndexToX, priceToY, resolveBarIndex } from '../../viewport/ScaleMapping.js';\n\n/**\n * Anchored VWAP drawing tool.\n * One anchor sets the start bar. The VWAP line is computed from that bar\n * to the end of visible data using cumulative (price * volume) / volume.\n * Optionally renders +/-1 and +/-2 standard deviation bands.\n */\nexport class AnchoredVWAPTool extends DrawingBase {\n descriptor = { type: 'anchoredVWAP' as const, name: 'Anchored VWAP', requiredAnchors: 1 };\n\n private dataGetter: (() => DataSeries) | null = null;\n private showBands = true;\n\n setDataGetter(getter: () => DataSeries): void {\n this.dataGetter = getter;\n }\n\n setShowBands(show: boolean): void {\n this.showBands = show;\n }\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 1 || !this.dataGetter) return;\n\n const data = this.dataGetter();\n const startIdx = Math.max(0, Math.round(resolveBarIndex(state.anchors[0].time, viewport)));\n if (startIdx >= data.length) return;\n\n // Compute anchored VWAP from startIdx to end\n const { vwap, upper1, lower1, upper2, lower2 } = this.computeVWAP(data, startIdx);\n\n const { chartRect } = viewport;\n const barUnit = viewport.barWidth + viewport.barSpacing;\n\n // Draw VWAP line\n this.applyLineStyle(ctx, state.style);\n ctx.lineWidth = state.style.lineWidth + 0.5;\n\n this.drawLine(ctx, vwap, startIdx, viewport, chartRect, barUnit);\n\n // Draw bands\n if (this.showBands && vwap.length > 1) {\n ctx.globalAlpha = 0.4;\n ctx.lineWidth = Math.max(0.5, state.style.lineWidth * 0.6);\n ctx.setLineDash([4, 3]);\n\n this.drawLine(ctx, upper1, startIdx, viewport, chartRect, barUnit);\n this.drawLine(ctx, lower1, startIdx, viewport, chartRect, barUnit);\n\n ctx.globalAlpha = 0.25;\n this.drawLine(ctx, upper2, startIdx, viewport, chartRect, barUnit);\n this.drawLine(ctx, lower2, startIdx, viewport, chartRect, barUnit);\n\n ctx.globalAlpha = 1;\n }\n\n this.resetLineStyle(ctx);\n\n // Label\n if (vwap.length > 0) {\n const lastPrice = vwap[vwap.length - 1];\n const lastIdx = startIdx + vwap.length - 1;\n const x = barIndexToX(lastIdx, viewport);\n const y = priceToY(lastPrice, viewport);\n if (x >= chartRect.x && x <= chartRect.x + chartRect.width) {\n ctx.fillStyle = state.style.color;\n ctx.font = 'bold 9px sans-serif';\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.fillText(`AVWAP ${lastPrice.toFixed(2)}`, x + 6, y);\n }\n }\n\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n private drawLine(\n ctx: CanvasRenderingContext2D,\n prices: number[],\n startIdx: number,\n viewport: ViewportState,\n chartRect: { x: number; width: number },\n barUnit: number,\n ): void {\n ctx.beginPath();\n let started = false;\n for (let i = 0; i < prices.length; i++) {\n const x = barIndexToX(startIdx + i, viewport);\n if (x < chartRect.x - barUnit) continue;\n if (x > chartRect.x + chartRect.width + barUnit) break;\n const y = priceToY(prices[i], viewport);\n if (!started) {\n ctx.moveTo(x, y);\n started = true;\n } else {\n ctx.lineTo(x, y);\n }\n }\n ctx.stroke();\n }\n\n private computeVWAP(data: DataSeries, startIdx: number): {\n vwap: number[];\n upper1: number[];\n lower1: number[];\n upper2: number[];\n lower2: number[];\n } {\n const len = data.length - startIdx;\n const vwap: number[] = new Array(len);\n const upper1: number[] = new Array(len);\n const lower1: number[] = new Array(len);\n const upper2: number[] = new Array(len);\n const lower2: number[] = new Array(len);\n\n let cumPV = 0;\n let cumV = 0;\n let cumPV2 = 0; // For standard deviation\n\n for (let i = 0; i < len; i++) {\n const bar = data[startIdx + i];\n const tp = (bar.high + bar.low + bar.close) / 3; // Typical price\n const vol = bar.volume ?? 1;\n\n cumPV += tp * vol;\n cumV += vol;\n cumPV2 += tp * tp * vol;\n\n const v = cumV > 0 ? cumPV / cumV : tp;\n vwap[i] = v;\n\n // Standard deviation of price from VWAP\n const variance = cumV > 0 ? (cumPV2 / cumV) - v * v : 0;\n const stdDev = Math.sqrt(Math.max(0, variance));\n\n upper1[i] = v + stdDev;\n lower1[i] = v - stdDev;\n upper2[i] = v + 2 * stdDev;\n lower2[i] = v - 2 * stdDev;\n }\n\n return { vwap, upper1, lower1, upper2, lower2 };\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 1 || !this.dataGetter) return false;\n\n const data = this.dataGetter();\n const startIdx = Math.max(0, Math.round(resolveBarIndex(state.anchors[0].time, viewport)));\n if (startIdx >= data.length) return false;\n\n const { vwap } = this.computeVWAP(data, startIdx);\n\n // Check if point is close to any segment of the VWAP line\n for (let i = 1; i < vwap.length; i++) {\n const p1x = barIndexToX(startIdx + i - 1, viewport);\n const p1y = priceToY(vwap[i - 1], viewport);\n const p2x = barIndexToX(startIdx + i, viewport);\n const p2y = priceToY(vwap[i], viewport);\n const dist = this.distanceToLine(point, { x: p1x, y: p1y }, { x: p2x, y: p2y });\n if (dist <= tolerance) return true;\n }\n\n return false;\n }\n}\n","import type { DrawingState, Point, ViewportState, DataSeries } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\nimport { barIndexToX, priceToY, resolveBarIndex } from '../../viewport/ScaleMapping.js';\n\n/**\n * Volume Profile (Visible/Fixed Range) drawing tool.\n * Two anchors define a time range. The tool computes volume distribution\n * across price levels within that range and renders a horizontal histogram.\n */\nexport class VolumeProfileRangeTool extends DrawingBase {\n descriptor = { type: 'volumeProfileRange' as const, name: 'Volume Profile (Range)', requiredAnchors: 2 };\n\n private dataGetter: (() => DataSeries) | null = null;\n private numBins = 40;\n\n setDataGetter(getter: () => DataSeries): void {\n this.dataGetter = getter;\n }\n\n render(ctx: CanvasRenderingContext2D, state: DrawingState, viewport: ViewportState, selected: boolean): void {\n if (state.anchors.length < 2 || !this.dataGetter) return;\n\n const data = this.dataGetter();\n const idx0 = Math.round(resolveBarIndex(state.anchors[0].time, viewport));\n const idx1 = Math.round(resolveBarIndex(state.anchors[1].time, viewport));\n const startIdx = Math.max(0, Math.min(idx0, idx1));\n const endIdx = Math.min(data.length - 1, Math.max(idx0, idx1));\n\n if (startIdx >= data.length || endIdx < 0 || startIdx > endIdx) return;\n\n // Find price range within the selected bars\n let pMin = Infinity, pMax = -Infinity;\n for (let i = startIdx; i <= endIdx; i++) {\n if (data[i].low < pMin) pMin = data[i].low;\n if (data[i].high > pMax) pMax = data[i].high;\n }\n if (pMin >= pMax) return;\n\n // Build volume histogram\n const binSize = (pMax - pMin) / this.numBins;\n const bins = new Float64Array(this.numBins);\n let maxBinVol = 0;\n\n for (let i = startIdx; i <= endIdx; i++) {\n const bar = data[i];\n const vol = bar.volume ?? 1;\n // Distribute volume across the bins the bar spans\n const lowBin = Math.max(0, Math.floor((bar.low - pMin) / binSize));\n const highBin = Math.min(this.numBins - 1, Math.floor((bar.high - pMin) / binSize));\n const span = highBin - lowBin + 1;\n const volPerBin = vol / span;\n for (let b = lowBin; b <= highBin; b++) {\n bins[b] += volPerBin;\n if (bins[b] > maxBinVol) maxBinVol = bins[b];\n }\n }\n\n if (maxBinVol === 0) return;\n\n // Find POC (Point of Control)\n let pocBin = 0;\n for (let i = 1; i < this.numBins; i++) {\n if (bins[i] > bins[pocBin]) pocBin = i;\n }\n\n // Render histogram on the right side of the selected range\n const rightX = barIndexToX(endIdx, viewport) + viewport.barWidth;\n const maxBarWidth = 100; // Max histogram bar width in pixels\n const color = state.style.color;\n const pocColor = state.style.fillColor ?? '#FF9800';\n\n ctx.save();\n\n for (let b = 0; b < this.numBins; b++) {\n const ratio = bins[b] / maxBinVol;\n const barW = ratio * maxBarWidth;\n\n const priceTop = pMin + (b + 1) * binSize;\n const priceBot = pMin + b * binSize;\n const yTop = priceToY(priceTop, viewport);\n const yBot = priceToY(priceBot, viewport);\n const barH = Math.abs(yBot - yTop);\n\n ctx.globalAlpha = 0.35;\n ctx.fillStyle = b === pocBin ? pocColor : color;\n ctx.fillRect(rightX, Math.min(yTop, yBot), barW, Math.max(1, barH - 0.5));\n }\n\n // POC line\n const pocPrice = pMin + (pocBin + 0.5) * binSize;\n const pocY = priceToY(pocPrice, viewport);\n ctx.globalAlpha = 0.7;\n ctx.strokeStyle = pocColor;\n ctx.lineWidth = 1;\n ctx.setLineDash([4, 3]);\n ctx.beginPath();\n const leftX = barIndexToX(startIdx, viewport) - viewport.barWidth / 2;\n ctx.moveTo(leftX, pocY);\n ctx.lineTo(rightX + maxBarWidth, pocY);\n ctx.stroke();\n\n // POC label\n ctx.fillStyle = pocColor;\n ctx.font = '9px sans-serif';\n ctx.textAlign = 'left';\n ctx.textBaseline = 'bottom';\n ctx.globalAlpha = 0.8;\n ctx.fillText(`POC ${pocPrice.toFixed(2)}`, rightX + maxBarWidth + 4, pocY - 2);\n\n ctx.restore();\n\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(point: Point, state: DrawingState, viewport: ViewportState, tolerance: number): boolean {\n if (state.anchors.length < 2) return false;\n\n const p1 = this.anchorToPixel(state.anchors[0], viewport);\n const p2 = this.anchorToPixel(state.anchors[1], viewport);\n\n const left = Math.min(p1.x, p2.x) - tolerance;\n const right = Math.max(p1.x, p2.x) + 100 + tolerance; // +100 for histogram width\n const top = Math.min(p1.y, p2.y) - tolerance;\n const bottom = Math.max(p1.y, p2.y) + tolerance;\n\n return point.x >= left && point.x <= right && point.y >= top && point.y <= bottom;\n }\n}\n","import type { DrawingState, Point, ViewportState } from '@tradecanvas/commons';\nimport { DrawingBase } from '../DrawingBase.js';\nimport { timeToX } from '../../viewport/ScaleMapping.js';\n\n/**\n * Vertical lines at Fibonacci intervals (1, 2, 3, 5, 8, 13, 21, 34, 55)\n * measured from a two-anchor time span. The first anchor defines time 0,\n * the second defines the unit (1× span). Each level i draws a vertical line\n * at `anchorA.time + (anchorB.time - anchorA.time) * fib[i]`.\n *\n * Useful for projecting future turning points based on prior swing duration.\n */\nconst FIB_TIME_LEVELS = [1, 2, 3, 5, 8, 13, 21, 34, 55];\n\nexport class FibTimeZonesTool extends DrawingBase {\n descriptor = {\n type: 'fibTimeZones' as const,\n name: 'Fibonacci Time Zones',\n requiredAnchors: 2,\n };\n\n render(\n ctx: CanvasRenderingContext2D,\n state: DrawingState,\n viewport: ViewportState,\n selected: boolean,\n ): void {\n if (state.anchors.length < 2) return;\n const anchorA = state.anchors[0];\n const anchorB = state.anchors[1];\n const unit = anchorB.time - anchorA.time;\n if (unit === 0) return;\n\n const { chartRect } = viewport;\n ctx.font = '11px sans-serif';\n ctx.textBaseline = 'top';\n ctx.textAlign = 'center';\n\n this.applyLineStyle(ctx, state.style);\n for (const mult of FIB_TIME_LEVELS) {\n const t = anchorA.time + unit * mult;\n const x = timeToX(t, viewport);\n if (x < chartRect.x || x > chartRect.x + chartRect.width) continue;\n\n ctx.globalAlpha = mult === 1 ? 1 : 0.55;\n ctx.beginPath();\n ctx.moveTo(x, chartRect.y);\n ctx.lineTo(x, chartRect.y + chartRect.height);\n ctx.stroke();\n\n ctx.fillStyle = state.style.color;\n ctx.fillText(String(mult), x, chartRect.y + 2);\n }\n ctx.globalAlpha = 1;\n this.resetLineStyle(ctx);\n\n if (selected) this.renderAnchorHandles(ctx, state, viewport);\n }\n\n hitTest(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): boolean {\n if (state.anchors.length < 2) return false;\n const anchorA = state.anchors[0];\n const anchorB = state.anchors[1];\n const unit = anchorB.time - anchorA.time;\n if (unit === 0) return false;\n const { chartRect } = viewport;\n if (point.y < chartRect.y || point.y > chartRect.y + chartRect.height) {\n return false;\n }\n for (const mult of FIB_TIME_LEVELS) {\n const t = anchorA.time + unit * mult;\n const x = timeToX(t, viewport);\n if (Math.abs(point.x - x) <= tolerance) return true;\n }\n return false;\n }\n}\n","export { TrendLineTool } from './TrendLine.js';\nexport { HorizontalLineTool } from './HorizontalLine.js';\nexport { VerticalLineTool } from './VerticalLine.js';\nexport { RayTool } from './Ray.js';\nexport { ExtendedLineTool } from './ExtendedLine.js';\nexport { ParallelChannelTool } from './ParallelChannel.js';\nexport { RegressionChannelTool } from './RegressionChannel.js';\nexport { FibRetracementTool } from './FibRetracement.js';\nexport { FibExtensionTool } from './FibExtension.js';\nexport { RectangleTool } from './Rectangle.js';\nexport { EllipseTool } from './Ellipse.js';\nexport { TriangleTool } from './Triangle.js';\nexport { PitchforkTool } from './Pitchfork.js';\nexport { ElliottWaveTool } from './ElliottWave.js';\nexport { PriceRangeTool } from './PriceRange.js';\nexport { DateRangeTool } from './DateRange.js';\nexport { MeasureTool } from './Measure.js';\nexport { TextAnnotationTool } from './TextAnnotation.js';\nexport { ArrowTool } from './Arrow.js';\nexport { GannFanTool } from './GannFan.js';\nexport { GannBoxTool } from './GannBox.js';\nexport { AnchoredVWAPTool } from './AnchoredVWAP.js';\nexport { VolumeProfileRangeTool } from './VolumeProfileRange.js';\nexport { FibTimeZonesTool } from './FibTimeZones.js';\n\nimport type { DrawingManager } from '../DrawingManager.js';\nimport { TrendLineTool } from './TrendLine.js';\nimport { HorizontalLineTool } from './HorizontalLine.js';\nimport { VerticalLineTool } from './VerticalLine.js';\nimport { RayTool } from './Ray.js';\nimport { ExtendedLineTool } from './ExtendedLine.js';\nimport { ParallelChannelTool } from './ParallelChannel.js';\nimport { RegressionChannelTool } from './RegressionChannel.js';\nimport { FibRetracementTool } from './FibRetracement.js';\nimport { FibExtensionTool } from './FibExtension.js';\nimport { RectangleTool } from './Rectangle.js';\nimport { EllipseTool } from './Ellipse.js';\nimport { TriangleTool } from './Triangle.js';\nimport { PitchforkTool } from './Pitchfork.js';\nimport { ElliottWaveTool } from './ElliottWave.js';\nimport { PriceRangeTool } from './PriceRange.js';\nimport { DateRangeTool } from './DateRange.js';\nimport { MeasureTool } from './Measure.js';\nimport { TextAnnotationTool } from './TextAnnotation.js';\nimport { ArrowTool } from './Arrow.js';\nimport { GannFanTool } from './GannFan.js';\nimport { GannBoxTool } from './GannBox.js';\nimport { AnchoredVWAPTool } from './AnchoredVWAP.js';\nimport { VolumeProfileRangeTool } from './VolumeProfileRange.js';\nimport { FibTimeZonesTool } from './FibTimeZones.js';\n\nexport function registerBuiltInDrawingTools(manager: DrawingManager): void {\n manager.register(new TrendLineTool());\n manager.register(new HorizontalLineTool());\n manager.register(new VerticalLineTool());\n manager.register(new RayTool());\n manager.register(new ExtendedLineTool());\n manager.register(new ParallelChannelTool());\n manager.register(new RegressionChannelTool());\n manager.register(new FibRetracementTool());\n manager.register(new FibExtensionTool());\n manager.register(new RectangleTool());\n manager.register(new EllipseTool());\n manager.register(new TriangleTool());\n manager.register(new PitchforkTool());\n manager.register(new ElliottWaveTool());\n manager.register(new PriceRangeTool());\n manager.register(new DateRangeTool());\n manager.register(new MeasureTool());\n manager.register(new TextAnnotationTool());\n manager.register(new ArrowTool());\n manager.register(new GannFanTool());\n manager.register(new GannBoxTool());\n manager.register(new AnchoredVWAPTool());\n manager.register(new VolumeProfileRangeTool());\n manager.register(new FibTimeZonesTool());\n}\n","import type { TradingOrder, TradingConfig, ViewportState, Theme } from '@tradecanvas/commons';\nimport { priceToY } from '../viewport/ScaleMapping.js';\nimport { PRICE_AXIS_WIDTH } from '@tradecanvas/commons';\n\nexport interface DragState {\n orderId: string;\n sourceType: 'order' | 'stopLoss' | 'takeProfit';\n startPrice: number;\n currentPrice: number;\n}\n\nexport class OrderRenderer {\n render(\n ctx: CanvasRenderingContext2D,\n orders: TradingOrder[],\n viewport: ViewportState,\n theme: Theme,\n config: TradingConfig,\n dragState: DragState | null,\n ): void {\n const buyColor = config.orderColors?.buy ?? '#26A69A';\n const sellColor = config.orderColors?.sell ?? '#EF5350';\n const { chartRect } = viewport;\n\n for (const order of orders) {\n const isDragging = dragState?.orderId === order.id && dragState.sourceType === 'order';\n const price = isDragging ? dragState!.currentPrice : order.price;\n const y = priceToY(price, viewport);\n\n if (y < chartRect.y || y > chartRect.y + chartRect.height) continue;\n\n const color = order.side === 'buy' ? buyColor : sellColor;\n\n // Dashed order line\n ctx.setLineDash([6, 4]);\n ctx.strokeStyle = color;\n ctx.lineWidth = 1;\n ctx.beginPath();\n ctx.moveTo(chartRect.x, Math.round(y) + 0.5);\n ctx.lineTo(chartRect.x + chartRect.width, Math.round(y) + 0.5);\n ctx.stroke();\n ctx.setLineDash([]);\n\n // Order type label (left side)\n const label = order.label ?? order.type.toUpperCase();\n ctx.font = `bold 10px ${theme.font.family}`;\n const labelWidth = ctx.measureText(label).width + 8;\n ctx.fillStyle = color;\n ctx.fillRect(chartRect.x + 4, y - 8, labelWidth, 16);\n ctx.fillStyle = '#FFFFFF';\n ctx.textBaseline = 'middle';\n ctx.textAlign = 'left';\n ctx.fillText(label, chartRect.x + 8, y);\n\n // Price + qty badge on axis — rendered separately via renderAxisBadges()\n // on the UI layer so it paints on top of the price axis labels.\n\n // Side indicator (small triangle)\n const triX = chartRect.x + 4 + labelWidth + 6;\n ctx.fillStyle = color;\n ctx.beginPath();\n if (order.side === 'buy') {\n ctx.moveTo(triX, y + 4);\n ctx.lineTo(triX + 5, y - 2);\n ctx.lineTo(triX + 10, y + 4);\n } else {\n ctx.moveTo(triX, y - 4);\n ctx.lineTo(triX + 5, y + 2);\n ctx.lineTo(triX + 10, y - 4);\n }\n ctx.fill();\n\n // Ghost line at original price if dragging\n if (isDragging) {\n const origY = priceToY(dragState!.startPrice, viewport);\n ctx.setLineDash([2, 4]);\n ctx.strokeStyle = color;\n ctx.globalAlpha = 0.3;\n ctx.beginPath();\n ctx.moveTo(chartRect.x, Math.round(origY) + 0.5);\n ctx.lineTo(chartRect.x + chartRect.width, Math.round(origY) + 0.5);\n ctx.stroke();\n ctx.globalAlpha = 1;\n ctx.setLineDash([]);\n }\n }\n }\n\n /**\n * Draw order price badges on the price axis. Called from the UI layer\n * so they paint ON TOP of the regular axis tick labels.\n */\n renderAxisBadges(\n ctx: CanvasRenderingContext2D,\n orders: TradingOrder[],\n viewport: ViewportState,\n theme: Theme,\n config: TradingConfig,\n dragState: DragState | null,\n ): void {\n const buyColor = config.orderColors?.buy ?? '#26A69A';\n const sellColor = config.orderColors?.sell ?? '#EF5350';\n const precision = config.pricePrecision ?? 2;\n const { chartRect } = viewport;\n const axisX = chartRect.x + chartRect.width + 1;\n\n for (const order of orders) {\n const isDragging = dragState?.orderId === order.id && dragState.sourceType === 'order';\n const price = isDragging ? dragState!.currentPrice : order.price;\n const y = priceToY(price, viewport);\n if (y < chartRect.y || y > chartRect.y + chartRect.height) continue;\n\n const color = order.side === 'buy' ? buyColor : sellColor;\n const priceText = `${price.toFixed(precision)} x ${order.quantity}`;\n ctx.font = `11px ${theme.font.family}`;\n const badgeWidth = ctx.measureText(priceText).width + 10;\n ctx.fillStyle = color;\n ctx.fillRect(axisX, y - 9, Math.min(badgeWidth, PRICE_AXIS_WIDTH - 2), 18);\n ctx.fillStyle = '#FFFFFF';\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.fillText(priceText, axisX + 5, y);\n }\n }\n\n hitTest(\n y: number,\n orders: TradingOrder[],\n viewport: ViewportState,\n tolerance: number,\n ): TradingOrder | null {\n for (const order of orders) {\n if (order.draggable === false) continue;\n const orderY = priceToY(order.price, viewport);\n if (Math.abs(y - orderY) <= tolerance) return order;\n }\n return null;\n }\n}\n","import type {\r\n PnLThreshold,\r\n PositionLabelContext,\r\n TradingPosition,\r\n} from '@tradecanvas/commons';\r\n\r\n/**\r\n * Compute live P&L context for a position. Pure — no canvas, no side effects.\r\n * `closedQuantity` is clamped into [0, quantity]; remaining open quantity drives the P&L.\r\n */\r\nexport function buildPositionLabelContext(\r\n pos: TradingPosition,\r\n currentPrice: number,\r\n precision: number,\r\n): PositionLabelContext {\r\n const closed = Math.min(Math.max(pos.closedQuantity ?? 0, 0), pos.quantity);\r\n const open = pos.quantity - closed;\r\n const direction = pos.side === 'buy' ? 1 : -1;\r\n const pnl = (currentPrice - pos.entryPrice) * open * direction;\r\n const pnlPct =\r\n pos.entryPrice === 0\r\n ? 0\r\n : ((currentPrice - pos.entryPrice) / pos.entryPrice) * 100 * direction;\r\n return {\r\n side: pos.side,\r\n quantity: pos.quantity,\r\n closedQuantity: closed,\r\n openQuantity: open,\r\n entryPrice: pos.entryPrice,\r\n currentPrice,\r\n pnl,\r\n pnlPct,\r\n precision,\r\n };\r\n}\r\n\r\nconst TOKEN_RE = /\\{(side|qty|closedQty|openQty|entry|price|pnl|pnlPct|pnlSign)\\}/g;\r\n\r\nexport function formatPositionLabel(\r\n template: string,\r\n ctx: PositionLabelContext,\r\n): string {\r\n return template.replace(TOKEN_RE, (_, key: string) => {\r\n switch (key) {\r\n case 'side':\r\n return ctx.side.toUpperCase();\r\n case 'qty':\r\n return String(ctx.quantity);\r\n case 'closedQty':\r\n return String(ctx.closedQuantity);\r\n case 'openQty':\r\n return String(ctx.openQuantity);\r\n case 'entry':\r\n return ctx.entryPrice.toFixed(ctx.precision);\r\n case 'price':\r\n return ctx.currentPrice.toFixed(ctx.precision);\r\n case 'pnl':\r\n return ctx.pnl.toFixed(ctx.precision);\r\n case 'pnlPct':\r\n return `${ctx.pnlPct.toFixed(2)}%`;\r\n case 'pnlSign':\r\n return ctx.pnl >= 0 ? '+' : '';\r\n default:\r\n return '';\r\n }\r\n });\r\n}\r\n\r\nexport const DEFAULT_POSITION_LABEL =\r\n '{side} {qty} | P&L: {pnlSign}{pnl}';\r\n\r\nexport function resolvePositionLabel(\r\n template: string | ((ctx: PositionLabelContext) => string) | undefined,\r\n ctx: PositionLabelContext,\r\n): string {\r\n if (typeof template === 'function') return template(ctx);\r\n return formatPositionLabel(template ?? DEFAULT_POSITION_LABEL, ctx);\r\n}\r\n\r\n/**\r\n * Pick the color matching `pnl` from a threshold list. The chosen entry is the\r\n * highest one whose `pnl` ≤ the live P&L. Returns `fallback` when no entry qualifies.\r\n */\r\nexport function pickPnLColor(\r\n pnl: number,\r\n thresholds: PnLThreshold[] | undefined,\r\n fallback: string,\r\n): string {\r\n if (!thresholds || thresholds.length === 0) return fallback;\r\n const sorted = [...thresholds].sort((a, b) => a.pnl - b.pnl);\r\n let chosen: string | undefined;\r\n for (const t of sorted) {\r\n if (pnl >= t.pnl) chosen = t.color;\r\n else break;\r\n }\r\n return chosen ?? fallback;\r\n}\r\n","import type { TradingPosition, TradingConfig, ViewportState, Theme } from '@tradecanvas/commons';\r\nimport { priceToY } from '../viewport/ScaleMapping.js';\r\nimport { PRICE_AXIS_WIDTH } from '@tradecanvas/commons';\r\nimport {\r\n buildPositionLabelContext,\r\n pickPnLColor,\r\n resolvePositionLabel,\r\n} from './positionFormat.js';\r\n\r\nexport class PositionRenderer {\r\n render(\r\n ctx: CanvasRenderingContext2D,\r\n positions: TradingPosition[],\r\n currentPrice: number | null,\r\n viewport: ViewportState,\r\n theme: Theme,\r\n config: TradingConfig,\r\n ): void {\r\n const { chartRect } = viewport;\r\n const profitColor = config.positionColors?.profit ?? '#26A69A';\r\n const lossColor = config.positionColors?.loss ?? '#EF5350';\r\n const entryColor = config.positionColors?.entry ?? '#2196F3';\r\n const precision = config.pricePrecision ?? 2;\r\n\r\n for (const pos of positions) {\r\n const entryY = priceToY(pos.entryPrice, viewport);\r\n\r\n // Entry line\r\n ctx.strokeStyle = entryColor;\r\n ctx.lineWidth = 1.5;\r\n ctx.setLineDash([]);\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, Math.round(entryY) + 0.5);\r\n ctx.lineTo(chartRect.x + chartRect.width, Math.round(entryY) + 0.5);\r\n ctx.stroke();\r\n\r\n // P&L zone\r\n if (currentPrice !== null) {\r\n const currentY = priceToY(currentPrice, viewport);\r\n const labelCtx = buildPositionLabelContext(pos, currentPrice, precision);\r\n const pnl = labelCtx.pnl;\r\n const isProfit = pnl >= 0;\r\n const fallbackZone = isProfit ? profitColor : lossColor;\r\n const zoneColor = pickPnLColor(pnl, config.pnlThresholds, fallbackZone);\r\n\r\n ctx.fillStyle = zoneColor;\r\n ctx.globalAlpha = 0.08;\r\n const top = Math.min(entryY, currentY);\r\n const height = Math.abs(currentY - entryY);\r\n ctx.fillRect(chartRect.x, top, chartRect.width, height);\r\n ctx.globalAlpha = 1;\r\n\r\n // Partial-close strip on the left edge — proportional dim band signalling\r\n // the closed fraction of the position.\r\n if (labelCtx.closedQuantity > 0 && pos.quantity > 0) {\r\n const closedFrac = labelCtx.closedQuantity / pos.quantity;\r\n ctx.fillStyle = entryColor;\r\n ctx.globalAlpha = 0.25;\r\n ctx.fillRect(chartRect.x, top, Math.max(2, chartRect.width * closedFrac * 0.04) + 2, height);\r\n ctx.globalAlpha = 1;\r\n }\r\n\r\n const pnlText = resolvePositionLabel(config.positionLabel, labelCtx);\r\n ctx.font = `bold 11px ${theme.font.family}`;\r\n const lblWidth = ctx.measureText(pnlText).width + 12;\r\n const lblX = chartRect.x + 8;\r\n ctx.fillStyle = zoneColor;\r\n ctx.globalAlpha = 0.9;\r\n ctx.fillRect(lblX, entryY - 10, lblWidth, 20);\r\n ctx.globalAlpha = 1;\r\n ctx.fillStyle = '#FFFFFF';\r\n ctx.textBaseline = 'middle';\r\n ctx.textAlign = 'left';\r\n ctx.fillText(pnlText, lblX + 6, entryY);\r\n }\r\n\r\n // Entry badge on axis — rendered separately via renderAxisBadges()\r\n // on the UI layer so it paints on top of the price axis labels.\r\n\r\n // SL line\r\n if (pos.stopLoss !== undefined) {\r\n const slY = priceToY(pos.stopLoss, viewport);\r\n ctx.setLineDash([4, 4]);\r\n ctx.strokeStyle = lossColor;\r\n ctx.lineWidth = 1;\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, Math.round(slY) + 0.5);\r\n ctx.lineTo(chartRect.x + chartRect.width, Math.round(slY) + 0.5);\r\n ctx.stroke();\r\n\r\n ctx.font = `bold 10px ${theme.font.family}`;\r\n ctx.fillStyle = lossColor;\r\n ctx.fillRect(chartRect.x + 4, slY - 8, 24, 16);\r\n ctx.fillStyle = '#FFFFFF';\r\n ctx.textAlign = 'left';\r\n ctx.textBaseline = 'middle';\r\n ctx.fillText('SL', chartRect.x + 8, slY);\r\n }\r\n\r\n // TP line\r\n if (pos.takeProfit !== undefined) {\r\n const tpY = priceToY(pos.takeProfit, viewport);\r\n ctx.setLineDash([4, 4]);\r\n ctx.strokeStyle = profitColor;\r\n ctx.lineWidth = 1;\r\n ctx.beginPath();\r\n ctx.moveTo(chartRect.x, Math.round(tpY) + 0.5);\r\n ctx.lineTo(chartRect.x + chartRect.width, Math.round(tpY) + 0.5);\r\n ctx.stroke();\r\n\r\n ctx.font = `bold 10px ${theme.font.family}`;\r\n ctx.fillStyle = profitColor;\r\n ctx.fillRect(chartRect.x + 4, tpY - 8, 24, 16);\r\n ctx.fillStyle = '#FFFFFF';\r\n ctx.textAlign = 'left';\r\n ctx.textBaseline = 'middle';\r\n ctx.fillText('TP', chartRect.x + 8, tpY);\r\n }\r\n\r\n ctx.setLineDash([]);\r\n }\r\n }\r\n\r\n /**\r\n * Draw position entry badges on the price axis. Called from the UI layer\r\n * so they paint ON TOP of the regular axis tick labels.\r\n */\r\n renderAxisBadges(\r\n ctx: CanvasRenderingContext2D,\r\n positions: TradingPosition[],\r\n viewport: ViewportState,\r\n theme: Theme,\r\n config: TradingConfig,\r\n ): void {\r\n const { chartRect } = viewport;\r\n const entryColor = config.positionColors?.entry ?? '#2196F3';\r\n const precision = config.pricePrecision ?? 2;\r\n const axisX = chartRect.x + chartRect.width + 1;\r\n\r\n for (const pos of positions) {\r\n const entryY = priceToY(pos.entryPrice, viewport);\r\n ctx.fillStyle = entryColor;\r\n ctx.fillRect(axisX, entryY - 9, PRICE_AXIS_WIDTH - 2, 18);\r\n ctx.fillStyle = '#FFFFFF';\r\n ctx.font = `11px ${theme.font.family}`;\r\n ctx.textAlign = 'left';\r\n ctx.textBaseline = 'middle';\r\n ctx.fillText(pos.entryPrice.toFixed(precision), axisX + 5, entryY);\r\n }\r\n }\r\n}\r\n","import type { DepthData, TradingConfig, ViewportState } from '@tradecanvas/commons';\nimport { priceToY } from '../viewport/ScaleMapping.js';\n\nexport class DepthOverlay {\n render(\n ctx: CanvasRenderingContext2D,\n depth: DepthData,\n viewport: ViewportState,\n config: TradingConfig,\n ): void {\n if (!config.depthOverlay?.enabled) return;\n\n const { chartRect } = viewport;\n const bidColor = config.depthOverlay.bidColor ?? 'rgba(38,166,154,0.15)';\n const askColor = config.depthOverlay.askColor ?? 'rgba(239,83,80,0.15)';\n const maxWidth = config.depthOverlay.maxWidth ?? 100;\n\n // Compute cumulative volumes\n let maxCumVol = 0;\n const bidCum: { price: number; cumVol: number }[] = [];\n let cumVol = 0;\n for (const level of depth.bids) {\n cumVol += level.volume;\n bidCum.push({ price: level.price, cumVol });\n if (cumVol > maxCumVol) maxCumVol = cumVol;\n }\n\n const askCum: { price: number; cumVol: number }[] = [];\n cumVol = 0;\n for (const level of depth.asks) {\n cumVol += level.volume;\n askCum.push({ price: level.price, cumVol });\n if (cumVol > maxCumVol) maxCumVol = cumVol;\n }\n\n if (maxCumVol === 0) return;\n\n // Estimate bar height from price spacing\n const barHeight = Math.max(1, (depth.bids.length > 1\n ? Math.abs(priceToY(depth.bids[0].price, viewport) - priceToY(depth.bids[1].price, viewport))\n : 4));\n\n const rightEdge = chartRect.x + chartRect.width;\n\n // Draw bids (right-aligned, growing left)\n ctx.fillStyle = bidColor;\n for (const { price, cumVol: cv } of bidCum) {\n const y = priceToY(price, viewport);\n if (y < chartRect.y || y > chartRect.y + chartRect.height) continue;\n const barW = (cv / maxCumVol) * maxWidth;\n ctx.fillRect(rightEdge - barW, y - barHeight / 2, barW, barHeight);\n }\n\n // Draw asks\n ctx.fillStyle = askColor;\n for (const { price, cumVol: cv } of askCum) {\n const y = priceToY(price, viewport);\n if (y < chartRect.y || y > chartRect.y + chartRect.height) continue;\n const barW = (cv / maxCumVol) * maxWidth;\n ctx.fillRect(rightEdge - barW, y - barHeight / 2, barW, barHeight);\n }\n }\n}\n","import type { TradingOrder, TradingPosition, ViewportState, Point } from '@tradecanvas/commons';\nimport { priceToY, yToPrice } from '../viewport/ScaleMapping.js';\nimport type { DragState } from './OrderRenderer.js';\n\nexport interface DragResult {\n sourceType: 'order' | 'stopLoss' | 'takeProfit';\n id: string;\n newPrice: number;\n previousPrice: number;\n}\n\nexport class TradingDragHandler {\n private dragState: DragState | null = null;\n private startY = 0;\n private dragging = false;\n\n constructor(private dragThreshold = 3) {}\n\n onPointerDown(\n pos: Point,\n orders: TradingOrder[],\n positions: TradingPosition[],\n viewport: ViewportState,\n tolerance: number,\n ): boolean {\n // Check order lines\n for (const order of orders) {\n if (order.draggable === false) continue;\n const y = priceToY(order.price, viewport);\n if (Math.abs(pos.y - y) <= tolerance) {\n this.dragState = {\n orderId: order.id,\n sourceType: 'order',\n startPrice: order.price,\n currentPrice: order.price,\n };\n this.startY = pos.y;\n this.dragging = false;\n return true;\n }\n }\n\n // Check SL/TP lines on positions\n for (const pos2 of positions) {\n if (pos2.stopLoss !== undefined) {\n const slY = priceToY(pos2.stopLoss, viewport);\n if (Math.abs(pos.y - slY) <= tolerance) {\n this.dragState = {\n orderId: pos2.id,\n sourceType: 'stopLoss',\n startPrice: pos2.stopLoss,\n currentPrice: pos2.stopLoss,\n };\n this.startY = pos.y;\n this.dragging = false;\n return true;\n }\n }\n if (pos2.takeProfit !== undefined) {\n const tpY = priceToY(pos2.takeProfit, viewport);\n if (Math.abs(pos.y - tpY) <= tolerance) {\n this.dragState = {\n orderId: pos2.id,\n sourceType: 'takeProfit',\n startPrice: pos2.takeProfit,\n currentPrice: pos2.takeProfit,\n };\n this.startY = pos.y;\n this.dragging = false;\n return true;\n }\n }\n }\n\n return false;\n }\n\n onPointerMove(pos: Point, viewport: ViewportState): boolean {\n if (!this.dragState) return false;\n\n if (!this.dragging) {\n if (Math.abs(pos.y - this.startY) < this.dragThreshold) return true;\n this.dragging = true;\n }\n\n this.dragState.currentPrice = yToPrice(pos.y, viewport);\n return true;\n }\n\n onPointerUp(): DragResult | null {\n if (!this.dragState) return null;\n const state = this.dragState;\n this.dragState = null;\n\n if (!this.dragging) return null;\n this.dragging = false;\n\n return {\n sourceType: state.sourceType,\n id: state.orderId,\n newPrice: state.currentPrice,\n previousPrice: state.startPrice,\n };\n }\n\n getDragState(): DragState | null {\n return this.dragState;\n }\n\n isActive(): boolean {\n return this.dragState !== null;\n }\n}\n","import type { OrderPlaceIntent, TradingConfig, Point } from '@tradecanvas/commons';\n\nexport class TradingContextMenu {\n private menuElement: HTMLElement | null = null;\n private removeHandler: (() => void) | null = null;\n onItemSelect: ((intent: OrderPlaceIntent) => void) | null = null;\n\n show(pos: Point, price: number, container: HTMLElement, config: TradingConfig): void {\n this.hide();\n if (!config.contextMenu?.enabled) return;\n\n const precision = config.pricePrecision ?? 2;\n const priceStr = price.toFixed(precision);\n\n const menu = document.createElement('div');\n menu.style.cssText = `\n position: absolute;\n left: ${pos.x}px;\n top: ${pos.y}px;\n background: #1e222d;\n border: 1px solid #363a45;\n border-radius: 6px;\n padding: 4px 0;\n z-index: 1000;\n min-width: 180px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.4);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n font-size: 12px;\n `;\n\n const items: { label: string; intent: OrderPlaceIntent }[] = [\n { label: `Buy Limit @ ${priceStr}`, intent: { side: 'buy', type: 'limit', price } },\n { label: `Sell Limit @ ${priceStr}`, intent: { side: 'sell', type: 'limit', price } },\n { label: `Buy Stop @ ${priceStr}`, intent: { side: 'buy', type: 'stop', price } },\n { label: `Sell Stop @ ${priceStr}`, intent: { side: 'sell', type: 'stop', price } },\n ];\n\n for (const item of items) {\n const el = document.createElement('div');\n const isBuy = item.intent.side === 'buy';\n el.textContent = item.label;\n el.style.cssText = `\n padding: 6px 12px;\n cursor: pointer;\n color: ${isBuy ? '#26A69A' : '#EF5350'};\n transition: background 0.1s;\n `;\n el.addEventListener('mouseenter', () => { el.style.background = '#2a2e39'; });\n el.addEventListener('mouseleave', () => { el.style.background = 'transparent'; });\n el.addEventListener('click', () => {\n this.onItemSelect?.(item.intent);\n this.hide();\n });\n menu.appendChild(el);\n }\n\n container.appendChild(menu);\n this.menuElement = menu;\n\n // Close on outside click or Escape\n const closeHandler = (e: Event) => {\n if (e instanceof KeyboardEvent && e.key === 'Escape') {\n this.hide();\n } else if (e instanceof MouseEvent && !menu.contains(e.target as Node)) {\n this.hide();\n }\n };\n document.addEventListener('mousedown', closeHandler);\n document.addEventListener('keydown', closeHandler);\n this.removeHandler = () => {\n document.removeEventListener('mousedown', closeHandler);\n document.removeEventListener('keydown', closeHandler);\n };\n }\n\n hide(): void {\n this.menuElement?.remove();\n this.menuElement = null;\n this.removeHandler?.();\n this.removeHandler = null;\n }\n\n destroy(): void {\n this.hide();\n this.onItemSelect = null;\n }\n}\n","import type {\n TradingOrder,\n TradingPosition,\n DepthData,\n TradingConfig,\n ViewportState,\n Theme,\n Point,\n} from '@tradecanvas/commons';\nimport { DEFAULT_TRADING_CONFIG } from '@tradecanvas/commons';\nimport { yToPrice } from '../viewport/ScaleMapping.js';\nimport { OrderRenderer } from './OrderRenderer.js';\nimport { PositionRenderer } from './PositionRenderer.js';\nimport { DepthOverlay } from './DepthOverlay.js';\nimport { TradingDragHandler } from './TradingDragHandler.js';\nimport { TradingContextMenu } from './TradingContextMenu.js';\n\nexport class TradingManager {\n private orders: TradingOrder[] = [];\n private positions: TradingPosition[] = [];\n private depthData: DepthData | null = null;\n private currentPrice: number | null = null;\n private config: TradingConfig;\n\n private orderRenderer = new OrderRenderer();\n private positionRenderer = new PositionRenderer();\n private depthOverlay = new DepthOverlay();\n private dragHandler: TradingDragHandler;\n private contextMenu = new TradingContextMenu();\n\n private requestRender: (() => void) | null = null;\n private eventCallback: ((event: string, data: unknown) => void) | null = null;\n private container: HTMLElement | null = null;\n\n constructor(config?: Partial<TradingConfig>) {\n this.config = { ...DEFAULT_TRADING_CONFIG, ...config };\n this.dragHandler = new TradingDragHandler(this.config.dragThreshold);\n\n this.contextMenu.onItemSelect = (intent) => {\n this.eventCallback?.('orderPlace', intent);\n };\n }\n\n setContainer(container: HTMLElement): void {\n this.container = container;\n }\n\n setRequestRender(cb: () => void): void {\n this.requestRender = cb;\n }\n\n setEventCallback(cb: (event: string, data: unknown) => void): void {\n this.eventCallback = cb;\n }\n\n // --- State ---\n\n setOrders(orders: TradingOrder[]): void {\n this.orders = orders;\n this.requestRender?.();\n }\n\n setPositions(positions: TradingPosition[]): void {\n this.positions = positions;\n this.requestRender?.();\n }\n\n setDepthData(depth: DepthData | null): void {\n this.depthData = depth;\n this.requestRender?.();\n }\n\n setCurrentPrice(price: number): void {\n this.currentPrice = price;\n this.requestRender?.();\n }\n\n setConfig(config: Partial<TradingConfig>): void {\n Object.assign(this.config, config);\n this.requestRender?.();\n }\n\n // --- Pointer events ---\n\n onPointerDown(pos: Point, viewport: ViewportState): boolean {\n if (!this.config.enabled) return false;\n return this.dragHandler.onPointerDown(pos, this.orders, this.positions, viewport, 8);\n }\n\n onPointerMove(pos: Point, viewport: ViewportState): boolean {\n if (!this.dragHandler.isActive()) return false;\n const consumed = this.dragHandler.onPointerMove(pos, viewport);\n if (consumed) this.requestRender?.();\n return consumed;\n }\n\n onPointerUp(): boolean {\n const result = this.dragHandler.onPointerUp();\n if (result) {\n if (result.sourceType === 'order') {\n this.eventCallback?.('orderModify', {\n orderId: result.id,\n newPrice: result.newPrice,\n previousPrice: result.previousPrice,\n });\n } else {\n this.eventCallback?.('positionModify', {\n positionId: result.id,\n [result.sourceType]: result.newPrice,\n });\n }\n this.requestRender?.();\n return true;\n }\n return false;\n }\n\n onContextMenu(pos: Point, viewport: ViewportState): boolean {\n if (!this.config.enabled || !this.config.contextMenu?.enabled || !this.container) return false;\n const price = yToPrice(pos.y, viewport);\n this.contextMenu.show(pos, price, this.container, this.config);\n return true;\n }\n\n // --- Render ---\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n if (!this.config.enabled) return;\n\n // Depth overlay (back)\n if (this.depthData) {\n this.depthOverlay.render(ctx, this.depthData, viewport, this.config);\n }\n\n // Positions (middle)\n if (this.positions.length > 0) {\n this.positionRenderer.render(ctx, this.positions, this.currentPrice, viewport, theme, this.config);\n }\n\n // Orders (front)\n if (this.orders.length > 0) {\n this.orderRenderer.render(ctx, this.orders, viewport, theme, this.config, this.dragHandler.getDragState());\n }\n }\n\n /**\n * Draw position/order price badges on the price axis. Intended for the\n * UI layer so they paint ON TOP of the regular axis labels.\n */\n renderAxisBadges(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n if (!this.config.enabled) return;\n if (this.positions.length > 0) {\n this.positionRenderer.renderAxisBadges(ctx, this.positions, viewport, theme, this.config);\n }\n if (this.orders.length > 0) {\n this.orderRenderer.renderAxisBadges(ctx, this.orders, viewport, theme, this.config, this.dragHandler.getDragState());\n }\n }\n\n destroy(): void {\n this.contextMenu.destroy();\n }\n}\n","import type { ViewportState, Theme } from '@tradecanvas/commons';\nimport type { TradingManager } from './TradingManager.js';\n\nexport class TradingRenderer {\n constructor(private manager: TradingManager) {}\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n this.manager.render(ctx, viewport, theme);\n }\n\n /**\n * Draw position/order price badges on the price axis. Call this from the\n * UI layer AFTER priceAxis.render() so the badges paint on top of the\n * regular tick labels — matching MT4/MT5 behaviour.\n */\n renderAxisBadges(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n this.manager.renderAxisBadges(ctx, viewport, theme);\n }\n}\n","/**\n * Typed event emitter. Foundation for adapters and stream manager.\n * Keeps listeners in insertion order, supports once() for one-shot listeners.\n */\nexport class Emitter<EventMap extends Record<string, unknown>> {\n private listeners = new Map<keyof EventMap, Set<(data: any) => void>>();\n\n on<K extends keyof EventMap>(event: K, listener: (data: EventMap[K]) => void): () => void {\n let set = this.listeners.get(event);\n if (!set) {\n set = new Set();\n this.listeners.set(event, set);\n }\n set.add(listener);\n return () => set!.delete(listener);\n }\n\n once<K extends keyof EventMap>(event: K, listener: (data: EventMap[K]) => void): () => void {\n const wrapper = (data: EventMap[K]) => {\n unsub();\n listener(data);\n };\n const unsub = this.on(event, wrapper);\n return unsub;\n }\n\n off<K extends keyof EventMap>(event: K, listener: (data: EventMap[K]) => void): void {\n this.listeners.get(event)?.delete(listener);\n }\n\n protected emit<K extends keyof EventMap>(event: K, data: EventMap[K]): void {\n const set = this.listeners.get(event);\n if (set) {\n for (const listener of set) {\n listener(data);\n }\n }\n }\n\n removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","import type { OHLCBar, TimeFrame, RawTick, AggregatedBar } from '@tradecanvas/commons';\nimport { timeframeToMs } from '@tradecanvas/commons';\nimport { Emitter } from './Emitter.js';\n\ninterface AggregatorEvents {\n bar: AggregatedBar; // bar updated (forming)\n barClose: AggregatedBar; // bar closed (finalized)\n [key: string]: unknown;\n}\n\n/**\n * Aggregates raw ticks into OHLCV bars aligned to timeframe boundaries.\n *\n * Handles:\n * - Tick-to-bar conversion with proper timeframe alignment\n * - Bar close detection (when time crosses boundary)\n * - Volume accumulation\n * - Tick counting\n *\n * Note: Emitted bars are references to internal state.\n * Listeners MUST NOT mutate them — treat as readonly.\n */\nexport class TickAggregator extends Emitter<AggregatorEvents> {\n private currentBar: AggregatedBar | null = null;\n private timeframeMs: number;\n\n // Ring buffer for tick storage — O(1) push and eviction\n private tickRing: RawTick[];\n private ringHead = 0;\n private ringCount = 0;\n private readonly ringCapacity: number;\n\n constructor(\n _timeframe: TimeFrame,\n bufferSize = 1000,\n ) {\n super();\n this.timeframeMs = timeframeToMs(_timeframe);\n this.ringCapacity = bufferSize;\n this.tickRing = new Array<RawTick>(bufferSize);\n }\n\n setTimeframe(tf: TimeFrame): void {\n this.timeframeMs = timeframeToMs(tf);\n this.currentBar = null;\n this.ringHead = 0;\n this.ringCount = 0;\n }\n\n processTick(tick: RawTick): void {\n // Ring buffer push — O(1)\n const writeIdx = (this.ringHead + this.ringCount) % this.ringCapacity;\n this.tickRing[writeIdx] = tick;\n if (this.ringCount < this.ringCapacity) {\n this.ringCount++;\n } else {\n // Buffer full — advance head, dropping oldest tick\n this.ringHead = (this.ringHead + 1) % this.ringCapacity;\n }\n\n const barTime = this.alignToTimeframe(tick.time);\n\n if (!this.currentBar || this.currentBar.time !== barTime) {\n // Close previous bar\n if (this.currentBar) {\n this.currentBar.closed = true;\n this.emit('barClose', this.currentBar);\n }\n\n // Start new bar\n this.currentBar = {\n time: barTime,\n open: tick.price,\n high: tick.price,\n low: tick.price,\n close: tick.price,\n volume: tick.volume,\n closed: false,\n tickCount: 1,\n };\n } else {\n // Update current bar\n this.currentBar.high = Math.max(this.currentBar.high, tick.price);\n this.currentBar.low = Math.min(this.currentBar.low, tick.price);\n this.currentBar.close = tick.price;\n this.currentBar.volume += tick.volume;\n this.currentBar.tickCount++;\n }\n\n this.emit('bar', this.currentBar);\n }\n\n /**\n * Process a pre-formed bar (from adapter that already provides OHLCV).\n * Detects close by checking if this bar's time differs from current.\n */\n processBar(bar: OHLCBar, closed: boolean): void {\n if (closed && this.currentBar && this.currentBar.time === bar.time) {\n // Close the bar\n this.currentBar = { ...bar, closed: true, tickCount: this.currentBar.tickCount + 1 };\n this.emit('barClose', this.currentBar);\n this.currentBar = null;\n } else if (!closed) {\n // Update forming bar\n this.currentBar = { ...bar, closed: false, tickCount: (this.currentBar?.tickCount ?? 0) + 1 };\n this.emit('bar', this.currentBar);\n } else {\n // New closed bar without a forming bar preceding it\n const aggBar: AggregatedBar = { ...bar, closed: true, tickCount: 1 };\n this.emit('barClose', aggBar);\n this.currentBar = null;\n }\n }\n\n getCurrentBar(): AggregatedBar | null {\n return this.currentBar ? { ...this.currentBar } : null;\n }\n\n getTickBuffer(): readonly RawTick[] {\n // Materialize ring into ordered array for external consumers\n const result: RawTick[] = new Array(this.ringCount);\n for (let i = 0; i < this.ringCount; i++) {\n result[i] = this.tickRing[(this.ringHead + i) % this.ringCapacity];\n }\n return result;\n }\n\n reset(): void {\n this.currentBar = null;\n this.ringHead = 0;\n this.ringCount = 0;\n }\n\n private alignToTimeframe(timestamp: number): number {\n return Math.floor(timestamp / this.timeframeMs) * this.timeframeMs;\n }\n}\n","import type { ReconnectConfig } from '@tradecanvas/commons';\nimport { DEFAULT_RECONNECT } from '@tradecanvas/commons';\nimport { Emitter } from './Emitter.js';\n\ninterface ReconnectEvents {\n attempt: { attempt: number; delay: number };\n success: void;\n giveUp: { attempts: number };\n [key: string]: unknown;\n}\n\n/**\n * Exponential backoff reconnection manager.\n *\n * Features:\n * - Exponential backoff with jitter\n * - Configurable max retries and max delay\n * - Reset on successful connection\n * - Cancellable pending reconnection\n */\nexport class ReconnectManager extends Emitter<ReconnectEvents> {\n private config: ReconnectConfig;\n private attempt = 0;\n private timer: ReturnType<typeof setTimeout> | null = null;\n private active = false;\n\n constructor(config?: Partial<ReconnectConfig>) {\n super();\n this.config = { ...DEFAULT_RECONNECT, ...config };\n }\n\n schedule(connectFn: () => void): void {\n if (!this.config.enabled || !this.active) return;\n\n this.attempt++;\n\n if (this.attempt > this.config.maxRetries) {\n this.emit('giveUp', { attempts: this.attempt - 1 });\n this.active = false;\n return;\n }\n\n const delay = this.computeDelay();\n this.emit('attempt', { attempt: this.attempt, delay });\n\n this.timer = setTimeout(() => {\n this.timer = null;\n if (this.active) connectFn();\n }, delay);\n }\n\n onConnected(): void {\n this.attempt = 0;\n this.cancel();\n this.emit('success', undefined as any);\n }\n\n start(): void {\n this.active = true;\n }\n\n stop(): void {\n this.active = false;\n this.cancel();\n this.attempt = 0;\n }\n\n cancel(): void {\n if (this.timer) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n }\n\n getAttempt(): number {\n return this.attempt;\n }\n\n isActive(): boolean {\n return this.active;\n }\n\n private computeDelay(): number {\n const base = this.config.baseDelay;\n const mult = Math.pow(this.config.backoffMultiplier, this.attempt - 1);\n const delay = Math.min(base * mult, this.config.maxDelay);\n // Add jitter (±25%)\n const jitter = delay * 0.25 * (Math.random() * 2 - 1);\n return Math.max(0, Math.round(delay + jitter));\n }\n}\n","import type { ViewportState, Theme } from '@tradecanvas/commons';\nimport { priceToY } from '../viewport/ScaleMapping.js';\nimport { PRICE_AXIS_WIDTH } from '@tradecanvas/commons';\n\n/**\n * Renders the current (last) price as a horizontal line with a badge.\n * Updates at high frequency without triggering full chart redraws.\n */\nexport class CurrentPriceLine {\n private price: number | null = null;\n private previousClose: number | null = null;\n private visible = true;\n private flashUntil = 0;\n private pricePrecision = 2;\n\n setPrice(price: number, previousClose?: number): void {\n if (this.price !== null && price !== this.price) {\n this.flashUntil = Date.now() + 300;\n }\n this.previousClose = previousClose ?? this.price ?? price;\n this.price = price;\n }\n\n setVisible(v: boolean): void {\n this.visible = v;\n }\n\n setPricePrecision(precision: number): void {\n this.pricePrecision = precision;\n }\n\n getPrice(): number | null {\n return this.price;\n }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n if (!this.visible || this.price === null) return;\n\n const y = priceToY(this.price, viewport);\n const { chartRect } = viewport;\n\n if (y < chartRect.y || y > chartRect.y + chartRect.height) return;\n\n const isUp = this.previousClose !== null ? this.price >= this.previousClose : true;\n const color = isUp ? (theme.candleUp ?? '#26A69A') : (theme.candleDown ?? '#EF5350');\n const isFlashing = Date.now() < this.flashUntil;\n\n // Dashed price line\n ctx.setLineDash([4, 3]);\n ctx.strokeStyle = color;\n ctx.lineWidth = 1;\n ctx.globalAlpha = isFlashing ? 1 : 0.7;\n ctx.beginPath();\n ctx.moveTo(chartRect.x, Math.round(y) + 0.5);\n ctx.lineTo(chartRect.x + chartRect.width, Math.round(y) + 0.5);\n ctx.stroke();\n ctx.setLineDash([]);\n ctx.globalAlpha = 1;\n\n // Price badge on axis\n const axisX = chartRect.x + chartRect.width + 1;\n const text = this.price.toFixed(this.pricePrecision);\n ctx.font = `bold 11px ${theme.font.family}`;\n const textWidth = ctx.measureText(text).width;\n const badgeWidth = Math.min(textWidth + 12, PRICE_AXIS_WIDTH - 2);\n\n ctx.fillStyle = color;\n ctx.fillRect(axisX, y - 10, badgeWidth, 20);\n\n // Arrow indicator\n const arrowX = axisX - 5;\n ctx.beginPath();\n ctx.moveTo(arrowX, y);\n ctx.lineTo(arrowX + 5, y - 5);\n ctx.lineTo(arrowX + 5, y + 5);\n ctx.closePath();\n ctx.fill();\n\n ctx.fillStyle = '#FFFFFF';\n ctx.textBaseline = 'middle';\n ctx.textAlign = 'left';\n ctx.fillText(text, axisX + 5, y);\n }\n}\n","import type {\n StreamConfig,\n ConnectionState,\n ConnectionInfo,\n DataAdapter,\n OHLCBar,\n RawTick,\n AggregatedBar,\n TimeFrame,\n} from '@tradecanvas/commons';\nimport { DEFAULT_STREAM_CONFIG, DEFAULT_RECONNECT } from '@tradecanvas/commons';\nimport { Emitter } from './Emitter.js';\nimport { TickAggregator } from './TickAggregator.js';\nimport { ReconnectManager } from './ReconnectManager.js';\nimport { CurrentPriceLine } from './CurrentPriceLine.js';\n\nexport interface StreamEvents {\n /** Historical data loaded */\n snapshot: OHLCBar[];\n /** New closed bar appended */\n barClose: AggregatedBar;\n /** Current forming bar updated */\n barUpdate: AggregatedBar;\n /** Raw tick received */\n tick: RawTick;\n /** Current price changed */\n priceChange: { price: number; previousClose: number | null };\n /** Connection state changed */\n connectionChange: ConnectionInfo;\n /** Error occurred */\n error: { message: string; code?: string };\n [key: string]: unknown;\n}\n\n/**\n * StreamManager — orchestrates data flow from adapter to chart.\n *\n * Responsibilities:\n * 1. Manages adapter lifecycle (connect, disconnect, reconnect)\n * 2. Loads historical data on connect\n * 3. Routes incoming data through TickAggregator\n * 4. Maintains current price for the price line\n * 5. Provides clean event interface for the Chart class\n *\n * Usage:\n * const stream = new StreamManager();\n * stream.on('snapshot', (bars) => chart.setData(bars));\n * stream.on('barClose', (bar) => chart.appendBar(bar));\n * stream.on('barUpdate', (bar) => chart.updateLastBar(bar));\n * stream.connect({ adapter, symbol: 'BTCUSDT', timeframe: '1m' });\n */\nexport class StreamManager extends Emitter<StreamEvents> {\n private config: StreamConfig | null = null;\n private adapter: DataAdapter | null = null;\n private aggregator: TickAggregator | null = null;\n private reconnector: ReconnectManager;\n readonly priceLine = new CurrentPriceLine();\n\n private state: ConnectionState = 'disconnected';\n private lastPrice: number | null = null;\n private previousClose: number | null = null;\n private unsubscribers: (() => void)[] = [];\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private lastMessageTime = 0;\n\n constructor() {\n super();\n this.reconnector = new ReconnectManager();\n this.wireReconnector();\n }\n\n // --- Public API ---\n\n async connect(config: StreamConfig): Promise<void> {\n // Clean up previous connection\n this.disconnect();\n\n this.config = { ...DEFAULT_STREAM_CONFIG, ...config } as StreamConfig;\n this.adapter = config.adapter;\n this.aggregator = new TickAggregator(config.timeframe);\n\n // Replace reconnector — clean up old listeners first\n this.reconnector.removeAllListeners();\n this.reconnector.stop();\n this.reconnector = new ReconnectManager(config.reconnect ?? DEFAULT_RECONNECT);\n this.wireReconnector();\n\n // Wire aggregator events -> stream events\n this.aggregator.on('bar', (bar) => {\n this.emit('barUpdate', bar);\n this.updatePrice(bar.close);\n });\n this.aggregator.on('barClose', (bar) => {\n this.previousClose = bar.close;\n this.emit('barClose', bar);\n });\n\n // Wire adapter events\n this.wireAdapter();\n\n // Start connection\n this.reconnector.start();\n await this.doConnect();\n }\n\n disconnect(): void {\n this.reconnector.stop();\n this.stopHeartbeat();\n\n for (const unsub of this.unsubscribers) unsub();\n this.unsubscribers = [];\n\n if (this.adapter) {\n this.adapter.disconnect();\n this.adapter = null;\n }\n\n this.aggregator?.reset();\n this.aggregator?.removeAllListeners();\n this.aggregator = null;\n this.config = null;\n this.lastPrice = null;\n this.previousClose = null;\n\n this.setState('disconnected');\n }\n\n /**\n * Switch symbol or timeframe without full teardown.\n * Reloads history and restarts streaming.\n */\n async switchTo(symbol: string, timeframe: TimeFrame): Promise<void> {\n if (!this.config || !this.adapter) return;\n\n this.adapter.disconnect();\n this.aggregator?.reset();\n this.aggregator?.setTimeframe(timeframe);\n this.lastPrice = null;\n this.previousClose = null;\n\n this.config.symbol = symbol;\n this.config.timeframe = timeframe;\n\n await this.doConnect();\n }\n\n getConnectionState(): ConnectionState {\n return this.state;\n }\n\n getConnectionInfo(): ConnectionInfo {\n return {\n state: this.state,\n reconnectAttempt: this.reconnector.getAttempt(),\n lastMessageTime: this.lastMessageTime,\n };\n }\n\n getLastPrice(): number | null {\n return this.lastPrice;\n }\n\n // --- Internal ---\n\n private async doConnect(): Promise<void> {\n if (!this.config || !this.adapter) return;\n\n this.setState('connecting');\n\n try {\n // 1. Load historical data\n const history = await this.adapter.fetchHistory(\n this.config.symbol,\n this.config.timeframe,\n this.config.historyLimit ?? 500,\n );\n\n if (history.length > 0) {\n this.previousClose = history[history.length - 1].close;\n this.updatePrice(history[history.length - 1].close);\n }\n\n this.emit('snapshot', history);\n\n // 2. Start streaming\n this.adapter.connect({\n symbol: this.config.symbol,\n timeframe: this.config.timeframe,\n });\n\n this.startHeartbeat();\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n this.emit('error', { message, code: 'CONNECT_FAILED' });\n this.setState('error');\n this.reconnector.schedule(() => this.doConnect());\n }\n }\n\n private wireReconnector(): void {\n this.reconnector.on('attempt', ({ attempt, delay: _delay }) => {\n this.setState('reconnecting');\n this.emit('connectionChange', {\n state: 'reconnecting',\n reconnectAttempt: attempt,\n lastMessageTime: this.lastMessageTime,\n });\n });\n this.reconnector.on('giveUp', ({ attempts }) => {\n this.setState('error');\n this.emit('error', { message: `Reconnection failed after ${attempts} attempts`, code: 'RECONNECT_EXHAUSTED' });\n });\n }\n\n private wireAdapter(): void {\n if (!this.adapter) return;\n const adapter = this.adapter;\n\n // Connection state changes\n const onConnectionChange = (e: any) => {\n const newState = e.data as ConnectionState;\n this.lastMessageTime = Date.now();\n\n if (newState === 'connected') {\n this.reconnector.onConnected();\n this.setState('connected');\n } else if (newState === 'disconnected' || newState === 'error') {\n this.reconnector.schedule(() => this.doConnect());\n }\n };\n adapter.on('connectionChange', onConnectionChange as any);\n this.unsubscribers.push(() => adapter.off('connectionChange', onConnectionChange as any));\n\n // Tick data\n const onTick = (e: any) => {\n this.lastMessageTime = Date.now();\n const tick = e.data as RawTick;\n this.emit('tick', tick);\n\n if (this.config?.aggregateTicks && this.aggregator) {\n this.aggregator.processTick(tick);\n } else {\n this.updatePrice(tick.price);\n }\n };\n adapter.on('tick', onTick as any);\n this.unsubscribers.push(() => adapter.off('tick', onTick as any));\n\n // Pre-formed bar data (most adapters provide this)\n const onBar = (e: any) => {\n this.lastMessageTime = Date.now();\n const { bar, closed } = e.data as { bar: OHLCBar; closed: boolean };\n\n if (this.aggregator) {\n this.aggregator.processBar(bar, closed);\n }\n };\n adapter.on('bar', onBar as any);\n this.unsubscribers.push(() => adapter.off('bar', onBar as any));\n\n // Error\n const onError = (e: any) => {\n this.emit('error', { message: e.data?.message ?? 'Adapter error' });\n };\n adapter.on('error', onError as any);\n this.unsubscribers.push(() => adapter.off('error', onError as any));\n }\n\n private updatePrice(price: number): void {\n if (price !== this.lastPrice) {\n this.lastPrice = price;\n this.priceLine.setPrice(price, this.previousClose ?? undefined);\n this.emit('priceChange', { price, previousClose: this.previousClose });\n }\n }\n\n private setState(state: ConnectionState): void {\n if (this.state === state) return;\n this.state = state;\n this.emit('connectionChange', {\n state,\n reconnectAttempt: this.reconnector.getAttempt(),\n lastMessageTime: this.lastMessageTime,\n });\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat();\n this.heartbeatTimer = setInterval(() => {\n const stale = Date.now() - this.lastMessageTime > 60000;\n if (stale && this.state === 'connected') {\n this.emit('error', { message: 'Heartbeat timeout', code: 'HEARTBEAT_TIMEOUT' });\n this.adapter?.disconnect();\n this.reconnector.schedule(() => this.doConnect());\n }\n }, 30000);\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n dispose(): void {\n this.disconnect();\n this.removeAllListeners();\n }\n}\n","import type { OHLCBar, DataSeries } from '@tradecanvas/commons';\nimport { Emitter } from './Emitter.js';\n\nexport type ReplayStatus = 'idle' | 'playing' | 'paused' | 'finished';\n\nexport interface ReplayBarEvent {\n bar: OHLCBar;\n index: number;\n total: number;\n}\n\nexport interface ReplayStateChangeEvent {\n status: ReplayStatus;\n index: number;\n total: number;\n}\n\nexport interface ReplayEventMap {\n bar: ReplayBarEvent;\n finished: { total: number };\n stateChange: ReplayStateChangeEvent;\n [key: string]: unknown;\n}\n\nexport interface ReplayOptions {\n /** Full historical dataset to replay through. */\n data: DataSeries;\n /** Bars emitted per second. Default 1. */\n speed?: number;\n /** Index of the first bar to emit (0-based). Default 0. */\n startIndex?: number;\n /** Auto-start when constructed. Default false. */\n autoStart?: boolean;\n}\n\n/**\n * Drives historical bars forward at a controlled speed.\n *\n * Decoupled from Chart — consumers subscribe to `bar` events and wire them\n * into a Chart (via appendBar) or a Backtester. The controller never touches\n * the chart directly, which keeps it reusable for headless analytics.\n */\nexport class ReplayController extends Emitter<ReplayEventMap> {\n private readonly data: ReadonlyArray<OHLCBar>;\n private speed: number;\n private index: number;\n private status: ReplayStatus = 'idle';\n private timer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(opts: ReplayOptions) {\n super();\n if (opts.data.length === 0) {\n throw new Error('ReplayController requires non-empty data');\n }\n this.data = opts.data;\n this.speed = Math.max(0.01, opts.speed ?? 1);\n this.index = Math.max(0, Math.min(opts.startIndex ?? 0, opts.data.length));\n\n if (opts.autoStart) this.start();\n }\n\n getStatus(): ReplayStatus {\n return this.status;\n }\n\n getIndex(): number {\n return this.index;\n }\n\n getTotal(): number {\n return this.data.length;\n }\n\n /** Bars at indices [0, index) — useful for seeding the chart before replay. */\n getPrefix(): DataSeries {\n return this.data.slice(0, this.index);\n }\n\n /** Begin emitting from current index. Idempotent if already playing. */\n start(): void {\n if (this.status === 'playing') return;\n if (this.index >= this.data.length) {\n this.transition('finished');\n return;\n }\n this.transition('playing');\n this.scheduleNext();\n }\n\n pause(): void {\n if (this.status !== 'playing') return;\n this.clearTimer();\n this.transition('paused');\n }\n\n resume(): void {\n if (this.status === 'paused') this.start();\n }\n\n stop(): void {\n this.clearTimer();\n this.index = 0;\n this.transition('idle');\n }\n\n /** Emit N bars synchronously without waiting for the timer. */\n step(n = 1): void {\n if (n <= 0) return;\n this.clearTimer();\n for (let i = 0; i < n; i++) {\n if (!this.emitNext()) return;\n }\n if (this.status !== 'finished') this.transition('paused');\n }\n\n /** Jump to a specific index without emitting bars in between. */\n seek(index: number): void {\n const clamped = Math.max(0, Math.min(index, this.data.length));\n this.clearTimer();\n this.index = clamped;\n const next: ReplayStatus = clamped >= this.data.length ? 'finished' : 'paused';\n this.transition(next);\n }\n\n setSpeed(barsPerSecond: number): void {\n this.speed = Math.max(0.01, barsPerSecond);\n if (this.status === 'playing') {\n this.clearTimer();\n this.scheduleNext();\n }\n }\n\n destroy(): void {\n this.clearTimer();\n this.removeAllListeners();\n }\n\n private scheduleNext(): void {\n const delayMs = 1000 / this.speed;\n this.timer = setTimeout(() => {\n this.timer = null;\n if (this.status !== 'playing') return;\n const more = this.emitNext();\n if (more) this.scheduleNext();\n }, delayMs);\n }\n\n private emitNext(): boolean {\n if (this.index >= this.data.length) {\n this.transition('finished');\n this.emit('finished', { total: this.data.length });\n return false;\n }\n const bar = this.data[this.index];\n const index = this.index;\n this.index++;\n this.emit('bar', { bar, index, total: this.data.length });\n if (this.index >= this.data.length) {\n this.transition('finished');\n this.emit('finished', { total: this.data.length });\n return false;\n }\n return true;\n }\n\n private clearTimer(): void {\n if (this.timer !== null) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n }\n\n private transition(next: ReplayStatus): void {\n if (this.status === next) return;\n this.status = next;\n this.emit('stateChange', {\n status: next,\n index: this.index,\n total: this.data.length,\n });\n }\n}\n","import type { OHLCBar } from '@tradecanvas/commons';\r\n\r\n/**\r\n * Binance REST `/klines` returns a 12-element array per kline.\r\n * Index map (per Binance docs):\r\n * 0 openTime, 1 open, 2 high, 3 low, 4 close, 5 volume,\r\n * 6 closeTime, 7 quoteVolume, 8 trades, 9 takerBuyBase,\r\n * 10 takerBuyQuote, 11 ignore\r\n * Numeric fields come back as strings except the timestamps.\r\n */\r\nexport type BinanceRestKline = readonly [\r\n number, // 0 openTime\r\n string, // 1 open\r\n string, // 2 high\r\n string, // 3 low\r\n string, // 4 close\r\n string, // 5 volume\r\n number, // 6 closeTime\r\n string, // 7 quoteVolume\r\n number, // 8 trades\r\n string, // 9 takerBuyBase\r\n string, // 10 takerBuyQuote\r\n string, // 11 ignore\r\n];\r\n\r\n/** Binance WS kline payload (`msg.k`). All numeric fields arrive as strings. */\r\nexport interface BinanceWsKline {\r\n t: number; // start time\r\n T: number; // close time\r\n s: string; // symbol\r\n i: string; // interval\r\n o: string; // open\r\n c: string; // close\r\n h: string; // high\r\n l: string; // low\r\n v: string; // base volume\r\n n: number; // trades\r\n x: boolean; // closed\r\n q?: string; // quote volume\r\n}\r\n\r\nexport interface BinanceWsMessage {\r\n e?: string; // event type\r\n E?: number; // event time\r\n s?: string;\r\n k?: BinanceWsKline;\r\n}\r\n\r\n/**\r\n * Validate and parse a single REST kline tuple. Returns `null` on shape mismatch\r\n * or non-finite numeric values. Pure — no fetch, no side effects — testable.\r\n */\r\nexport function parseRestKline(raw: unknown): OHLCBar | null {\r\n if (!Array.isArray(raw) || raw.length < 6) return null;\r\n const time = raw[0];\r\n if (typeof time !== 'number' || !Number.isFinite(time)) return null;\r\n\r\n const open = toFiniteNumber(raw[1]);\r\n const high = toFiniteNumber(raw[2]);\r\n const low = toFiniteNumber(raw[3]);\r\n const close = toFiniteNumber(raw[4]);\r\n const volume = toFiniteNumber(raw[5]);\r\n if (open === null || high === null || low === null || close === null || volume === null) {\r\n return null;\r\n }\r\n return { time, open, high, low, close, volume };\r\n}\r\n\r\n/**\r\n * Validate and parse the `k` payload of a WS kline message.\r\n * Returns `{ bar, closed }` or `null` if the payload is malformed.\r\n */\r\nexport function parseWsKline(\r\n raw: unknown,\r\n): { bar: OHLCBar; closed: boolean } | null {\r\n if (!isObject(raw)) return null;\r\n const time = raw.t;\r\n if (typeof time !== 'number' || !Number.isFinite(time)) return null;\r\n\r\n const open = toFiniteNumber(raw.o);\r\n const high = toFiniteNumber(raw.h);\r\n const low = toFiniteNumber(raw.l);\r\n const close = toFiniteNumber(raw.c);\r\n const volume = toFiniteNumber(raw.v);\r\n if (open === null || high === null || low === null || close === null || volume === null) {\r\n return null;\r\n }\r\n const closed = typeof raw.x === 'boolean' ? raw.x : false;\r\n return { bar: { time, open, high, low, close, volume }, closed };\r\n}\r\n\r\nfunction toFiniteNumber(value: unknown): number | null {\r\n if (typeof value === 'number') {\r\n return Number.isFinite(value) ? value : null;\r\n }\r\n if (typeof value === 'string') {\r\n const n = parseFloat(value);\r\n return Number.isFinite(n) ? n : null;\r\n }\r\n return null;\r\n}\r\n\r\nfunction isObject(value: unknown): value is Record<string, unknown> {\r\n return typeof value === 'object' && value !== null;\r\n}\r\n","import type {\r\n DataAdapter,\r\n DataAdapterConfig,\r\n DataAdapterEventType,\r\n DataAdapterListener,\r\n ConnectionState,\r\n OHLCBar,\r\n TimeFrame,\r\n} from '@tradecanvas/commons';\r\nimport { parseRestKline, parseWsKline } from './binanceTypes.js';\r\n\r\nconst TF_MAP: Record<string, string> = {\r\n '1s': '1s', '1m': '1m', '3m': '3m', '5m': '5m', '15m': '15m', '30m': '30m',\r\n '1h': '1h', '2h': '2h', '4h': '4h', '6h': '6h', '8h': '8h', '12h': '12h',\r\n '1d': '1d', '3d': '3d', '1w': '1w', '1M': '1M',\r\n};\r\n\r\n/**\r\n * Binance public API adapter (no API key required).\r\n *\r\n * Supports:\r\n * - REST klines for historical data\r\n * - WebSocket kline stream for real-time data\r\n * - Auto-reconnection via the StreamManager\r\n *\r\n * Usage:\r\n * const adapter = new BinanceAdapter();\r\n * const stream = new StreamManager();\r\n * stream.connect({ adapter, symbol: 'BTCUSDT', timeframe: '1m' });\r\n */\r\nexport class BinanceAdapter implements DataAdapter {\r\n readonly name = 'binance';\r\n\r\n private ws: WebSocket | null = null;\r\n private state: ConnectionState = 'disconnected';\r\n private listeners = new Map<DataAdapterEventType, Set<DataAdapterListener>>();\r\n private config: DataAdapterConfig | null = null;\r\n private restBase: string;\r\n private wsBase: string;\r\n\r\n constructor(options?: { restBase?: string; wsBase?: string }) {\r\n this.restBase = options?.restBase ?? 'https://api.binance.com/api/v3';\r\n this.wsBase = options?.wsBase ?? 'wss://stream.binance.com:9443/ws';\r\n }\r\n\r\n // --- DataAdapter interface ---\r\n\r\n connect(config: DataAdapterConfig): void {\r\n this.config = config;\r\n this.connectWs();\r\n }\r\n\r\n disconnect(): void {\r\n if (this.ws) {\r\n this.ws.onclose = null; // prevent reconnect trigger\r\n this.ws.close();\r\n this.ws = null;\r\n }\r\n this.setState('disconnected');\r\n }\r\n\r\n getConnectionState(): ConnectionState {\r\n return this.state;\r\n }\r\n\r\n async fetchHistory(symbol: string, timeframe: TimeFrame, limit = 500): Promise<OHLCBar[]> {\r\n const interval = TF_MAP[timeframe] ?? '15m';\r\n const url = `${this.restBase}/klines?symbol=${symbol}&interval=${interval}&limit=${limit}`;\r\n const res = await fetch(url);\r\n\r\n if (!res.ok) throw new Error(`Binance REST error: ${res.status}`);\r\n\r\n const data: unknown = await res.json();\r\n if (!Array.isArray(data)) return [];\r\n const bars: OHLCBar[] = [];\r\n for (const raw of data) {\r\n const parsed = parseRestKline(raw);\r\n if (parsed) bars.push(parsed);\r\n }\r\n return bars;\r\n }\r\n\r\n on<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void {\r\n let set = this.listeners.get(event);\r\n if (!set) {\r\n set = new Set();\r\n this.listeners.set(event, set);\r\n }\r\n set.add(listener as DataAdapterListener);\r\n }\r\n\r\n off<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void {\r\n this.listeners.get(event)?.delete(listener as DataAdapterListener);\r\n }\r\n\r\n dispose(): void {\r\n this.disconnect();\r\n this.listeners.clear();\r\n }\r\n\r\n // --- Internal ---\r\n\r\n private connectWs(): void {\r\n if (!this.config) return;\r\n\r\n const symbol = this.config.symbol.toLowerCase();\r\n const interval = TF_MAP[this.config.timeframe] ?? '15m';\r\n const stream = `${symbol}@kline_${interval}`;\r\n const url = `${this.wsBase}/${stream}`;\r\n\r\n this.setState('connecting');\r\n\r\n try {\r\n this.ws = new WebSocket(url);\r\n } catch {\r\n this.setState('error');\r\n this.emitEvent('error', { message: 'WebSocket creation failed' });\r\n this.emitEvent('connectionChange', 'error');\r\n return;\r\n }\r\n\r\n this.ws.onopen = () => {\r\n this.setState('connected');\r\n this.emitEvent('connectionChange', 'connected');\r\n };\r\n\r\n this.ws.onmessage = (event) => {\r\n let msg: unknown;\r\n try {\r\n msg = JSON.parse(typeof event.data === 'string' ? event.data : '');\r\n } catch {\r\n return;\r\n }\r\n if (\r\n typeof msg === 'object' &&\r\n msg !== null &&\r\n (msg as { e?: unknown }).e === 'kline'\r\n ) {\r\n this.handleKline((msg as { k?: unknown }).k);\r\n }\r\n };\r\n\r\n this.ws.onerror = () => {\r\n this.setState('error');\r\n this.emitEvent('error', { message: 'WebSocket error' });\r\n };\r\n\r\n this.ws.onclose = () => {\r\n this.setState('disconnected');\r\n this.emitEvent('connectionChange', 'disconnected');\r\n };\r\n }\r\n\r\n private handleKline(k: unknown): void {\r\n const parsed = parseWsKline(k);\r\n if (!parsed) return;\r\n const { bar, closed } = parsed;\r\n\r\n this.emitEvent('bar', { bar, closed });\r\n this.emitEvent('tick', {\r\n time: Date.now(),\r\n price: bar.close,\r\n volume: bar.volume,\r\n });\r\n }\r\n\r\n private setState(state: ConnectionState): void {\r\n this.state = state;\r\n }\r\n\r\n private emitEvent(type: DataAdapterEventType, data: unknown): void {\r\n const set = this.listeners.get(type);\r\n if (set) {\r\n const event = { type, data, timestamp: Date.now() };\r\n for (const listener of set) {\r\n listener(event);\r\n }\r\n }\r\n }\r\n}\r\n","import type {\n DataAdapter,\n DataAdapterConfig,\n DataAdapterEventType,\n DataAdapterListener,\n ConnectionState,\n OHLCBar,\n TimeFrame,\n} from '@tradecanvas/commons';\nimport { timeframeToMs } from '@tradecanvas/commons';\n\nexport interface MockAdapterOptions {\n /** Base price to generate data around */\n basePrice?: number;\n /** Volatility as percentage (default: 1.5) */\n volatility?: number;\n /** Tick interval in ms (default: 2000) */\n tickInterval?: number;\n /** Number of historical bars to generate */\n historySize?: number;\n /** Custom history generator */\n historyGenerator?: (symbol: string, timeframe: TimeFrame, limit: number) => OHLCBar[];\n}\n\n/**\n * Mock data adapter for testing, demos, and markets without free APIs.\n *\n * Generates realistic OHLCV data with configurable volatility.\n * Useful for:\n * - Unit/integration testing\n * - VN stock market simulation\n * - Offline development\n */\nexport class MockAdapter implements DataAdapter {\n readonly name = 'mock';\n\n private state: ConnectionState = 'disconnected';\n private listeners = new Map<DataAdapterEventType, Set<DataAdapterListener>>();\n private config: DataAdapterConfig | null = null;\n private options: MockAdapterOptions;\n private tickTimer: ReturnType<typeof setInterval> | null = null;\n private currentPrice: number;\n\n constructor(options?: MockAdapterOptions) {\n this.options = {\n basePrice: 100,\n volatility: 1.5,\n tickInterval: 2000,\n historySize: 500,\n ...options,\n };\n this.currentPrice = this.options.basePrice!;\n }\n\n connect(config: DataAdapterConfig): void {\n this.config = config;\n this.state = 'connected';\n this.emitEvent('connectionChange', 'connected');\n this.startTicking();\n }\n\n disconnect(): void {\n this.stopTicking();\n this.state = 'disconnected';\n this.emitEvent('connectionChange', 'disconnected');\n }\n\n getConnectionState(): ConnectionState {\n return this.state;\n }\n\n async fetchHistory(symbol: string, timeframe: TimeFrame, limit?: number): Promise<OHLCBar[]> {\n if (this.options.historyGenerator) {\n return this.options.historyGenerator(symbol, timeframe, limit ?? this.options.historySize!);\n }\n return this.generateHistory(timeframe, limit ?? this.options.historySize!);\n }\n\n on<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void {\n let set = this.listeners.get(event);\n if (!set) { set = new Set(); this.listeners.set(event, set); }\n set.add(listener as DataAdapterListener);\n }\n\n off<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void {\n this.listeners.get(event)?.delete(listener as DataAdapterListener);\n }\n\n dispose(): void {\n this.disconnect();\n this.listeners.clear();\n }\n\n // --- Internal ---\n\n private generateHistory(timeframe: TimeFrame, count: number): OHLCBar[] {\n const bars: OHLCBar[] = [];\n const now = Date.now();\n const intervalMs = timeframeToMs(timeframe);\n let price = this.options.basePrice!;\n const vol = this.options.volatility! / 100;\n\n for (let i = count - 1; i >= 0; i--) {\n const time = now - i * intervalMs;\n const change = (Math.random() - 0.48) * price * vol;\n const open = price;\n price += change;\n const high = Math.max(open, price) + Math.random() * price * vol * 0.3;\n const low = Math.min(open, price) - Math.random() * price * vol * 0.3;\n const volume = Math.floor(10000 + Math.random() * 100000);\n bars.push({ time, open, high, low, close: price, volume });\n }\n\n this.currentPrice = price;\n return bars;\n }\n\n private startTicking(): void {\n this.stopTicking();\n const interval = this.options.tickInterval ?? 2000;\n\n this.tickTimer = setInterval(() => {\n if (this.state !== 'connected' || !this.config) return;\n\n const vol = this.options.volatility! / 100;\n const change = (Math.random() - 0.48) * this.currentPrice * vol * 0.3;\n this.currentPrice += change;\n\n const now = Date.now();\n const intervalMs = timeframeToMs(this.config.timeframe);\n const barTime = Math.floor(now / intervalMs) * intervalMs;\n\n const bar: OHLCBar = {\n time: barTime,\n open: this.currentPrice - change,\n high: Math.max(this.currentPrice, this.currentPrice - change) + Math.abs(change) * 0.2,\n low: Math.min(this.currentPrice, this.currentPrice - change) - Math.abs(change) * 0.2,\n close: this.currentPrice,\n volume: Math.floor(100 + Math.random() * 5000),\n };\n\n // Check if bar closed (crossed timeframe boundary)\n const closed = false; // In mock, we mostly send forming bars\n\n this.emitEvent('bar', { bar, closed });\n this.emitEvent('tick', { time: now, price: this.currentPrice, volume: bar.volume });\n }, interval);\n }\n\n private stopTicking(): void {\n if (this.tickTimer) {\n clearInterval(this.tickTimer);\n this.tickTimer = null;\n }\n }\n\n private emitEvent(type: DataAdapterEventType, data: unknown): void {\n const set = this.listeners.get(type);\n if (set) {\n const event = { type, data, timestamp: Date.now() };\n for (const listener of set) listener(event);\n }\n }\n}\n","import type { ViewportState, Theme, OHLCBar, DataSeries } from '@tradecanvas/commons';\n\nexport interface LegendConfig {\n visible: boolean;\n showSymbol: boolean;\n showOHLC: boolean;\n showChange: boolean;\n showVolume: boolean;\n position: 'top-left' | 'top-right';\n fontSize: number;\n}\n\nexport const DEFAULT_LEGEND_CONFIG: LegendConfig = {\n visible: true,\n showSymbol: true,\n showOHLC: true,\n showChange: true,\n showVolume: true,\n position: 'top-left',\n fontSize: 12,\n};\n\n/**\n * Renders an OHLCV legend overlay on the chart (like TradingView top-left).\n * Shows: Symbol, O, H, L, C, Change%, Volume\n * Updates on crosshair hover or shows last bar by default.\n */\nexport class ChartLegend {\n private config: LegendConfig = { ...DEFAULT_LEGEND_CONFIG };\n private symbol = '';\n private timeframe = '';\n private hoverBar: OHLCBar | null = null;\n private indicators: { name: string; color: string; value: string }[] = [];\n private statusText: string | null = null;\n\n setConfig(config: Partial<LegendConfig>): void {\n Object.assign(this.config, config);\n }\n\n setSymbol(symbol: string): void {\n this.symbol = symbol;\n }\n\n setTimeframe(tf: string): void {\n this.timeframe = tf;\n }\n\n setChartType(_type: string): void {\n // reserved for future use\n }\n\n setHoverBar(bar: OHLCBar | null): void {\n this.hoverBar = bar;\n }\n\n setIndicatorValues(values: { name: string; color: string; value: string }[]): void {\n this.indicators = values;\n }\n\n setStatusText(text: string | null): void {\n this.statusText = text;\n }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme, data: DataSeries): void {\n if (!this.config.visible || data.length === 0) return;\n\n const bar = this.hoverBar ?? data[data.length - 1];\n const prevBar = data.length > 1 ? data[data.length - 2] : bar;\n const { chartRect } = viewport;\n const fs = this.config.fontSize;\n const isLeft = this.config.position === 'top-left';\n\n let x = isLeft ? chartRect.x + 8 : chartRect.x + chartRect.width - 8;\n let y = chartRect.y + 6;\n\n ctx.textAlign = isLeft ? 'left' : 'right';\n ctx.textBaseline = 'top';\n\n // Symbol + timeframe + chart type + status text\n if (this.config.showSymbol) {\n ctx.font = `bold ${fs + 2}px ${theme.font.family}`;\n ctx.fillStyle = theme.text;\n const symbolText = [this.symbol, this.timeframe].filter(Boolean).join(' · ');\n const displayText = this.statusText ? `${symbolText} ${this.statusText}` : symbolText;\n ctx.fillText(displayText, x, y);\n y += fs + 6;\n } else if (this.statusText) {\n ctx.font = `${fs}px ${theme.font.family}`;\n ctx.fillStyle = theme.textSecondary;\n ctx.fillText(this.statusText, x, y);\n y += fs + 4;\n }\n\n // OHLC values\n if (this.config.showOHLC) {\n ctx.font = `${fs}px ${theme.font.family}`;\n const isUp = bar.close >= bar.open;\n const fmt = (v: number) => v.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });\n\n const items = [\n { label: 'O', value: fmt(bar.open), color: theme.text },\n { label: 'H', value: fmt(bar.high), color: theme.text },\n { label: 'L', value: fmt(bar.low), color: theme.text },\n { label: 'C', value: fmt(bar.close), color: isUp ? theme.candleUp : theme.candleDown },\n ];\n\n if (this.config.showChange) {\n const change = bar.close - prevBar.close;\n const changePct = prevBar.close !== 0 ? (change / prevBar.close) * 100 : 0;\n const sign = change >= 0 ? '+' : '';\n items.push({\n label: '',\n value: `${sign}${fmt(change)} (${sign}${changePct.toFixed(2)}%)`,\n color: change >= 0 ? theme.candleUp : theme.candleDown,\n });\n }\n\n // Render inline\n let cx = x;\n if (isLeft) {\n for (const item of items) {\n if (item.label) {\n ctx.fillStyle = theme.textSecondary;\n ctx.fillText(item.label, cx, y);\n cx += ctx.measureText(item.label + ' ').width;\n }\n ctx.fillStyle = item.color;\n ctx.fillText(item.value, cx, y);\n cx += ctx.measureText(item.value + ' ').width;\n }\n } else {\n // Right-aligned: build full string and measure\n const fullText = items.map((i) => `${i.label} ${i.value}`).join(' ');\n ctx.fillStyle = theme.text;\n ctx.fillText(fullText, x, y);\n }\n y += fs + 3;\n }\n\n // Volume\n if (this.config.showVolume) {\n ctx.font = `${fs - 1}px ${theme.font.family}`;\n ctx.fillStyle = theme.textSecondary;\n const vol = bar.volume >= 1e6 ? `${(bar.volume / 1e6).toFixed(2)}M` : bar.volume >= 1e3 ? `${(bar.volume / 1e3).toFixed(2)}K` : bar.volume.toFixed(0);\n ctx.fillText(`Vol ${vol}`, x, y);\n y += fs + 2;\n }\n\n // Active indicator values\n if (this.indicators.length > 0) {\n ctx.font = `${fs - 1}px ${theme.font.family}`;\n let ix = x;\n for (const ind of this.indicators) {\n ctx.fillStyle = ind.color;\n const text = `${ind.name} ${ind.value}`;\n ctx.fillText(text, ix, y);\n ix += ctx.measureText(text + ' ').width;\n }\n }\n }\n}\n","/**\n * Captures the chart as an image by compositing all canvas layers.\n */\nexport class Screenshot {\n /**\n * Export the chart container as a PNG data URL.\n */\n static toDataURL(container: HTMLElement, background?: string): string {\n const canvases = container.querySelectorAll('canvas');\n if (canvases.length === 0) return '';\n\n const first = canvases[0];\n const width = first.width;\n const height = first.height;\n\n const compositeCanvas = document.createElement('canvas');\n compositeCanvas.width = width;\n compositeCanvas.height = height;\n const ctx = compositeCanvas.getContext('2d')!;\n\n // Background\n if (background) {\n ctx.fillStyle = background;\n ctx.fillRect(0, 0, width, height);\n }\n\n // Composite all layers in order (lowest z-index first)\n const sorted = Array.from(canvases).sort((a, b) => {\n return (parseInt(a.style.zIndex) || 0) - (parseInt(b.style.zIndex) || 0);\n });\n\n for (const canvas of sorted) {\n ctx.drawImage(canvas, 0, 0);\n }\n\n return compositeCanvas.toDataURL('image/png');\n }\n\n /**\n * Export as Blob (for file saving).\n */\n static async toBlob(container: HTMLElement, background?: string): Promise<Blob | null> {\n const dataURL = this.toDataURL(container, background);\n if (!dataURL) return null;\n\n const res = await fetch(dataURL);\n return res.blob();\n }\n\n /**\n * Trigger browser download of the chart image.\n */\n static download(container: HTMLElement, filename = 'chart.png', background?: string): void {\n const dataURL = this.toDataURL(container, background);\n if (!dataURL) return;\n\n const link = document.createElement('a');\n link.href = dataURL;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n }\n}\n","import type { ViewportState, Theme, WatermarkConfig } from '@tradecanvas/commons';\n\n/**\n * Renders a centered watermark text on the chart background.\n * Semi-transparent, non-interactive.\n */\nexport class Watermark {\n private config: WatermarkConfig | null = null;\n\n setConfig(config: WatermarkConfig | null): void {\n this.config = config;\n }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n if (!this.config?.text) return;\n\n const { chartRect } = viewport;\n const fontSize = this.config.fontSize ?? 48;\n const color = this.config.color ?? theme.textSecondary;\n\n ctx.save();\n ctx.globalAlpha = 0.07;\n ctx.font = `bold ${fontSize}px ${theme.font.family}`;\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(\n this.config.text,\n chartRect.x + chartRect.width / 2,\n chartRect.y + chartRect.height / 2,\n );\n ctx.restore();\n }\n}\n","import type { ViewportState, Theme, DataSeries } from '@tradecanvas/commons';\nimport { barIndexToX } from '../viewport/ScaleMapping.js';\n\nexport class BarCountdown {\n private visible = true;\n private timeframeMs = 0;\n\n setVisible(v: boolean): void { this.visible = v; }\n isVisible(): boolean { return this.visible; }\n\n setTimeframeMs(ms: number): void { this.timeframeMs = ms; }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme, data: DataSeries): void {\n if (!this.visible || this.timeframeMs <= 0 || data.length === 0) return;\n\n const lastBar = data[data.length - 1];\n // Handle both ms and s timestamps\n const timeMs = lastBar.time > 1e12 ? lastBar.time : lastBar.time * 1000;\n const nextBarTime = timeMs + this.timeframeMs;\n const remainingMs = nextBarTime - Date.now();\n if (remainingMs <= 0) return;\n\n const text = this.formatRemaining(remainingMs);\n\n // Position: below the last bar's X, at the bottom of the chart area (above time axis)\n const x = barIndexToX(data.length - 1, viewport);\n const y = viewport.chartRect.y + viewport.chartRect.height - 4;\n\n // Only render if X is within visible area\n if (x < viewport.chartRect.x || x > viewport.chartRect.x + viewport.chartRect.width) return;\n\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n ctx.textBaseline = 'bottom';\n ctx.textAlign = 'center';\n ctx.fillStyle = theme.textSecondary;\n ctx.fillText(text, x, y);\n }\n\n private formatRemaining(ms: number): string {\n const totalSec = Math.ceil(ms / 1000);\n const hours = Math.floor(totalSec / 3600);\n const mins = Math.floor((totalSec % 3600) / 60);\n const secs = totalSec % 60;\n if (hours > 0) {\n return `${hours}:${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;\n }\n return `${mins}:${String(secs).padStart(2, '0')}`;\n }\n}\n","import type { ViewportState, Theme, DataSeries } from '@tradecanvas/commons';\nimport { barIndexToX } from '../viewport/ScaleMapping.js';\n\nexport interface SessionBreakConfig {\n /** Whether to show session break lines */\n visible: boolean;\n /** Session open/close times as { open: 'HH:MM', close: 'HH:MM' } in exchange local time */\n sessionTimes?: { open: string; close: string };\n /** Line color override (defaults to theme.axisLine with reduced opacity) */\n color?: string;\n /** Line style: 'solid' | 'dashed' | 'dotted' */\n lineStyle?: 'solid' | 'dashed' | 'dotted';\n /** Line width (default 1) */\n lineWidth?: number;\n}\n\n/**\n * Renders vertical session break lines on the chart.\n * Detects day boundaries from bar timestamps and draws vertical separators.\n */\nexport class SessionBreaks {\n private config: SessionBreakConfig = { visible: false };\n private cachedBreaks: number[] = [];\n private cachedBreaksTyped: { idx: number; kind: 'day' | 'week' | 'month' | 'year'; date: Date }[] = [];\n private lastDataLength = 0;\n\n setConfig(config: Partial<SessionBreakConfig>): void {\n Object.assign(this.config, config);\n }\n\n isVisible(): boolean {\n return this.config.visible;\n }\n\n setVisible(visible: boolean): void {\n this.config.visible = visible;\n }\n\n /**\n * Find bar indices where a new trading day begins. Each entry also carries\n * the strength of the break: 'day' < 'week' < 'month' < 'year'. Renderer\n * uses this to draw progressively heavier separators + labels.\n */\n private computeBreaksTyped(data: DataSeries): { idx: number; kind: 'day' | 'week' | 'month' | 'year'; date: Date }[] {\n if (data.length < 2) return [];\n\n // Cache: only recompute when data changes\n if (data.length === this.lastDataLength && this.cachedBreaksTyped.length > 0) {\n return this.cachedBreaksTyped;\n }\n\n const out: { idx: number; kind: 'day' | 'week' | 'month' | 'year'; date: Date }[] = [];\n let prev = new Date(this.toMs(data[0].time));\n\n for (let i = 1; i < data.length; i++) {\n const d = new Date(this.toMs(data[i].time));\n if (d.getFullYear() !== prev.getFullYear()) {\n out.push({ idx: i, kind: 'year', date: d });\n } else if (d.getMonth() !== prev.getMonth()) {\n out.push({ idx: i, kind: 'month', date: d });\n } else if (d.getDate() !== prev.getDate()) {\n // Monday (1) is the most common \"week start\" anchor.\n const isWeekStart = d.getDay() === 1;\n out.push({ idx: i, kind: isWeekStart ? 'week' : 'day', date: d });\n }\n prev = d;\n }\n\n this.lastDataLength = data.length;\n this.cachedBreaksTyped = out;\n this.cachedBreaks = out.map(b => b.idx);\n return out;\n }\n\n private toMs(timestamp: number): number {\n return timestamp > 1e12 ? timestamp : timestamp * 1000;\n }\n\n /** Legacy (kept for compatibility) — returns just the indices. */\n private computeBreaks(data: DataSeries): number[] {\n return this.computeBreaksTyped(data).map(b => b.idx);\n }\n\n /** Get a day key from a timestamp (seconds or milliseconds) */\n private getDayKey(timestamp: number): string {\n // Auto-detect seconds vs milliseconds\n const ms = timestamp > 1e12 ? timestamp : timestamp * 1000;\n const d = new Date(ms);\n return `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;\n }\n\n render(\n ctx: CanvasRenderingContext2D,\n viewport: ViewportState,\n theme: Theme,\n data: DataSeries,\n ): void {\n if (!this.config.visible || data.length < 2) return;\n\n const breaks = this.computeBreaksTyped(data);\n if (breaks.length === 0) return;\n\n // Suppress separators when the dataset is already at day-or-coarser\n // granularity — every bar would be a \"day boundary\" and the screen\n // would fill with lines.\n const medianStep = medianBarInterval(data);\n if (medianStep >= 23 * 60 * 60 * 1000) return;\n\n const { chartRect } = viewport;\n const baseColor = this.config.color ?? theme.axisLine;\n const lineWidth = this.config.lineWidth ?? 1;\n const lineStyle = this.config.lineStyle ?? 'dashed';\n\n ctx.save();\n if (lineStyle === 'dashed') {\n ctx.setLineDash([6, 4]);\n } else if (lineStyle === 'dotted') {\n ctx.setLineDash([2, 3]);\n }\n ctx.font = `600 11px ${theme.font.family}`;\n ctx.textBaseline = 'top';\n ctx.textAlign = 'left';\n\n for (const brk of breaks) {\n const x = barIndexToX(brk.idx, viewport) - (viewport.barWidth + viewport.barSpacing) / 2;\n if (x < chartRect.x - 1 || x > chartRect.x + chartRect.width + 1) continue;\n const px = Math.round(x) + 0.5;\n\n // Heavier line + label as the boundary gets more significant.\n let alpha = 0.25;\n let width = lineWidth;\n let label: string | null = null;\n if (brk.kind === 'day') {\n alpha = 0.22;\n } else if (brk.kind === 'week') {\n alpha = 0.34;\n label = formatMonthDay(brk.date);\n } else if (brk.kind === 'month') {\n alpha = 0.5;\n width = lineWidth + 0.5;\n label = formatMonthYear(brk.date);\n } else {\n alpha = 0.7;\n width = lineWidth + 1;\n label = String(brk.date.getFullYear());\n }\n\n ctx.globalAlpha = alpha;\n ctx.strokeStyle = baseColor;\n ctx.lineWidth = width;\n ctx.beginPath();\n ctx.moveTo(px, chartRect.y);\n ctx.lineTo(px, chartRect.y + chartRect.height);\n ctx.stroke();\n\n if (label) {\n ctx.globalAlpha = Math.min(1, alpha + 0.35);\n ctx.fillStyle = theme.textSecondary;\n ctx.fillText(label, px + 4, chartRect.y + 4);\n }\n }\n\n ctx.restore();\n }\n\n /** Invalidate cache when data changes */\n invalidateCache(): void {\n this.lastDataLength = 0;\n this.cachedBreaks = [];\n this.cachedBreaksTyped = [];\n }\n}\n\nconst MONTH_ABBR = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n\nfunction formatMonthDay(d: Date): string {\n return `${MONTH_ABBR[d.getMonth()]} ${d.getDate()}`;\n}\n\nfunction formatMonthYear(d: Date): string {\n return `${MONTH_ABBR[d.getMonth()]} ${String(d.getFullYear()).slice(-2)}`;\n}\n\n/**\n * Median time between bars in ms. Used to gate the day-separator render so\n * daily/weekly/monthly datasets don't pile up redundant separators. A median\n * is robust against single-bar gaps (weekends, halts).\n */\nfunction medianBarInterval(data: { time: number }[]): number {\n if (data.length < 2) return 0;\n const sample = Math.min(50, data.length - 1);\n const diffs: number[] = [];\n for (let i = 1; i <= sample; i++) {\n const a = data[i - 1].time;\n const b = data[i].time;\n const ams = a > 1e12 ? a : a * 1000;\n const bms = b > 1e12 ? b : b * 1000;\n diffs.push(bms - ams);\n }\n diffs.sort((x, y) => x - y);\n return diffs[Math.floor(diffs.length / 2)];\n}\n","import type { ViewportState, Theme } from '@tradecanvas/commons';\nimport { priceToY } from '../viewport/ScaleMapping.js';\nimport { Emitter } from '../realtime/Emitter.js';\n\nexport type AlertCondition = 'crossingUp' | 'crossingDown' | 'crossing' | 'greaterThan' | 'lessThan';\n\nexport interface PriceAlert {\n id: string;\n price: number;\n condition: AlertCondition;\n message?: string;\n triggered: boolean;\n repeating: boolean;\n}\n\ninterface AlertEvents {\n triggered: PriceAlert;\n added: PriceAlert;\n removed: string;\n [key: string]: unknown;\n}\n\nlet alertId = 1;\n\n/**\n * Manages price alerts. Renders alert lines on the chart overlay.\n * Checks each price update against configured alerts and emits 'triggered'.\n */\nexport class AlertManager extends Emitter<AlertEvents> {\n private alerts: PriceAlert[] = [];\n private lastPrice: number | null = null;\n private requestRender: (() => void) | null = null;\n private pricePrecision = 2;\n\n setRequestRender(cb: () => void): void {\n this.requestRender = cb;\n }\n\n setPricePrecision(precision: number): void {\n this.pricePrecision = precision;\n }\n\n addAlert(price: number, condition: AlertCondition = 'crossing', message?: string, repeating = false): string {\n const id = `tc_alert_${alertId++}`;\n const alert: PriceAlert = { id, price, condition, message, triggered: false, repeating };\n this.alerts.push(alert);\n this.emit('added', alert);\n this.requestRender?.();\n return id;\n }\n\n removeAlert(id: string): void {\n this.alerts = this.alerts.filter((a) => a.id !== id);\n this.emit('removed', id);\n this.requestRender?.();\n }\n\n getAlerts(): PriceAlert[] {\n return [...this.alerts];\n }\n\n clearAlerts(): void {\n this.alerts = [];\n this.requestRender?.();\n }\n\n /** Call on each price update to check alerts */\n checkPrice(price: number): void {\n if (this.lastPrice === null) {\n this.lastPrice = price;\n return;\n }\n\n for (const alert of this.alerts) {\n if (alert.triggered && !alert.repeating) continue;\n\n let triggered = false;\n switch (alert.condition) {\n case 'crossingUp':\n triggered = this.lastPrice < alert.price && price >= alert.price;\n break;\n case 'crossingDown':\n triggered = this.lastPrice > alert.price && price <= alert.price;\n break;\n case 'crossing':\n triggered = (this.lastPrice < alert.price && price >= alert.price) ||\n (this.lastPrice > alert.price && price <= alert.price);\n break;\n case 'greaterThan':\n triggered = price > alert.price;\n break;\n case 'lessThan':\n triggered = price < alert.price;\n break;\n }\n\n if (triggered) {\n alert.triggered = true;\n this.emit('triggered', { ...alert });\n }\n }\n\n this.lastPrice = price;\n }\n\n saveToStorage(key: string): void {\n try {\n const data = this.alerts.map(a => ({\n id: a.id, price: a.price, condition: a.condition,\n message: a.message, triggered: a.triggered,\n }));\n localStorage.setItem(key, JSON.stringify(data));\n } catch { /* storage unavailable or full */ }\n }\n\n loadFromStorage(key: string): void {\n try {\n const json = localStorage.getItem(key);\n if (!json) return;\n const data = JSON.parse(json);\n if (!Array.isArray(data)) return;\n for (const a of data) {\n if (a.price && a.condition && !a.triggered) {\n this.addAlert(a.price, a.condition, a.message);\n }\n }\n } catch { /* storage unavailable or corrupt data */ }\n }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n const { chartRect } = viewport;\n\n for (const alert of this.alerts) {\n const y = priceToY(alert.price, viewport);\n if (y < chartRect.y || y > chartRect.y + chartRect.height) continue;\n\n const color = alert.triggered ? '#FF9800' : '#FFD700';\n\n // Alert line\n ctx.setLineDash([2, 6]);\n ctx.strokeStyle = color;\n ctx.lineWidth = 1;\n ctx.beginPath();\n ctx.moveTo(chartRect.x, Math.round(y) + 0.5);\n ctx.lineTo(chartRect.x + chartRect.width, Math.round(y) + 0.5);\n ctx.stroke();\n ctx.setLineDash([]);\n\n // Bell icon + price label\n ctx.font = `10px ${theme.font.family}`;\n ctx.fillStyle = color;\n ctx.textBaseline = 'bottom';\n ctx.textAlign = 'right';\n const label = `🔔 ${alert.price.toFixed(this.pricePrecision)}${alert.message ? ` - ${alert.message}` : ''}`;\n ctx.fillText(label, chartRect.x + chartRect.width - 4, y - 2);\n }\n }\n}\n","import type { OHLCBar, DataSeries } from '@tradecanvas/commons';\nimport { Emitter } from '../realtime/Emitter.js';\n\nexport interface ReplayConfig {\n speed: number; // Multiplier: 1 = real-time, 2 = 2x, 0.5 = half speed\n interval: number; // Base tick interval in ms (default: 500)\n startIndex?: number; // Bar index to start from\n}\n\ninterface ReplayEvents {\n bar: { bar: OHLCBar; index: number; total: number };\n complete: void;\n stateChange: 'playing' | 'paused' | 'stopped';\n [key: string]: unknown;\n}\n\n/**\n * Replays historical data bar-by-bar for backtesting and review.\n * Feeds bars to the chart sequentially at configurable speed.\n */\nexport class ReplayManager extends Emitter<ReplayEvents> {\n private data: DataSeries = [];\n private currentIndex = 0;\n private timer: ReturnType<typeof setInterval> | null = null;\n private state: 'playing' | 'paused' | 'stopped' = 'stopped';\n private config: ReplayConfig = { speed: 1, interval: 500 };\n\n load(data: DataSeries): void {\n this.stop();\n this.data = data;\n this.currentIndex = 0;\n }\n\n play(config?: Partial<ReplayConfig>): void {\n if (this.data.length === 0) return;\n if (config) Object.assign(this.config, config);\n if (config?.startIndex !== undefined) this.currentIndex = config.startIndex;\n\n this.state = 'playing';\n this.emit('stateChange', 'playing');\n\n this.timer = setInterval(() => {\n if (this.currentIndex >= this.data.length) {\n this.stop();\n this.emit('complete', undefined as any);\n return;\n }\n\n const bar = this.data[this.currentIndex];\n this.emit('bar', { bar, index: this.currentIndex, total: this.data.length });\n this.currentIndex++;\n }, this.config.interval / this.config.speed);\n }\n\n pause(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n this.state = 'paused';\n this.emit('stateChange', 'paused');\n }\n\n resume(): void {\n if (this.state === 'paused') {\n this.play();\n }\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n this.state = 'stopped';\n this.currentIndex = 0;\n this.emit('stateChange', 'stopped');\n }\n\n /**\n * Jump to a specific bar. Emits `bar` synchronously so chart consumers can\n * re-render the slice — without this, seeking while paused leaves the chart\n * stuck on whichever bar last fired through the timer.\n */\n seekTo(index: number): void {\n if (this.data.length === 0) return;\n const clamped = Math.max(0, Math.min(index, this.data.length - 1));\n this.currentIndex = clamped;\n const bar = this.data[clamped];\n this.emit('bar', { bar, index: clamped, total: this.data.length });\n }\n\n setSpeed(speed: number): void {\n this.config.speed = speed;\n if (this.state === 'playing') {\n this.pause();\n this.play();\n }\n }\n\n getState(): 'playing' | 'paused' | 'stopped' {\n return this.state;\n }\n\n getProgress(): { current: number; total: number; percent: number } {\n return {\n current: this.currentIndex,\n total: this.data.length,\n percent: this.data.length > 0 ? (this.currentIndex / this.data.length) * 100 : 0,\n };\n }\n\n dispose(): void {\n this.stop();\n this.removeAllListeners();\n this.data = [];\n }\n}\n","import type { ChartType, DrawingState, TradingOrder, TradingPosition, Theme } from '@tradecanvas/commons';\r\nimport type { PriceAlert } from './AlertManager.js';\r\n\r\n/**\r\n * Serializable chart state for save/load functionality.\r\n * Contains everything needed to restore a chart to its exact state.\r\n */\r\nexport interface ChartSnapshot {\r\n version: number;\r\n timestamp: number;\r\n\r\n // Chart config\r\n symbol?: string;\r\n timeframe?: string;\r\n chartType: ChartType;\r\n\r\n // Viewport\r\n viewport: {\r\n barWidth: number;\r\n barSpacing: number;\r\n offset: number;\r\n };\r\n\r\n // Visual\r\n theme?: string | Theme;\r\n locale?: string;\r\n\r\n // Indicators\r\n indicators: {\r\n id: string;\r\n instanceId: string;\r\n params: Record<string, unknown>;\r\n position?: string;\r\n }[];\r\n\r\n // Drawings (fully serializable)\r\n drawings: DrawingState[];\r\n\r\n // Trading\r\n orders: TradingOrder[];\r\n positions: TradingPosition[];\r\n\r\n // Alerts\r\n alerts: PriceAlert[];\r\n}\r\n\r\nconst CURRENT_VERSION = 1;\r\n\r\nfunction isObject(v: unknown): v is Record<string, unknown> {\r\n return typeof v === 'object' && v !== null && !Array.isArray(v);\r\n}\r\n\r\nfunction asArray(v: unknown): unknown[] {\r\n return Array.isArray(v) ? v : [];\r\n}\r\n\r\nfunction asString(v: unknown, fallback: string): string {\r\n return typeof v === 'string' ? v : fallback;\r\n}\r\n\r\nfunction asNumber(v: unknown, fallback: number): number {\r\n return typeof v === 'number' && Number.isFinite(v) ? v : fallback;\r\n}\r\n\r\nfunction validateDrawing(raw: unknown): DrawingState | null {\r\n if (!isObject(raw)) return null;\r\n if (typeof raw.id !== 'string' || typeof raw.type !== 'string') return null;\r\n if (!Array.isArray(raw.anchors) || raw.anchors.length === 0) return null;\r\n if (!isObject(raw.style)) return null;\r\n\r\n const anchors: DrawingState['anchors'] = [];\r\n for (const a of raw.anchors) {\r\n if (!isObject(a)) return null;\r\n if (typeof a.time !== 'number' || typeof a.price !== 'number') return null;\r\n if (!Number.isFinite(a.time) || !Number.isFinite(a.price)) return null;\r\n anchors.push({ time: a.time, price: a.price });\r\n }\r\n\r\n const style = raw.style;\r\n if (typeof style.color !== 'string' || typeof style.lineWidth !== 'number') {\r\n return null;\r\n }\r\n\r\n return {\r\n id: raw.id,\r\n type: raw.type as DrawingState['type'],\r\n anchors,\r\n style: style as unknown as DrawingState['style'],\r\n visible: typeof raw.visible === 'boolean' ? raw.visible : true,\r\n locked: typeof raw.locked === 'boolean' ? raw.locked : false,\r\n meta: isObject(raw.meta) ? raw.meta : undefined,\r\n };\r\n}\r\n\r\nfunction validateOrder(raw: unknown): TradingOrder | null {\r\n if (!isObject(raw)) return null;\r\n if (typeof raw.id !== 'string' || typeof raw.side !== 'string') return null;\r\n if (typeof raw.type !== 'string' || typeof raw.price !== 'number') return null;\r\n if (typeof raw.quantity !== 'number') return null;\r\n return raw as unknown as TradingOrder;\r\n}\r\n\r\nfunction validatePosition(raw: unknown): TradingPosition | null {\r\n if (!isObject(raw)) return null;\r\n if (typeof raw.id !== 'string' || typeof raw.side !== 'string') return null;\r\n if (typeof raw.entryPrice !== 'number' || typeof raw.quantity !== 'number') return null;\r\n return raw as unknown as TradingPosition;\r\n}\r\n\r\nexport function validateSnapshot(raw: unknown): ChartSnapshot {\r\n if (!isObject(raw)) {\r\n return emptySnapshot();\r\n }\r\n\r\n if (typeof raw.version === 'number' && raw.version !== CURRENT_VERSION) {\r\n console.warn(`Chart state version mismatch: ${raw.version} vs ${CURRENT_VERSION}`);\r\n }\r\n\r\n const viewport = isObject(raw.viewport) ? raw.viewport : {};\r\n\r\n const indicators: ChartSnapshot['indicators'] = [];\r\n for (const ind of asArray(raw.indicators)) {\r\n if (!isObject(ind)) continue;\r\n if (typeof ind.id !== 'string' || typeof ind.instanceId !== 'string') continue;\r\n if (!isObject(ind.params)) continue;\r\n indicators.push({\r\n id: ind.id,\r\n instanceId: ind.instanceId,\r\n params: ind.params,\r\n position: typeof ind.position === 'string' ? ind.position : undefined,\r\n });\r\n }\r\n\r\n const drawings: DrawingState[] = [];\r\n for (const d of asArray(raw.drawings)) {\r\n const v = validateDrawing(d);\r\n if (v) drawings.push(v);\r\n }\r\n\r\n const orders: TradingOrder[] = [];\r\n for (const o of asArray(raw.orders)) {\r\n const v = validateOrder(o);\r\n if (v) orders.push(v);\r\n }\r\n\r\n const positions: TradingPosition[] = [];\r\n for (const p of asArray(raw.positions)) {\r\n const v = validatePosition(p);\r\n if (v) positions.push(v);\r\n }\r\n\r\n const alerts: PriceAlert[] = [];\r\n for (const a of asArray(raw.alerts)) {\r\n if (isObject(a) && typeof a.id === 'string') alerts.push(a as unknown as PriceAlert);\r\n }\r\n\r\n return {\r\n version: typeof raw.version === 'number' ? raw.version : CURRENT_VERSION,\r\n timestamp: asNumber(raw.timestamp, Date.now()),\r\n symbol: typeof raw.symbol === 'string' ? raw.symbol : undefined,\r\n timeframe: typeof raw.timeframe === 'string' ? raw.timeframe : undefined,\r\n chartType: asString(raw.chartType, 'candlestick') as ChartType,\r\n viewport: {\r\n barWidth: asNumber(viewport.barWidth, 8),\r\n barSpacing: asNumber(viewport.barSpacing, 2),\r\n offset: asNumber(viewport.offset, 0),\r\n },\r\n theme: typeof raw.theme === 'string' ? raw.theme : undefined,\r\n locale: typeof raw.locale === 'string' ? raw.locale : undefined,\r\n indicators,\r\n drawings,\r\n orders,\r\n positions,\r\n alerts,\r\n };\r\n}\r\n\r\nfunction emptySnapshot(): ChartSnapshot {\r\n return {\r\n version: CURRENT_VERSION,\r\n timestamp: Date.now(),\r\n chartType: 'candlestick',\r\n viewport: { barWidth: 8, barSpacing: 2, offset: 0 },\r\n indicators: [],\r\n drawings: [],\r\n orders: [],\r\n positions: [],\r\n alerts: [],\r\n };\r\n}\r\n\r\nexport class ChartStateManager {\r\n /**\r\n * Capture current chart state as a serializable snapshot.\r\n */\r\n static capture(chart: {\r\n getDrawings: () => DrawingState[];\r\n getOrders?: () => TradingOrder[];\r\n getPositions?: () => TradingPosition[];\r\n getAlerts?: () => PriceAlert[];\r\n getTheme: () => Theme;\r\n getIndicators?: () => { id: string; instanceId: string; params: Record<string, unknown> }[];\r\n }, meta?: { symbol?: string; timeframe?: string; chartType?: ChartType }): ChartSnapshot {\r\n return {\r\n version: CURRENT_VERSION,\r\n timestamp: Date.now(),\r\n chartType: meta?.chartType ?? 'candlestick',\r\n symbol: meta?.symbol,\r\n timeframe: meta?.timeframe,\r\n viewport: { barWidth: 8, barSpacing: 2, offset: 0 },\r\n theme: chart.getTheme().name,\r\n indicators: chart.getIndicators?.() ?? [],\r\n drawings: chart.getDrawings(),\r\n orders: chart.getOrders?.() ?? [],\r\n positions: chart.getPositions?.() ?? [],\r\n alerts: chart.getAlerts?.() ?? [],\r\n };\r\n }\r\n\r\n /** Serialize to JSON string */\r\n static serialize(snapshot: ChartSnapshot): string {\r\n return JSON.stringify(snapshot);\r\n }\r\n\r\n /**\r\n * Deserialize from JSON string. Validates the top-level shape and filters\r\n * malformed array entries instead of trusting `JSON.parse`. Missing or\r\n * wrong-typed fields fall back to safe defaults so older saves still load.\r\n */\r\n static deserialize(json: string): ChartSnapshot {\r\n const raw: unknown = JSON.parse(json);\r\n return validateSnapshot(raw);\r\n }\r\n\r\n /** Save to localStorage */\r\n static saveToStorage(key: string, snapshot: ChartSnapshot): void {\r\n localStorage.setItem(key, this.serialize(snapshot));\r\n }\r\n\r\n /** Load from localStorage */\r\n static loadFromStorage(key: string): ChartSnapshot | null {\r\n const json = localStorage.getItem(key);\r\n return json ? this.deserialize(json) : null;\r\n }\r\n\r\n /** Download as JSON file */\r\n static downloadFile(snapshot: ChartSnapshot, filename = 'tc-chart-state.json'): void {\r\n const blob = new Blob([this.serialize(snapshot)], { type: 'application/json' });\r\n const url = URL.createObjectURL(blob);\r\n const link = document.createElement('a');\r\n link.href = url;\r\n link.download = filename;\r\n document.body.appendChild(link);\r\n link.click();\r\n document.body.removeChild(link);\r\n URL.revokeObjectURL(url);\r\n }\r\n\r\n /** Load from file (returns promise) */\r\n static loadFromFile(): Promise<ChartSnapshot> {\r\n return new Promise((resolve, reject) => {\r\n const input = document.createElement('input');\r\n input.type = 'file';\r\n input.accept = '.json';\r\n input.onchange = async () => {\r\n const file = input.files?.[0];\r\n if (!file) { reject(new Error('No file selected')); return; }\r\n const text = await file.text();\r\n resolve(this.deserialize(text));\r\n };\r\n input.click();\r\n });\r\n }\r\n}\r\n","import type { DrawingState } from '@tradecanvas/commons';\n\nexport interface UndoableAction {\n type: 'drawingCreate' | 'drawingRemove' | 'drawingModify';\n /** State before the action (null for create) */\n before: DrawingState | null;\n /** State after the action (null for remove) */\n after: DrawingState | null;\n}\n\nexport class UndoRedoManager {\n private undoStack: UndoableAction[] = [];\n private redoStack: UndoableAction[] = [];\n private maxHistory = 50;\n private onChange: (() => void) | null = null;\n\n setOnChange(cb: () => void): void {\n this.onChange = cb;\n }\n\n push(action: UndoableAction): void {\n this.undoStack.push(action);\n if (this.undoStack.length > this.maxHistory) {\n this.undoStack.shift();\n }\n // Any new action clears the redo stack\n this.redoStack.length = 0;\n this.onChange?.();\n }\n\n canUndo(): boolean {\n return this.undoStack.length > 0;\n }\n\n canRedo(): boolean {\n return this.redoStack.length > 0;\n }\n\n undo(): UndoableAction | null {\n const action = this.undoStack.pop();\n if (!action) return null;\n this.redoStack.push(action);\n this.onChange?.();\n return action;\n }\n\n redo(): UndoableAction | null {\n const action = this.redoStack.pop();\n if (!action) return null;\n this.undoStack.push(action);\n this.onChange?.();\n return action;\n }\n\n clear(): void {\n this.undoStack.length = 0;\n this.redoStack.length = 0;\n }\n\n getState(): { canUndo: boolean; canRedo: boolean; undoCount: number; redoCount: number } {\n return {\n canUndo: this.undoStack.length > 0,\n canRedo: this.redoStack.length > 0,\n undoCount: this.undoStack.length,\n redoCount: this.redoStack.length,\n };\n }\n}\n","import type { OHLCBar } from '@tradecanvas/commons';\n\nexport class DataExporter {\n static toCSV(data: ReadonlyArray<OHLCBar>): string {\n const header = 'Time,Open,High,Low,Close,Volume';\n const rows = data.map(bar => {\n const time = new Date(bar.time).toISOString();\n return `${time},${bar.open},${bar.high},${bar.low},${bar.close},${bar.volume}`;\n });\n return [header, ...rows].join('\\n');\n }\n\n static toJSON(data: ReadonlyArray<OHLCBar>): string {\n return JSON.stringify(data.map(bar => ({\n time: new Date(bar.time).toISOString(),\n open: bar.open,\n high: bar.high,\n low: bar.low,\n close: bar.close,\n volume: bar.volume,\n })), null, 2);\n }\n\n static download(content: string, filename: string, mimeType: string): void {\n const blob = new Blob([content], { type: mimeType });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n }\n}\n","import type { ViewportState, Theme, DataSeries, SignalMarker, SignalMarkerStyle } from '@tradecanvas/commons';\nimport { DEFAULT_SIGNAL_STYLE } from '@tradecanvas/commons';\nimport { priceToY, barIndexToX, timestampToBarIndex } from '../viewport/ScaleMapping.js';\nimport { Emitter } from '../realtime/Emitter.js';\n\ninterface SignalMarkerEvents {\n added: SignalMarker;\n removed: string;\n cleared: void;\n [key: string]: unknown;\n}\n\nlet markerId = 1;\n\nexport class SignalMarkerManager extends Emitter<SignalMarkerEvents> {\n private markers: SignalMarker[] = [];\n private style: SignalMarkerStyle = { ...DEFAULT_SIGNAL_STYLE };\n private requestRender: (() => void) | null = null;\n private dataGetter: (() => DataSeries) | null = null;\n\n setRequestRender(cb: () => void): void {\n this.requestRender = cb;\n }\n\n setDataGetter(getter: () => DataSeries): void {\n this.dataGetter = getter;\n }\n\n setStyle(style: Partial<SignalMarkerStyle>): void {\n this.style = { ...this.style, ...style };\n this.requestRender?.();\n }\n\n getStyle(): SignalMarkerStyle {\n return { ...this.style };\n }\n\n addMarker(marker: Omit<SignalMarker, 'id'> & { id?: string }): string {\n const id = marker.id ?? `tc_signal_${markerId++}`;\n const full: SignalMarker = { ...marker, id };\n this.markers.push(full);\n this.emit('added', full);\n this.requestRender?.();\n return id;\n }\n\n removeMarker(id: string): void {\n this.markers = this.markers.filter(m => m.id !== id);\n this.emit('removed', id);\n this.requestRender?.();\n }\n\n getMarkers(): SignalMarker[] {\n return [...this.markers];\n }\n\n clearMarkers(): void {\n this.markers = [];\n this.emit('cleared', undefined as unknown as void);\n this.requestRender?.();\n }\n\n setMarkers(markers: SignalMarker[]): void {\n this.markers = [...markers];\n this.requestRender?.();\n }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n const data = this.dataGetter?.();\n if (!data || data.length === 0 || this.markers.length === 0) return;\n\n const { chartRect, visibleRange } = viewport;\n const style = this.style;\n const arrowSize = style.arrowSize ?? 12;\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(chartRect.x, chartRect.y, chartRect.width, chartRect.height);\n ctx.clip();\n\n for (const marker of this.markers) {\n const barIdx = timestampToBarIndex(marker.time, data);\n if (barIdx < visibleRange.from - 1 || barIdx > visibleRange.to + 1) continue;\n\n const x = barIndexToX(barIdx, viewport);\n const y = priceToY(marker.price, viewport);\n\n if (x < chartRect.x - arrowSize || x > chartRect.x + chartRect.width + arrowSize) continue;\n if (y < chartRect.y - arrowSize || y > chartRect.y + chartRect.height + arrowSize) continue;\n\n const color = this.resolveColor(marker, style);\n const scaledSize = arrowSize * Math.max(0.6, Math.min(1, marker.confidence));\n\n this.renderArrow(ctx, x, y, marker.direction, scaledSize, color);\n\n if (style.showLabel && marker.label) {\n ctx.font = `10px ${theme.font.family}`;\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = marker.direction === 'long' ? 'top' : 'bottom';\n const labelY = marker.direction === 'long' ? y + scaledSize + 3 : y - scaledSize - 3;\n ctx.fillText(marker.label, x, labelY);\n }\n\n if (style.showConfidence && marker.confidence < 1) {\n ctx.font = `9px ${theme.font.family}`;\n ctx.fillStyle = color;\n ctx.globalAlpha = 0.7;\n ctx.textAlign = 'center';\n ctx.textBaseline = marker.direction === 'long' ? 'top' : 'bottom';\n const confY = marker.direction === 'long'\n ? y + scaledSize + (marker.label ? 14 : 3)\n : y - scaledSize - (marker.label ? 14 : 3);\n ctx.fillText(`${Math.round(marker.confidence * 100)}%`, x, confY);\n ctx.globalAlpha = 1;\n }\n }\n\n ctx.restore();\n }\n\n private resolveColor(marker: SignalMarker, style: SignalMarkerStyle): string {\n if (marker.color) return marker.color;\n if (style.sourceColors?.[marker.source]) return style.sourceColors[marker.source];\n switch (marker.direction) {\n case 'long': return style.longColor ?? '#26A69A';\n case 'short': return style.shortColor ?? '#EF5350';\n default: return style.neutralColor ?? '#9E9E9E';\n }\n }\n\n private renderArrow(\n ctx: CanvasRenderingContext2D,\n x: number, y: number,\n direction: string,\n size: number,\n color: string,\n ): void {\n ctx.fillStyle = color;\n ctx.beginPath();\n\n if (direction === 'long') {\n ctx.moveTo(x, y - size);\n ctx.lineTo(x - size * 0.6, y);\n ctx.lineTo(x - size * 0.2, y);\n ctx.lineTo(x - size * 0.2, y + size * 0.4);\n ctx.lineTo(x + size * 0.2, y + size * 0.4);\n ctx.lineTo(x + size * 0.2, y);\n ctx.lineTo(x + size * 0.6, y);\n } else if (direction === 'short') {\n ctx.moveTo(x, y + size);\n ctx.lineTo(x - size * 0.6, y);\n ctx.lineTo(x - size * 0.2, y);\n ctx.lineTo(x - size * 0.2, y - size * 0.4);\n ctx.lineTo(x + size * 0.2, y - size * 0.4);\n ctx.lineTo(x + size * 0.2, y);\n ctx.lineTo(x + size * 0.6, y);\n } else {\n ctx.arc(x, y, size * 0.4, 0, Math.PI * 2);\n }\n\n ctx.closePath();\n ctx.fill();\n }\n}\n","import type { ViewportState, Theme, DataSeries, TradeZone, TradeZoneStyle } from '@tradecanvas/commons';\nimport { DEFAULT_TRADE_ZONE_STYLE } from '@tradecanvas/commons';\nimport { priceToY, barIndexToX, timestampToBarIndex } from '../viewport/ScaleMapping.js';\nimport { Emitter } from '../realtime/Emitter.js';\n\ninterface TradeZoneEvents {\n added: TradeZone;\n removed: string;\n cleared: void;\n [key: string]: unknown;\n}\n\nlet zoneId = 1;\n\nexport class TradeZoneManager extends Emitter<TradeZoneEvents> {\n private zones: TradeZone[] = [];\n private style: TradeZoneStyle = { ...DEFAULT_TRADE_ZONE_STYLE };\n private requestRender: (() => void) | null = null;\n private dataGetter: (() => DataSeries) | null = null;\n private pricePrecision = 2;\n\n setRequestRender(cb: () => void): void {\n this.requestRender = cb;\n }\n\n setDataGetter(getter: () => DataSeries): void {\n this.dataGetter = getter;\n }\n\n setPricePrecision(precision: number): void {\n this.pricePrecision = precision;\n }\n\n setStyle(style: Partial<TradeZoneStyle>): void {\n this.style = { ...this.style, ...style };\n this.requestRender?.();\n }\n\n getStyle(): TradeZoneStyle {\n return { ...this.style };\n }\n\n addZone(zone: Omit<TradeZone, 'id'> & { id?: string }): string {\n const id = zone.id ?? `tc_zone_${zoneId++}`;\n const full: TradeZone = { ...zone, id };\n this.zones.push(full);\n this.emit('added', full);\n this.requestRender?.();\n return id;\n }\n\n updateZone(id: string, updates: Partial<Omit<TradeZone, 'id'>>): void {\n const idx = this.zones.findIndex(z => z.id === id);\n if (idx === -1) return;\n this.zones[idx] = { ...this.zones[idx], ...updates };\n this.requestRender?.();\n }\n\n removeZone(id: string): void {\n this.zones = this.zones.filter(z => z.id !== id);\n this.emit('removed', id);\n this.requestRender?.();\n }\n\n getZones(): TradeZone[] {\n return [...this.zones];\n }\n\n clearZones(): void {\n this.zones = [];\n this.emit('cleared', undefined as unknown as void);\n this.requestRender?.();\n }\n\n setZones(zones: TradeZone[]): void {\n this.zones = [...zones];\n this.requestRender?.();\n }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n const data = this.dataGetter?.();\n if (!data || data.length === 0 || this.zones.length === 0) return;\n\n const { chartRect } = viewport;\n const style = this.style;\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(chartRect.x, chartRect.y, chartRect.width, chartRect.height);\n ctx.clip();\n\n for (const zone of this.zones) {\n this.renderZone(ctx, zone, data, viewport, theme, style);\n }\n\n ctx.restore();\n }\n\n private renderZone(\n ctx: CanvasRenderingContext2D,\n zone: TradeZone,\n data: DataSeries,\n viewport: ViewportState,\n theme: Theme,\n style: TradeZoneStyle,\n ): void {\n const { chartRect, visibleRange } = viewport;\n\n const entryIdx = timestampToBarIndex(zone.entryTime, data);\n const exitIdx = zone.exitTime != null\n ? timestampToBarIndex(zone.exitTime, data)\n : data.length - 1;\n\n if (exitIdx < visibleRange.from || entryIdx > visibleRange.to) return;\n\n const x1 = barIndexToX(entryIdx, viewport);\n const x2 = barIndexToX(exitIdx, viewport);\n const left = Math.max(chartRect.x, Math.min(x1, x2));\n const right = Math.min(chartRect.x + chartRect.width, Math.max(x1, x2));\n if (right - left < 1) return;\n\n const entryY = priceToY(zone.entryPrice, viewport);\n const exitY = zone.exitPrice != null\n ? priceToY(zone.exitPrice, viewport)\n : priceToY(zone.entryPrice, viewport);\n\n const top = Math.min(entryY, exitY);\n const bottom = Math.max(entryY, exitY);\n const height = Math.max(bottom - top, 2);\n\n const isActive = zone.exitTime == null;\n const isProfit = zone.pnl != null ? zone.pnl >= 0 : (\n zone.direction === 'long'\n ? (zone.exitPrice ?? zone.entryPrice) >= zone.entryPrice\n : (zone.exitPrice ?? zone.entryPrice) <= zone.entryPrice\n );\n\n const fillColor = isActive\n ? (style.activeColor ?? '#2196F3')\n : isProfit\n ? (style.profitColor ?? '#26A69A')\n : (style.lossColor ?? '#EF5350');\n\n ctx.fillStyle = fillColor;\n ctx.globalAlpha = style.fillOpacity ?? 0.12;\n ctx.fillRect(left, top, right - left, height);\n ctx.globalAlpha = 1;\n\n const borderWidth = style.borderWidth ?? 1;\n ctx.strokeStyle = fillColor;\n ctx.lineWidth = borderWidth;\n\n ctx.setLineDash([]);\n ctx.beginPath();\n ctx.moveTo(left, Math.round(entryY) + 0.5);\n ctx.lineTo(right, Math.round(entryY) + 0.5);\n ctx.stroke();\n\n if (!isActive && zone.exitPrice != null) {\n ctx.setLineDash([3, 3]);\n ctx.beginPath();\n ctx.moveTo(left, Math.round(exitY) + 0.5);\n ctx.lineTo(right, Math.round(exitY) + 0.5);\n ctx.stroke();\n ctx.setLineDash([]);\n }\n\n const dirIcon = zone.direction === 'long' ? '▲' : '▼';\n ctx.font = `bold 10px ${theme.font.family}`;\n ctx.fillStyle = fillColor;\n ctx.textBaseline = 'bottom';\n ctx.textAlign = 'left';\n ctx.fillText(`${dirIcon} ${zone.entryPrice.toFixed(this.pricePrecision)}`, left + 4, entryY - 3);\n\n if (style.showPnl && !isActive && zone.pnl != null) {\n const pnlSign = zone.pnl >= 0 ? '+' : '';\n const pnlText = zone.pnlPercent != null\n ? `${pnlSign}${zone.pnl.toFixed(2)} (${pnlSign}${zone.pnlPercent.toFixed(2)}%)`\n : `${pnlSign}${zone.pnl.toFixed(2)}`;\n\n ctx.font = `bold 10px ${theme.font.family}`;\n ctx.fillStyle = fillColor;\n ctx.textBaseline = 'top';\n ctx.textAlign = 'right';\n\n const bgWidth = ctx.measureText(pnlText).width + 8;\n const bgX = right - bgWidth - 2;\n const bgY = top + 2;\n ctx.globalAlpha = 0.85;\n ctx.fillStyle = theme.background;\n ctx.fillRect(bgX, bgY, bgWidth, 14);\n ctx.globalAlpha = 1;\n ctx.fillStyle = fillColor;\n ctx.fillText(pnlText, right - 4, bgY + 1);\n }\n\n if (style.showLabel && zone.label) {\n ctx.font = `9px ${theme.font.family}`;\n ctx.fillStyle = fillColor;\n ctx.globalAlpha = 0.8;\n ctx.textBaseline = 'top';\n ctx.textAlign = 'left';\n ctx.fillText(zone.label, left + 4, entryY + 3);\n ctx.globalAlpha = 1;\n }\n }\n}\n","import type { Point, ViewportState, Theme, DataSeries } from '@tradecanvas/commons';\nimport { xToBarIndex, yToPrice, barIndexToX, priceToY } from '../viewport/ScaleMapping.js';\n\n/**\n * Transient \"measure\" overlay (TradingView shift-drag ruler).\n *\n * The tool is owned by the chart but lives outside the persistent drawing\n * system on purpose: it is reset on every mouseup so it never clutters saved\n * state, and it doesn't participate in undo/redo.\n *\n * Coordinates are stored in data space (bar index + price) so the overlay\n * tracks the data correctly during pan/zoom while the user is still holding\n * shift.\n */\nexport class MeasureOverlay {\n private active = false;\n private startBar = 0;\n private startPrice = 0;\n private endBar = 0;\n private endPrice = 0;\n private startTime: number | null = null;\n private endTime: number | null = null;\n\n isActive(): boolean {\n return this.active;\n }\n\n begin(pos: Point, viewport: ViewportState, data: DataSeries): void {\n const bar = Math.round(xToBarIndex(pos.x, viewport));\n const price = yToPrice(pos.y, viewport);\n this.startBar = bar;\n this.startPrice = price;\n this.endBar = bar;\n this.endPrice = price;\n this.startTime = barTime(bar, data);\n this.endTime = this.startTime;\n this.active = true;\n }\n\n update(pos: Point, viewport: ViewportState, data: DataSeries): void {\n if (!this.active) return;\n const bar = Math.round(xToBarIndex(pos.x, viewport));\n this.endBar = bar;\n this.endPrice = yToPrice(pos.y, viewport);\n this.endTime = barTime(bar, data);\n }\n\n end(): void {\n this.active = false;\n }\n\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme): void {\n if (!this.active) return;\n\n const x1 = barIndexToX(this.startBar, viewport);\n const x2 = barIndexToX(this.endBar, viewport);\n const y1 = priceToY(this.startPrice, viewport);\n const y2 = priceToY(this.endPrice, viewport);\n\n const left = Math.min(x1, x2);\n const right = Math.max(x1, x2);\n const top = Math.min(y1, y2);\n const bottom = Math.max(y1, y2);\n const w = right - left;\n const h = bottom - top;\n\n const goingUp = this.endPrice >= this.startPrice;\n const color = goingUp ? theme.candleUp : theme.candleDown;\n const fill = withAlpha(color, 0.14);\n\n ctx.save();\n\n // Selection rectangle\n ctx.fillStyle = fill;\n ctx.fillRect(left, top, w, h);\n\n ctx.strokeStyle = color;\n ctx.lineWidth = 1;\n ctx.setLineDash([4, 3]);\n ctx.strokeRect(left + 0.5, top + 0.5, w, h);\n ctx.setLineDash([]);\n\n // Direction line (start anchor → end anchor)\n ctx.strokeStyle = color;\n ctx.lineWidth = 1.5;\n ctx.beginPath();\n ctx.moveTo(x1, y1);\n ctx.lineTo(x2, y2);\n ctx.stroke();\n\n // Anchor dots\n drawDot(ctx, x1, y1, color);\n drawDot(ctx, x2, y2, color);\n\n // Info pill — placed near the end anchor\n const bars = Math.abs(this.endBar - this.startBar);\n const priceDelta = this.endPrice - this.startPrice;\n const pricePct = this.startPrice !== 0 ? (priceDelta / this.startPrice) * 100 : 0;\n const timeSpan = this.startTime !== null && this.endTime !== null\n ? formatTimeSpan(Math.abs(this.endTime - this.startTime))\n : null;\n\n const lines: string[] = [];\n const sign = priceDelta > 0 ? '+' : priceDelta < 0 ? '−' : '';\n const absDelta = Math.abs(priceDelta);\n lines.push(`${sign}${formatPrice(absDelta)} (${sign}${Math.abs(pricePct).toFixed(2)}%)`);\n lines.push(`${bars} bars${timeSpan ? ' · ' + timeSpan : ''}`);\n\n drawPill(ctx, x2, y2, lines, color, theme);\n\n ctx.restore();\n }\n}\n\nfunction barTime(barIdx: number, data: DataSeries): number | null {\n if (barIdx < 0 || barIdx >= data.length) return null;\n const t = data[barIdx].time;\n return t > 1e12 ? t : t * 1000;\n}\n\nfunction formatPrice(v: number): string {\n if (v >= 1000) return v.toFixed(2);\n if (v >= 1) return v.toFixed(4);\n return v.toPrecision(4);\n}\n\nfunction formatTimeSpan(ms: number): string {\n const sec = ms / 1000;\n if (sec < 60) return `${sec.toFixed(0)}s`;\n const min = sec / 60;\n if (min < 60) return `${min.toFixed(1)}m`;\n const hr = min / 60;\n if (hr < 24) return `${hr.toFixed(1)}h`;\n const days = hr / 24;\n if (days < 30) return `${days.toFixed(1)}d`;\n const months = days / 30;\n if (months < 12) return `${months.toFixed(1)}mo`;\n return `${(days / 365).toFixed(1)}y`;\n}\n\nfunction drawDot(ctx: CanvasRenderingContext2D, x: number, y: number, color: string): void {\n ctx.fillStyle = color;\n ctx.beginPath();\n ctx.arc(x, y, 3.5, 0, Math.PI * 2);\n ctx.fill();\n ctx.fillStyle = '#fff';\n ctx.beginPath();\n ctx.arc(x, y, 1.5, 0, Math.PI * 2);\n ctx.fill();\n}\n\nfunction drawPill(\n ctx: CanvasRenderingContext2D,\n anchorX: number,\n anchorY: number,\n lines: string[],\n accent: string,\n theme: Theme,\n): void {\n const padX = 8;\n const padY = 6;\n const lineH = 14;\n const font = `600 11px ${theme.font.family}`;\n ctx.font = font;\n\n let maxW = 0;\n for (const line of lines) {\n const w = ctx.measureText(line).width;\n if (w > maxW) maxW = w;\n }\n const w = Math.ceil(maxW) + padX * 2;\n const h = lines.length * lineH + padY * 2;\n\n // Position below the end anchor by default; flip up if it would go off canvas.\n let x = anchorX + 8;\n let y = anchorY + 8;\n const canvasW = ctx.canvas.clientWidth || ctx.canvas.width;\n if (x + w > canvasW - 4) x = anchorX - w - 8;\n if (x < 4) x = 4;\n\n // Background\n ctx.fillStyle = theme.background;\n ctx.globalAlpha = 0.96;\n roundRect(ctx, x, y, w, h, 6);\n ctx.fill();\n ctx.globalAlpha = 1;\n\n ctx.strokeStyle = accent;\n ctx.lineWidth = 1;\n roundRect(ctx, x + 0.5, y + 0.5, w - 1, h - 1, 6);\n ctx.stroke();\n\n ctx.fillStyle = theme.text;\n ctx.textBaseline = 'top';\n ctx.textAlign = 'left';\n for (let i = 0; i < lines.length; i++) {\n ctx.fillStyle = i === 0 ? accent : theme.textSecondary;\n ctx.fillText(lines[i], x + padX, y + padY + i * lineH);\n }\n}\n\nfunction roundRect(ctx: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, r: number): void {\n ctx.beginPath();\n ctx.moveTo(x + r, y);\n ctx.arcTo(x + w, y, x + w, y + h, r);\n ctx.arcTo(x + w, y + h, x, y + h, r);\n ctx.arcTo(x, y + h, x, y, r);\n ctx.arcTo(x, y, x + w, y, r);\n ctx.closePath();\n}\n\nfunction withAlpha(color: string, alpha: number): string {\n // Cheap rgba/hex → rgba conversion. Handles #rgb, #rrggbb, rgb(), rgba().\n if (color.startsWith('#')) {\n let r = 0, g = 0, b = 0;\n if (color.length === 4) {\n r = parseInt(color[1] + color[1], 16);\n g = parseInt(color[2] + color[2], 16);\n b = parseInt(color[3] + color[3], 16);\n } else if (color.length >= 7) {\n r = parseInt(color.slice(1, 3), 16);\n g = parseInt(color.slice(3, 5), 16);\n b = parseInt(color.slice(5, 7), 16);\n }\n return `rgba(${r},${g},${b},${alpha})`;\n }\n if (color.startsWith('rgb')) {\n const nums = color.match(/[\\d.]+/g);\n if (nums && nums.length >= 3) {\n return `rgba(${nums[0]},${nums[1]},${nums[2]},${alpha})`;\n }\n }\n return color;\n}\n","/**\n * Easing functions for smooth animations.\n */\nexport const Easing = {\n linear: (t: number) => t,\n easeOutCubic: (t: number) => 1 - Math.pow(1 - t, 3),\n easeOutQuart: (t: number) => 1 - Math.pow(1 - t, 4),\n easeInOutCubic: (t: number) => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2,\n easeOutExpo: (t: number) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t),\n easeOutElastic: (t: number) => {\n if (t === 0 || t === 1) return t;\n return Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * (2 * Math.PI / 3)) + 1;\n },\n spring: (t: number) => 1 - Math.pow(Math.E, -6 * t) * Math.cos(8 * t),\n};\n\nexport type EasingFn = (t: number) => number;\n\nexport interface AnimationOptions {\n duration: number;\n easing?: EasingFn;\n onUpdate: (progress: number) => void;\n onComplete?: () => void;\n}\n\n/**\n * Lightweight animation scheduler.\n * Runs multiple concurrent animations on the rAF loop.\n */\nexport class Animator {\n private animations = new Map<string, AnimationState>();\n private frameId = 0;\n private running = false;\n\n /**\n * Start a named animation. If one with the same name is running, it's replaced.\n */\n animate(name: string, opts: AnimationOptions): void {\n this.animations.set(name, {\n startTime: -1,\n duration: opts.duration,\n easing: opts.easing ?? Easing.easeOutCubic,\n onUpdate: opts.onUpdate,\n onComplete: opts.onComplete,\n });\n\n if (!this.running) {\n this.running = true;\n this.tick();\n }\n }\n\n /** Cancel a specific animation */\n cancel(name: string): void {\n this.animations.delete(name);\n if (this.animations.size === 0) this.stop();\n }\n\n /** Cancel all animations */\n cancelAll(): void {\n this.animations.clear();\n this.stop();\n }\n\n isAnimating(name?: string): boolean {\n if (name) return this.animations.has(name);\n return this.animations.size > 0;\n }\n\n private tick(): void {\n this.frameId = requestAnimationFrame((now) => {\n const toRemove: string[] = [];\n\n for (const [name, anim] of this.animations) {\n if (anim.startTime < 0) anim.startTime = now;\n\n const elapsed = now - anim.startTime;\n const t = Math.min(1, elapsed / anim.duration);\n const progress = anim.easing(t);\n\n anim.onUpdate(progress);\n\n if (t >= 1) {\n anim.onComplete?.();\n toRemove.push(name);\n }\n }\n\n for (const name of toRemove) this.animations.delete(name);\n\n if (this.animations.size > 0) {\n this.tick();\n } else {\n this.running = false;\n }\n });\n }\n\n private stop(): void {\n if (this.frameId) {\n cancelAnimationFrame(this.frameId);\n this.frameId = 0;\n }\n this.running = false;\n }\n\n dispose(): void {\n this.cancelAll();\n }\n}\n\ninterface AnimationState {\n startTime: number;\n duration: number;\n easing: EasingFn;\n onUpdate: (progress: number) => void;\n onComplete?: () => void;\n}\n","import type { Theme, ThemeName } from '@tradecanvas/commons';\nimport { DARK_THEME, LIGHT_THEME } from '@tradecanvas/commons';\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\nexport abstract class BaseFinanceChart {\n protected canvas: HTMLCanvasElement;\n protected ctx: CanvasRenderingContext2D;\n protected container: HTMLElement;\n protected theme: Theme;\n protected width = 0;\n protected height = 0;\n protected dpr = 1;\n private frameId: number | null = null;\n private resizeObserver: ResizeObserver;\n\n constructor(container: HTMLElement, theme?: ThemeName | Theme) {\n this.container = container;\n this.theme = resolveTheme(theme);\n\n this.canvas = document.createElement('canvas');\n this.canvas.style.width = '100%';\n this.canvas.style.height = '100%';\n this.canvas.style.display = 'block';\n container.appendChild(this.canvas);\n this.ctx = this.canvas.getContext('2d')!;\n\n this.dpr = window.devicePixelRatio || 1;\n this.updateSize();\n\n this.resizeObserver = new ResizeObserver(() => {\n this.updateSize();\n this.requestRender();\n });\n this.resizeObserver.observe(container);\n }\n\n private updateSize(): void {\n this.dpr = window.devicePixelRatio || 1;\n const rect = this.container.getBoundingClientRect();\n this.width = rect.width || this.container.clientWidth;\n this.height = rect.height || this.container.clientHeight;\n this.canvas.width = Math.max(1, Math.floor(this.width * this.dpr));\n this.canvas.height = Math.max(1, Math.floor(this.height * this.dpr));\n }\n\n requestRender(): void {\n if (this.frameId !== null) return;\n this.frameId = requestAnimationFrame(() => {\n this.frameId = null;\n // Ensure we have current size (may have been 0 on first mount)\n if (this.width === 0 || this.height === 0) {\n this.updateSize();\n }\n if (this.width === 0 || this.height === 0) return;\n this.ctx.save();\n this.ctx.scale(this.dpr, this.dpr);\n this.ctx.clearRect(0, 0, this.width, this.height);\n this.renderChart(this.ctx, this.width, this.height, this.theme);\n this.ctx.restore();\n });\n }\n\n protected abstract renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void;\n\n setTheme(theme: ThemeName | Theme): void {\n this.theme = resolveTheme(theme);\n this.requestRender();\n }\n\n destroy(): void {\n if (this.frameId !== null) cancelAnimationFrame(this.frameId);\n this.resizeObserver.disconnect();\n this.canvas.remove();\n }\n}\n","export class FinanceCrosshair {\n private pos: { x: number; y: number } | null = null;\n private canvas: HTMLCanvasElement;\n private onUpdate: () => void;\n\n private handleMove: (e: PointerEvent) => void;\n private handleLeave: () => void;\n\n constructor(canvas: HTMLCanvasElement, onUpdate: () => void) {\n this.canvas = canvas;\n this.onUpdate = onUpdate;\n\n this.handleMove = (e: PointerEvent) => {\n const rect = canvas.getBoundingClientRect();\n this.pos = { x: e.clientX - rect.left, y: e.clientY - rect.top };\n this.onUpdate();\n };\n this.handleLeave = () => {\n this.pos = null;\n this.onUpdate();\n };\n\n canvas.addEventListener('pointermove', this.handleMove);\n canvas.addEventListener('pointerleave', this.handleLeave);\n }\n\n getPosition(): { x: number; y: number } | null {\n return this.pos;\n }\n\n isActive(): boolean {\n return this.pos !== null;\n }\n\n drawCrosshair(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n color: string,\n ): void {\n if (!this.pos) return;\n ctx.save();\n ctx.strokeStyle = color;\n ctx.lineWidth = 0.5;\n ctx.setLineDash([4, 4]);\n // Vertical line\n ctx.beginPath();\n ctx.moveTo(this.pos.x, 0);\n ctx.lineTo(this.pos.x, height);\n ctx.stroke();\n // Horizontal line\n ctx.beginPath();\n ctx.moveTo(0, this.pos.y);\n ctx.lineTo(width, this.pos.y);\n ctx.stroke();\n ctx.restore();\n }\n\n destroy(): void {\n this.canvas.removeEventListener('pointermove', this.handleMove);\n this.canvas.removeEventListener('pointerleave', this.handleLeave);\n }\n}\n","import type { SparklineOptions, Theme } from '@tradecanvas/commons';\n\nexport function renderSparkline(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n options: SparklineOptions,\n theme: Theme,\n): void {\n const { data, mode = 'area', lineWidth = 1.5, showLastPoint = false, showMinMax = false } = options;\n if (data.length < 2 || width <= 0 || height <= 0) return;\n\n const color = options.color ?? theme.lineColor;\n const fillColor = options.fillColor ?? color;\n\n const padding = 2;\n const w = width - padding * 2;\n const h = height - padding * 2;\n\n let min = Infinity;\n let max = -Infinity;\n let minIdx = 0;\n let maxIdx = 0;\n for (let i = 0; i < data.length; i++) {\n if (data[i] < min) { min = data[i]; minIdx = i; }\n if (data[i] > max) { max = data[i]; maxIdx = i; }\n }\n const range = max - min || 1;\n\n const toX = (i: number): number => padding + (i / (data.length - 1)) * w;\n const toY = (v: number): number => padding + h - ((v - min) / range) * h;\n\n // Area fill\n if (mode === 'area') {\n const gradient = ctx.createLinearGradient(0, padding, 0, height - padding);\n gradient.addColorStop(0, fillColor + (fillColor.startsWith('#') ? '40' : ''));\n gradient.addColorStop(1, 'transparent');\n\n ctx.beginPath();\n ctx.moveTo(toX(0), toY(data[0]));\n for (let i = 1; i < data.length; i++) ctx.lineTo(toX(i), toY(data[i]));\n ctx.lineTo(toX(data.length - 1), height - padding);\n ctx.lineTo(toX(0), height - padding);\n ctx.closePath();\n ctx.fillStyle = gradient;\n ctx.fill();\n }\n\n // Line\n ctx.beginPath();\n ctx.moveTo(toX(0), toY(data[0]));\n for (let i = 1; i < data.length; i++) ctx.lineTo(toX(i), toY(data[i]));\n ctx.strokeStyle = color;\n ctx.lineWidth = lineWidth;\n ctx.lineJoin = 'round';\n ctx.stroke();\n\n // Last point dot\n if (showLastPoint) {\n const lastColor = options.lastPointColor ?? color;\n const lx = toX(data.length - 1);\n const ly = toY(data[data.length - 1]);\n ctx.beginPath();\n ctx.arc(lx, ly, 3, 0, Math.PI * 2);\n ctx.fillStyle = lastColor;\n ctx.fill();\n }\n\n // Min/max dots\n if (showMinMax) {\n const minColor = options.minPointColor ?? theme.candleDown;\n const maxColor = options.maxPointColor ?? theme.candleUp;\n // Min\n ctx.beginPath();\n ctx.arc(toX(minIdx), toY(min), 2.5, 0, Math.PI * 2);\n ctx.fillStyle = minColor;\n ctx.fill();\n // Max\n ctx.beginPath();\n ctx.arc(toX(maxIdx), toY(max), 2.5, 0, Math.PI * 2);\n ctx.fillStyle = maxColor;\n ctx.fill();\n }\n}\n","import type { DepthChartOptions, DepthLevel, Theme } from '@tradecanvas/commons';\nimport { computeTickStep } from '@tradecanvas/commons';\n\ninterface CumulativeLevel {\n price: number;\n cumulativeVolume: number;\n}\n\ninterface DepthLayout {\n left: number;\n right: number;\n top: number;\n bottom: number;\n plotWidth: number;\n plotHeight: number;\n}\n\nconst MARGIN_LEFT = 50;\nconst MARGIN_RIGHT = 60;\nconst PADDING_TB = 20;\nconst PRICE_EXTEND_FACTOR = 0.2;\n\nfunction buildCumulativeBids(bids: readonly DepthLevel[]): readonly CumulativeLevel[] {\n const sorted = [...bids].sort((a, b) => b.price - a.price);\n const result: CumulativeLevel[] = [];\n let cumVol = 0;\n for (const level of sorted) {\n cumVol += level.volume;\n result.push({ price: level.price, cumulativeVolume: cumVol });\n }\n return result;\n}\n\nfunction buildCumulativeAsks(asks: readonly DepthLevel[]): readonly CumulativeLevel[] {\n const sorted = [...asks].sort((a, b) => a.price - b.price);\n const result: CumulativeLevel[] = [];\n let cumVol = 0;\n for (const level of sorted) {\n cumVol += level.volume;\n result.push({ price: level.price, cumulativeVolume: cumVol });\n }\n return result;\n}\n\nfunction computeLayout(width: number, height: number): DepthLayout {\n return {\n left: MARGIN_LEFT,\n right: width - MARGIN_RIGHT,\n top: PADDING_TB,\n bottom: height - PADDING_TB,\n plotWidth: width - MARGIN_LEFT - MARGIN_RIGHT,\n plotHeight: height - PADDING_TB * 2,\n };\n}\n\nfunction drawBackground(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n bg: string,\n): void {\n ctx.fillStyle = bg;\n ctx.fillRect(0, 0, width, height);\n}\n\nfunction drawGrid(\n ctx: CanvasRenderingContext2D,\n layout: DepthLayout,\n priceMin: number,\n priceMax: number,\n volMax: number,\n theme: Theme,\n priceFormat: (p: number) => string,\n volumeFormat: (v: number) => string,\n): void {\n const { left, right, top, bottom, plotWidth, plotHeight } = layout;\n\n ctx.save();\n ctx.strokeStyle = theme.grid;\n ctx.lineWidth = 0.5;\n ctx.fillStyle = theme.axisLabel;\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n\n // Horizontal grid (volume)\n const volStep = computeTickStep(0, volMax, 5);\n for (let v = 0; v <= volMax; v += volStep) {\n const y = bottom - (v / volMax) * plotHeight;\n ctx.beginPath();\n ctx.moveTo(left, y);\n ctx.lineTo(right, y);\n ctx.stroke();\n ctx.textAlign = 'right';\n ctx.textBaseline = 'middle';\n ctx.fillText(volumeFormat(v), left - 4, y);\n }\n\n // Vertical grid (price)\n const priceRange = priceMax - priceMin;\n const priceStep = computeTickStep(priceMin, priceMax, 6);\n const firstTick = Math.ceil(priceMin / priceStep) * priceStep;\n for (let p = firstTick; p <= priceMax; p += priceStep) {\n const x = left + ((p - priceMin) / priceRange) * plotWidth;\n ctx.beginPath();\n ctx.moveTo(x, top);\n ctx.lineTo(x, bottom);\n ctx.stroke();\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.fillText(priceFormat(p), x, bottom + 4);\n }\n\n ctx.restore();\n}\n\nfunction drawStepArea(\n ctx: CanvasRenderingContext2D,\n levels: readonly CumulativeLevel[],\n layout: DepthLayout,\n priceMin: number,\n priceRange: number,\n volMax: number,\n fillColor: string,\n lineColor: string,\n direction: 'bid' | 'ask',\n): void {\n if (levels.length === 0) return;\n\n const { left, bottom, plotWidth, plotHeight } = layout;\n const toX = (price: number): number => left + ((price - priceMin) / priceRange) * plotWidth;\n const toY = (vol: number): number => bottom - (vol / volMax) * plotHeight;\n\n // Build step path\n ctx.beginPath();\n if (direction === 'bid') {\n // Bids go right-to-left (highest price first in the sorted array)\n ctx.moveTo(toX(levels[0].price), bottom);\n for (let i = 0; i < levels.length; i++) {\n const x = toX(levels[i].price);\n const y = toY(levels[i].cumulativeVolume);\n ctx.lineTo(x, y);\n if (i < levels.length - 1) {\n ctx.lineTo(toX(levels[i + 1].price), y);\n }\n }\n ctx.lineTo(toX(levels[levels.length - 1].price), bottom);\n } else {\n // Asks go left-to-right (lowest price first)\n ctx.moveTo(toX(levels[0].price), bottom);\n for (let i = 0; i < levels.length; i++) {\n const x = toX(levels[i].price);\n const y = toY(levels[i].cumulativeVolume);\n ctx.lineTo(x, y);\n if (i < levels.length - 1) {\n ctx.lineTo(toX(levels[i + 1].price), y);\n }\n }\n ctx.lineTo(toX(levels[levels.length - 1].price), bottom);\n }\n ctx.closePath();\n\n // Fill\n ctx.fillStyle = fillColor;\n ctx.fill();\n\n // Stroke the step line\n ctx.beginPath();\n if (direction === 'bid') {\n ctx.moveTo(toX(levels[0].price), toY(levels[0].cumulativeVolume));\n for (let i = 0; i < levels.length; i++) {\n const x = toX(levels[i].price);\n const y = toY(levels[i].cumulativeVolume);\n if (i > 0) {\n ctx.lineTo(x, toY(levels[i - 1].cumulativeVolume));\n }\n ctx.lineTo(x, y);\n }\n } else {\n ctx.moveTo(toX(levels[0].price), toY(levels[0].cumulativeVolume));\n for (let i = 1; i < levels.length; i++) {\n const prevY = toY(levels[i - 1].cumulativeVolume);\n const x = toX(levels[i].price);\n const y = toY(levels[i].cumulativeVolume);\n ctx.lineTo(x, prevY);\n ctx.lineTo(x, y);\n }\n }\n ctx.strokeStyle = lineColor;\n ctx.lineWidth = 1.5;\n ctx.stroke();\n}\n\nfunction drawMidPriceLine(\n ctx: CanvasRenderingContext2D,\n midPrice: number,\n spread: number,\n layout: DepthLayout,\n priceMin: number,\n priceRange: number,\n theme: Theme,\n showSpreadLabel: boolean,\n priceFormat: (p: number) => string,\n): void {\n const { left, top, bottom, plotWidth } = layout;\n const x = left + ((midPrice - priceMin) / priceRange) * plotWidth;\n\n ctx.save();\n ctx.strokeStyle = theme.textSecondary;\n ctx.lineWidth = 1;\n ctx.setLineDash([4, 4]);\n ctx.beginPath();\n ctx.moveTo(x, top);\n ctx.lineTo(x, bottom);\n ctx.stroke();\n ctx.restore();\n\n if (showSpreadLabel) {\n const label = `Spread: ${priceFormat(spread)}`;\n ctx.save();\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n ctx.fillStyle = theme.textSecondary;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'bottom';\n ctx.fillText(label, x, top - 2);\n ctx.restore();\n }\n}\n\nfunction drawCrosshairTooltip(\n ctx: CanvasRenderingContext2D,\n crosshairPos: { x: number; y: number },\n cumBids: readonly CumulativeLevel[],\n cumAsks: readonly CumulativeLevel[],\n layout: DepthLayout,\n priceMin: number,\n priceRange: number,\n volMax: number,\n theme: Theme,\n priceFormat: (p: number) => string,\n volumeFormat: (v: number) => string,\n): void {\n const { left, top, bottom, plotWidth, plotHeight } = layout;\n const mx = crosshairPos.x;\n\n if (mx < left || mx > layout.right) return;\n\n const price = priceMin + ((mx - left) / plotWidth) * priceRange;\n\n // Find cumulative volume at this price\n let cumVol = 0;\n let side = '';\n // Check bids (sorted descending by price)\n if (cumBids.length > 0 && price <= cumBids[0].price) {\n side = 'Bid';\n for (const level of cumBids) {\n if (price <= level.price) {\n cumVol = level.cumulativeVolume;\n } else {\n break;\n }\n }\n }\n // Check asks (sorted ascending by price)\n if (cumAsks.length > 0 && price >= cumAsks[0].price) {\n side = 'Ask';\n for (const level of cumAsks) {\n if (price >= level.price) {\n cumVol = level.cumulativeVolume;\n } else {\n break;\n }\n }\n }\n\n // Draw vertical crosshair line\n ctx.save();\n ctx.strokeStyle = theme.crosshair;\n ctx.lineWidth = 0.5;\n ctx.setLineDash([4, 4]);\n ctx.beginPath();\n ctx.moveTo(mx, top);\n ctx.lineTo(mx, bottom);\n ctx.stroke();\n\n // Draw horizontal line at volume level\n if (cumVol > 0) {\n const vy = bottom - (cumVol / volMax) * plotHeight;\n ctx.beginPath();\n ctx.moveTo(left, vy);\n ctx.lineTo(layout.right, vy);\n ctx.stroke();\n }\n ctx.restore();\n\n // Tooltip\n const lines = [\n `Price: ${priceFormat(price)}`,\n side ? `${side} Vol: ${volumeFormat(cumVol)}` : '',\n ].filter(Boolean);\n\n ctx.save();\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n const maxTextWidth = Math.max(...lines.map(l => ctx.measureText(l).width));\n const tooltipW = maxTextWidth + 16;\n const tooltipH = lines.length * (theme.font.sizeSmall + 4) + 12;\n\n let tx = mx + 10;\n let ty = crosshairPos.y - tooltipH / 2;\n if (tx + tooltipW > layout.right) tx = mx - tooltipW - 10;\n if (ty < top) ty = top;\n if (ty + tooltipH > bottom) ty = bottom - tooltipH;\n\n ctx.fillStyle = theme.axisLabelBackground;\n ctx.globalAlpha = 0.9;\n ctx.fillRect(tx, ty, tooltipW, tooltipH);\n ctx.globalAlpha = 1;\n ctx.fillStyle = theme.text;\n ctx.textBaseline = 'top';\n ctx.textAlign = 'left';\n for (let i = 0; i < lines.length; i++) {\n ctx.fillText(lines[i], tx + 8, ty + 6 + i * (theme.font.sizeSmall + 4));\n }\n ctx.restore();\n}\n\nfunction defaultPriceFormat(price: number): string {\n return price.toFixed(2);\n}\n\nfunction defaultVolumeFormat(vol: number): string {\n if (vol >= 1_000_000) return (vol / 1_000_000).toFixed(2) + 'M';\n if (vol >= 1_000) return (vol / 1_000).toFixed(1) + 'K';\n return vol.toFixed(0);\n}\n\nexport function renderDepthChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n options: DepthChartOptions,\n theme: Theme,\n crosshairPos: { x: number; y: number } | null,\n): void {\n const { data } = options;\n if (data.bids.length === 0 && data.asks.length === 0) return;\n if (width <= 0 || height <= 0) return;\n\n const bidColor = options.bidColor ?? theme.candleUp;\n const askColor = options.askColor ?? theme.candleDown;\n const bidFillColor = options.bidFillColor ?? (bidColor + '40');\n const askFillColor = options.askFillColor ?? (askColor + '40');\n const midPriceLine = options.midPriceLine !== false;\n const spreadLabel = options.spreadLabel !== false;\n const priceFormat = options.priceFormat ?? defaultPriceFormat;\n const volumeFormat = options.volumeFormat ?? defaultVolumeFormat;\n\n const cumBids = buildCumulativeBids(data.bids);\n const cumAsks = buildCumulativeAsks(data.asks);\n\n // Compute ranges\n const highestBid = cumBids.length > 0 ? cumBids[0].price : 0;\n const lowestAsk = cumAsks.length > 0 ? cumAsks[0].price : 0;\n const midPrice = cumBids.length > 0 && cumAsks.length > 0\n ? (highestBid + lowestAsk) / 2\n : highestBid || lowestAsk;\n const spread = cumAsks.length > 0 && cumBids.length > 0\n ? lowestAsk - highestBid\n : 0;\n\n const lowestBid = cumBids.length > 0 ? cumBids[cumBids.length - 1].price : midPrice;\n const highestAsk = cumAsks.length > 0 ? cumAsks[cumAsks.length - 1].price : midPrice;\n const rawRange = Math.max(midPrice - lowestBid, highestAsk - midPrice);\n const extendedRange = rawRange * (1 + PRICE_EXTEND_FACTOR);\n\n const priceMin = midPrice - extendedRange;\n const priceMax = midPrice + extendedRange;\n const priceRange = priceMax - priceMin;\n\n const maxBidVol = cumBids.length > 0 ? cumBids[cumBids.length - 1].cumulativeVolume : 0;\n const maxAskVol = cumAsks.length > 0 ? cumAsks[cumAsks.length - 1].cumulativeVolume : 0;\n const volMax = Math.max(maxBidVol, maxAskVol) || 1;\n\n const layout = computeLayout(width, height);\n\n drawBackground(ctx, width, height, theme.background);\n drawGrid(ctx, layout, priceMin, priceMax, volMax, theme, priceFormat, volumeFormat);\n\n drawStepArea(ctx, cumBids, layout, priceMin, priceRange, volMax, bidFillColor, bidColor, 'bid');\n drawStepArea(ctx, cumAsks, layout, priceMin, priceRange, volMax, askFillColor, askColor, 'ask');\n\n if (midPriceLine) {\n drawMidPriceLine(ctx, midPrice, spread, layout, priceMin, priceRange, theme, spreadLabel, priceFormat);\n }\n\n if (crosshairPos) {\n drawCrosshairTooltip(\n ctx, crosshairPos, cumBids, cumAsks,\n layout, priceMin, priceRange, volMax,\n theme, priceFormat, volumeFormat,\n );\n }\n}\n","import type { EquityCurveOptions, EquityPoint, Theme } from '@tradecanvas/commons';\nimport { computeTickStep } from '@tradecanvas/commons';\n\ninterface EquityLayout {\n left: number;\n right: number;\n top: number;\n bottom: number;\n plotWidth: number;\n plotHeight: number;\n}\n\nconst MARGIN_LEFT = 70;\nconst MARGIN_BOTTOM = 30;\nconst PADDING_RIGHT = 20;\nconst PADDING_TOP = 20;\nconst VALUE_PADDING_FACTOR = 0.05;\n\nfunction computeLayout(width: number, height: number): EquityLayout {\n return {\n left: MARGIN_LEFT,\n right: width - PADDING_RIGHT,\n top: PADDING_TOP,\n bottom: height - MARGIN_BOTTOM,\n plotWidth: width - MARGIN_LEFT - PADDING_RIGHT,\n plotHeight: height - PADDING_TOP - MARGIN_BOTTOM,\n };\n}\n\nfunction computeValueRange(\n data: readonly EquityPoint[],\n benchmark: readonly EquityPoint[] | undefined,\n): { valMin: number; valMax: number } {\n let min = Infinity;\n let max = -Infinity;\n for (const pt of data) {\n if (pt.value < min) min = pt.value;\n if (pt.value > max) max = pt.value;\n }\n if (benchmark) {\n for (const pt of benchmark) {\n if (pt.value < min) min = pt.value;\n if (pt.value > max) max = pt.value;\n }\n }\n const padding = (max - min) * VALUE_PADDING_FACTOR;\n return { valMin: min - padding, valMax: max + padding };\n}\n\nfunction buildPeakArray(data: readonly EquityPoint[]): readonly number[] {\n const peaks: number[] = [];\n let peak = -Infinity;\n for (const pt of data) {\n if (pt.value > peak) peak = pt.value;\n peaks.push(peak);\n }\n return peaks;\n}\n\nfunction selectTimeFormat(\n rangeMs: number,\n): (ts: number) => string {\n const DAY = 86_400_000;\n const YEAR = 365.25 * DAY;\n\n if (rangeMs < 7 * DAY) {\n // Show hours\n const fmt = new Intl.DateTimeFormat(undefined, { hour: '2-digit', minute: '2-digit' });\n return (ts: number) => fmt.format(new Date(ts));\n }\n if (rangeMs < YEAR) {\n // Show month/day\n const fmt = new Intl.DateTimeFormat(undefined, { month: 'short', day: 'numeric' });\n return (ts: number) => fmt.format(new Date(ts));\n }\n // Show month/year\n const fmt = new Intl.DateTimeFormat(undefined, { month: 'short', year: 'numeric' });\n return (ts: number) => fmt.format(new Date(ts));\n}\n\nfunction defaultValueFormat(val: number): string {\n if (Math.abs(val) >= 1_000_000) return (val / 1_000_000).toFixed(2) + 'M';\n if (Math.abs(val) >= 1_000) return (val / 1_000).toFixed(1) + 'K';\n return val.toFixed(2);\n}\n\nfunction drawBackground(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n bg: string,\n): void {\n ctx.fillStyle = bg;\n ctx.fillRect(0, 0, width, height);\n}\n\nfunction drawGrid(\n ctx: CanvasRenderingContext2D,\n layout: EquityLayout,\n valMin: number,\n valMax: number,\n timeMin: number,\n timeMax: number,\n theme: Theme,\n valueFormat: (v: number) => string,\n formatTime: (ts: number) => string,\n): void {\n const { left, right, top, bottom, plotWidth, plotHeight } = layout;\n\n ctx.save();\n ctx.strokeStyle = theme.grid;\n ctx.lineWidth = 0.5;\n ctx.fillStyle = theme.axisLabel;\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n\n // Value axis (left) - horizontal grid lines\n const valStep = computeTickStep(valMin, valMax, 6);\n const firstValTick = Math.ceil(valMin / valStep) * valStep;\n for (let v = firstValTick; v <= valMax; v += valStep) {\n const y = bottom - ((v - valMin) / (valMax - valMin)) * plotHeight;\n ctx.beginPath();\n ctx.moveTo(left, y);\n ctx.lineTo(right, y);\n ctx.stroke();\n ctx.textAlign = 'right';\n ctx.textBaseline = 'middle';\n ctx.fillText(valueFormat(v), left - 6, y);\n }\n\n // Time axis (bottom) - vertical grid lines\n const timeRange = timeMax - timeMin;\n const timeStep = computeTickStep(timeMin, timeMax, 6);\n const firstTimeTick = Math.ceil(timeMin / timeStep) * timeStep;\n for (let t = firstTimeTick; t <= timeMax; t += timeStep) {\n const x = left + ((t - timeMin) / timeRange) * plotWidth;\n ctx.beginPath();\n ctx.moveTo(x, top);\n ctx.lineTo(x, bottom);\n ctx.stroke();\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.fillText(formatTime(t), x, bottom + 4);\n }\n\n ctx.restore();\n}\n\nfunction drawLine(\n ctx: CanvasRenderingContext2D,\n data: readonly EquityPoint[],\n layout: EquityLayout,\n timeMin: number,\n timeRange: number,\n valMin: number,\n valRange: number,\n color: string,\n lineWidth: number,\n): void {\n if (data.length < 2) return;\n\n const { left, bottom, plotWidth, plotHeight } = layout;\n const toX = (ts: number): number => left + ((ts - timeMin) / timeRange) * plotWidth;\n const toY = (v: number): number => bottom - ((v - valMin) / valRange) * plotHeight;\n\n ctx.save();\n ctx.beginPath();\n ctx.moveTo(toX(data[0].time), toY(data[0].value));\n for (let i = 1; i < data.length; i++) {\n ctx.lineTo(toX(data[i].time), toY(data[i].value));\n }\n ctx.strokeStyle = color;\n ctx.lineWidth = lineWidth;\n ctx.lineJoin = 'round';\n ctx.stroke();\n ctx.restore();\n}\n\nfunction drawAreaFill(\n ctx: CanvasRenderingContext2D,\n data: readonly EquityPoint[],\n layout: EquityLayout,\n timeMin: number,\n timeRange: number,\n valMin: number,\n valRange: number,\n color: string,\n): void {\n if (data.length < 2) return;\n\n const { left, bottom, plotWidth, plotHeight } = layout;\n const toX = (ts: number): number => left + ((ts - timeMin) / timeRange) * plotWidth;\n const toY = (v: number): number => bottom - ((v - valMin) / valRange) * plotHeight;\n\n const gradient = ctx.createLinearGradient(0, layout.top, 0, bottom);\n gradient.addColorStop(0, color + '40');\n gradient.addColorStop(1, 'transparent');\n\n ctx.save();\n ctx.beginPath();\n ctx.moveTo(toX(data[0].time), toY(data[0].value));\n for (let i = 1; i < data.length; i++) {\n ctx.lineTo(toX(data[i].time), toY(data[i].value));\n }\n ctx.lineTo(toX(data[data.length - 1].time), bottom);\n ctx.lineTo(toX(data[0].time), bottom);\n ctx.closePath();\n ctx.fillStyle = gradient;\n ctx.fill();\n ctx.restore();\n}\n\nfunction drawDrawdown(\n ctx: CanvasRenderingContext2D,\n data: readonly EquityPoint[],\n peaks: readonly number[],\n layout: EquityLayout,\n timeMin: number,\n timeRange: number,\n valMin: number,\n valRange: number,\n drawdownColor: string,\n): void {\n if (data.length < 2) return;\n\n const { left, bottom, plotWidth, plotHeight } = layout;\n const toX = (ts: number): number => left + ((ts - timeMin) / timeRange) * plotWidth;\n const toY = (v: number): number => bottom - ((v - valMin) / valRange) * plotHeight;\n\n ctx.save();\n ctx.fillStyle = drawdownColor;\n ctx.beginPath();\n\n // Draw peak line forward\n ctx.moveTo(toX(data[0].time), toY(peaks[0]));\n for (let i = 1; i < data.length; i++) {\n ctx.lineTo(toX(data[i].time), toY(peaks[i]));\n }\n // Draw equity line backward\n for (let i = data.length - 1; i >= 0; i--) {\n ctx.lineTo(toX(data[i].time), toY(data[i].value));\n }\n ctx.closePath();\n ctx.fill();\n ctx.restore();\n}\n\nfunction drawBenchmarkLabel(\n ctx: CanvasRenderingContext2D,\n benchmark: readonly EquityPoint[],\n layout: EquityLayout,\n timeMin: number,\n timeRange: number,\n valMin: number,\n valRange: number,\n label: string,\n color: string,\n theme: Theme,\n): void {\n if (benchmark.length === 0) return;\n\n const { left, bottom, plotWidth, plotHeight } = layout;\n const last = benchmark[benchmark.length - 1];\n const x = left + ((last.time - timeMin) / timeRange) * plotWidth;\n const y = bottom - ((last.value - valMin) / valRange) * plotHeight;\n\n ctx.save();\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n ctx.fillStyle = color;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, x + 4, y);\n ctx.restore();\n}\n\nfunction drawCrosshairTooltip(\n ctx: CanvasRenderingContext2D,\n crosshairPos: { x: number; y: number },\n data: readonly EquityPoint[],\n benchmark: readonly EquityPoint[] | undefined,\n layout: EquityLayout,\n timeMin: number,\n timeRange: number,\n valMin: number,\n valRange: number,\n theme: Theme,\n formatTime: (ts: number) => string,\n valueFormat: (v: number) => string,\n): void {\n const { left, top, bottom, plotWidth, plotHeight } = layout;\n const mx = crosshairPos.x;\n\n if (mx < left || mx > layout.right) return;\n\n // Vertical crosshair line\n ctx.save();\n ctx.strokeStyle = theme.crosshair;\n ctx.lineWidth = 0.5;\n ctx.setLineDash([4, 4]);\n ctx.beginPath();\n ctx.moveTo(mx, top);\n ctx.lineTo(mx, bottom);\n ctx.stroke();\n ctx.restore();\n\n // Find closest data point\n const timeAtMouse = timeMin + ((mx - left) / plotWidth) * timeRange;\n let closestIdx = 0;\n let closestDist = Infinity;\n for (let i = 0; i < data.length; i++) {\n const dist = Math.abs(data[i].time - timeAtMouse);\n if (dist < closestDist) {\n closestDist = dist;\n closestIdx = i;\n }\n }\n\n const pt = data[closestIdx];\n const lines = [\n formatTime(pt.time),\n `Value: ${valueFormat(pt.value)}`,\n ];\n\n if (benchmark && benchmark.length > closestIdx) {\n lines.push(`Benchmark: ${valueFormat(benchmark[closestIdx].value)}`);\n }\n\n // Draw dot on equity line\n const dotX = left + ((pt.time - timeMin) / timeRange) * plotWidth;\n const dotY = bottom - ((pt.value - valMin) / valRange) * plotHeight;\n ctx.beginPath();\n ctx.arc(dotX, dotY, 3, 0, Math.PI * 2);\n ctx.fillStyle = theme.lineColor;\n ctx.fill();\n\n // Tooltip box\n ctx.save();\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n const maxTextWidth = Math.max(...lines.map(l => ctx.measureText(l).width));\n const tooltipW = maxTextWidth + 16;\n const tooltipH = lines.length * (theme.font.sizeSmall + 4) + 12;\n\n let tx = mx + 10;\n let ty = crosshairPos.y - tooltipH / 2;\n if (tx + tooltipW > layout.right) tx = mx - tooltipW - 10;\n if (ty < top) ty = top;\n if (ty + tooltipH > bottom) ty = bottom - tooltipH;\n\n ctx.fillStyle = theme.axisLabelBackground;\n ctx.globalAlpha = 0.9;\n ctx.fillRect(tx, ty, tooltipW, tooltipH);\n ctx.globalAlpha = 1;\n ctx.fillStyle = theme.text;\n ctx.textBaseline = 'top';\n ctx.textAlign = 'left';\n for (let i = 0; i < lines.length; i++) {\n ctx.fillText(lines[i], tx + 8, ty + 6 + i * (theme.font.sizeSmall + 4));\n }\n ctx.restore();\n}\n\nexport function renderEquityCurve(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n options: EquityCurveOptions,\n theme: Theme,\n crosshairPos: { x: number; y: number } | null,\n): void {\n const { data } = options;\n if (data.length < 2 || width <= 0 || height <= 0) return;\n\n const lineColor = options.lineColor ?? theme.lineColor;\n const lineWidth = options.lineWidth ?? 1.5;\n const drawdownEnabled = options.drawdown === true;\n const drawdownColor = options.drawdownColor ?? (theme.candleDown + '30');\n const fillArea = options.fillArea === true;\n const benchmark = options.benchmark;\n const benchmarkColor = options.benchmarkColor ?? theme.textSecondary;\n const benchmarkLabel = options.benchmarkLabel ?? 'Benchmark';\n const valueFormat = options.valueFormat ?? defaultValueFormat;\n\n const { valMin, valMax } = computeValueRange(data, benchmark);\n const valRange = valMax - valMin || 1;\n\n const timeMin = data[0].time;\n const timeMax = data[data.length - 1].time;\n const timeRange = timeMax - timeMin || 1;\n\n const formatTime = options.timeFormat ?? selectTimeFormat(timeRange);\n const layout = computeLayout(width, height);\n\n drawBackground(ctx, width, height, theme.background);\n drawGrid(ctx, layout, valMin, valMax, timeMin, timeMax, theme, valueFormat, formatTime);\n\n // Drawdown shading\n if (drawdownEnabled) {\n const peaks = buildPeakArray(data);\n drawDrawdown(ctx, data, peaks, layout, timeMin, timeRange, valMin, valRange, drawdownColor);\n }\n\n // Area fill under equity line\n if (fillArea) {\n drawAreaFill(ctx, data, layout, timeMin, timeRange, valMin, valRange, lineColor);\n }\n\n // Equity line\n drawLine(ctx, data, layout, timeMin, timeRange, valMin, valRange, lineColor, lineWidth);\n\n // Benchmark line\n if (benchmark && benchmark.length >= 2) {\n drawLine(ctx, benchmark, layout, timeMin, timeRange, valMin, valRange, benchmarkColor, 1);\n drawBenchmarkLabel(ctx, benchmark, layout, timeMin, timeRange, valMin, valRange, benchmarkLabel, benchmarkColor, theme);\n }\n\n // Crosshair\n if (crosshairPos) {\n drawCrosshairTooltip(\n ctx, crosshairPos, data, benchmark,\n layout, timeMin, timeRange, valMin, valRange,\n theme, formatTime, valueFormat,\n );\n }\n}\n","export interface LayoutRect {\n id: string;\n rect: { x: number; y: number; width: number; height: number };\n}\n\ninterface Bounds {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport function layoutUniformGrid(\n cells: readonly { id: string }[],\n bounds: Bounds,\n padding: number,\n): LayoutRect[] {\n if (cells.length === 0) return [];\n\n const n = cells.length;\n const cols = Math.ceil(Math.sqrt(n));\n const rows = Math.ceil(n / cols);\n\n const cellW = bounds.width / cols;\n const cellH = bounds.height / rows;\n\n const result: LayoutRect[] = [];\n for (let i = 0; i < n; i++) {\n const col = i % cols;\n const row = Math.floor(i / cols);\n result.push({\n id: cells[i].id,\n rect: {\n x: bounds.x + col * cellW + padding,\n y: bounds.y + row * cellH + padding,\n width: Math.max(0, cellW - padding * 2),\n height: Math.max(0, cellH - padding * 2),\n },\n });\n }\n\n return result;\n}\n\nfunction worstAspectRatio(\n row: readonly number[],\n sideLength: number,\n): number {\n const sumRow = row.reduce((a, b) => a + b, 0);\n if (sumRow === 0 || sideLength === 0) return Infinity;\n\n let worst = 0;\n for (const area of row) {\n const rowHeight = sumRow / sideLength;\n const cellWidth = area / rowHeight;\n const ratio = rowHeight > cellWidth\n ? rowHeight / cellWidth\n : cellWidth / rowHeight;\n if (ratio > worst) worst = ratio;\n }\n return worst;\n}\n\nfunction layoutRow(\n row: readonly number[],\n ids: readonly string[],\n bounds: Bounds,\n isWide: boolean,\n padding: number,\n results: LayoutRect[],\n): void {\n const sideLength = isWide ? bounds.height : bounds.width;\n const rowSum = row.reduce((a, b) => a + b, 0);\n const rowThickness = sideLength > 0 ? rowSum / sideLength : 0;\n\n let offset = 0;\n for (let i = 0; i < row.length; i++) {\n const cellLength = rowThickness > 0 ? row[i] / rowThickness : 0;\n\n let rect: { x: number; y: number; width: number; height: number };\n if (isWide) {\n rect = {\n x: bounds.x + padding,\n y: bounds.y + offset + padding,\n width: Math.max(0, rowThickness - padding * 2),\n height: Math.max(0, cellLength - padding * 2),\n };\n } else {\n rect = {\n x: bounds.x + offset + padding,\n y: bounds.y + padding,\n width: Math.max(0, cellLength - padding * 2),\n height: Math.max(0, rowThickness - padding * 2),\n };\n }\n\n results.push({ id: ids[i], rect });\n offset += cellLength;\n }\n}\n\nfunction squarify(\n areas: number[],\n ids: string[],\n bounds: Bounds,\n padding: number,\n results: LayoutRect[],\n): void {\n if (areas.length === 0) return;\n\n const isWide = bounds.width >= bounds.height;\n const sideLength = isWide ? bounds.height : bounds.width;\n\n if (areas.length === 1) {\n layoutRow(areas, ids, bounds, isWide, padding, results);\n return;\n }\n\n const currentRow: number[] = [];\n const currentIds: string[] = [];\n\n let i = 0;\n while (i < areas.length) {\n const testRow = [...currentRow, areas[i]];\n\n if (\n currentRow.length === 0 ||\n worstAspectRatio(testRow, sideLength) <= worstAspectRatio(currentRow, sideLength)\n ) {\n currentRow.push(areas[i]);\n currentIds.push(ids[i]);\n i++;\n } else {\n layoutRow(currentRow, currentIds, bounds, isWide, padding, results);\n const rowSum = currentRow.reduce((a, b) => a + b, 0);\n const rowThickness = sideLength > 0 ? rowSum / sideLength : 0;\n\n if (isWide) {\n bounds = {\n x: bounds.x + rowThickness,\n y: bounds.y,\n width: bounds.width - rowThickness,\n height: bounds.height,\n };\n } else {\n bounds = {\n x: bounds.x,\n y: bounds.y + rowThickness,\n width: bounds.width,\n height: bounds.height - rowThickness,\n };\n }\n\n squarify(areas.slice(i), ids.slice(i), bounds, padding, results);\n return;\n }\n }\n\n if (currentRow.length > 0) {\n layoutRow(currentRow, currentIds, bounds, isWide, padding, results);\n }\n}\n\nexport function layoutSquarifiedTreemap(\n cells: readonly { id: string; weight: number }[],\n bounds: Bounds,\n padding: number,\n): LayoutRect[] {\n if (cells.length === 0) return [];\n\n const sorted = [...cells].sort((a, b) => b.weight - a.weight);\n const totalWeight = sorted.reduce((s, c) => s + Math.max(0, c.weight), 0);\n if (totalWeight === 0) return [];\n\n const totalArea = bounds.width * bounds.height;\n const areas = sorted.map(c => (Math.max(0, c.weight) / totalWeight) * totalArea);\n const ids = sorted.map(c => c.id);\n\n const results: LayoutRect[] = [];\n squarify(areas, ids, { ...bounds }, padding, results);\n return results;\n}\n","import type { HeatmapCell, HeatmapOptions, Theme } from '@tradecanvas/commons';\nimport { lerpColor } from '@tradecanvas/commons';\nimport type { LayoutRect } from './HeatmapLayout.js';\n\nfunction defaultValueFormat(value: number): string {\n const sign = value >= 0 ? '+' : '';\n return sign + value.toFixed(2) + '%';\n}\n\nfunction defaultLabelFormat(cell: HeatmapCell): string {\n return cell.label;\n}\n\nfunction computeCellColor(\n value: number,\n colorScale: NonNullable<HeatmapOptions['colorScale']>,\n): string {\n const min = colorScale.min ?? -5;\n const max = colorScale.max ?? 5;\n\n if (value <= min) return colorScale.negative;\n if (value >= max) return colorScale.positive;\n\n if (value < 0) {\n const t = 1 - value / min;\n return lerpColor(colorScale.negative, colorScale.zero, t);\n }\n const t = value / max;\n return lerpColor(colorScale.zero, colorScale.positive, t);\n}\n\nfunction roundRect(\n ctx: CanvasRenderingContext2D,\n x: number,\n y: number,\n w: number,\n h: number,\n r: number,\n): void {\n const radius = Math.min(r, w / 2, h / 2);\n ctx.beginPath();\n ctx.moveTo(x + radius, y);\n ctx.lineTo(x + w - radius, y);\n ctx.arcTo(x + w, y, x + w, y + radius, radius);\n ctx.lineTo(x + w, y + h - radius);\n ctx.arcTo(x + w, y + h, x + w - radius, y + h, radius);\n ctx.lineTo(x + radius, y + h);\n ctx.arcTo(x, y + h, x, y + h - radius, radius);\n ctx.lineTo(x, y + radius);\n ctx.arcTo(x, y, x + radius, y, radius);\n ctx.closePath();\n}\n\nexport interface HeatmapHitResult {\n cell: HeatmapCell;\n rect: LayoutRect;\n}\n\nfunction drawCellText(\n ctx: CanvasRenderingContext2D,\n cell: HeatmapCell,\n x: number,\n y: number,\n rw: number,\n rh: number,\n theme: Theme,\n showLabels: boolean,\n showValues: boolean,\n formatLabel: (c: HeatmapCell) => string,\n formatValue: (v: number) => string,\n): void {\n if (rw < 40 || rh < 30) return;\n\n const cx = x + rw / 2;\n const cy = y + rh / 2;\n\n ctx.save();\n ctx.shadowColor = 'rgba(0,0,0,0.6)';\n ctx.shadowBlur = 2;\n ctx.fillStyle = '#FFFFFF';\n ctx.textAlign = 'center';\n\n if (showLabels) {\n const labelText = formatLabel(cell);\n const fontSize = Math.min(theme.font.sizeMedium, rw / labelText.length * 1.5, rh / 4);\n ctx.font = 'bold ' + Math.max(8, fontSize) + 'px ' + theme.font.family;\n ctx.textBaseline = showValues ? 'bottom' : 'middle';\n ctx.fillText(labelText, cx, showValues ? cy - 1 : cy, rw - 8);\n }\n\n if (showValues) {\n const valText = formatValue(cell.value);\n const valSize = Math.min(theme.font.sizeSmall, rw / valText.length * 1.5, rh / 4);\n ctx.font = Math.max(7, valSize) + 'px ' + theme.font.family;\n ctx.textBaseline = showLabels ? 'top' : 'middle';\n ctx.fillText(valText, cx, showLabels ? cy + 1 : cy, rw - 8);\n }\n\n ctx.restore();\n}\n\nfunction drawTooltip(\n ctx: CanvasRenderingContext2D,\n cell: HeatmapCell,\n crosshairPos: { x: number; y: number },\n width: number,\n height: number,\n theme: Theme,\n formatLabel: (c: HeatmapCell) => string,\n formatValue: (v: number) => string,\n): void {\n const lines = [\n formatLabel(cell),\n formatValue(cell.value),\n ];\n if (cell.meta) {\n for (const [key, val] of Object.entries(cell.meta)) {\n lines.push(key + ': ' + String(val));\n }\n }\n\n ctx.save();\n ctx.font = theme.font.sizeSmall + 'px ' + theme.font.family;\n const maxTextW = Math.max(...lines.map(l => ctx.measureText(l).width));\n const tooltipW = maxTextW + 16;\n const lineH = theme.font.sizeSmall + 4;\n const tooltipH = lines.length * lineH + 12;\n\n let tx = crosshairPos.x + 14;\n let ty = crosshairPos.y - tooltipH / 2;\n if (tx + tooltipW > width) tx = crosshairPos.x - tooltipW - 14;\n if (ty < 0) ty = 0;\n if (ty + tooltipH > height) ty = height - tooltipH;\n\n ctx.fillStyle = theme.axisLabelBackground;\n ctx.globalAlpha = 0.92;\n roundRect(ctx, tx, ty, tooltipW, tooltipH, 4);\n ctx.fill();\n ctx.globalAlpha = 1;\n ctx.fillStyle = theme.text;\n ctx.textBaseline = 'top';\n ctx.textAlign = 'left';\n for (let i = 0; i < lines.length; i++) {\n ctx.fillText(lines[i], tx + 8, ty + 6 + i * lineH);\n }\n ctx.restore();\n}\n\nexport function renderHeatmap(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n cells: readonly HeatmapCell[],\n layoutRects: readonly LayoutRect[],\n options: HeatmapOptions,\n theme: Theme,\n crosshairPos: { x: number; y: number } | null,\n): HeatmapHitResult | null {\n if (cells.length === 0 || layoutRects.length === 0 || width <= 0 || height <= 0) return null;\n\n const colorScale = options.colorScale ?? {\n negative: '#EF5350',\n zero: '#424242',\n positive: '#26A69A',\n };\n const cellRadius = options.cellRadius ?? 4;\n const showLabels = options.showLabels !== false;\n const showValues = options.showValues !== false;\n const formatValue = options.valueFormat ?? defaultValueFormat;\n const formatLabel = options.labelFormat ?? defaultLabelFormat;\n\n const cellMap = new Map<string, HeatmapCell>();\n for (const c of cells) cellMap.set(c.id, c);\n\n let hoveredId: string | null = null;\n let hitResult: HeatmapHitResult | null = null;\n\n if (crosshairPos) {\n for (const lr of layoutRects) {\n const { x, y, width: rw, height: rh } = lr.rect;\n if (\n crosshairPos.x >= x &&\n crosshairPos.x <= x + rw &&\n crosshairPos.y >= y &&\n crosshairPos.y <= y + rh\n ) {\n hoveredId = lr.id;\n const cell = cellMap.get(lr.id);\n if (cell) {\n hitResult = { cell, rect: lr };\n }\n break;\n }\n }\n }\n\n ctx.fillStyle = theme.background;\n ctx.fillRect(0, 0, width, height);\n\n for (const lr of layoutRects) {\n const cell = cellMap.get(lr.id);\n if (!cell) continue;\n\n const { x, y, width: rw, height: rh } = lr.rect;\n if (rw <= 0 || rh <= 0) continue;\n\n const bgColor = computeCellColor(cell.value, colorScale);\n roundRect(ctx, x, y, rw, rh, cellRadius);\n ctx.fillStyle = bgColor;\n ctx.fill();\n\n drawCellText(ctx, cell, x, y, rw, rh, theme, showLabels, showValues, formatLabel, formatValue);\n\n if (lr.id === hoveredId) {\n roundRect(ctx, x, y, rw, rh, cellRadius);\n ctx.strokeStyle = '#FFFFFF';\n ctx.lineWidth = 1.5;\n ctx.stroke();\n }\n }\n\n if (hitResult && crosshairPos) {\n drawTooltip(ctx, hitResult.cell, crosshairPos, width, height, theme, formatLabel, formatValue);\n }\n\n return hitResult;\n}\n","import type { Theme, WaterfallBar, WaterfallOptions } from '@tradecanvas/commons';\nimport { computeTickStep } from '@tradecanvas/commons';\n\ntype BarType = 'positive' | 'negative' | 'total' | 'subtotal';\n\ninterface WaterfallLayoutBar {\n label: string;\n value: number;\n start: number;\n end: number;\n type: BarType;\n rectX: number;\n rectY: number;\n rectW: number;\n rectH: number;\n slotX: number;\n slotW: number;\n}\n\ninterface WaterfallLayout {\n left: number;\n right: number;\n top: number;\n bottom: number;\n plotWidth: number;\n plotHeight: number;\n}\n\nconst MARGIN_LEFT = 60;\nconst MARGIN_RIGHT = 12;\nconst MARGIN_TOP = 24;\nconst MARGIN_BOTTOM = 40;\nconst DEFAULT_BAR_WIDTH_RATIO = 0.7;\nconst MIN_BAR_HEIGHT = 1;\n\nfunction resolveType(bar: WaterfallBar): BarType {\n if (bar.type) return bar.type;\n if (bar.value > 0) return 'positive';\n if (bar.value < 0) return 'negative';\n return 'subtotal';\n}\n\nfunction defaultValueFormat(v: number): string {\n const abs = Math.abs(v);\n if (abs >= 1_000_000) return (v / 1_000_000).toFixed(2) + 'M';\n if (abs >= 1_000) return (v / 1_000).toFixed(1) + 'K';\n return v.toFixed(2);\n}\n\nfunction computeLayout(width: number, height: number): WaterfallLayout {\n return {\n left: MARGIN_LEFT,\n right: width - MARGIN_RIGHT,\n top: MARGIN_TOP,\n bottom: height - MARGIN_BOTTOM,\n plotWidth: width - MARGIN_LEFT - MARGIN_RIGHT,\n plotHeight: height - MARGIN_TOP - MARGIN_BOTTOM,\n };\n}\n\nfunction buildLayoutBars(\n data: readonly WaterfallBar[],\n layout: WaterfallLayout,\n barWidthRatio: number,\n valMin: number,\n valRange: number,\n): { bars: WaterfallLayoutBar[]; cumulatives: number[] } {\n const bars: WaterfallLayoutBar[] = new Array(data.length);\n const cumulatives: number[] = new Array(data.length);\n const slotWidth = layout.plotWidth / data.length;\n const barW = slotWidth * barWidthRatio;\n const slotPadding = (slotWidth - barW) / 2;\n const { left, bottom, plotHeight } = layout;\n\n let cumulative = 0;\n for (let i = 0; i < data.length; i++) {\n const bar = data[i];\n const type = resolveType(bar);\n let start: number;\n let end: number;\n\n if (type === 'total' || type === 'subtotal') {\n start = 0;\n end = bar.value;\n cumulative = bar.value;\n } else {\n start = cumulative;\n end = cumulative + bar.value;\n cumulative = end;\n }\n\n const top = Math.min(start, end);\n const bot = Math.max(start, end);\n const topY = bottom - ((top - valMin) / valRange) * plotHeight;\n const botY = bottom - ((bot - valMin) / valRange) * plotHeight;\n const rectY = Math.min(topY, botY);\n const rectH = Math.max(Math.abs(botY - topY), MIN_BAR_HEIGHT);\n const slotX = left + i * slotWidth;\n const rectX = slotX + slotPadding;\n\n bars[i] = {\n label: bar.label,\n value: bar.value,\n start,\n end,\n type,\n rectX,\n rectY,\n rectW: barW,\n rectH,\n slotX,\n slotW: slotWidth,\n };\n cumulatives[i] = cumulative;\n }\n\n return { bars, cumulatives };\n}\n\nfunction computeValueRange(\n data: readonly WaterfallBar[],\n): { valMin: number; valMax: number } {\n if (data.length === 0) return { valMin: 0, valMax: 1 };\n\n let min = 0;\n let max = 0;\n let cumulative = 0;\n\n for (let i = 0; i < data.length; i++) {\n const bar = data[i];\n const type = resolveType(bar);\n let start: number;\n let end: number;\n\n if (type === 'total' || type === 'subtotal') {\n start = 0;\n end = bar.value;\n cumulative = bar.value;\n } else {\n start = cumulative;\n end = cumulative + bar.value;\n cumulative = end;\n }\n\n if (start < min) min = start;\n if (end < min) min = end;\n if (start > max) max = start;\n if (end > max) max = end;\n }\n\n const range = max - min || 1;\n const padding = range * 0.1;\n return { valMin: min - padding, valMax: max + padding };\n}\n\nfunction drawBackground(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n bg: string,\n): void {\n ctx.fillStyle = bg;\n ctx.fillRect(0, 0, width, height);\n}\n\nfunction drawGrid(\n ctx: CanvasRenderingContext2D,\n layout: WaterfallLayout,\n valMin: number,\n valMax: number,\n theme: Theme,\n valueFormat: (v: number) => string,\n): void {\n const { left, right, top, bottom, plotHeight } = layout;\n const valRange = valMax - valMin || 1;\n\n ctx.strokeStyle = theme.grid;\n ctx.lineWidth = 0.5;\n ctx.fillStyle = theme.axisLabel;\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n ctx.textAlign = 'right';\n ctx.textBaseline = 'middle';\n\n const step = computeTickStep(valMin, valMax, 5);\n const firstTick = Math.ceil(valMin / step) * step;\n\n // Batch horizontal grid lines\n ctx.beginPath();\n for (let v = firstTick; v <= valMax; v += step) {\n const y = Math.round(bottom - ((v - valMin) / valRange) * plotHeight) + 0.5;\n if (y < top || y > bottom) continue;\n ctx.moveTo(left, y);\n ctx.lineTo(right, y);\n }\n ctx.stroke();\n\n // Labels\n for (let v = firstTick; v <= valMax; v += step) {\n const y = bottom - ((v - valMin) / valRange) * plotHeight;\n if (y < top - 1 || y > bottom + 1) continue;\n ctx.fillText(valueFormat(v), left - 6, y);\n }\n\n // Zero baseline\n if (valMin < 0 && valMax > 0) {\n const zeroY = Math.round(bottom - ((0 - valMin) / valRange) * plotHeight) + 0.5;\n ctx.strokeStyle = theme.axisLine;\n ctx.lineWidth = 1;\n ctx.beginPath();\n ctx.moveTo(left, zeroY);\n ctx.lineTo(right, zeroY);\n ctx.stroke();\n }\n}\n\nfunction drawBars(\n ctx: CanvasRenderingContext2D,\n bars: readonly WaterfallLayoutBar[],\n colors: Record<BarType, string>,\n): void {\n // Group bars by color, draw each color group in a single fill() call.\n // This minimizes fillStyle mutations and path starts.\n const groupOrder: BarType[] = ['positive', 'negative', 'total', 'subtotal'];\n for (let g = 0; g < groupOrder.length; g++) {\n const type = groupOrder[g];\n const color = colors[type];\n let hasAny = false;\n ctx.beginPath();\n for (let i = 0; i < bars.length; i++) {\n const b = bars[i];\n if (b.type !== type) continue;\n const x = Math.round(b.rectX);\n const y = Math.round(b.rectY);\n const w = Math.round(b.rectW);\n const h = Math.round(b.rectH);\n ctx.rect(x, y, w, h);\n hasAny = true;\n }\n if (hasAny) {\n ctx.fillStyle = color;\n ctx.fill();\n }\n }\n}\n\nfunction drawConnectors(\n ctx: CanvasRenderingContext2D,\n bars: readonly WaterfallLayoutBar[],\n layout: WaterfallLayout,\n valMin: number,\n valRange: number,\n color: string,\n style: 'dashed' | 'solid' | 'none',\n): void {\n if (style === 'none' || bars.length < 2) return;\n\n const { bottom, plotHeight } = layout;\n\n ctx.strokeStyle = color;\n ctx.lineWidth = 1;\n if (style === 'dashed') {\n ctx.setLineDash([4, 4]);\n } else {\n ctx.setLineDash([]);\n }\n\n // Batch all connectors into a single path\n ctx.beginPath();\n for (let i = 0; i < bars.length - 1; i++) {\n const current = bars[i];\n const next = bars[i + 1];\n\n // Connector sits at the \"end\" of current bar (running total).\n // For total/subtotal bars, end is bar.value (absolute).\n // For gain/loss, end is the post-bar cumulative.\n const endValue = current.end;\n const y = Math.round(bottom - ((endValue - valMin) / valRange) * plotHeight) + 0.5;\n\n const x1 = Math.round(current.rectX + current.rectW);\n const x2 = Math.round(next.rectX);\n if (x2 <= x1) continue;\n\n ctx.moveTo(x1, y);\n ctx.lineTo(x2, y);\n }\n ctx.stroke();\n ctx.setLineDash([]);\n}\n\nfunction drawValueLabels(\n ctx: CanvasRenderingContext2D,\n bars: readonly WaterfallLayoutBar[],\n cumulatives: readonly number[],\n theme: Theme,\n valueFormat: (v: number) => string,\n showDelta: boolean,\n): void {\n ctx.fillStyle = theme.text;\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n ctx.textAlign = 'center';\n\n for (let i = 0; i < bars.length; i++) {\n const b = bars[i];\n let text: string;\n if (b.type === 'total' || b.type === 'subtotal') {\n text = valueFormat(b.value);\n } else if (showDelta) {\n const sign = b.value >= 0 ? '+' : '';\n text = `${sign}${valueFormat(b.value)}`;\n } else {\n text = valueFormat(cumulatives[i]);\n }\n\n const cx = b.rectX + b.rectW / 2;\n // If bar goes down (negative gain/loss), put label below\n const isDown = b.end < b.start;\n if (isDown) {\n ctx.textBaseline = 'top';\n ctx.fillText(text, cx, b.rectY + b.rectH + 4);\n } else {\n ctx.textBaseline = 'bottom';\n ctx.fillText(text, cx, b.rectY - 4);\n }\n }\n}\n\nfunction drawCategoryLabels(\n ctx: CanvasRenderingContext2D,\n bars: readonly WaterfallLayoutBar[],\n layout: WaterfallLayout,\n theme: Theme,\n labelFormat: (label: string) => string,\n): void {\n ctx.fillStyle = theme.axisLabel;\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n\n const labelY = layout.bottom + 6;\n const maxWidth = bars.length > 0 ? bars[0].slotW - 4 : 0;\n\n // Rotate if any label would overflow its slot\n let needsRotate = false;\n for (let i = 0; i < bars.length; i++) {\n const w = ctx.measureText(labelFormat(bars[i].label)).width;\n if (w > maxWidth) { needsRotate = true; break; }\n }\n\n if (!needsRotate) {\n for (let i = 0; i < bars.length; i++) {\n const b = bars[i];\n const cx = b.slotX + b.slotW / 2;\n ctx.fillText(labelFormat(b.label), cx, labelY);\n }\n return;\n }\n\n // Rotated path: save/restore once, mutate transform per label\n ctx.save();\n ctx.textAlign = 'right';\n ctx.textBaseline = 'middle';\n for (let i = 0; i < bars.length; i++) {\n const b = bars[i];\n const cx = b.slotX + b.slotW / 2;\n ctx.setTransform(1, 0, 0, 1, cx, labelY + 4);\n ctx.rotate(-Math.PI / 4);\n ctx.fillText(labelFormat(b.label), 0, 0);\n }\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.restore();\n}\n\nfunction findHitBar(\n bars: readonly WaterfallLayoutBar[],\n x: number,\n layout: WaterfallLayout,\n): number | null {\n if (x < layout.left || x > layout.right) return null;\n // Slot-based hit test (covers gaps between bars too)\n for (let i = 0; i < bars.length; i++) {\n const b = bars[i];\n if (x >= b.slotX && x <= b.slotX + b.slotW) return i;\n }\n return null;\n}\n\nfunction drawCrosshairTooltip(\n ctx: CanvasRenderingContext2D,\n bars: readonly WaterfallLayoutBar[],\n cumulatives: readonly number[],\n hitIndex: number,\n crosshairPos: { x: number; y: number },\n layout: WaterfallLayout,\n theme: Theme,\n valueFormat: (v: number) => string,\n): void {\n const bar = bars[hitIndex];\n const cumulative = cumulatives[hitIndex];\n\n // Vertical guide line across the slot center\n const cx = Math.round(bar.slotX + bar.slotW / 2) + 0.5;\n ctx.strokeStyle = theme.crosshair;\n ctx.lineWidth = 0.5;\n ctx.setLineDash([4, 4]);\n ctx.beginPath();\n ctx.moveTo(cx, layout.top);\n ctx.lineTo(cx, layout.bottom);\n ctx.stroke();\n ctx.setLineDash([]);\n\n const lines = [\n bar.label,\n `Value: ${bar.value >= 0 && (bar.type === 'positive' || bar.type === 'negative') ? '+' : ''}${valueFormat(bar.value)}`,\n `Total: ${valueFormat(cumulative)}`,\n ];\n\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n let maxTextWidth = 0;\n for (let i = 0; i < lines.length; i++) {\n const w = ctx.measureText(lines[i]).width;\n if (w > maxTextWidth) maxTextWidth = w;\n }\n const tooltipW = maxTextWidth + 16;\n const tooltipH = lines.length * (theme.font.sizeSmall + 4) + 12;\n\n let tx = crosshairPos.x + 10;\n let ty = crosshairPos.y - tooltipH / 2;\n if (tx + tooltipW > layout.right) tx = crosshairPos.x - tooltipW - 10;\n if (ty < layout.top) ty = layout.top;\n if (ty + tooltipH > layout.bottom) ty = layout.bottom - tooltipH;\n\n ctx.fillStyle = theme.axisLabelBackground;\n ctx.globalAlpha = 0.9;\n ctx.fillRect(tx, ty, tooltipW, tooltipH);\n ctx.globalAlpha = 1;\n ctx.fillStyle = theme.text;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'top';\n const lineH = theme.font.sizeSmall + 4;\n for (let i = 0; i < lines.length; i++) {\n ctx.fillText(lines[i], tx + 8, ty + 6 + i * lineH);\n }\n}\n\nexport function renderWaterfall(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n options: WaterfallOptions,\n theme: Theme,\n crosshairPos: { x: number; y: number } | null,\n): { hitBar: number | null } {\n const { data } = options;\n if (!data || data.length === 0 || width <= 0 || height <= 0) {\n return { hitBar: null };\n }\n\n const positiveColor = options.positiveColor ?? theme.candleUp;\n const negativeColor = options.negativeColor ?? theme.candleDown;\n const totalColor = options.totalColor ?? theme.lineColor;\n const subtotalColor = options.subtotalColor ?? theme.textSecondary;\n const connectorColor = options.connectorColor ?? theme.textSecondary;\n const connectorStyle = options.connectorStyle ?? 'dashed';\n const barWidthRatio = options.barWidth ?? DEFAULT_BAR_WIDTH_RATIO;\n const showValues = options.showValues !== false;\n const showDelta = options.showDelta !== false;\n const valueFormat = options.valueFormat ?? defaultValueFormat;\n const labelFormat = options.labelFormat ?? ((l: string) => l);\n\n const { valMin, valMax } = computeValueRange(data);\n const valRange = valMax - valMin || 1;\n const layout = computeLayout(width, height);\n const { bars, cumulatives } = buildLayoutBars(data, layout, barWidthRatio, valMin, valRange);\n\n drawBackground(ctx, width, height, theme.background);\n drawGrid(ctx, layout, valMin, valMax, theme, valueFormat);\n\n // Connectors first (behind bars)\n drawConnectors(ctx, bars, layout, valMin, valRange, connectorColor, connectorStyle);\n\n // Bars (batched by color)\n drawBars(ctx, bars, {\n positive: positiveColor,\n negative: negativeColor,\n total: totalColor,\n subtotal: subtotalColor,\n });\n\n if (showValues) {\n drawValueLabels(ctx, bars, cumulatives, theme, valueFormat, showDelta);\n }\n\n drawCategoryLabels(ctx, bars, layout, theme, labelFormat);\n\n // Crosshair / tooltip\n const hitBar = crosshairPos ? findHitBar(bars, crosshairPos.x, layout) : null;\n if (crosshairPos && hitBar !== null) {\n drawCrosshairTooltip(ctx, bars, cumulatives, hitBar, crosshairPos, layout, theme, valueFormat);\n }\n\n return { hitBar };\n}\n","import type { GaugeOptions, GaugeZone, Theme } from '@tradecanvas/commons';\n\nconst DEG_TO_RAD = Math.PI / 180;\nconst DEFAULT_START_DEG = 135; // bottom-left (canvas: angle measured from +x axis, clockwise)\nconst DEFAULT_END_DEG = 405; // bottom-right (135 + 270)\nconst DEFAULT_THICKNESS = 0.25;\n\ninterface GaugeGeometry {\n cx: number;\n cy: number;\n radius: number;\n innerRadius: number;\n startAngle: number;\n endAngle: number;\n angleRange: number;\n min: number;\n max: number;\n range: number;\n}\n\nfunction defaultValueFormat(v: number): string {\n const abs = Math.abs(v);\n if (abs >= 1_000_000) return (v / 1_000_000).toFixed(2) + 'M';\n if (abs >= 1_000) return (v / 1_000).toFixed(1) + 'K';\n if (Number.isInteger(v)) return v.toFixed(0);\n return v.toFixed(1);\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n if (value < min) return min;\n if (value > max) return max;\n return value;\n}\n\nfunction computeGeometry(\n width: number,\n height: number,\n options: GaugeOptions,\n): GaugeGeometry {\n const min = options.min ?? 0;\n const max = options.max ?? 100;\n const range = (max - min) || 1;\n\n const startAngle = (options.startAngle ?? DEFAULT_START_DEG) * DEG_TO_RAD;\n const endAngle = (options.endAngle ?? DEFAULT_END_DEG) * DEG_TO_RAD;\n const thicknessRatio = options.thickness ?? DEFAULT_THICKNESS;\n\n // Leave room for labels\n const margin = 24;\n const cx = width / 2;\n // Bias center down a bit so the open bottom has room for labels\n const cy = height / 2 + height * 0.05;\n const radius = Math.max(10, Math.min(width, height) / 2 - margin);\n const innerRadius = Math.max(2, radius * (1 - thicknessRatio));\n\n return {\n cx,\n cy,\n radius,\n innerRadius,\n startAngle,\n endAngle,\n angleRange: endAngle - startAngle,\n min,\n max,\n range,\n };\n}\n\nfunction valueToAngle(value: number, geo: GaugeGeometry): number {\n const t = clamp((value - geo.min) / geo.range, 0, 1);\n return geo.startAngle + geo.angleRange * t;\n}\n\nfunction drawBackground(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n bg: string,\n): void {\n ctx.fillStyle = bg;\n ctx.fillRect(0, 0, width, height);\n}\n\nfunction drawTrackArc(\n ctx: CanvasRenderingContext2D,\n geo: GaugeGeometry,\n trackColor: string,\n): void {\n ctx.beginPath();\n ctx.arc(geo.cx, geo.cy, geo.radius, geo.startAngle, geo.endAngle, false);\n ctx.arc(geo.cx, geo.cy, geo.innerRadius, geo.endAngle, geo.startAngle, true);\n ctx.closePath();\n ctx.fillStyle = trackColor;\n ctx.fill();\n}\n\nfunction drawZoneArc(\n ctx: CanvasRenderingContext2D,\n geo: GaugeGeometry,\n zone: GaugeZone,\n): void {\n const from = clamp(zone.from, geo.min, geo.max);\n const to = clamp(zone.to, geo.min, geo.max);\n if (to <= from) return;\n\n const a0 = valueToAngle(from, geo);\n const a1 = valueToAngle(to, geo);\n\n ctx.beginPath();\n ctx.arc(geo.cx, geo.cy, geo.radius, a0, a1, false);\n ctx.arc(geo.cx, geo.cy, geo.innerRadius, a1, a0, true);\n ctx.closePath();\n ctx.fillStyle = zone.color;\n ctx.fill();\n}\n\nfunction drawValueArc(\n ctx: CanvasRenderingContext2D,\n geo: GaugeGeometry,\n value: number,\n color: string,\n alpha: number,\n): void {\n const valueAngle = valueToAngle(value, geo);\n if (valueAngle <= geo.startAngle) return;\n\n ctx.globalAlpha = alpha;\n ctx.beginPath();\n ctx.arc(geo.cx, geo.cy, geo.radius, geo.startAngle, valueAngle, false);\n ctx.arc(geo.cx, geo.cy, geo.innerRadius, valueAngle, geo.startAngle, true);\n ctx.closePath();\n ctx.fillStyle = color;\n ctx.fill();\n ctx.globalAlpha = 1;\n}\n\nfunction drawNeedle(\n ctx: CanvasRenderingContext2D,\n geo: GaugeGeometry,\n value: number,\n color: string,\n): void {\n const angle = valueToAngle(value, geo);\n // Cache trig\n const cos = Math.cos(angle);\n const sin = Math.sin(angle);\n\n const tipRadius = geo.radius - 2;\n const baseRadius = geo.innerRadius * 0.25;\n\n // Needle as a narrow triangle for better presence; all in one path.\n const perpX = -sin;\n const perpY = cos;\n const baseHalf = 4;\n\n const tipX = geo.cx + cos * tipRadius;\n const tipY = geo.cy + sin * tipRadius;\n const leftX = geo.cx + perpX * baseHalf - cos * baseRadius;\n const leftY = geo.cy + perpY * baseHalf - sin * baseRadius;\n const rightX = geo.cx - perpX * baseHalf - cos * baseRadius;\n const rightY = geo.cy - perpY * baseHalf - sin * baseRadius;\n\n ctx.beginPath();\n ctx.moveTo(tipX, tipY);\n ctx.lineTo(leftX, leftY);\n ctx.lineTo(rightX, rightY);\n ctx.closePath();\n ctx.fillStyle = color;\n ctx.fill();\n\n // Center hub\n ctx.beginPath();\n ctx.arc(geo.cx, geo.cy, Math.max(4, geo.innerRadius * 0.12), 0, Math.PI * 2);\n ctx.fill();\n}\n\nfunction drawCenterLabel(\n ctx: CanvasRenderingContext2D,\n geo: GaugeGeometry,\n valueText: string,\n subtitle: string | undefined,\n theme: Theme,\n): void {\n const mainSize = Math.round(geo.innerRadius * 0.55);\n const subSize = Math.round(theme.font.sizeMedium);\n\n ctx.fillStyle = theme.text;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.font = `600 ${mainSize}px ${theme.font.family}`;\n\n const hasSubtitle = !!subtitle;\n const mainY = hasSubtitle ? geo.cy - subSize * 0.6 : geo.cy - mainSize * 0.1;\n ctx.fillText(valueText, geo.cx, mainY);\n\n if (hasSubtitle) {\n ctx.fillStyle = theme.textSecondary;\n ctx.font = `${subSize}px ${theme.font.family}`;\n ctx.fillText(subtitle!, geo.cx, geo.cy + mainSize * 0.55);\n }\n}\n\nfunction drawEndLabels(\n ctx: CanvasRenderingContext2D,\n geo: GaugeGeometry,\n valueFormat: (v: number) => string,\n theme: Theme,\n): void {\n ctx.fillStyle = theme.textSecondary;\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n\n // Min at start angle, max at end angle — positioned slightly outside the track\n const labelRadius = geo.radius + 10;\n\n const minCos = Math.cos(geo.startAngle);\n const minSin = Math.sin(geo.startAngle);\n const maxCos = Math.cos(geo.endAngle);\n const maxSin = Math.sin(geo.endAngle);\n\n const minX = geo.cx + minCos * labelRadius;\n const minY = geo.cy + minSin * labelRadius;\n const maxX = geo.cx + maxCos * labelRadius;\n const maxY = geo.cy + maxSin * labelRadius;\n\n ctx.textBaseline = 'middle';\n ctx.textAlign = minCos < -0.2 ? 'right' : minCos > 0.2 ? 'left' : 'center';\n ctx.fillText(valueFormat(geo.min), minX, minY);\n\n ctx.textAlign = maxCos < -0.2 ? 'right' : maxCos > 0.2 ? 'left' : 'center';\n ctx.fillText(valueFormat(geo.max), maxX, maxY);\n}\n\nfunction drawZoneLabels(\n ctx: CanvasRenderingContext2D,\n geo: GaugeGeometry,\n zones: readonly GaugeZone[],\n theme: Theme,\n): void {\n ctx.fillStyle = theme.textSecondary;\n ctx.font = `${theme.font.sizeSmall}px ${theme.font.family}`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n\n const labelRadius = (geo.radius + geo.innerRadius) / 2;\n\n for (let i = 0; i < zones.length; i++) {\n const zone = zones[i];\n if (!zone.label) continue;\n const mid = (clamp(zone.from, geo.min, geo.max) + clamp(zone.to, geo.min, geo.max)) / 2;\n const angle = valueToAngle(mid, geo);\n const x = geo.cx + Math.cos(angle) * labelRadius;\n const y = geo.cy + Math.sin(angle) * labelRadius;\n ctx.fillText(zone.label, x, y);\n }\n}\n\nexport function renderGauge(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n options: GaugeOptions,\n theme: Theme,\n displayValue: number,\n): void {\n if (width <= 0 || height <= 0) return;\n\n const geo = computeGeometry(width, height, options);\n const trackColor = options.trackColor ?? theme.grid;\n const needleColor = options.needleColor ?? theme.text;\n const showValue = options.showValue !== false;\n const showZoneLabels = options.showZoneLabels === true;\n const valueFormat = options.valueFormat ?? defaultValueFormat;\n\n const clampedValue = clamp(displayValue, geo.min, geo.max);\n\n drawBackground(ctx, width, height, theme.background);\n\n // 1. Track\n drawTrackArc(ctx, geo, trackColor);\n\n // 2. Zones\n const zones = options.zones;\n if (zones && zones.length > 0) {\n for (let i = 0; i < zones.length; i++) {\n drawZoneArc(ctx, geo, zones[i]);\n }\n }\n\n // 3. Value arc — subtle tint using needle color (or text color) so the filled\n // portion reads even when zones are transparent.\n drawValueArc(ctx, geo, clampedValue, needleColor, 0.12);\n\n // 4. Needle + hub\n drawNeedle(ctx, geo, clampedValue, needleColor);\n\n // 5. Center labels\n if (showValue) {\n drawCenterLabel(ctx, geo, valueFormat(clampedValue), options.label, theme);\n }\n\n // 6. Min/max labels\n drawEndLabels(ctx, geo, valueFormat, theme);\n\n // 7. Zone labels\n if (showZoneLabels && zones && zones.length > 0) {\n drawZoneLabels(ctx, geo, zones, theme);\n }\n}\n"],"mappings":"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"}