@tradecanvas/commons 1.65.0 → 1.66.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.
- package/dist/icons/iconSet.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/types/drawing.d.ts +9 -1
- package/dist/types/drawing.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/types/rendering.ts","../src/types/style.ts","../src/types/drawing.ts","../src/types/trading.ts","../src/types/signal.ts","../src/types/realtime.ts","../src/types/quote.ts","../src/types/news.ts","../src/utils/math.ts","../src/utils/data.ts","../src/utils/color.ts","../src/utils/timezone.ts","../src/utils/time.ts","../src/utils/precision.ts","../src/utils/priceSource.ts","../src/utils/resample.ts","../src/utils/symbols.ts","../src/utils/marketStatus.ts","../src/utils/drawingOptions.ts","../src/utils/drawingStyle.ts","../src/utils/chartTypeOptions.ts","../src/constants/themes.ts","../src/utils/chartStyle.ts","../src/constants/defaults.ts","../src/constants/golden.ts","../src/i18n/en.ts","../src/i18n/vi.ts","../src/i18n/index.ts","../src/market/presets.ts","../src/icons/iconSet.ts"],"sourcesContent":["export interface Point {\n x: number;\n y: number;\n}\n\nexport interface Size {\n width: number;\n height: number;\n}\n\nexport interface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport type PriceScaleMode = 'regular' | 'logarithmic' | 'percentage' | 'indexedTo100';\n\nexport interface ViewportState {\n visibleRange: { from: number; to: number };\n priceRange: { min: number; max: number };\n barWidth: number;\n barSpacing: number;\n offset: number;\n chartRect: Rect;\n /**\n * Logarithmic price geometry. Kept for back-compat; mirrors\n * `scaleMode === 'logarithmic'`. Prefer reading `scaleMode`.\n */\n logScale?: boolean;\n /**\n * Price-scale presentation. `regular`, `percentage`, and `indexedTo100` share\n * the same linear geometry — only the axis labels differ (rebased to\n * `scaleBaseline`). `logarithmic` changes the geometry. Defaults to\n * `regular` when unset.\n */\n scaleMode?: PriceScaleMode;\n /**\n * Reference price for `percentage` / `indexedTo100` axis labels — usually the\n * close of the first visible bar. Set by the chart each frame.\n */\n scaleBaseline?: number;\n /** Upside down: higher prices lower on screen. */\n invertScale?: boolean;\n /**\n * How prices on this scale read, when the chart has a price format of its\n * own (`ChartOptions.priceFormat`). Unset: decimals. Indicator panes leave\n * it unset.\n */\n formatPrice?: (price: number) => string;\n /** The number locale prices on this scale are grouped in (`'vi-VN'`: 72.202,13). Unset: en-US. */\n numberLocale?: string;\n /**\n * A bar's time as the chart writes it under the crosshair (its time zone,\n * its time formatter): a vertical line's time label. Unset: drawings show\n * no time.\n */\n formatTime?: (time: number) => string;\n /**\n * Decimals prices on this scale show, when the market or the symbol sets\n * them (`setMarket`, `SymbolInfo.pricePrecision`): drawing labels, price\n * limits and the tags beside the axis use them. Unset: each label keeps its\n * own decimals. Indicator panes and the left scale leave it unset.\n */\n pricePrecision?: number;\n /**\n * The step prices move in under that format (a 32nd): the axis puts its\n * ticks on whole numbers of it.\n */\n priceUnit?: number;\n /**\n * Optional reference to the current bar series. When set, drawings/indicators\n * treat `anchor.time` as a real timestamp and convert to bar index via\n * `timestampToBarIndex(time, data)` at render/hit-test time. This lets\n * anchors survive timeframe / symbol switches. When unset,\n * `anchor.time` is treated as a raw bar index (legacy behavior).\n */\n data?: ReadonlyArray<{ time: number }>;\n /**\n * Width of the price axis strip right of `chartRect`, in CSS pixels. The\n * chart widens it to fit long labels (sub-cent prices); renderers drawing\n * badges on the axis size them to it. Defaults to `PRICE_AXIS_WIDTH`.\n */\n priceAxisWidth?: number;\n}\n\n/**\n * What changed, for `requestRender()`. The chart paints two canvases: a scene\n * (everything that follows data, viewport and chart objects) and a thin top\n * canvas for pointer-tied visuals. Any type except `Hover` redraws both;\n * `Hover` redraws only the top canvas (crosshair, its axis pills, legend,\n * bar countdown, measure ruler, selection box).\n */\nexport enum LayerType {\n Background = 0,\n Main = 1,\n Panel = 2,\n Overlay = 3,\n UI = 4,\n Hover = 5,\n}\n","import type { LineStyle } from './chart.js';\n\n/** The kind of value a style key takes. */\nexport type StyleValueKind = 'color' | 'lineStyle' | 'width' | 'boolean';\n\n/**\n * Every key `chart.applyOverrides()` takes, and the kind of its value.\n *\n * - `series.<chartType>.*` style the main series while it is drawn as that\n * type. A candle's wick takes its body's colour (`upColor`, `downColor`)\n * unless `wickUpColor` / `wickDownColor` set one of its own. Up and down\n * colours fall back to `series.candlestick.*`, line\n * colours and widths to `series.line.*`, area fills to `series.area.*`,\n * then to the theme.\n * - The rest style one part of the chart each, falling back to the theme's\n * tokens: with no overrides the chart looks as its theme makes it.\n */\nexport const CHART_STYLE_KEYS = {\n 'background.color': 'color',\n\n 'panes.background': 'color',\n 'panes.separatorColor': 'color',\n 'panes.titleColor': 'color',\n\n 'grid.horizontal.visible': 'boolean',\n 'grid.horizontal.color': 'color',\n 'grid.horizontal.style': 'lineStyle',\n 'grid.horizontal.width': 'width',\n 'grid.vertical.visible': 'boolean',\n 'grid.vertical.color': 'color',\n 'grid.vertical.style': 'lineStyle',\n 'grid.vertical.width': 'width',\n\n 'crosshair.horizontal.visible': 'boolean',\n 'crosshair.horizontal.color': 'color',\n 'crosshair.horizontal.style': 'lineStyle',\n 'crosshair.horizontal.width': 'width',\n 'crosshair.vertical.visible': 'boolean',\n 'crosshair.vertical.color': 'color',\n 'crosshair.vertical.style': 'lineStyle',\n 'crosshair.vertical.width': 'width',\n 'crosshair.labelBackground': 'color',\n 'crosshair.labelTextColor': 'color',\n\n 'axis.price.lineColor': 'color',\n 'axis.price.textColor': 'color',\n 'axis.time.lineColor': 'color',\n 'axis.time.textColor': 'color',\n\n 'legend.textColor': 'color',\n 'legend.labelColor': 'color',\n\n 'watermark.color': 'color',\n\n 'lastPrice.visible': 'boolean',\n 'lastPrice.upColor': 'color',\n 'lastPrice.downColor': 'color',\n 'lastPrice.style': 'lineStyle',\n 'lastPrice.width': 'width',\n\n 'volume.upColor': 'color',\n 'volume.downColor': 'color',\n\n 'sessionBreaks.color': 'color',\n 'sessionBreaks.style': 'lineStyle',\n 'sessionBreaks.width': 'width',\n\n 'highLow.color': 'color',\n\n 'trading.buyColor': 'color',\n 'trading.sellColor': 'color',\n 'trading.profitColor': 'color',\n 'trading.lossColor': 'color',\n 'trading.entryColor': 'color',\n\n 'markers.longColor': 'color',\n 'markers.shortColor': 'color',\n 'markers.neutralColor': 'color',\n\n 'tradeZones.profitColor': 'color',\n 'tradeZones.lossColor': 'color',\n 'tradeZones.activeColor': 'color',\n\n 'drawings.handleColor': 'color',\n\n 'series.candlestick.upColor': 'color',\n 'series.candlestick.downColor': 'color',\n 'series.candlestick.wickUpColor': 'color',\n 'series.candlestick.wickDownColor': 'color',\n 'series.heikinAshi.upColor': 'color',\n 'series.heikinAshi.downColor': 'color',\n 'series.heikinAshi.wickUpColor': 'color',\n 'series.heikinAshi.wickDownColor': 'color',\n 'series.hollowCandle.upColor': 'color',\n 'series.hollowCandle.downColor': 'color',\n 'series.volumeCandles.upColor': 'color',\n 'series.volumeCandles.downColor': 'color',\n 'series.volumeCandles.wickUpColor': 'color',\n 'series.volumeCandles.wickDownColor': 'color',\n 'series.equivolume.upColor': 'color',\n 'series.equivolume.downColor': 'color',\n 'series.equivolume.wickUpColor': 'color',\n 'series.equivolume.wickDownColor': 'color',\n 'series.bar.upColor': 'color',\n 'series.bar.downColor': 'color',\n 'series.hiLo.upColor': 'color',\n 'series.hiLo.downColor': 'color',\n 'series.renko.upColor': 'color',\n 'series.renko.downColor': 'color',\n 'series.lineBreak.upColor': 'color',\n 'series.lineBreak.downColor': 'color',\n 'series.rangeBars.upColor': 'color',\n 'series.rangeBars.downColor': 'color',\n 'series.kagi.upColor': 'color',\n 'series.kagi.downColor': 'color',\n 'series.pointAndFigure.upColor': 'color',\n 'series.pointAndFigure.downColor': 'color',\n 'series.baseline.upColor': 'color',\n 'series.baseline.downColor': 'color',\n 'series.baseline.lineWidth': 'width',\n 'series.line.color': 'color',\n 'series.line.lineWidth': 'width',\n 'series.stepLine.color': 'color',\n 'series.stepLine.lineWidth': 'width',\n 'series.lineWithMarkers.color': 'color',\n 'series.lineWithMarkers.lineWidth': 'width',\n 'series.area.lineColor': 'color',\n 'series.area.lineWidth': 'width',\n 'series.area.topColor': 'color',\n 'series.area.bottomColor': 'color',\n 'series.hlcArea.lineColor': 'color',\n 'series.hlcArea.lineWidth': 'width',\n 'series.hlcArea.topColor': 'color',\n 'series.hlcArea.bottomColor': 'color',\n} as const satisfies Record<string, StyleValueKind>;\n\nexport type ChartStyleKey = keyof typeof CHART_STYLE_KEYS;\n\n/** The value a key of `kind` takes. */\nexport type StyleValue<K extends StyleValueKind> = K extends 'color'\n ? string\n : K extends 'lineStyle'\n ? LineStyle\n : K extends 'width'\n ? number\n : boolean;\n\n/** Style overrides, by key. */\nexport type ChartStyleOverrides = {\n [K in ChartStyleKey]?: StyleValue<(typeof CHART_STYLE_KEYS)[K]>;\n};\n\n/** A change to overrides: a value sets a key, `null` takes it away. */\nexport type ChartStyleOverridesPatch = {\n [K in ChartStyleKey]?: StyleValue<(typeof CHART_STYLE_KEYS)[K]> | null;\n};\n\n/**\n * Where an override goes. `'host'`: your app's, kept through theme changes\n * and never saved. `'user'`: what the person using the chart chose (the\n * widget's Settings write here), kept per theme and saved with `saveState`.\n */\nexport type StyleLayer = 'host' | 'user';\n\n/** One indicator pane's own look, over the panes' (`chart.setPaneStyle`). */\nexport interface PaneStyle {\n background?: string;\n separator?: string;\n}\n\n/** A line's look, as resolved. */\nexport interface ResolvedLineLook {\n visible: boolean;\n color: string;\n style: LineStyle;\n width: number;\n}\n\n/**\n * The chart's finer looks, worked out from the theme and its overrides once\n * per change. Renderers read it from `theme.style`; a theme without one (a\n * plugin's own) draws as before.\n */\nexport interface ResolvedChartStyle {\n panes: { background: string; separator: string; title: string };\n grid: { horizontal: ResolvedLineLook; vertical: ResolvedLineLook };\n crosshair: {\n horizontal: ResolvedLineLook;\n vertical: ResolvedLineLook;\n labelBackground: string;\n labelText: string;\n };\n axis: { price: { line: string; text: string }; time: { line: string; text: string } };\n legend: { text: string; label: string };\n /** Null: the watermark's own colour, or the theme's. */\n watermark: { color: string | null };\n lastPrice: { visible: boolean; up: string; down: string; style: LineStyle; width: number };\n /** Null: the session breaks' own settings, or the theme's. */\n sessionBreaks: { color: string | null; style: LineStyle | null; width: number | null };\n /** Null: the high and low lines' own colour. */\n highLow: { color: string | null };\n /** Orders (buy, sell) and positions (profit, loss, entry). Null: the trading config's colours. */\n trading: { buy: string | null; sell: string | null; profit: string | null; loss: string | null; entry: string | null };\n /** Signal markers. Null: their own style's colours. */\n markers: { long: string | null; short: string | null; neutral: string | null };\n /** Trade zones. Null: their own style's colours. */\n tradeZones: { profit: string | null; loss: string | null; active: string | null };\n /** A selected drawing's handles. Null: white. */\n drawings: { handle: string | null };\n /** The main series' line width, for the chart types drawn as a line. */\n series: { lineWidth: number };\n}\n","import type { Point, ViewportState } from './rendering.js';\nimport type { OHLCBar } from './ohlc.js';\nimport type { IndicatorIntervals } from './indicator.js';\n\n/** The drawing tools TradeCanvas ships. */\nexport type BuiltInDrawingToolType =\n | 'trendLine' | 'horizontalLine' | 'horizontalRay' | 'verticalLine' | 'ray' | 'extendedLine'\n | 'crossLine' | 'trendAngle' | 'infoLine'\n | 'parallelChannel' | 'regressionChannel'\n | 'fibRetracement' | 'fibExtension' | 'fibTimeZones' | 'fibChannel' | 'fibSpeedResistanceFan'\n | 'rectangle' | 'ellipse' | 'triangle' | 'circle'\n | 'pitchfork' | 'schiffPitchfork' | 'modifiedSchiffPitchfork' | 'elliottWave'\n | 'xabcdPattern' | 'abcdPattern' | 'headAndShoulders'\n | 'priceRange' | 'dateRange' | 'dateAndPriceRange' | 'measure'\n | 'text' | 'arrow' | 'priceLabel'\n | 'gannFan' | 'gannBox' | 'cyclicLines'\n | 'anchoredVWAP'\n | 'volumeProfileRange'\n | 'riskReward'\n | 'note' | 'callout' | 'flag' | 'arrowMark' | 'icon'\n | 'brush' | 'highlighter' | 'path' | 'polyline' | 'curve' | 'arc'\n | 'fibCircles' | 'fibSpiral' | 'fibArcs' | 'fibWedge' | 'pitchfan' | 'gannSquare'\n | 'elliottImpulse' | 'elliottCorrection' | 'elliottTriangle' | 'elliottDoubleCombo' | 'elliottTripleCombo'\n | 'threeDrives' | 'cypherPattern'\n | 'timeCycles' | 'sineLine'\n | 'forecast' | 'projection' | 'barsPattern';\n\n/**\n * A drawing tool's name: a built-in one, or the name a plugin registered\n * (`DrawingPlugin.descriptor.type`). Built-in names still complete in an editor.\n */\nexport type DrawingToolType = BuiltInDrawingToolType | (string & {});\n\nexport interface AnchorPoint {\n time: number;\n price: number;\n}\n\nexport interface DrawingStyle {\n color: string;\n lineWidth: number;\n lineStyle: 'solid' | 'dashed' | 'dotted';\n fillColor?: string;\n fillOpacity?: number;\n fontSize?: number;\n text?: string;\n /** The text in bold. */\n bold?: boolean;\n /** The text in italics. */\n italic?: boolean;\n /**\n * Where each line of the text lines up in its box. On a line or a box (a\n * trend line, a rectangle): at which end of it the text sits, the middle\n * when left out.\n */\n textAlign?: 'left' | 'center' | 'right';\n /**\n * On a line: above it, on it, or under it. In a box: at its top, its\n * middle or its bottom. Left out: the top.\n */\n textVAlign?: 'top' | 'middle' | 'bottom';\n /** The text's colour; `color` when left out (a note keeps `color` for its pin). */\n textColor?: string;\n /**\n * A box behind the text, in `fillColor` at `fillOpacity`. Left out: as the\n * tool draws it (a note and a callout have one, a text has none).\n */\n textBackground?: boolean;\n /** A border round the text's box, in `borderColor` (`color` when left out). Left out: as the tool draws it. */\n textBorder?: boolean;\n borderColor?: string;\n /** Widest a line of the text gets before it wraps, px; 0: it breaks only where the text does. Left out: the tool's own width. */\n textWrap?: number;\n}\n\nexport interface DrawingState {\n id: string;\n type: DrawingToolType;\n anchors: AnchorPoint[];\n style: DrawingStyle;\n visible: boolean;\n locked: boolean;\n /** The tool's own settings (levels, extend left/right…); see `DrawingDescriptor.options`. */\n options?: DrawingOptions;\n /** The group it belongs to: drawings selected, hidden and locked together. */\n group?: { id: string; name: string };\n /** Its own name, as the object tree lists it (at most 80 characters); unset: its tool's name. */\n name?: string;\n /**\n * The intervals it shows on, as an indicator's are (`{ minutes: false }`:\n * not on minute charts); unset: all of them.\n */\n intervals?: IndicatorIntervals;\n /**\n * The indicator pane it is drawn on: the pane's id, as `getIndicatorPanes()`\n * lists them, and its anchors' prices are that pane's values. Unset: the\n * price pane.\n */\n paneId?: string;\n meta?: Record<string, unknown>;\n}\n\n/** One level of a Fibonacci or Gann tool: a ratio, shown or not, in its own colour. */\nexport interface DrawingLevel {\n value: number;\n visible: boolean;\n /** CSS colour; the drawing's colour when left out. */\n color?: string;\n}\n\nexport type DrawingOptionValue = boolean | number | string | DrawingLevel[];\n\n/** A drawing's settings beyond the shared style, by key. Missing keys take the tool's defaults. */\nexport type DrawingOptions = Record<string, DrawingOptionValue>;\n\n/** A setting a drawing tool offers beyond the shared style, with its default. */\nexport type DrawingOptionDef =\n | { kind: 'boolean'; label: string; default: boolean }\n | { kind: 'number'; label: string; default: number; min?: number; max?: number; step?: number }\n | { kind: 'choice'; label: string; default: string; choices: readonly { value: string; label: string }[] }\n | { kind: 'levels'; label: string; default: readonly DrawingLevel[] }\n | { kind: 'text'; label: string; default: string };\n\nexport type DrawingOptionDefs = Readonly<Record<string, DrawingOptionDef>>;\n\nexport interface DrawingDescriptor {\n type: DrawingToolType;\n name: string;\n requiredAnchors: number;\n singleClick?: boolean;\n /** Settings the tool offers beyond the shared style; a settings dialog is built from them. */\n options?: DrawingOptionDefs;\n /** It fills an area with `style.fillColor` (a settings dialog offers the fill). */\n fill?: boolean;\n /** It draws `style.text` (a settings dialog offers the text and its size). */\n text?: boolean;\n /**\n * How it is drawn with the pointer. 'clicks' (the default): a click per\n * anchor up to `requiredAnchors`. 'freehand': press and drag, a point every\n * few pixels, release to finish. 'path': a click per point, at least\n * `requiredAnchors` and at most `maxAnchors`; a double-click, Enter or a\n * click on the last point finishes it.\n */\n creation?: 'clicks' | 'freehand' | 'path';\n /** Most points a 'path' takes (100 when left out). */\n maxAnchors?: number;\n /**\n * It reads the bars' prices or volumes (an anchored VWAP, a volume profile,\n * a position): drawn on the price pane only, never on an indicator pane.\n */\n priceOnly?: boolean;\n}\n\nexport interface DrawingPlugin {\n descriptor: DrawingDescriptor;\n render(\n ctx: CanvasRenderingContext2D,\n state: DrawingState,\n viewport: ViewportState,\n selected: boolean,\n ): void;\n hitTest(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): boolean;\n hitTestAnchor(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): number;\n /**\n * The drawing after handle `index` (from `hitTestAnchor`) is dragged to\n * `anchor`. Without it, the handle is anchor `index` and moves there. A\n * tool with handles that are not anchors (a position's target, say)\n * changes its options instead.\n */\n moveHandle?(state: DrawingState, index: number, anchor: AnchorPoint): DrawingState;\n /**\n * The prices of the drawing's lines at `time` (what an alert on it\n * crosses), or null where it doesn't reach. Tools without it take no alerts.\n * With `viewport` the lines follow the chart as drawn: straight across bars\n * (not clock time, so a weekend gap doesn't bend them) and on a log scale\n * straight in log price.\n */\n priceAt?(state: DrawingState, time: number, viewport?: ViewportState): number[] | null;\n /**\n * For a tool drawn from the chart's bars (an anchored VWAP, a volume\n * profile): the chart hands it a getter for them when it is registered,\n * and `revision`, whose number moves when a bar was replaced in the same\n * array (`updateBar`): a tool that keeps what it computed from the bars,\n * by the array and its length, computes it again then.\n */\n setDataGetter?(getter: () => readonly OHLCBar[], revision?: () => number): void;\n}\n\nexport const DEFAULT_DRAWING_STYLE: DrawingStyle = {\n color: '#4c8dff',\n lineWidth: 1,\n lineStyle: 'solid',\n fillColor: 'rgba(76, 141, 255, 0.1)',\n fillOpacity: 0.1,\n fontSize: 12,\n};\n","export type OrderSide = 'buy' | 'sell';\nexport type OrderType = 'market' | 'limit' | 'stop' | 'stopLimit';\nexport type OrderStatus = 'pending' | 'filled' | 'cancelled' | 'rejected';\nexport type OrderLabel = 'LIMIT' | 'STOP' | 'SL' | 'TP' | 'STOP LIMIT';\n\n/** How long an order works: good till cancelled, or for the day. */\nexport type TimeInForce = 'gtc' | 'day';\n\nexport interface TradingOrder {\n id: string;\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity: number;\n label?: OrderLabel;\n draggable?: boolean;\n /** Stop-loss and take-profit the position gets when the order fills. */\n stopLoss?: number;\n takeProfit?: number;\n timeInForce?: TimeInForce;\n meta?: Record<string, unknown>;\n}\n\nexport interface TradingPosition {\n id: string;\n side: OrderSide;\n entryPrice: number;\n quantity: number;\n /** Quantity already closed (for partial-close visualization). 0 ≤ closedQuantity ≤ quantity. */\n closedQuantity?: number;\n stopLoss?: number;\n takeProfit?: number;\n meta?: Record<string, unknown>;\n}\n\n/** Threshold-based P&L color stop. Sorted ascending by `pnl` is recommended. */\nexport interface PnLThreshold {\n /** Inclusive lower bound. Use -Infinity for the bottom-most stop. */\n pnl: number;\n color: string;\n}\n\n/** Tokens passed to position label templates. */\nexport interface PositionLabelContext {\n side: OrderSide;\n quantity: number;\n closedQuantity: number;\n openQuantity: number;\n entryPrice: number;\n currentPrice: number;\n pnl: number;\n pnlPct: number;\n precision: number;\n /** The chart's price format, for `{entry}` and `{price}` (decimals at `precision` without one). */\n formatPrice?: (price: number) => string;\n /** The number locale `{pnl}` (and prices without a format) are grouped in. Unset: en-US. */\n locale?: string;\n}\n\nexport interface DepthLevel {\n price: number;\n volume: number;\n}\n\nexport interface DepthData {\n bids: DepthLevel[];\n asks: DepthLevel[];\n}\n\nexport interface TradingConfig {\n enabled: boolean;\n orderColors?: { buy?: string; sell?: string };\n positionColors?: { profit?: string; loss?: string; entry?: string };\n /**\n * Optional gradient of colors keyed to P&L value. When provided, the rendered\n * position zone uses the color of the highest threshold whose `pnl` ≤ live P&L.\n * Falls back to `positionColors.profit`/`.loss` when unset.\n */\n pnlThresholds?: PnLThreshold[];\n /**\n * The words on a position's tag after its open quantity, in place of its\n * side and its open profit. A template with the tokens {side} {qty}\n * {closedQty} {openQty} {entry} {price} {pnl} {pnlPct} {pnlSign}, or a\n * function for full control. Unset: the side (\"Long\", \"Short\") and the\n * profit in the profit or loss colour.\n */\n positionLabel?: string | ((ctx: PositionLabelContext) => string);\n depthOverlay?: {\n enabled?: boolean;\n bidColor?: string;\n askColor?: string;\n maxWidth?: number;\n };\n contextMenu?: { enabled?: boolean };\n /**\n * Buttons on the lines: × on an order cancels it, × on a position closes it\n * and ⇅ reverses it, × on a stop-loss or take-profit removes it. All on by\n * default.\n */\n lineButtons?: { cancel?: boolean; close?: boolean; reverse?: boolean; removeStops?: boolean };\n /** Marks where orders filled (from the execution adapter's fills). On by default. */\n fillMarks?: boolean;\n /** Decimals of the prices on the trading tags; unset, the price axis's (the market's or the range's). */\n pricePrecision?: number;\n dragThreshold?: number;\n}\n\nexport interface OrderPlaceIntent {\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity?: number;\n /** Stop-loss and take-profit for the position the order opens. */\n stopLoss?: number;\n takeProfit?: number;\n timeInForce?: TimeInForce;\n}\n\nexport interface OrderModifyIntent {\n orderId: string;\n newPrice: number;\n /** The price before the change, when known (e.g. from a drag). Optional so\n * the chart's `orderModify` event payload routes straight to an adapter. */\n previousPrice?: number;\n}\n\nexport interface OrderCancelIntent {\n orderId: string;\n}\n\nexport interface PositionModifyIntent {\n positionId: string;\n /** A new stop-loss; null removes it, left out keeps it. */\n stopLoss?: number | null;\n /** A new take-profit; null removes it, left out keeps it. */\n takeProfit?: number | null;\n}\n\nexport interface PositionCloseIntent {\n positionId: string;\n}\n\n/** Close a position and open the same size the other way. */\nexport interface PositionReverseIntent {\n positionId: string;\n}\n\nexport const DEFAULT_TRADING_CONFIG: TradingConfig = {\n enabled: true,\n orderColors: { buy: '#1fa874', sell: '#e8505b' },\n positionColors: { profit: '#1fa874', loss: '#e8505b', entry: '#4c8dff' },\n depthOverlay: { enabled: false, bidColor: 'rgba(31, 168, 116,0.15)', askColor: 'rgba(232, 80, 91,0.15)', maxWidth: 100 },\n contextMenu: { enabled: true },\n lineButtons: { cancel: true, close: true, reverse: true, removeStops: true },\n fillMarks: true,\n dragThreshold: 3,\n};\n","export type SignalDirection = 'long' | 'short' | 'neutral';\n\nexport interface SignalMarker {\n id: string;\n time: number;\n price: number;\n direction: SignalDirection;\n confidence: number;\n source: string;\n label?: string;\n color?: string;\n meta?: Record<string, unknown>;\n}\n\nexport interface SignalMarkerStyle {\n longColor?: string;\n shortColor?: string;\n neutralColor?: string;\n arrowSize?: number;\n showLabel?: boolean;\n showConfidence?: boolean;\n sourceColors?: Record<string, string>;\n}\n\nexport const DEFAULT_SIGNAL_STYLE: SignalMarkerStyle = {\n longColor: '#1fa874',\n shortColor: '#e8505b',\n neutralColor: '#9E9E9E',\n arrowSize: 12,\n showLabel: true,\n showConfidence: true,\n};\n\nexport type TradeZoneDirection = 'long' | 'short';\n\nexport interface TradeZone {\n id: string;\n entryTime: number;\n entryPrice: number;\n exitTime?: number;\n exitPrice?: number;\n direction: TradeZoneDirection;\n pnl?: number;\n pnlPercent?: number;\n label?: string;\n meta?: Record<string, unknown>;\n}\n\nexport interface TradeZoneStyle {\n profitColor?: string;\n lossColor?: string;\n activeColor?: string;\n fillOpacity?: number;\n borderWidth?: number;\n showLabel?: boolean;\n showPnl?: boolean;\n}\n\nexport const DEFAULT_TRADE_ZONE_STYLE: TradeZoneStyle = {\n profitColor: '#1fa874',\n lossColor: '#e8505b',\n activeColor: '#4c8dff',\n fillOpacity: 0.12,\n borderWidth: 1,\n showLabel: true,\n showPnl: true,\n};\n","import type { OHLCBar, TimeFrame } from './ohlc.js';\nimport type { SymbolInfo, SymbolSearchOptions } from './symbol.js';\nimport type { Quote } from './quote.js';\nimport type { NewsItem } from './news.js';\n\n/** One trade: when (ms), at what price, how much. */\nexport interface Trade {\n time: number;\n price: number;\n volume: number;\n}\n\n// --- Connection ---\n\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';\n\nexport interface ConnectionInfo {\n state: ConnectionState;\n latency?: number;\n reconnectAttempt?: number;\n lastMessageTime?: number;\n error?: string;\n}\n\n// --- Ticks & Trades ---\n\nexport interface RawTick {\n time: number;\n price: number;\n volume: number;\n side?: 'buy' | 'sell';\n /** The best bid and ask with it, when the feed has them (the chart marks them). */\n bid?: number;\n ask?: number;\n}\n\nexport interface AggregatedBar extends OHLCBar {\n /** True once the bar's interval is over and it no longer changes. */\n closed: boolean;\n /** How many ticks made the bar. */\n tickCount: number;\n}\n\n// --- Data Adapter (Strategy Pattern) ---\n\n/**\n * What `adapter.connect(config)` is given. The chart's stream\n * (`connectStream`) passes `symbol` and `timeframe` only; the other fields\n * are for an adapter you connect yourself, and none of the built-in\n * adapters reads them. The stream reconnects by `StreamConfig.reconnect`.\n */\nexport interface DataAdapterConfig {\n symbol: string;\n timeframe: TimeFrame;\n /** Connect again when the connection drops. Not passed by the stream. */\n reconnect?: boolean;\n /** Tries before giving up. Not passed by the stream. */\n reconnectMaxRetries?: number;\n /** The wait before the first try, ms. Not passed by the stream. */\n reconnectBaseDelay?: number;\n /** The longest wait between tries, ms. Not passed by the stream. */\n reconnectMaxDelay?: number;\n /** How often to check the connection is alive, ms. Not passed by the stream. */\n heartbeatInterval?: number;\n /** The most ticks to keep while they can't be delivered. Not passed by the stream. */\n bufferSize?: number;\n}\n\nexport type DataAdapterEventType =\n | 'tick'\n | 'bar'\n | 'barClose'\n /** The first bars, loaded at the start. */\n | 'snapshot'\n | 'connectionChange'\n | 'error'\n /**\n * The feed learned about the connected symbol after the chart asked\n * (`resolveSymbol`), for instance on its first message: `data` is the\n * `SymbolInfo`. The chart applies it (precision, price step, hours).\n */\n | 'symbolInfo';\n\nexport interface DataAdapterEvent<T = unknown> {\n type: DataAdapterEventType;\n data: T;\n timestamp: number;\n}\n\nexport type DataAdapterListener<T = unknown> = (event: DataAdapterEvent<T>) => void;\n\n/**\n * Data adapter interface. Implements the observer pattern:\n * - connect() to start receiving data\n * - on('bar'|'tick'|'connectionChange', handler) to receive events\n * - disconnect() to stop, then connect() again to switch symbols/timeframes\n * - No separate subscribe/unsubscribe — reconnect is the intended pattern\n *\n * Strategy pattern for pluggable data sources.\n * Implementations handle the specifics of each data source (WebSocket, REST,\n * SSE, etc.) while the StreamManager orchestrates lifecycle and aggregation.\n *\n * Built-in: BinanceAdapter\n * Implement this for: custom exchange APIs, broker feeds, mock data\n */\nexport interface DataAdapter {\n readonly name: string;\n\n /**\n * Optional: the timeframes the feed serves. Charts build any other\n * timeframe (7m, 90m, 2d…) from the coarsest of these that divides it.\n * Days, weeks, months and the hour frames that divide a day (2h to 12h)\n * they build start at the midnight of the symbol's `timeZone`\n * (`resolveSymbol`), else at UTC's; daily bars stamped at 00:00 UTC are\n * read as their dates. Leave it out when the feed serves every timeframe.\n */\n readonly supportedTimeframes?: readonly TimeFrame[];\n\n connect(config: DataAdapterConfig): void;\n disconnect(): void;\n getConnectionState(): ConnectionState;\n\n /**\n * Load historical bars. Called once on connect, before streaming starts.\n * Returns bars sorted by time ascending.\n */\n fetchHistory(symbol: string, timeframe: TimeFrame, limit?: number): Promise<OHLCBar[]>;\n\n /**\n * Optional: load up to `limit` bars older than `before` (the oldest loaded\n * bar's time, in the bars' own unit), sorted by time ascending. Return an\n * empty array when no older data exists. A chart connected to an adapter\n * with this method loads older bars as the user scrolls back in time.\n */\n fetchHistoryBefore?(symbol: string, timeframe: TimeFrame, before: number, limit: number): Promise<OHLCBar[]>;\n\n /** Optional: symbols matching `query`, best first — for a symbol search box. */\n searchSymbols?(query: string, options?: SymbolSearchOptions): Promise<SymbolInfo[]>;\n\n /**\n * Optional: what the feed knows about `symbol` (name, price step, the\n * exchange's `timeZone` and hours), or null when it doesn't know it. A\n * connected chart asks for it and applies it.\n */\n resolveSymbol?(symbol: string): Promise<SymbolInfo | null>;\n\n /**\n * Optional: live quotes (last price, the day's change, high, low, volume)\n * for many symbols at once, until the function it returns is called. A\n * widget's watchlist fills its rows from it.\n */\n subscribeQuotes?(symbols: readonly string[], onQuotes: (quotes: Quote[]) => void): () => void;\n\n /** Optional: recent headlines about `symbol`, newest first. */\n fetchNews?(symbol: string, limit?: number): Promise<NewsItem[]>;\n\n /**\n * Optional, with `subscribeTrades`: up to `limit` recent trades, oldest\n * first. A chart builds tick timeframes (`'100T'`) from a feed's trades.\n */\n fetchTrades?(symbol: string, limit?: number): Promise<Trade[]>;\n\n /** Optional, with `fetchTrades`: live trades of `symbol` until the function it returns is called. */\n subscribeTrades?(symbol: string, onTrades: (trades: Trade[]) => void): () => void;\n\n on<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n off<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n\n dispose(): void;\n}\n\n// --- Stream Manager Config ---\n\nexport interface StreamConfig {\n adapter: DataAdapter;\n symbol: string;\n timeframe: TimeFrame;\n /** Bars to load at the start. Default 500. */\n historyLimit?: number;\n /** Bars per request when scrolling back for older bars (needs `adapter.fetchHistoryBefore`), default: 500. */\n historyPageSize?: number;\n /**\n * Follow a new bar while the view is at the newest one (a view scrolled\n * back stays). Sets `chart.setAutoScroll`. Default `true`.\n */\n autoScroll?: boolean;\n /** Not read: the stream leaves the last price's line as the chart shows it. */\n showCurrentPriceLine?: boolean;\n /** Build the bars from the feed's ticks instead of taking its bars. Default `false`. */\n aggregateTicks?: boolean;\n reconnect?: ReconnectConfig;\n}\n\nexport interface ReconnectConfig {\n /** Connect again when the connection drops. Default `true`. */\n enabled: boolean;\n /** Tries before giving up. Default `Infinity`. */\n maxRetries: number;\n /** The wait before the first try, ms. Default 1000. */\n baseDelay: number;\n /** The longest wait between tries, ms, before a jitter of up to 25% either way. Default 30000. */\n maxDelay: number;\n /** Each wait is the last times this. Default 2. */\n backoffMultiplier: number;\n}\n\nexport const DEFAULT_RECONNECT: ReconnectConfig = {\n enabled: true,\n maxRetries: Infinity,\n baseDelay: 1000,\n maxDelay: 30000,\n backoffMultiplier: 2,\n};\n\nexport const DEFAULT_STREAM_CONFIG: Partial<StreamConfig> = {\n historyLimit: 500,\n autoScroll: true,\n showCurrentPriceLine: true,\n aggregateTicks: false,\n};\n","/**\n * A symbol's latest quote: its price and the day's move, for a watchlist row\n * or a symbol's details. Prices are in the symbol's quote currency.\n */\nexport interface Quote {\n symbol: string;\n /** The last traded price. */\n last: number;\n /** The move from the reference price (the prior close; 24 h ago for crypto). */\n change?: number;\n /** The same move, in percent. */\n changePercent?: number;\n open?: number;\n high?: number;\n low?: number;\n /** The prior session's close. */\n prevClose?: number;\n /** Volume over the same period, in the base unit. */\n volume?: number;\n bid?: number;\n ask?: number;\n /** When the quote was made, in ms since the epoch. */\n time?: number;\n}\n\n/** Live quotes for many symbols at once. */\nexport interface QuoteSource {\n /**\n * Send quotes for `symbols` to `onQuotes` as they change (any number per\n * call) until the function it returns is called.\n */\n subscribeQuotes(symbols: readonly string[], onQuotes: (quotes: Quote[]) => void): () => void;\n}\n\nconst QUOTE_NUMBERS = ['change', 'changePercent', 'open', 'high', 'low', 'prevClose', 'volume', 'bid', 'ask', 'time'] as const;\n\n/**\n * A quote from untrusted input (a host's push, a feed's frame): its symbol\n * and last price must be usable; any other field that isn't a finite number\n * is left out. The change is worked out from the prior close or the open when\n * the input has none. Null when it isn't a quote.\n */\nexport function readQuote(raw: unknown): Quote | null {\n if (!raw || typeof raw !== 'object') return null;\n const r = raw as Record<string, unknown>;\n const symbol = typeof r.symbol === 'string' ? r.symbol.trim() : '';\n if (!symbol || symbol.length > 64 || !isFiniteNumber(r.last)) return null;\n const quote: Quote = { symbol, last: r.last };\n for (const key of QUOTE_NUMBERS) {\n const v = r[key];\n if (isFiniteNumber(v)) quote[key] = v;\n }\n const ref = quote.prevClose ?? quote.open;\n if (quote.change === undefined && ref !== undefined) quote.change = quote.last - ref;\n if (quote.changePercent === undefined && quote.change !== undefined) {\n const base = quote.last - quote.change;\n if (base !== 0) quote.changePercent = (quote.change / base) * 100;\n }\n return quote;\n}\n\nfunction isFiniteNumber(v: unknown): v is number {\n return typeof v === 'number' && Number.isFinite(v);\n}\n","/** A news headline about a symbol. */\nexport interface NewsItem {\n title: string;\n /** When it was published, in ms since the epoch. */\n time: number;\n /** The article; only http(s) links are kept. */\n url?: string;\n source?: string;\n summary?: string;\n id?: string;\n}\n\nconst MAX_TITLE = 300;\nconst MAX_TEXT = 1000;\n\nconst text = (v: unknown, max: number): string | undefined => {\n if (typeof v !== 'string') return undefined;\n const t = v.trim();\n return t ? t.slice(0, max) : undefined;\n};\n\nconst webUrl = (v: unknown): string | undefined => {\n if (typeof v !== 'string') return undefined;\n try {\n const url = new URL(v);\n return url.protocol === 'https:' || url.protocol === 'http:' ? url.href : undefined;\n } catch {\n return undefined;\n }\n};\n\n/**\n * Headlines from untrusted input (a feed, a host): each needs a title and a\n * time; links that aren't web pages are dropped. Newest first, at most\n * `limit`.\n */\nexport function readNews(raw: unknown, limit = 20): NewsItem[] {\n if (!Array.isArray(raw)) return [];\n const items: NewsItem[] = [];\n for (const entry of raw) {\n if (!entry || typeof entry !== 'object') continue;\n const r = entry as Record<string, unknown>;\n const title = text(r.title, MAX_TITLE);\n if (!title || typeof r.time !== 'number' || !Number.isFinite(r.time)) continue;\n const item: NewsItem = { title, time: r.time };\n const url = webUrl(r.url);\n if (url) item.url = url;\n const source = text(r.source, MAX_TITLE);\n if (source) item.source = source;\n const summary = text(r.summary, MAX_TEXT);\n if (summary) item.summary = summary;\n const id = text(r.id, MAX_TITLE);\n if (id) item.id = id;\n items.push(item);\n }\n return items.sort((a, b) => b.time - a.time).slice(0, Math.max(0, limit));\n}\n","export function clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nexport function inverseLerp(a: number, b: number, value: number): number {\n if (a === b) return 0;\n return (value - a) / (b - a);\n}\n\nexport function roundToStep(value: number, step: number): number {\n return Math.round(value / step) * step;\n}\n\nexport function niceNumber(value: number, round: boolean): number {\n const exp = Math.floor(Math.log10(value));\n const frac = value / Math.pow(10, exp);\n let nice: number;\n if (round) {\n if (frac < 1.5) nice = 1;\n else if (frac < 3) nice = 2;\n else if (frac < 7) nice = 5;\n else nice = 10;\n } else {\n if (frac <= 1) nice = 1;\n else if (frac <= 2) nice = 2;\n else if (frac <= 5) nice = 5;\n else nice = 10;\n }\n return nice * Math.pow(10, exp);\n}\n\nexport function computeTickStep(min: number, max: number, maxTicks: number): number {\n const range = niceNumber(max - min, false);\n return niceNumber(range / (maxTicks - 1), true);\n}\n","import type { OHLCBar, DataSeries } from '../types/ohlc.js';\n\n/**\n * Bar times at or above this are milliseconds (from March 1973 on), below it\n * seconds (up to the year 5138).\n */\nexport const MS_TIME_THRESHOLD = 1e11;\n\n/** Milliseconds in one unit of a series' bar times: 1 for milliseconds, 1000 for seconds. */\nexport type BarTimeUnit = 1 | 1000;\n\n/**\n * The unit of a series' bar times, decided once from its newest bar, so its\n * old bars keep the series' unit: a millisecond bar from 2000 is below 1e12\n * and would pass for seconds on its own. Milliseconds when there are no bars.\n */\nexport function barTimeUnit(data: ArrayLike<{ time: number }>): BarTimeUnit {\n const last = data.length > 0 ? data[data.length - 1].time : NaN;\n if (!Number.isFinite(last)) return 1;\n return Math.abs(last) >= MS_TIME_THRESHOLD ? 1 : 1000;\n}\n\n/**\n * Normalize bar timestamp to milliseconds. Pass the series' unit\n * (`barTimeUnit(data)`) when there is one; on its own a time is taken as\n * milliseconds from `MS_TIME_THRESHOLD` (1973) up, seconds below.\n */\nexport function normalizeBarTime(time: number, unit?: BarTimeUnit): number {\n if (unit !== undefined) return time * unit;\n return Math.abs(time) >= MS_TIME_THRESHOLD ? time : time * 1000;\n}\n\n/**\n * Normalize a bar's timestamp field to milliseconds.\n * Accepts either { time } (ms or s) or { t, o, h, l, c, v } wire format.\n */\nexport function normalizeBar(raw: Record<string, number>): OHLCBar {\n const time = normalizeBarTime(raw.time ?? raw.t ?? 0);\n return {\n time,\n open: raw.open ?? raw.o ?? 0,\n high: raw.high ?? raw.h ?? 0,\n low: raw.low ?? raw.l ?? 0,\n close: raw.close ?? raw.c ?? 0,\n volume: raw.volume ?? raw.v ?? 0,\n };\n}\n\nexport function sliceVisibleData(\n data: DataSeries,\n from: number,\n to: number,\n): DataSeries {\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length, to + 1);\n return data.slice(startIdx, endIdx);\n}\n\nexport function findBarIndex(data: DataSeries, timestamp: number): number {\n let lo = 0;\n let hi = data.length - 1;\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n if (data[mid].time < timestamp) lo = mid + 1;\n else if (data[mid].time > timestamp) hi = mid - 1;\n else return mid;\n }\n return lo;\n}\n\n/**\n * `min`..`max` with room above and below: `padding` of the span on each side,\n * or on a log scale the same share of its log span, so the range stays above\n * zero and the room looks the same top and bottom.\n */\nexport function padPriceRange(min: number, max: number, padding: number, log = false): { min: number; max: number } {\n const logSpan = log && min > 0 && max > 0 ? Math.log(max / min) : Number.NaN;\n if (Number.isFinite(logSpan)) {\n const span = logSpan || Math.log(1 + 2 * padding);\n const factor = Math.exp(span * padding);\n return { min: min / factor, max: max * factor };\n }\n const range = max - min || 1;\n return { min: min - range * padding, max: max + range * padding };\n}\n\n/** Room above and below the prices on a scale, as shares of its height (0.1: a tenth). */\nexport interface ScaleMargins {\n top: number;\n bottom: number;\n}\n\n/**\n * The range that shows `min`..`max` with `margins` of the scale's height\n * above and below them; on a log scale, shares of its log span. A flat price\n * gets a span of 1 (a hundredth of itself on a log scale) to sit in.\n */\nexport function fitPriceRange(min: number, max: number, margins: ScaleMargins, log = false): { min: number; max: number } {\n const share = Math.max(1 - margins.top - margins.bottom, Number.EPSILON);\n const logSpan = log && min > 0 && max > 0 ? Math.log(max / min) : Number.NaN;\n if (Number.isFinite(logSpan)) {\n const total = (logSpan || Math.log(1.01)) / share;\n return { min: min / Math.exp(total * margins.bottom), max: max * Math.exp(total * margins.top) };\n }\n const total = (max - min || 1) / share;\n return { min: min - total * margins.bottom, max: max + total * margins.top };\n}\n\nexport function computePriceRange(\n data: DataSeries,\n from: number,\n to: number,\n padding = 0.05,\n /** Pad as a log scale shows it (`padPriceRange`). */\n log = false,\n): { min: number; max: number } {\n if (data.length === 0) return { min: 0, max: 1 };\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length - 1, to);\n let min = Infinity;\n let max = -Infinity;\n for (let i = startIdx; i <= endIdx; i++) {\n if (data[i].low < min) min = data[i].low;\n if (data[i].high > max) max = data[i].high;\n }\n if (min === Infinity) return { min: 0, max: 1 };\n return padPriceRange(min, max, padding, log);\n}\n\n/**\n * A trade into the bar it falls in: its high, low, close and volume. The bar\n * keeps its own time, where its interval opens; a trade later in it moving\n * the time made the next update for that bar look older than the bar.\n */\nexport function mergeBar(existing: OHLCBar, tick: { price: number; volume?: number; time: number }): OHLCBar {\n return {\n ...existing,\n high: Math.max(existing.high, tick.price),\n low: Math.min(existing.low, tick.price),\n close: tick.price,\n volume: existing.volume + (tick.volume ?? 0),\n };\n}\n","export function hexToRgba(hex: string, alpha = 1): string {\n // #rgb and #rgba are short for #rrggbb and #rrggbbaa; a hex alpha gives way to `alpha`.\n let h = hex.slice(1);\n if (h.length === 3 || h.length === 4) h = [...h.slice(0, 3)].map((c) => c + c).join('');\n const r = parseInt(h.slice(0, 2), 16);\n const g = parseInt(h.slice(2, 4), 16);\n const b = parseInt(h.slice(4, 6), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\n/**\n * `color` at `alpha`: hex (#rgb, #rgba, #rrggbb, #rrggbbaa) and rgb()/rgba()\n * with commas or spaces. Any other colour (a name, hsl()) comes back as it is.\n */\nexport function withAlpha(color: string, alpha: number): string {\n const c = color.trim();\n if (/^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(c)) {\n return hexToRgba(c, alpha);\n }\n const rgb = c.match(/^rgba?\\(\\s*(\\d+(?:\\.\\d+)?)[\\s,]+(\\d+(?:\\.\\d+)?)[\\s,]+(\\d+(?:\\.\\d+)?)/i);\n if (rgb) {\n return `rgba(${rgb[1]}, ${rgb[2]}, ${rgb[3]}, ${alpha})`;\n }\n return color;\n}\n\n/** A colour's channels (0-255) and alpha (0-1). */\ninterface Rgba {\n r: number;\n g: number;\n b: number;\n a: number;\n}\n\n/** Decimals an alpha is written with: finer than a screen's 8 bits. */\nconst ALPHA_DECIMALS = 3;\n\n/** Hex (#rgb, #rgba, #rrggbb, #rrggbbaa) or rgb()/rgba() with commas or spaces; null for any other colour. */\nfunction parseColor(color: string): Rgba | null {\n const c = color.trim();\n const hex = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.exec(c);\n if (hex) {\n let h = hex[1];\n if (h.length <= 4) h = [...h].map((d) => d + d).join('');\n const at = (i: number) => parseInt(h.slice(i, i + 2), 16);\n return { r: at(0), g: at(2), b: at(4), a: h.length === 8 ? at(6) / 255 : 1 };\n }\n const rgb = /^rgba?\\(\\s*([\\d.]+)[\\s,]+([\\d.]+)[\\s,]+([\\d.]+)(?:\\s*[,/]\\s*([\\d.]+)(%)?)?\\s*\\)$/i.exec(c);\n if (!rgb) return null;\n const alpha = rgb[4] === undefined ? 1 : Number(rgb[4]) / (rgb[5] ? 100 : 1);\n return { r: Number(rgb[1]), g: Number(rgb[2]), b: Number(rgb[3]), a: Math.min(1, Math.max(0, alpha)) };\n}\n\n/**\n * The colour `t` of the way from `colorA` to `colorB` (0 to 1), each hex or\n * rgb()/rgba(): `rgb(r,g,b)`, or `rgba(…)` when either is see-through. The\n * alpha is mixed as `color-mix` mixes it, weighting each colour by its own,\n * so a fade toward a see-through colour (a panel's faint surface) keeps the\n * hue of the other instead of washing toward the surface's. A colour it can't\n * read (a name, hsl()) comes back as it is, from the end `t` is nearer.\n */\nexport function lerpColor(colorA: string, colorB: string, t: number): string {\n const a = parseColor(colorA);\n const b = parseColor(colorB);\n if (!a || !b) return t < 0.5 ? colorA : colorB;\n const alpha = a.a + (b.a - a.a) * t;\n // Each channel weighted by its colour's alpha, then the mix's taken out again.\n const channel = (x: number, y: number) => (alpha === 0 ? 0 : Math.round((x * a.a + (y * b.a - x * a.a) * t) / alpha));\n const rgb = `${channel(a.r, b.r)},${channel(a.g, b.g)},${channel(a.b, b.b)}`;\n return alpha >= 1 ? `rgb(${rgb})` : `rgba(${rgb},${Number(alpha.toFixed(ALPHA_DECIMALS))})`;\n}\n\n/** A colour's WCAG relative luminance, 0 (black) to 1 (white); null for a colour it can't read. */\nfunction relativeLuminance(color: string): number | null {\n const c = parseColor(color);\n if (!c) return null;\n const linear = (v: number) => {\n const s = v / 255;\n return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;\n };\n return 0.2126 * linear(c.r) + 0.7152 * linear(c.g) + 0.0722 * linear(c.b);\n}\n\n/** WCAG contrast of two opaque colours, 1 to 21; null when either can't be read. */\nexport function contrastRatio(a: string, b: string): number | null {\n const la = relativeLuminance(a);\n const lb = relativeLuminance(b);\n if (la === null || lb === null) return null;\n return (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05);\n}\n\n/** Steps a colour takes toward the ink while it looks for enough contrast. */\nconst READABLE_STEPS = 20;\n\n/**\n * `color`, or the nearest mix of it toward `ink` that reads at `minRatio` on\n * `background`: a hue kept, only deepened (or lightened) as far as it must\n * be. `color` as it is when it already reads, or when a colour can't be read.\n */\nexport function readableOn(color: string, background: string, ink: string, minRatio: number): string {\n const ratio = contrastRatio(color, background);\n if (ratio === null || ratio >= minRatio) return color;\n for (let step = 1; step <= READABLE_STEPS; step++) {\n const mixed = lerpColor(color, ink, step / READABLE_STEPS);\n if ((contrastRatio(mixed, background) ?? 0) >= minRatio) return mixed;\n }\n return ink;\n}\n\n/** Of `a` and `b`, the one that reads better on `fill`: the text for a tag of that colour. */\nexport function inkOn(fill: string, a: string, b: string): string {\n return (contrastRatio(fill, a) ?? 0) >= (contrastRatio(fill, b) ?? 0) ? a : b;\n}\n","/**\n * The display timezone: an IANA name (`'America/New_York'`, `'UTC'`), a fixed\n * offset in minutes east of UTC (`-300`), or null for the browser's own zone.\n */\nexport type TimeZoneSetting = string | number | null;\n\nconst MINUTE_MS = 60_000;\nconst DAY_MS = 24 * 60 * MINUTE_MS;\n/** Zones change their offset on quarter hours, so it holds for each 15 minutes. */\nconst OFFSET_BUCKET_MS = 15 * MINUTE_MS;\nconst OFFSET_CACHE_MAX = 8192;\n/**\n * Clocks change months apart, so a week whose offset is the same at both\n * ends holds it throughout: one lookup serves a week of bars.\n */\nconst WEEK_MS = 7 * DAY_MS;\nconst WEEK_CACHE_MAX = 4096;\n/** Names of UTC itself: no lookup needed. */\nconst UTC_ZONES = new Set(['UTC', 'Etc/UTC', 'GMT', 'Etc/GMT', 'UCT', 'Etc/UCT', 'Universal', 'Etc/Universal', 'Zulu', 'Etc/Zulu']);\n\nconst zoneFormats = new Map<string, Intl.DateTimeFormat>();\nconst offsetCache = new Map<string, number>();\n/** A week's offsets: `before` until the clocks change at `change`, then `after`. */\ninterface WeekOffsets {\n before: number;\n change: number;\n after: number;\n}\n/** Per zone, the offsets of each week looked at. */\nconst weekOffsets = new Map<string, Map<number, WeekOffsets>>();\n\nfunction zoneFormat(zone: string): Intl.DateTimeFormat {\n let format = zoneFormats.get(zone);\n if (!format) {\n format = new Intl.DateTimeFormat('en-US', {\n timeZone: zone,\n hourCycle: 'h23',\n year: 'numeric',\n month: 'numeric',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n second: 'numeric',\n });\n zoneFormats.set(zone, format);\n }\n return format;\n}\n\n/** Whether `zone` is a time zone this browser knows (an IANA name such as `'Europe/London'`). */\nexport function isValidTimeZone(zone: string): boolean {\n if (!zone) return false;\n try {\n zoneFormat(zone);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * The zone's offset from UTC, in minutes east, at `timeMs` — daylight saving\n * time included. Throws a RangeError for a zone the browser doesn't know.\n */\nexport function zoneOffsetMinutes(zone: string, timeMs: number): number {\n if (!Number.isFinite(timeMs) || UTC_ZONES.has(zone)) return 0;\n let weeks = weekOffsets.get(zone);\n if (!weeks) {\n weeks = new Map();\n weekOffsets.set(zone, weeks);\n }\n const week = Math.floor(timeMs / WEEK_MS);\n let offsets = weeks.get(week);\n if (!offsets) {\n offsets = readWeek(zone, week * WEEK_MS);\n if (weeks.size >= WEEK_CACHE_MAX) weeks.clear();\n weeks.set(week, offsets);\n }\n return timeMs < offsets.change ? offsets.before : offsets.after;\n}\n\n/** The offsets of the week from `start`, and the quarter hour the clocks change in it, if they do. */\nfunction readWeek(zone: string, start: number): WeekOffsets {\n const before = bucketOffset(zone, start);\n let last = start + WEEK_MS - OFFSET_BUCKET_MS;\n const after = bucketOffset(zone, last);\n if (after === before) return { before, change: Infinity, after };\n // Halve the week down to the first quarter hour on the new offset.\n let first = start;\n while (last - first > OFFSET_BUCKET_MS) {\n const mid = first + Math.floor((last - first) / OFFSET_BUCKET_MS / 2) * OFFSET_BUCKET_MS;\n if (bucketOffset(zone, mid) === before) first = mid;\n else last = mid;\n }\n return { before, change: last, after };\n}\n\n/** The zone's offset over the quarter hour holding `timeMs`. */\nfunction bucketOffset(zone: string, timeMs: number): number {\n const bucket = Math.floor(timeMs / OFFSET_BUCKET_MS);\n const key = `${zone}|${bucket}`;\n const cached = offsetCache.get(key);\n if (cached !== undefined) return cached;\n\n const at = bucket * OFFSET_BUCKET_MS;\n let year = 1970, month = 1, day = 1, hour = 0, minute = 0, second = 0;\n for (const part of zoneFormat(zone).formatToParts(new Date(at))) {\n const value = Number(part.value);\n switch (part.type) {\n case 'year': year = value; break;\n case 'month': month = value; break;\n case 'day': day = value; break;\n case 'hour': hour = value % 24; break;\n case 'minute': minute = value; break;\n case 'second': second = value; break;\n }\n }\n const offset = Math.round((Date.UTC(year, month - 1, day, hour, minute, second) - at) / MINUTE_MS);\n if (offsetCache.size >= OFFSET_CACHE_MAX) offsetCache.clear();\n offsetCache.set(key, offset);\n return offset;\n}\n\n/** Whether `tz` keeps UTC's clock all year: a name of UTC itself, or an offset of 0. */\nexport function isUtcTimeZone(tz: TimeZoneSetting): boolean {\n return tz === 0 || (typeof tz === 'string' && UTC_ZONES.has(tz));\n}\n\n/** Minutes east of UTC at `timeMs` for any display timezone. */\nexport function offsetAt(tz: TimeZoneSetting, timeMs: number): number {\n if (tz === null) return -new Date(timeMs).getTimezoneOffset();\n if (typeof tz === 'number') return tz;\n return zoneOffsetMinutes(tz, timeMs);\n}\n\n/**\n * The instant whose wall clock in `tz` reads `wallMs` (a wall-clock time\n * written as if it were UTC, e.g. `Date.UTC(2026, 0, 15, 9, 30)`). A time\n * that occurs twice (clocks going back) is its first occurrence; a time a\n * spring-forward skips moves forward by the jump (02:30 → 03:30).\n */\nexport function wallToUtc(wallMs: number, tz: TimeZoneSetting): number {\n // The instant is within 14 hours of `wallMs`, so the offsets a day either\n // side bracket any clock change near it.\n const early = wallMs - offsetAt(tz, wallMs - DAY_MS) * MINUTE_MS;\n if (early + offsetAt(tz, early) * MINUTE_MS === wallMs) return early;\n const late = wallMs - offsetAt(tz, wallMs + DAY_MS) * MINUTE_MS;\n if (late + offsetAt(tz, late) * MINUTE_MS === wallMs) return late;\n return early; // skipped: read with the offset from before the jump\n}\n\nconst dateFormatters = new Map<string, (ms: number) => string>();\n\n/**\n * `Intl.DateTimeFormat#format` for dates in a display timezone, cached per\n * locale, options and zone (building a format costs ~40µs). A fixed offset\n * is applied by shifting the instant and formatting it as UTC.\n */\nexport function zonedDateFormatter(\n locale: string,\n options: Intl.DateTimeFormatOptions,\n tz: TimeZoneSetting,\n): (ms: number) => string {\n const key = `${locale}|${JSON.stringify(options)}|${tz === null ? 'local' : typeof tz === 'number' ? `fixed:${tz}` : tz}`;\n let formatter = dateFormatters.get(key);\n if (formatter) return formatter;\n\n const timeZone = tz === null ? undefined : typeof tz === 'number' ? 'UTC' : tz;\n let format: Intl.DateTimeFormat;\n try {\n format = new Intl.DateTimeFormat(locale, { ...options, timeZone });\n } catch {\n format = new Intl.DateTimeFormat('en-US', { ...options, timeZone }); // unknown locale tag\n }\n const shift = typeof tz === 'number' ? tz * MINUTE_MS : 0;\n formatter = (ms) => format.format(new Date(ms + shift));\n dateFormatters.set(key, formatter);\n return formatter;\n}\n","import type { KnownTimeFrame, TimeFrame, TimeFrameUnit } from '../types/ohlc.js';\nimport { isUtcTimeZone, offsetAt, wallToUtc, type TimeZoneSetting } from './timezone.js';\nimport { barTimeUnit } from './data.js';\n\nconst TIMEFRAME_MS: Record<KnownTimeFrame, number> = {\n '1s': 1_000,\n '5s': 5_000,\n '15s': 15_000,\n '30s': 30_000,\n '1m': 60_000,\n '3m': 180_000,\n '5m': 300_000,\n '15m': 900_000,\n '30m': 1_800_000,\n '45m': 2_700_000,\n '1h': 3_600_000,\n '2h': 7_200_000,\n '3h': 10_800_000,\n '4h': 14_400_000,\n '6h': 21_600_000,\n '8h': 28_800_000,\n '12h': 43_200_000,\n '1d': 86_400_000,\n '2d': 172_800_000,\n '3d': 259_200_000,\n '1w': 604_800_000,\n '2w': 1_209_600_000,\n '1M': 2_592_000_000,\n '3M': 7_776_000_000,\n '6M': 15_552_000_000,\n '12M': 31_536_000_000,\n};\n\n/** Milliseconds per unit; a month counts 30 days (a 12-month frame, 365). */\nconst UNIT_MS: Record<TimeFrameUnit, number> = {\n s: 1_000,\n m: 60_000,\n h: 3_600_000,\n d: 86_400_000,\n w: 604_800_000,\n M: 2_592_000_000,\n};\n\nconst TIMEFRAME_PATTERN = /^([1-9]\\d*)([smhdwM])$/;\n\n/** A timeframe's count and unit, or null when `value` isn't one (`'7m'` → 7 minutes). */\nexport function parseTimeframe(value: string): { count: number; unit: TimeFrameUnit } | null {\n const match = TIMEFRAME_PATTERN.exec(value);\n if (!match) return null;\n const count = Number(match[1]);\n return Number.isSafeInteger(count) ? { count, unit: match[2] as TimeFrameUnit } : null;\n}\n\n/** Most trades a tick bar may hold. */\nconst MAX_TICKS_PER_BAR = 1_000_000;\n\n/** The trades per bar of a tick timeframe (`'100T'` → 100), or null for any other. */\nexport function tickBarCount(timeframe: string): number | null {\n const match = /^([1-9]\\d*)T$/.exec(timeframe);\n if (!match) return null;\n const count = Number(match[1]);\n return Number.isSafeInteger(count) && count <= MAX_TICKS_PER_BAR ? count : null;\n}\n\nexport function isTimeFrame(value: string): value is TimeFrame {\n return parseTimeframe(value) !== null;\n}\n\n/** Length of a timeframe in milliseconds (approximate for months); NaN for a non-timeframe. */\nexport function timeframeToMs(tf: TimeFrame): number {\n const known = TIMEFRAME_MS[tf as KnownTimeFrame];\n if (known !== undefined) return known;\n const parsed = parseTimeframe(tf);\n return parsed ? parsed.count * UNIT_MS[parsed.unit] : Number.NaN;\n}\n\nexport function formatTimestamp(timestamp: number, tf: TimeFrame): string {\n const d = new Date(timestamp);\n const ms = timeframeToMs(tf);\n if (ms >= 86_400_000) {\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }\n if (ms >= 3_600_000) {\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\n }\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\nexport function alignToTimeframe(timestamp: number, tf: TimeFrame): number {\n const ms = timeframeToMs(tf);\n return Math.floor(timestamp / ms) * ms;\n}\n\nexport interface TimeParts {\n year: number;\n /** 1 to 12. */\n month: number;\n day: number;\n hours: number;\n minutes: number;\n}\n\n/**\n * Calendar parts of a timestamp in a display timezone: an IANA zone\n * (`'America/New_York'`, daylight saving time included), a fixed UTC offset in\n * minutes (e.g. -300 for EST) or the browser's zone (`null`).\n */\nexport function timeParts(timeMs: number, tz: TimeZoneSetting): TimeParts {\n if (tz === null) {\n const d = new Date(timeMs);\n return {\n year: d.getFullYear(),\n month: d.getMonth() + 1,\n day: d.getDate(),\n hours: d.getHours(),\n minutes: d.getMinutes(),\n };\n }\n const d = new Date(timeMs + offsetAt(tz, timeMs) * 60_000);\n return {\n year: d.getUTCFullYear(),\n month: d.getUTCMonth() + 1,\n day: d.getUTCDate(),\n hours: d.getUTCHours(),\n minutes: d.getUTCMinutes(),\n };\n}\n\n/**\n * A bar with no time-of-day component (a daily, weekly, monthly or yearly candle — always anchored\n * to a calendar-day boundary, so hours/minutes read 00:00) needs the YEAR in its label instead: a\n * bare `month/day` is ambiguous across years, and `00:00` tells a trader nothing. Detected from the\n * parts themselves rather than a separate timeframe parameter, so every caller that formats a bar's\n * time gets the same rule for free. It can't tell an hourly bar at midnight from a daily one:\n * callers that have the series ask `barsAreDaily` first and fall back to this.\n */\nexport function isDateOnly(parts: Pick<TimeParts, 'hours' | 'minutes'>): boolean {\n return parts.hours === 0 && parts.minutes === 0;\n}\n\n/** Gaps this long or longer (a day with a daylight-saving change is 23 h) mean daily-or-larger bars. */\nconst DAILY_GAP_MS = 20 * 3_600_000;\n\n/**\n * Whether bars are a day apart or more (daily, weekly, monthly): their labels\n * then carry a date and no time of day, while an hourly bar at midnight keeps\n * its time. Read from the smallest gap among the first bars, so a weekend or\n * a missing session doesn't make an intraday series look daily. Undefined for\n * fewer than two bars.\n */\nexport function barsAreDaily(data: ArrayLike<{ time: number }>): boolean | undefined {\n const n = Math.min(data.length, 64);\n if (n < 2) return undefined;\n const unit = barTimeUnit(data);\n let gap = Infinity;\n for (let i = 1; i < n; i++) {\n const d = Math.abs(data[i].time - data[i - 1].time) * unit;\n if (d > 0 && d < gap) gap = d;\n }\n return gap === Infinity ? undefined : gap >= DAILY_GAP_MS;\n}\n\n/** A short label like `UTC-5` or `UTC+5:30` for the offset in force at `atMs` (default: now). */\nexport function tzLabel(tz: TimeZoneSetting, atMs: number = Date.now()): string {\n const min = offsetAt(tz, atMs);\n const sign = min >= 0 ? '+' : '-';\n const abs = Math.abs(min);\n const h = Math.floor(abs / 60);\n const m = abs % 60;\n return m === 0 ? `UTC${sign}${h}` : `UTC${sign}${h}:${String(m).padStart(2, '0')}`;\n}\n\n/** Day-of-week for a Monday-anchored reference week (1970-01-05 was a Monday, UTC). */\nconst WEEK_ANCHOR_MS = Date.UTC(1970, 0, 5);\nconst MINUTE_MS = UNIT_MS.m;\nconst DAY_MS = UNIT_MS.d;\nconst HOURS_PER_DAY = 24;\n\n/** Where the buckets of `timeframeBucketStart` (and `resampleBars`) start. */\nexport interface BucketOptions {\n /** The day weeks start on: 0 Sunday, 1 Monday (the default). */\n weekStartsOn?: 0 | 1;\n /**\n * The zone whose midnight days start at: an IANA name such as\n * `'Asia/Ho_Chi_Minh'` (daylight saving time included), or minutes east of\n * UTC. Days, weeks, months and the hour frames that divide a day (2h, 3h,\n * 4h, 6h, 8h, 12h) follow it; 1h and shorter frames keep their epoch floor,\n * so the hour a fall-back night repeats stays two bars. Left out, UTC's.\n */\n timeZone?: string | number;\n /**\n * The times are bars a day long or more: one stamped at 00:00 UTC is the\n * date it names, and keeps that date's UTC bucket and stamp. Other times\n * are instants in `timeZone`.\n */\n dates?: boolean;\n}\n\ntype ParsedFrame = { count: number; unit: TimeFrameUnit };\n/** A frame that isn't one buckets as a minute, as it always has. */\nconst MINUTE_FRAME: ParsedFrame = { count: 1, unit: 'm' };\nconst PARSED_FRAMES_MAX = 256;\n/** Bars are bucketed one by one: read each timeframe's text once, not once a bar. */\nconst parsedFrames = new Map<string, ParsedFrame>();\n\nfunction parsedFrame(tf: TimeFrame): ParsedFrame {\n let frame = parsedFrames.get(tf);\n if (!frame) {\n frame = parseTimeframe(tf) ?? MINUTE_FRAME;\n if (parsedFrames.size >= PARSED_FRAMES_MAX) parsedFrames.clear();\n parsedFrames.set(tf, frame);\n }\n return frame;\n}\n\n/** Whether a frame's bars are a day long or more: days, weeks, months. */\nfunction spansDays({ unit }: ParsedFrame): boolean {\n return unit === 'd' || unit === 'w' || unit === 'M';\n}\n\n/** Whether a frame's buckets start at a day's midnight: days, weeks, months, and hours that divide a day. */\nfunction followsDays(frame: ParsedFrame): boolean {\n if (frame.unit === 'h') return frame.count > 1 && HOURS_PER_DAY % frame.count === 0;\n return spansDays(frame);\n}\n\n/** Whether `timeframeBucketStart` starts the buckets of `tf` at a zone's midnight when given one. */\nexport function timeframeFollowsDays(tf: TimeFrame): boolean {\n return followsDays(parsedFrame(tf));\n}\n\n/** Whether bars of `tf` are a day long or more (days, weeks, months), which feeds often stamp by date. */\nexport function timeframeSpansDays(tf: TimeFrame): boolean {\n return spansDays(parsedFrame(tf));\n}\n\n/** Whether `timeZone` moves a day's midnight away from UTC's. */\nfunction isZoned(timeZone: string | number | undefined): timeZone is string | number {\n return timeZone !== undefined && !isUtcTimeZone(timeZone);\n}\n\n/**\n * Start of the bucket a timestamp falls into for a given timeframe.\n *\n * Minutes and hours floor to multiples of the frame since the Unix epoch.\n * Days, weeks (from Monday, or `weekStartsOn`), months, quarters and years\n * start at midnight, and the hour frames that divide a day (2h to 12h) count\n * from it: UTC's, or `timeZone`'s when given (a day the clocks change is 23\n * or 25 hours long, its 4h bucket 3 or 5). A 3M frame starts on quarters, a\n * 12M one on 1 January. The third argument may also be the day weeks start\n * on alone. Throws a RangeError for a zone the browser doesn't know.\n */\nexport function timeframeBucketStart(\n timestamp: number,\n tf: TimeFrame,\n options: 0 | 1 | BucketOptions = 1,\n): number {\n const frame = parsedFrame(tf);\n const weekStartsOn = typeof options === 'number' ? options : options.weekStartsOn ?? 1;\n const timeZone = typeof options === 'number' ? undefined : options.timeZone;\n if (!isZoned(timeZone) || !followsDays(frame)) return utcBucketStart(timestamp, frame, weekStartsOn);\n // A date keeps the bucket of the day it names; only instants follow the zone.\n if (typeof options === 'object' && options.dates && timestamp % DAY_MS === 0) {\n return utcBucketStart(timestamp, frame, weekStartsOn);\n }\n // Bucket the zone's wall clock as if it were UTC, then find when that wall time happens there.\n const wall = timestamp + offsetAt(timeZone, timestamp) * MINUTE_MS;\n return wallToUtc(utcBucketStart(wall, frame, weekStartsOn), timeZone);\n}\n\n/** The bucket of `timestamp` on UTC's clock and calendar. */\nfunction utcBucketStart(timestamp: number, { count, unit }: ParsedFrame, weekStartsOn: 0 | 1): number {\n if (unit === 's' || unit === 'm' || unit === 'h' || unit === 'd') {\n const ms = count * UNIT_MS[unit];\n return Math.floor(timestamp / ms) * ms;\n }\n\n const d = new Date(timestamp);\n\n if (unit === 'w') {\n const dow = d.getUTCDay();\n const shift = (dow - weekStartsOn + 7) % 7;\n const weekStart = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate() - shift);\n if (count <= 1) return weekStart;\n const weekIndex = Math.floor((weekStart - WEEK_ANCHOR_MS) / (7 * DAY_MS));\n const grouped = Math.floor(weekIndex / count) * count;\n return WEEK_ANCHOR_MS + grouped * 7 * DAY_MS;\n }\n\n // months / quarters / years\n const totalMonths = d.getUTCFullYear() * 12 + d.getUTCMonth();\n const grouped = Math.floor(totalMonths / count) * count;\n return Date.UTC(Math.floor(grouped / 12), grouped % 12, 1);\n}\n\n/**\n * The zone a bar a day long or more is dated in, whatever zone the chart\n * shows (`tz`): UTC for one stamped at 00:00 UTC, the date it names; its\n * exchange's zone (`exchangeZone`) for one stamped at the exchange's\n * midnight, as the days a chart builds are; else `tz`, so a bar stamped at\n * the browser's midnight still reads its own date there.\n */\nexport function barDateZone(timeMs: number, tz: TimeZoneSetting, exchangeZone?: string | null): TimeZoneSetting {\n if (timeMs % DAY_MS === 0) return 0;\n if (exchangeZone && timeframeBucketStart(timeMs, '1d', { timeZone: exchangeZone }) === timeMs) return exchangeZone;\n return tz;\n}\n\n/** The calendar parts a bar a day long or more is labelled with: its date, in the zone `barDateZone` gives. */\nexport function barDateParts(timeMs: number, tz: TimeZoneSetting, exchangeZone?: string | null): TimeParts {\n return timeParts(timeMs, barDateZone(timeMs, tz, exchangeZone));\n}\n","const NUMBER_FORMAT_CACHE_LIMIT = 64;\nconst numberFormatCache = new Map<string, Intl.NumberFormat>();\n\n/**\n * `Number#toLocaleString(locale, options)` constructs a fresh\n * `Intl.NumberFormat` on every call — ~20µs in V8 versus ~0.4µs to reuse one.\n * Axis labels, the legend, crosshair pills and panel axes format dozens of\n * numbers per frame, so formatters are cached per (locale, precision). The\n * output is identical: per spec, `toLocaleString` is defined as exactly this.\n */\nfunction numberFormat(locale: string, precision: number): Intl.NumberFormat {\n const key = `${locale}|${precision}`;\n let nf = numberFormatCache.get(key);\n if (!nf) {\n if (numberFormatCache.size >= NUMBER_FORMAT_CACHE_LIMIT) numberFormatCache.clear();\n nf = new Intl.NumberFormat(locale, {\n minimumFractionDigits: precision,\n maximumFractionDigits: precision,\n });\n numberFormatCache.set(key, nf);\n }\n return nf;\n}\n\n/**\n * A price on a tag beside the axis (an order, a position, an alert) as the\n * axis writes one: the chart's price format when it has one, else grouped in\n * its number locale at `precision` decimals, or the market's or the symbol's\n * (`viewport.pricePrecision`), or the axis's own for the range on view when\n * neither is given.\n */\nexport function priceTagText(\n price: number,\n viewport: Pick<ViewportState, 'formatPrice' | 'numberLocale' | 'priceRange' | 'pricePrecision'>,\n precision?: number,\n): string {\n if (viewport.formatPrice) return viewport.formatPrice(price);\n const decimals = precision ?? viewport.pricePrecision ?? autoPricePrecision(viewport.priceRange.min, viewport.priceRange.max);\n return formatPrice(price, decimals, viewport.numberLocale ?? 'en-US');\n}\n\nexport function formatPrice(value: number, precision = 2, locale = 'en-US'): string {\n return numberFormat(locale, precision).format(value);\n}\n\n/**\n * Decimals the price axis uses for a visible price range: one more than its\n * tick step needs, 2 at minimum. Everything that prints a price next to the\n * axis (legend, crosshair pill, last-price tag) shares it, so a sub-cent\n * asset reads \"0.000004349\" everywhere instead of \"0.00\" off the axis.\n */\nexport function autoPricePrecision(min: number, max: number): number {\n if (!(max > min) || !Number.isFinite(min) || !Number.isFinite(max)) return 2;\n const step = computeTickStep(min, max, 8);\n return step > 0 && step < 1 ? Math.ceil(-Math.log10(step)) + 1 : 2;\n}\n\nimport type { PriceScaleMode, ViewportState } from '../types/rendering.js';\nimport type { PriceFormatter, PriceFraction } from '../types/chart.js';\nimport { computeTickStep } from './math.js';\n\n/** Decimals a percentage on the price scale shows. */\nconst PERCENT_DECIMALS = 2;\n\n/**\n * Format a price-axis label for a given scale mode, in the number locale.\n *\n * - `regular` / `logarithmic`: the raw price.\n * - `percentage`: change from `baseline`, e.g. `+12.34%` (`+12,34%` in\n * `de-DE`); one that reads as nothing has no sign.\n * - `indexedTo100`: the price rebased so `baseline` reads as 100.\n *\n * Falls back to a plain price when a baseline is required but missing/zero.\n */\nexport function formatPriceScaleLabel(\n price: number,\n mode: PriceScaleMode,\n baseline: number | undefined,\n precision = 2,\n locale = 'en-US',\n): string {\n if ((mode === 'percentage' || mode === 'indexedTo100') && baseline && baseline !== 0) {\n if (mode === 'percentage') {\n const pct = (price / baseline - 1) * 100;\n const text = formatPrice(Math.abs(pct), PERCENT_DECIMALS, locale);\n const sign = text === formatPrice(0, PERCENT_DECIMALS, locale) ? '' : pct > 0 ? '+' : '-';\n return `${sign}${text}%`;\n }\n const indexed = (price / baseline) * 100;\n return formatPrice(indexed, 2, locale);\n }\n return formatPrice(price, precision, locale);\n}\n\n/**\n * `value` in fractions of a point: whole points, an apostrophe, then the\n * fraction's numerator padded to the denominator's digits (`101'16` for\n * 101.5 in 32nds). A `subDenominator` of 2 or 4 adds the half or quarter of\n * that fraction as one more digit, as futures quote it (`101'165`, `110'162`,\n * `110'167`). Rounds to the nearest step. A denominator that isn't a whole\n * number above 1 gives plain digits.\n */\nexport function formatFraction(value: number, denominator: number, subDenominator = 1): string {\n const sub = Number.isInteger(subDenominator) && subDenominator > 1 ? subDenominator : 1;\n if (!Number.isFinite(value) || !Number.isInteger(denominator) || denominator < 2) return String(value);\n const steps = denominator * sub;\n const total = Math.round(Math.abs(value) * steps);\n const whole = Math.floor(total / steps);\n const rest = total - whole * steps;\n const numerator = Math.floor(rest / sub);\n const width = String(denominator - 1).length;\n const tail = sub > 1 ? String(Math.floor(((rest - numerator * sub) / sub) * 10)) : '';\n const sign = value < 0 && total > 0 ? '-' : '';\n return `${sign}${whole}'${String(numerator).padStart(width, '0')}${tail}`;\n}\n\n/**\n * The smallest step a fraction format prints (a 32nd; a quarter of one with\n * `subDenominator` 4), or null for a denominator it can't print (it falls\n * back to plain digits then).\n */\nexport function fractionTick(fraction: PriceFraction): number | null {\n if (!Number.isInteger(fraction.denominator) || fraction.denominator < 2) return null;\n const sub = Number.isInteger(fraction.subDenominator) && (fraction.subDenominator ?? 0) > 1 ? fraction.subDenominator as number : 1;\n return 1 / (fraction.denominator * sub);\n}\n\n/** The formatter a `priceFormat` option stands for: its function, its fraction's, or null for decimals. */\nexport function priceFormatterFor(format: PriceFormatter | PriceFraction | null | undefined): PriceFormatter | null {\n if (!format) return null;\n if (typeof format === 'function') return format;\n // A denominator it can't print leaves the chart's decimals.\n if (fractionTick(format) === null) return null;\n return (price) => formatFraction(price, format.denominator, format.subDenominator);\n}\n\nexport function formatVolume(value: number): string {\n if (value >= 1_000_000_000) return (value / 1_000_000_000).toFixed(2) + 'B';\n if (value >= 1_000_000) return (value / 1_000_000).toFixed(2) + 'M';\n if (value >= 1_000) return (value / 1_000).toFixed(2) + 'K';\n return value.toFixed(0);\n}\n\nexport function detectPrecision(values: number[]): number {\n let maxDecimals = 0;\n for (const v of values) {\n const str = v.toString();\n const dot = str.indexOf('.');\n if (dot >= 0) {\n maxDecimals = Math.max(maxDecimals, str.length - dot - 1);\n }\n }\n return Math.min(maxDecimals, 8);\n}\n","import type { OHLCBar } from '../types/ohlc.js';\n\n/** The price an indicator can be computed from. */\nexport const PRICE_SOURCES = ['close', 'open', 'high', 'low', 'hl2', 'hlc3', 'ohlc4', 'hlcc4'] as const;\n\nexport type PriceSource = (typeof PRICE_SOURCES)[number];\n\nexport function isPriceSource(value: unknown): value is PriceSource {\n return typeof value === 'string' && (PRICE_SOURCES as readonly string[]).includes(value);\n}\n\n/** A bar's price by source: `hl2` = (high + low) / 2, `hlc3`, `ohlc4`, `hlcc4` = (h + l + 2c) / 4. */\nexport function sourcePrice(bar: OHLCBar, source: PriceSource): number {\n switch (source) {\n case 'open': return bar.open;\n case 'high': return bar.high;\n case 'low': return bar.low;\n case 'hl2': return (bar.high + bar.low) / 2;\n case 'hlc3': return (bar.high + bar.low + bar.close) / 3;\n case 'ohlc4': return (bar.open + bar.high + bar.low + bar.close) / 4;\n case 'hlcc4': return (bar.high + bar.low + 2 * bar.close) / 4;\n default: return bar.close;\n }\n}\n\nconst INDICATOR_SOURCE = /^ind:([^:]+):(.+)$/;\n\n/** A source that is another indicator's line: `ind:<instanceId>:<key>`. */\nexport function indicatorSource(instanceId: string, key: string): string {\n return `ind:${instanceId}:${key}`;\n}\n\n/** The indicator line a source refers to, or null for a price source or anything else. */\nexport function parseIndicatorSource(value: unknown): { instanceId: string; key: string } | null {\n if (typeof value !== 'string') return null;\n const m = INDICATOR_SOURCE.exec(value);\n return m ? { instanceId: m[1], key: m[2] } : null;\n}\n","import type { OHLCBar, TimeFrame, TimeFrameUnit } from '../types/ohlc.js';\nimport { barsAreDaily, parseTimeframe, timeframeBucketStart, timeframeFollowsDays, timeframeToMs, type BucketOptions } from './time.js';\nimport { isUtcTimeZone, offsetAt } from './timezone.js';\n\nconst DAY_MS = 86_400_000;\nconst MINUTE_MS = 60_000;\n\n/**\n * Aggregate bars (ascending, times in ms) into a coarser timeframe: per\n * bucket (see `timeframeBucketStart`) the first open, the extremes, the last\n * close and the summed volume. The input bars are not changed.\n *\n * With a `timeZone`, days, weeks, months and the hour frames that divide a\n * day start at its midnight. Daily-or-longer bars stamped at 00:00 UTC are\n * read as the dates they name (unless `dates` says otherwise), so a Monday\n * stays in its own week west of UTC, and the weeks keep 00:00 UTC stamps.\n */\nexport function resampleBars(bars: readonly OHLCBar[], target: TimeFrame, options: 0 | 1 | BucketOptions = 1): OHLCBar[] {\n const bucket = bucketOptionsFor(bars, target, options);\n const out: OHLCBar[] = [];\n let current: OHLCBar | null = null;\n for (const bar of bars) {\n const key = timeframeBucketStart(bar.time, target, bucket);\n if (current === null || key !== current.time) {\n current = { time: key, open: bar.open, high: bar.high, low: bar.low, close: bar.close, volume: bar.volume };\n out.push(current);\n } else {\n if (bar.high > current.high) current.high = bar.high;\n if (bar.low < current.low) current.low = bar.low;\n current.close = bar.close;\n current.volume += bar.volume;\n }\n }\n return out;\n}\n\n/** The options as `timeframeBucketStart` takes them, with `dates` read from the bars when a zone needs it. */\nfunction bucketOptionsFor(bars: readonly OHLCBar[], target: TimeFrame, options: 0 | 1 | BucketOptions): 0 | 1 | BucketOptions {\n if (typeof options === 'number' || options.timeZone === undefined || options.dates !== undefined) return options;\n if (isUtcTimeZone(options.timeZone) || !timeframeFollowsDays(target)) return options;\n return { ...options, dates: barsAreDaily(bars) === true };\n}\n\nconst isFixedLength = (unit: TimeFrameUnit): boolean => unit === 's' || unit === 'm' || unit === 'h' || unit === 'd';\n\n/** Whether whole bars of `base` fill every bucket of `target` exactly. */\nfunction buildsInto(base: TimeFrame, target: TimeFrame): boolean {\n const b = parseTimeframe(base);\n const t = parseTimeframe(target);\n if (!b || !t) return false;\n const baseMs = timeframeToMs(base);\n // Feeds disagree on where a 3-day bar starts: only build from whole days.\n if (b.unit === 'd' && b.count > 1) return false;\n if (isFixedLength(t.unit)) {\n return isFixedLength(b.unit) && timeframeToMs(target) % baseMs === 0;\n }\n if (b.unit === t.unit) return t.count % b.count === 0;\n // Weeks and months start at midnight: build them from bars that never\n // cross one.\n return isFixedLength(b.unit) && DAY_MS % baseMs === 0;\n}\n\n/**\n * Whether bars of `base`, which feeds start on UTC's clock, also start on\n * every midnight of `timeZone`: its offset, in winter and in summer, is a\n * whole number of them. Bars of a day or more line up as dates.\n */\nfunction linesUpWith(base: TimeFrame, timeZone: string | number): boolean {\n const baseMs = timeframeToMs(base);\n if (!(baseMs < DAY_MS)) return true;\n const year = new Date().getUTCFullYear();\n return [Date.UTC(year, 0, 1), Date.UTC(year, 6, 1)].every((at) => (offsetAt(timeZone, at) * MINUTE_MS) % baseMs === 0);\n}\n\n/**\n * The coarsest of `supported` that builds `target` from whole bars (e.g. 7m\n * from 1m, 90m from 30m, a quarter from months), or null when none does.\n * With a `timeZone`, a target whose buckets start at its midnight (days,\n * weeks, months, 2h to 12h) takes only bars that line up with it: 1h for\n * Ho Chi Minh City's days, not 4h.\n */\nexport function pickBaseTimeframe(\n target: TimeFrame,\n supported: readonly TimeFrame[],\n options: Pick<BucketOptions, 'timeZone'> = {},\n): TimeFrame | null {\n const { timeZone } = options;\n const zone = timeZone !== undefined && !isUtcTimeZone(timeZone) && timeframeFollowsDays(target) ? timeZone : undefined;\n let best: TimeFrame | null = null;\n let bestMs = 0;\n for (const tf of supported) {\n if (!buildsInto(tf, target)) continue;\n if (zone !== undefined && !linesUpWith(tf, zone)) continue;\n const ms = timeframeToMs(tf);\n if (ms > bestMs) {\n best = tf;\n bestMs = ms;\n }\n }\n return best;\n}\n","import type { SymbolInfo } from '../types/symbol.js';\n\n/** How well `query` (upper case) matches `text` (upper case): 0 when it doesn't. */\nfunction score(text: string, query: string): number {\n if (!text) return 0;\n if (text === query) return 1000;\n if (text.startsWith(query)) return 600 - Math.min(100, text.length - query.length);\n const at = text.indexOf(query);\n return at >= 0 ? 300 - Math.min(100, at) : 0;\n}\n\n/**\n * Symbols matching `query`, best first: an exact ticker, then tickers that\n * start with it, then names that contain it. `boost` adds to a match's score\n * (say, for the quote currencies most traded). An empty query keeps the order\n * given. At most `limit` results.\n */\nexport function rankSymbols(\n symbols: readonly SymbolInfo[],\n query: string,\n limit = 50,\n boost?: (info: SymbolInfo) => number,\n): SymbolInfo[] {\n const q = query.trim().toUpperCase();\n if (!q) return symbols.slice(0, limit);\n const scored: { info: SymbolInfo; score: number }[] = [];\n for (const info of symbols) {\n const s = Math.max(\n score(info.symbol.toUpperCase(), q),\n score((info.description ?? '').toUpperCase(), q) * 0.8,\n );\n if (s > 0) scored.push({ info, score: s + (boost?.(info) ?? 0) });\n }\n scored.sort((a, b) => b.score - a.score || a.info.symbol.localeCompare(b.info.symbol));\n return scored.slice(0, limit).map((s) => s.info);\n}\n\n/** Decimals in a price step: `'0.01000000'` → 2, `'1'` → 0, `1e-8` → 8. */\nexport function stepDecimals(step: number | string): number {\n const value = typeof step === 'number' ? step : Number(step);\n if (!Number.isFinite(value) || value <= 0) return 0;\n for (let decimals = 0; decimals <= 12; decimals++) {\n const scaled = value * 10 ** decimals;\n if (Math.abs(scaled - Math.round(scaled)) < 1e-9 * Math.max(1, scaled)) return decimals;\n }\n return 12;\n}\n\n/** The zone a symbol keeps its hours in: its `timeZone`, else the older `timezone`. */\nexport function symbolTimeZone(info: Pick<SymbolInfo, 'timeZone' | 'timezone'> | null | undefined): string | undefined {\n return info?.timeZone ?? info?.timezone;\n}\n\n/** `'09:30'` → 570 (`'24:00'`, a day's end, → 1440), or null for anything that isn't a time of day. */\nexport function sessionMinute(time: string): number | null {\n const match = /^(\\d{1,2}):(\\d{2})$/.exec(time.trim());\n if (!match) return null;\n const hours = Number(match[1]);\n const minutes = Number(match[2]);\n if (hours === 24 && minutes === 0) return 1440;\n return hours < 24 && minutes < 60 ? hours * 60 + minutes : null;\n}\n","import type { SymbolInfo } from '../types/symbol.js';\nimport { sessionMinute, symbolTimeZone } from './symbols.js';\nimport { isValidTimeZone, zoneOffsetMinutes } from './timezone.js';\n\n/** Whether a symbol's market is trading now, and when that changes. */\nexport interface MarketStatus {\n /** `'always'`: no hours known (24/7, such as crypto). */\n state: 'open' | 'closed' | 'always';\n /** When it next closes (open) or opens (closed), in ms; null when unknown. */\n next: number | null;\n}\n\nconst DAY_MS = 86_400_000;\nconst MINUTE_MS = 60_000;\n/** Days looked ahead for the next open (a long weekend, a week of holidays). */\nconst LOOK_AHEAD_DAYS = 8;\n\n/**\n * The market status of `info` at `now`: in a session of its hours (in its\n * exchange's time zone, clocks changes included) or not, and when that\n * changes. Sessions that meet count as one; a session past midnight belongs\n * to the day it starts. Without hours or a zone it knows: `'always'`.\n */\nexport function marketStatus(info: SymbolInfo | null | undefined, now: number): MarketStatus {\n const zone = symbolTimeZone(info);\n const sessions = (info?.sessions ?? []).flatMap((s) => {\n const start = sessionMinute(s.start);\n const end = sessionMinute(s.end);\n if (start === null || end === null || start === end) return [];\n return [{ start, end, days: Array.isArray(s.days) ? s.days : null }];\n });\n if (!zone || !isValidTimeZone(zone) || sessions.length === 0 || !Number.isFinite(now)) {\n return { state: 'always', next: null };\n }\n\n const offset = zoneOffsetMinutes(zone, now) * MINUTE_MS;\n const today = Math.floor((now + offset) / DAY_MS) * DAY_MS;\n // A wall-clock time in the zone, back to UTC with the offset that holds then\n // (asked twice, so a time beside a clock change settles on its side).\n const toUtc = (local: number) => {\n const guess = local - zoneOffsetMinutes(zone, local - offset) * MINUTE_MS;\n return local - zoneOffsetMinutes(zone, guess) * MINUTE_MS;\n };\n\n const spans: [number, number][] = [];\n for (let d = -1; d <= LOOK_AHEAD_DAYS; d++) {\n const dayStart = today + d * DAY_MS;\n const weekday = (Math.floor(dayStart / DAY_MS) + 4) % 7; // 1 Jan 1970 was a Thursday\n for (const s of sessions) {\n if (s.days && !s.days.includes(weekday)) continue;\n const start = dayStart + s.start * MINUTE_MS;\n const end = (s.end > s.start ? dayStart : dayStart + DAY_MS) + s.end * MINUTE_MS;\n spans.push([toUtc(start), toUtc(end)]);\n }\n }\n spans.sort((a, b) => a[0] - b[0]);\n const merged: [number, number][] = [];\n for (const [start, end] of spans) {\n const last = merged[merged.length - 1];\n if (last && start <= last[1]) merged[merged.length - 1] = [last[0], Math.max(last[1], end)];\n else merged.push([start, end]);\n }\n\n const current = merged.find(([start, end]) => start <= now && now < end);\n if (current) return { state: 'open', next: current[1] };\n const upcoming = merged.find(([start]) => start > now);\n return { state: 'closed', next: upcoming ? upcoming[0] : null };\n}\n","import type { DrawingLevel, DrawingOptionDef, DrawingOptionDefs, DrawingOptionValue, DrawingOptions } from '../types/drawing.js';\n\n/** Most levels a drawing keeps; more is a pasted or hand-edited state, not a chart. */\nconst MAX_LEVELS = 48;\nconst MAX_TEXT = 2000;\n/** Largest level ratio kept (a Fibonacci level of 4.236, a time zone of 89 bars). */\nconst MAX_LEVEL_VALUE = 10_000;\n\nfunction sanitizeLevels(raw: unknown): DrawingLevel[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const levels: DrawingLevel[] = [];\n for (const item of raw) {\n if (levels.length >= MAX_LEVELS) break;\n if (typeof item !== 'object' || item === null) continue;\n const { value, visible, color } = item as Record<string, unknown>;\n if (typeof value !== 'number' || !Number.isFinite(value) || Math.abs(value) > MAX_LEVEL_VALUE) continue;\n if (visible !== undefined && typeof visible !== 'boolean') continue;\n const level: DrawingLevel = { value, visible: visible ?? true };\n if (typeof color === 'string' && color) level.color = color;\n levels.push(level);\n }\n return levels;\n}\n\n/** `raw` as a value for `def`, or undefined when it isn't one. */\nfunction sanitizeValue(def: DrawingOptionDef, raw: unknown): DrawingOptionValue | undefined {\n switch (def.kind) {\n case 'boolean':\n return typeof raw === 'boolean' ? raw : undefined;\n case 'number': {\n if (typeof raw !== 'number' || !Number.isFinite(raw)) return undefined;\n return Math.min(def.max ?? Infinity, Math.max(def.min ?? -Infinity, raw));\n }\n case 'choice':\n return typeof raw === 'string' && def.choices.some((c) => c.value === raw) ? raw : undefined;\n case 'levels':\n return sanitizeLevels(raw);\n case 'text':\n return typeof raw === 'string' ? raw.slice(0, MAX_TEXT) : undefined;\n }\n}\n\n/** The valid entries of `raw` for a tool's options: unknown keys and wrong values are dropped, numbers clamped. */\nexport function sanitizeDrawingOptions(defs: DrawingOptionDefs | undefined, raw: unknown): DrawingOptions {\n if (!defs || typeof raw !== 'object' || raw === null) return {};\n const out: DrawingOptions = {};\n for (const [key, value] of Object.entries(raw)) {\n const def = defs[key];\n if (!def) continue;\n const clean = sanitizeValue(def, value);\n if (clean !== undefined) out[key] = clean;\n }\n return out;\n}\n\nfunction copyValue(value: DrawingOptionValue | readonly DrawingLevel[]): DrawingOptionValue {\n return Array.isArray(value) ? value.map((level) => ({ ...level })) : (value as DrawingOptionValue);\n}\n\n/** One option of a drawing: its own value when valid, else the tool's default. */\nexport function drawingOption<T extends DrawingOptionValue = DrawingOptionValue>(\n defs: DrawingOptionDefs | undefined,\n options: DrawingOptions | undefined,\n key: string,\n): T {\n const def = defs?.[key];\n if (!def) return options?.[key] as T;\n const own = options && key in options ? sanitizeValue(def, options[key]) : undefined;\n return copyValue(own ?? def.default) as T;\n}\n\n/** Every option of a tool for a drawing, defaults filled in. */\nexport function resolveDrawingOptions(defs: DrawingOptionDefs | undefined, options: DrawingOptions | undefined): DrawingOptions {\n const out: DrawingOptions = {};\n for (const key of Object.keys(defs ?? {})) out[key] = drawingOption(defs, options, key);\n return out;\n}\n","import type { DrawingStyle } from '../types/drawing.js';\n\nconst LINE_STYLES: readonly DrawingStyle['lineStyle'][] = ['solid', 'dashed', 'dotted'];\nconst MAX_COLOR = 64;\nconst MAX_TEXT = 2000;\nconst MAX_LINE_WIDTH = 20;\nconst MAX_FONT_SIZE = 200;\n/** Widest a text may be set to run before it wraps, px. */\nconst MAX_TEXT_WRAP = 4000;\n/** Narrowest a wrap width may be, px: room for a short word. */\nconst MIN_TEXT_WRAP = 20;\nconst TEXT_ALIGNS: readonly NonNullable<DrawingStyle['textAlign']>[] = ['left', 'center', 'right'];\nconst TEXT_VALIGNS: readonly NonNullable<DrawingStyle['textVAlign']>[] = ['top', 'middle', 'bottom'];\n\nfunction finiteIn(value: unknown, min: number, max: number): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? Math.min(max, Math.max(min, value)) : undefined;\n}\n\nfunction colorValue(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 && value.length <= MAX_COLOR ? value : undefined;\n}\n\n/**\n * The valid fields of a drawing style from untrusted data (a saved layout, a\n * template): colours as short strings, a known line style, widths, opacity\n * and font size as finite numbers in range, text cut to length. Anything\n * else is dropped.\n */\nexport function sanitizeDrawingStyle(raw: unknown): Partial<DrawingStyle> {\n if (typeof raw !== 'object' || raw === null) return {};\n const obj = raw as Record<string, unknown>;\n const out: Partial<DrawingStyle> = {};\n const color = colorValue(obj.color);\n if (color !== undefined) out.color = color;\n const lineWidth = finiteIn(obj.lineWidth, 0.5, MAX_LINE_WIDTH);\n if (lineWidth !== undefined) out.lineWidth = lineWidth;\n if (LINE_STYLES.includes(obj.lineStyle as DrawingStyle['lineStyle'])) out.lineStyle = obj.lineStyle as DrawingStyle['lineStyle'];\n const fillColor = colorValue(obj.fillColor);\n if (fillColor !== undefined) out.fillColor = fillColor;\n const fillOpacity = finiteIn(obj.fillOpacity, 0, 1);\n if (fillOpacity !== undefined) out.fillOpacity = fillOpacity;\n const fontSize = finiteIn(obj.fontSize, 6, MAX_FONT_SIZE);\n if (fontSize !== undefined) out.fontSize = fontSize;\n if (typeof obj.text === 'string') out.text = obj.text.slice(0, MAX_TEXT);\n for (const key of ['bold', 'italic', 'textBackground', 'textBorder'] as const) {\n if (typeof obj[key] === 'boolean') out[key] = obj[key] as boolean;\n }\n if (TEXT_ALIGNS.includes(obj.textAlign as NonNullable<DrawingStyle['textAlign']>)) out.textAlign = obj.textAlign as DrawingStyle['textAlign'];\n if (TEXT_VALIGNS.includes(obj.textVAlign as NonNullable<DrawingStyle['textVAlign']>)) out.textVAlign = obj.textVAlign as DrawingStyle['textVAlign'];\n const textColor = colorValue(obj.textColor);\n if (textColor !== undefined) out.textColor = textColor;\n const borderColor = colorValue(obj.borderColor);\n if (borderColor !== undefined) out.borderColor = borderColor;\n // 0 wraps only where the text breaks; any other width is kept to what a word fits in and a screen could use.\n if (typeof obj.textWrap === 'number' && Number.isFinite(obj.textWrap) && obj.textWrap >= 0) {\n out.textWrap = obj.textWrap === 0 ? 0 : Math.min(MAX_TEXT_WRAP, Math.max(MIN_TEXT_WRAP, obj.textWrap));\n }\n return out;\n}\n","import type { ChartTypeOptions } from '../types/chart.js';\n\nconst positive = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v) && v > 0;\nconst wholeIn = (v: unknown, lo: number, hi: number): v is number =>\n typeof v === 'number' && Number.isInteger(v) && v >= lo && v <= hi;\nconst isObject = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null && !Array.isArray(v);\n\n/**\n * The chart type settings in `raw` the chart can use: boxes, ranges and\n * reversals above 0, whole line and box counts in range. A type given at\n * all is in the result (empty when none of its settings were usable), so\n * a type's settings can be put back to their defaults.\n */\nexport function readChartTypeOptions(raw: unknown): ChartTypeOptions {\n if (!isObject(raw)) return {};\n const out: ChartTypeOptions = {};\n if (isObject(raw.renko)) {\n const { boxSize, atrPeriod } = raw.renko;\n out.renko = {\n ...(positive(boxSize) || boxSize === 'atr' ? { boxSize } : {}),\n ...(wholeIn(atrPeriod, 1, 500) ? { atrPeriod } : {}),\n };\n }\n if (isObject(raw.lineBreak)) {\n const { lines } = raw.lineBreak;\n out.lineBreak = wholeIn(lines, 1, 10) ? { lines } : {};\n }\n if (isObject(raw.kagi)) {\n const { reversal, reversalType } = raw.kagi;\n out.kagi = {\n ...(positive(reversal) ? { reversal } : {}),\n ...(reversalType === 'percent' || reversalType === 'price' ? { reversalType } : {}),\n };\n }\n if (isObject(raw.pointAndFigure)) {\n const { boxSize, reversal } = raw.pointAndFigure;\n out.pointAndFigure = {\n ...(positive(boxSize) || boxSize === 'auto' ? { boxSize } : {}),\n ...(wholeIn(reversal, 1, 10) ? { reversal } : {}),\n };\n }\n if (isObject(raw.rangeBars)) {\n const { range } = raw.rangeBars;\n out.rangeBars = positive(range) || range === 'auto' ? { range } : {};\n }\n return out;\n}\n","import type { PriceLimitColors, Theme } from '../types/theme.js';\nimport { withAlpha } from '../utils/color.js';\n\n/**\n * The chart's own type: a monospaced face, so the figures on the axes, in the\n * legend and on the tags line up in columns, as in a printed price table.\n */\nexport const DEFAULT_FONT_FAMILY = \"'Cascadia Mono', 'SF Mono', ui-monospace, Menlo, Consolas, monospace\";\n\n/**\n * A proportional face every system has, for figures that read lighter: the\n * airy look's axes and legend (`chart.setFont({ family: SANS_FONT_FAMILY })`).\n * Each axis label stands alone, so proportional digits read well there; the\n * widget's columns of figures keep them one width with `tabular-nums`.\n */\nexport const SANS_FONT_FAMILY = \"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif\";\n\n/** Three sizes a third of φ apart (11, 13, 15), as the widget's type scale climbs. */\nconst DEFAULT_FONT = {\n family: DEFAULT_FONT_FAMILY,\n sizeSmall: 11,\n sizeMedium: 13,\n sizeLarge: 15,\n};\n\n/**\n * TradeCanvas palette. Themes pick their own candle colours for their\n * background; everything drawn on top of either theme (indicators, orders,\n * signals, drawings) uses the theme-neutral values below, which keep at\n * least 3:1 contrast on both the dark ink and the light paper. `amber` is\n * the brand accent for dark surfaces (2:1 on paper); light surfaces use\n * `ochre` instead.\n */\nexport const TC_PALETTE = {\n /** Brand amber, for marks on dark surfaces. */\n amber: '#f2a93b',\n /** Rising / bullish, legible on dark and light. */\n up: '#1c9e6d',\n /** Falling / bearish, legible on dark and light. */\n down: '#e8505b',\n /** Amber deep enough for white backgrounds; auto-coloured series use it. */\n ochre: '#c07c12',\n /** Secondary series, signal lines. */\n blue: '#4688fa',\n violet: '#9c73f8',\n cyan: '#1398a8',\n rose: '#e25592',\n /** Zero lines, neutral guides. */\n neutral: '#7d8696',\n /** Ink ground of the dark theme. */\n ink: '#131416',\n} as const;\n\n/**\n * How strongly volume bars show: the candle colour at this opacity, so they\n * read as a backdrop under the candles rather than a second chart.\n */\nexport const VOLUME_ALPHA = 0.22;\n\n/** The volume bar colour for a candle colour. */\nexport function volumeColor(candleColor: string): string {\n return withAlpha(candleColor, VOLUME_ALPHA);\n}\n\n/**\n * The built-in themes are paper and ink: an off-white and an off-black, never\n * pure, so text doesn't glare; grey for everything that is normal; colour\n * only where it means something (up, down, your orders). Volume is the ink at\n * low strength, lighter under falling bars: the candles above already say\n * which way the price went.\n */\nconst PAPER = '#fbfaf6';\nconst PAPER_INK = '#1b1d21';\nconst NIGHT = '#131416';\nconst NIGHT_INK = '#e6e3dc';\nconst LIGHT_UP = '#1f7a5c';\nconst LIGHT_DOWN = '#b8423f';\nconst DARK_UP = '#4fae8a';\nconst DARK_DOWN = '#e2706b';\n/**\n * The crosshair is the ink faded into the ground, mixed rather than\n * translucent: bar tints and guides drawn in it at their own opacity keep\n * their strength. 3:1 on the ground, quiet beside the data.\n */\nconst NIGHT_CROSSHAIR = '#6a6966';\nconst PAPER_CROSSHAIR = '#8d8a84';\n\n/**\n * The price limits on ink: bright magenta, cyan and gold, the colours a\n * price board marks the ceiling, floor and reference with; each reads at 5:1\n * or more there. Themes without limit colours of their own take these.\n */\nexport const DARK_PRICE_LIMITS: PriceLimitColors = { ceiling: '#FF00FF', floor: '#00FFFF', reference: '#FFD700' };\n\n/** The same hues deep enough for paper: 4.5:1 or more on it, as text needs. */\nexport const LIGHT_PRICE_LIMITS: PriceLimitColors = { ceiling: '#a21caf', floor: '#0e7490', reference: '#8a6a00' };\n\n/** Order in which overlay indicators are coloured when no colour is given. */\nexport const TC_SERIES_COLORS: readonly string[] = [\n TC_PALETTE.blue,\n TC_PALETTE.ochre,\n TC_PALETTE.violet,\n TC_PALETTE.cyan,\n TC_PALETTE.rose,\n];\n\nexport const DARK_THEME: Theme = {\n name: 'dark',\n background: NIGHT,\n text: NIGHT_INK,\n textSecondary: '#8d8b86',\n grid: '#1d1e21',\n crosshair: NIGHT_CROSSHAIR,\n candleUp: DARK_UP,\n candleDown: DARK_DOWN,\n candleUpWick: DARK_UP,\n candleDownWick: DARK_DOWN,\n lineColor: NIGHT_INK,\n areaTopColor: withAlpha(NIGHT_INK, 0.14),\n areaBottomColor: withAlpha(NIGHT_INK, 0),\n volumeUp: withAlpha(NIGHT_INK, 0.14),\n volumeDown: withAlpha(NIGHT_INK, 0.08),\n axisLine: '#2a2b2f',\n axisLabel: '#a9a6a0',\n axisLabelBackground: '#232427',\n font: DEFAULT_FONT,\n priceLimits: DARK_PRICE_LIMITS,\n};\n\nexport const LIGHT_THEME: Theme = {\n name: 'light',\n background: PAPER,\n text: PAPER_INK,\n textSecondary: '#6b6f76',\n grid: '#ece8df',\n crosshair: PAPER_CROSSHAIR,\n candleUp: LIGHT_UP,\n candleDown: LIGHT_DOWN,\n candleUpWick: LIGHT_UP,\n candleDownWick: LIGHT_DOWN,\n lineColor: PAPER_INK,\n areaTopColor: withAlpha(PAPER_INK, 0.12),\n areaBottomColor: withAlpha(PAPER_INK, 0),\n volumeUp: withAlpha(PAPER_INK, 0.13),\n volumeDown: withAlpha(PAPER_INK, 0.08),\n axisLine: '#cfcac0',\n axisLabel: '#4a4e57',\n axisLabelBackground: '#eeebe3',\n font: DEFAULT_FONT,\n priceLimits: LIGHT_PRICE_LIMITS,\n};\n\nexport const DARK_TERMINAL: Theme = {\n name: 'terminal',\n background: '#0E0E0E',\n text: '#C0C0C0',\n textSecondary: '#8A8A8A',\n grid: '#1A1A1A',\n crosshair: '#666666',\n candleUp: '#00FF87',\n candleDown: '#FF3B4D',\n candleUpWick: '#00FF87',\n candleDownWick: '#FF3B4D',\n lineColor: '#3D8BFD',\n areaTopColor: 'rgba(61, 139, 253, 0.3)',\n areaBottomColor: 'rgba(61, 139, 253, 0.0)',\n volumeUp: volumeColor('#00FF87'),\n volumeDown: volumeColor('#FF3B4D'),\n axisLine: '#1A1A1A',\n axisLabel: '#8A8A8A',\n axisLabelBackground: '#1A1A1A',\n font: {\n family: \"'Roboto Mono', 'JetBrains Mono', 'SF Mono', Consolas, monospace\",\n sizeSmall: 10,\n sizeMedium: 12,\n sizeLarge: 14,\n },\n};\n\n/** The volume colours of the presets that draw volume in their candles' colours. */\nconst PRESET_VOLUME = new Set([DARK_TERMINAL.volumeUp, DARK_TERMINAL.volumeDown]);\n\n/**\n * The volume bars' colours for `theme`: its own `volumeUp` / `volumeDown`,\n * except that a theme spread from a candle-coloured preset with new candle\n * colours (and the preset's volume left in place) gets volume in its new\n * candles' colours. Neutral volume stays neutral whatever the candles.\n */\nexport function resolveVolumeColors(theme: Pick<Theme, 'candleUp' | 'candleDown' | 'volumeUp' | 'volumeDown'>): { up: string; down: string } {\n const pick = (volume: string, candle: string): string => {\n if (!PRESET_VOLUME.has(volume)) return volume;\n const derived = volumeColor(candle);\n return derived === candle ? volume : derived;\n };\n return { up: pick(theme.volumeUp, theme.candleUp), down: pick(theme.volumeDown, theme.candleDown) };\n}\n","import type { ChartType, LineStyle } from '../types/chart.js';\nimport type { Theme } from '../types/theme.js';\nimport type { IndicatorPlotStyle } from '../types/indicator.js';\nimport {\n CHART_STYLE_KEYS,\n type ChartStyleKey,\n type ChartStyleOverrides,\n type ChartStyleOverridesPatch,\n type PaneStyle,\n type ResolvedChartStyle,\n type ResolvedLineLook,\n type StyleValueKind,\n} from '../types/style.js';\nimport { resolveVolumeColors } from '../constants/themes.js';\n\nconst LINE_STYLES: readonly LineStyle[] = ['solid', 'dashed', 'dotted'];\n/** Widths past this are a mistake, not a look. */\nconst MAX_WIDTH = 20;\n/** Long enough for any colour CSS writes, short enough to keep anything else out. */\nconst MAX_COLOR_LENGTH = 64;\n/** The main series' line width when nothing sets it. */\nconst DEFAULT_LINE_WIDTH = 2;\n\n/**\n * A colour as CSS writes one, and only that: hex, a name, or a colour\n * function (`rgb()`, `hsl()`, `oklch()`, `color()`…) of numbers, units and\n * words. Anything else is refused, so a value read from a saved layout can't\n * carry markup or script into a style or an attribute.\n */\nconst COLOR_PATTERNS = [\n /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i,\n /^[a-z]{3,30}$/i,\n /^(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch|color)\\([0-9a-z.,%/\\s-]*\\)$/i,\n];\n\nfunction isColor(value: unknown): value is string {\n return typeof value === 'string' && value.length <= MAX_COLOR_LENGTH && COLOR_PATTERNS.some((pattern) => pattern.test(value.trim()));\n}\n\nfunction isValue(kind: StyleValueKind, value: unknown): boolean {\n switch (kind) {\n case 'color': return isColor(value);\n case 'lineStyle': return LINE_STYLES.includes(value as LineStyle);\n case 'width': return typeof value === 'number' && Number.isFinite(value) && value > 0 && value <= MAX_WIDTH;\n case 'boolean': return typeof value === 'boolean';\n }\n}\n\nfunction isStyleKey(key: string): key is ChartStyleKey {\n return Object.prototype.hasOwnProperty.call(CHART_STYLE_KEYS, key);\n}\n\n/**\n * Overrides read from anywhere (your options, a saved layout): the keys it\n * knows with values of their kind, `null` taking a key away. `rejected`\n * names what was left out.\n */\nexport function readChartStyleOverrides(raw: unknown): { overrides: ChartStyleOverridesPatch; rejected: string[] } {\n const overrides: Record<string, unknown> = {};\n const rejected: string[] = [];\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) return { overrides: {}, rejected };\n for (const [key, value] of Object.entries(raw)) {\n if (!isStyleKey(key)) rejected.push(key);\n else if (value === null) overrides[key] = null;\n else if (isValue(CHART_STYLE_KEYS[key], value)) overrides[key] = value;\n else rejected.push(key);\n }\n return { overrides: overrides as ChartStyleOverridesPatch, rejected };\n}\n\n/** A pane's own style: the colours it can use, or null when it has none. */\nexport function readPaneStyle(raw: unknown): PaneStyle | null {\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) return null;\n const { background, separator } = raw as Record<string, unknown>;\n const style: PaneStyle = {\n ...(isColor(background) ? { background } : {}),\n ...(isColor(separator) ? { separator } : {}),\n };\n return Object.keys(style).length > 0 ? style : null;\n}\n\n/** A plot key as indicators name them: short, nothing odd in it. */\nconst PLOT_KEY = /^[A-Za-z0-9_]{1,32}$/;\n\n/** Plot styles read from anywhere: by plot key, a dash style and whether it shows; undefined when none. */\nexport function readIndicatorPlotStyles(raw: unknown): Record<string, IndicatorPlotStyle> | undefined {\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) return undefined;\n const out: Record<string, IndicatorPlotStyle> = {};\n for (const [key, value] of Object.entries(raw)) {\n if (!PLOT_KEY.test(key) || typeof value !== 'object' || value === null) continue;\n const { lineStyle, visible } = value as Record<string, unknown>;\n const plot: IndicatorPlotStyle = {\n ...(LINE_STYLES.includes(lineStyle as LineStyle) ? { lineStyle: lineStyle as LineStyle } : {}),\n ...(typeof visible === 'boolean' ? { visible } : {}),\n };\n if (Object.keys(plot).length > 0) out[key] = plot;\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\n/** A dash pattern for a line style: `dashed` its own, `dotted` dots as wide as the line. */\nexport function lineDash(style: LineStyle, dashed: readonly number[], width = 1): number[] {\n if (style === 'solid') return [];\n if (style === 'dotted') return [width, width * 2];\n return [...dashed];\n}\n\ntype Lookup = (key: string) => unknown;\n\n/** The main series' colours and widths, as the chart type `type` takes them. */\nfunction seriesLooks(base: Theme, o: Lookup, type: ChartType) {\n const own = (prop: string) => o(`series.${type}.${prop}`);\n const upSet = own('upColor') ?? o('series.candlestick.upColor');\n const downSet = own('downColor') ?? o('series.candlestick.downColor');\n const up = (upSet as string | undefined) ?? base.candleUp;\n const down = (downSet as string | undefined) ?? base.candleDown;\n return {\n up,\n down,\n // A wick takes its body's colour once that is set, as the theme's own do.\n wickUp: ((own('wickUpColor') ?? o('series.candlestick.wickUpColor')) as string | undefined) ?? (upSet !== undefined ? up : base.candleUpWick),\n wickDown: ((own('wickDownColor') ?? o('series.candlestick.wickDownColor')) as string | undefined) ?? (downSet !== undefined ? down : base.candleDownWick),\n line: ((own('color') ?? own('lineColor') ?? o('series.line.color')) as string | undefined) ?? base.lineColor,\n lineWidth: ((own('lineWidth') ?? o('series.line.lineWidth')) as number | undefined) ?? DEFAULT_LINE_WIDTH,\n top: ((own('topColor') ?? o('series.area.topColor')) as string | undefined) ?? base.areaTopColor,\n bottom: ((own('bottomColor') ?? o('series.area.bottomColor')) as string | undefined) ?? base.areaBottomColor,\n };\n}\n\nfunction lineLook(o: Lookup, prefix: string, fallback: ResolvedLineLook): ResolvedLineLook {\n return {\n visible: (o(`${prefix}.visible`) as boolean | undefined) ?? fallback.visible,\n color: (o(`${prefix}.color`) as string | undefined) ?? fallback.color,\n style: (o(`${prefix}.style`) as LineStyle | undefined) ?? fallback.style,\n width: (o(`${prefix}.width`) as number | undefined) ?? fallback.width,\n };\n}\n\n/**\n * The theme the chart draws with: `base` with `overrides` on its tokens (the\n * main series' as `chartType` takes them) and the finer looks in `style`.\n * `base` is left as it was.\n */\nexport function resolveChartTheme(base: Theme, chartType: ChartType, overrides: ChartStyleOverrides): Theme {\n const { style: _ignored, ...plain } = base;\n const map = overrides as Record<string, unknown>;\n const o: Lookup = (key) => map[key];\n const series = seriesLooks(plain, o, chartType);\n const background = (o('background.color') as string | undefined) ?? plain.background;\n const str = (key: ChartStyleKey, fallback: string) => (o(key) as string | undefined) ?? fallback;\n /** A colour of a part with its own settings: the override, or null to keep to them. */\n const ownColor = (key: ChartStyleKey): string | null => (o(key) as string | undefined) ?? null;\n\n const style: ResolvedChartStyle = {\n panes: {\n background: str('panes.background', background),\n separator: str('panes.separatorColor', plain.axisLine),\n title: str('panes.titleColor', plain.textSecondary),\n },\n grid: {\n horizontal: lineLook(o, 'grid.horizontal', { visible: true, color: plain.grid, style: 'solid', width: 1 }),\n vertical: lineLook(o, 'grid.vertical', { visible: true, color: plain.grid, style: 'solid', width: 1 }),\n },\n // Hairlines, solid: a dash pattern is noise the eye has to read past.\n crosshair: {\n horizontal: lineLook(o, 'crosshair.horizontal', { visible: true, color: plain.crosshair, style: 'solid', width: 1 }),\n vertical: lineLook(o, 'crosshair.vertical', { visible: true, color: plain.crosshair, style: 'solid', width: 1 }),\n labelBackground: str('crosshair.labelBackground', plain.text),\n labelText: str('crosshair.labelTextColor', background),\n },\n axis: {\n price: { line: str('axis.price.lineColor', plain.axisLine), text: str('axis.price.textColor', plain.axisLabel) },\n time: { line: str('axis.time.lineColor', plain.axisLine), text: str('axis.time.textColor', plain.axisLabel) },\n },\n legend: { text: str('legend.textColor', plain.text), label: str('legend.labelColor', plain.textSecondary) },\n watermark: { color: (o('watermark.color') as string | undefined) ?? null },\n lastPrice: {\n visible: (o('lastPrice.visible') as boolean | undefined) ?? true,\n up: str('lastPrice.upColor', series.up),\n down: str('lastPrice.downColor', series.down),\n style: (o('lastPrice.style') as LineStyle | undefined) ?? 'solid',\n width: (o('lastPrice.width') as number | undefined) ?? 1,\n },\n sessionBreaks: {\n color: (o('sessionBreaks.color') as string | undefined) ?? null,\n style: (o('sessionBreaks.style') as LineStyle | undefined) ?? null,\n width: (o('sessionBreaks.width') as number | undefined) ?? null,\n },\n highLow: { color: (o('highLow.color') as string | undefined) ?? null },\n series: { lineWidth: series.lineWidth },\n trading: {\n buy: ownColor('trading.buyColor'),\n sell: ownColor('trading.sellColor'),\n profit: ownColor('trading.profitColor'),\n loss: ownColor('trading.lossColor'),\n entry: ownColor('trading.entryColor'),\n },\n markers: { long: ownColor('markers.longColor'), short: ownColor('markers.shortColor'), neutral: ownColor('markers.neutralColor') },\n tradeZones: { profit: ownColor('tradeZones.profitColor'), loss: ownColor('tradeZones.lossColor'), active: ownColor('tradeZones.activeColor') },\n drawings: { handle: ownColor('drawings.handleColor') },\n };\n\n return {\n ...plain,\n background,\n candleUp: series.up,\n candleDown: series.down,\n candleUpWick: series.wickUp,\n candleDownWick: series.wickDown,\n lineColor: series.line,\n areaTopColor: series.top,\n areaBottomColor: series.bottom,\n volumeUp: str('volume.upColor', plain.volumeUp),\n volumeDown: str('volume.downColor', plain.volumeDown),\n style,\n };\n}\n\n/** How each key that isn't the series' reads back from the resolved theme. */\nconst READ_BACK: { [K in ChartStyleKey]?: (t: Theme, s: ResolvedChartStyle) => unknown } = {\n 'background.color': (t) => t.background,\n 'panes.background': (_t, s) => s.panes.background,\n 'panes.separatorColor': (_t, s) => s.panes.separator,\n 'panes.titleColor': (_t, s) => s.panes.title,\n 'crosshair.labelBackground': (_t, s) => s.crosshair.labelBackground,\n 'crosshair.labelTextColor': (_t, s) => s.crosshair.labelText,\n 'axis.price.lineColor': (_t, s) => s.axis.price.line,\n 'axis.price.textColor': (_t, s) => s.axis.price.text,\n 'axis.time.lineColor': (_t, s) => s.axis.time.line,\n 'axis.time.textColor': (_t, s) => s.axis.time.text,\n 'legend.textColor': (_t, s) => s.legend.text,\n 'legend.labelColor': (_t, s) => s.legend.label,\n 'watermark.color': (_t, s) => s.watermark.color,\n 'lastPrice.visible': (_t, s) => s.lastPrice.visible,\n 'lastPrice.upColor': (_t, s) => s.lastPrice.up,\n 'lastPrice.downColor': (_t, s) => s.lastPrice.down,\n 'lastPrice.style': (_t, s) => s.lastPrice.style,\n 'lastPrice.width': (_t, s) => s.lastPrice.width,\n // As drawn: a theme that sets only candle colours gets volume in those colours.\n 'volume.upColor': (t) => resolveVolumeColors(t).up,\n 'volume.downColor': (t) => resolveVolumeColors(t).down,\n 'sessionBreaks.color': (_t, s) => s.sessionBreaks.color,\n 'sessionBreaks.style': (_t, s) => s.sessionBreaks.style,\n 'sessionBreaks.width': (_t, s) => s.sessionBreaks.width,\n 'highLow.color': (_t, s) => s.highLow.color,\n 'trading.buyColor': (_t, s) => s.trading.buy,\n 'trading.sellColor': (_t, s) => s.trading.sell,\n 'trading.profitColor': (_t, s) => s.trading.profit,\n 'trading.lossColor': (_t, s) => s.trading.loss,\n 'trading.entryColor': (_t, s) => s.trading.entry,\n 'markers.longColor': (_t, s) => s.markers.long,\n 'markers.shortColor': (_t, s) => s.markers.short,\n 'markers.neutralColor': (_t, s) => s.markers.neutral,\n 'tradeZones.profitColor': (_t, s) => s.tradeZones.profit,\n 'tradeZones.lossColor': (_t, s) => s.tradeZones.loss,\n 'tradeZones.activeColor': (_t, s) => s.tradeZones.active,\n 'drawings.handleColor': (_t, s) => s.drawings.handle,\n};\n\nconst LINE_PROPS: Record<string, keyof ResolvedLineLook> = { visible: 'visible', color: 'color', style: 'style', width: 'width' };\n\n/**\n * What `key` resolves to: its override, or what it falls back to. A\n * `series.<type>.*` key resolves as that type would draw; the last price\n * follows `chartType`'s colours. Null for the parts that keep to their own\n * settings when not overridden (the watermark, session breaks, high/low).\n */\nexport function chartStyleValue(\n base: Theme,\n overrides: ChartStyleOverrides,\n key: ChartStyleKey,\n chartType: ChartType = 'candlestick',\n): string | number | boolean | null {\n const parts = key.split('.');\n if (parts[0] === 'series') {\n const looks = seriesLooks(base, (k) => (overrides as Record<string, unknown>)[k], parts[1] as ChartType);\n switch (parts[2]) {\n case 'upColor': return looks.up;\n case 'downColor': return looks.down;\n case 'wickUpColor': return looks.wickUp;\n case 'wickDownColor': return looks.wickDown;\n case 'color':\n case 'lineColor': return looks.line;\n case 'lineWidth': return looks.lineWidth;\n case 'topColor': return looks.top;\n case 'bottomColor': return looks.bottom;\n }\n }\n const theme = resolveChartTheme(base, chartType, overrides);\n const style = theme.style!;\n if (parts[0] === 'grid' || (parts[0] === 'crosshair' && (parts[1] === 'horizontal' || parts[1] === 'vertical'))) {\n const group = parts[0] === 'grid' ? style.grid : style.crosshair;\n return group[parts[1] as 'horizontal' | 'vertical'][LINE_PROPS[parts[2]]];\n }\n return (READ_BACK[key]?.(theme, style) ?? null) as string | number | boolean | null;\n}\n","import type { ChartOptions } from '../types/chart.js';\n\nexport const DEFAULT_CHART_OPTIONS: Required<Pick<ChartOptions, 'autoScale' | 'rightMargin' | 'minBarSpacing' | 'maxBarSpacing'>> & Pick<ChartOptions, 'grid' | 'crosshair'> = {\n autoScale: true,\n rightMargin: 5,\n minBarSpacing: 2,\n maxBarSpacing: 30,\n grid: {\n visible: true,\n hLineStyle: 'solid',\n vLineStyle: 'solid',\n },\n crosshair: {\n mode: 'magnet',\n },\n};\n\n// Standard timeframe presets for different market types\nimport type { TimeFrame } from '../types/ohlc.js';\n\n/** Crypto: all timeframes including seconds */\nexport const TIMEFRAMES_CRYPTO: TimeFrame[] = [\n '1s', '1m', '3m', '5m', '15m', '30m',\n '1h', '2h', '4h', '6h', '8h', '12h',\n '1d', '3d', '1w', '1M',\n];\n\n/** Stocks: minute-level and above (no seconds) */\nexport const TIMEFRAMES_STOCK: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '2h', '4h',\n '1d', '1w', '1M', '3M', '6M', '12M',\n];\n\n/** Forex: common forex timeframes */\nexport const TIMEFRAMES_FOREX: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '4h',\n '1d', '1w', '1M',\n];\n\n/** Default favorites shown in quick-access bar */\nexport const DEFAULT_TIMEFRAME_FAVORITES: TimeFrame[] = [\n '1m', '5m', '15m', '1h', '4h', '1d', '1w',\n];\n\nexport const DEFAULT_BAR_WIDTH = 8;\nexport const DEFAULT_BAR_SPACING = 2;\nexport const PRICE_AXIS_WIDTH = 70;\nexport const TIME_AXIS_HEIGHT = 30;\nexport const MIN_PANEL_HEIGHT = 60;\nexport const DEFAULT_PANEL_HEIGHT = 120;\n","/**\n * The golden ratio, which the built-in look keeps to. Sizes that sit together\n * stand in it (an icon, its button, the bar it sits in), spacing and corners\n * are Fibonacci numbers, whose neighbours approach it, and type climbs by its\n * cube root, so every third size is φ larger.\n */\nexport const PHI = (1 + Math.sqrt(5)) / 2;\n\n/** Spacing and corners, px: each the sum of the two before, so neighbours stand near φ. */\nexport const FIBONACCI = [1, 2, 3, 5, 8, 13, 21, 34, 55, 89] as const;\n\n/**\n * `base` moved `steps` along a scale that reaches φ in `perPhi` steps, in\n * whole pixels: `phiStep(16, 2, 2)` is 26, `phiStep(13, 3, 3)` is 21.\n */\nexport function phiStep(base: number, steps: number, perPhi = 1): number {\n return Math.round(base * PHI ** (steps / perPhi));\n}\n","import type { LocaleStrings } from './types.js';\n\nexport const en: LocaleStrings = {\n // Chart types\n candlestick: 'Candlestick',\n line: 'Line',\n area: 'Area',\n bar: 'OHLC Bar',\n\n // Axes\n price: 'Price',\n volume: 'Volume',\n time: 'Time',\n open: 'Open',\n high: 'High',\n low: 'Low',\n close: 'Close',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Bollinger Bands',\n vwap: 'VWAP',\n ichimoku: 'Ichimoku Cloud',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Keltner Channel',\n donchianChannel: 'Donchian Channel',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Std Dev',\n volumeProfile: 'Volume Profile',\n accumulationDistribution: 'A/D Line',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Trend Line',\n horizontalLine: 'Horizontal Line',\n verticalLine: 'Vertical Line',\n ray: 'Ray',\n extendedLine: 'Extended Line',\n parallelChannel: 'Parallel Channel',\n regressionChannel: 'Regression Channel',\n fibRetracement: 'Fibonacci Retracement',\n fibExtension: 'Fibonacci Extension',\n rectangle: 'Rectangle',\n ellipse: 'Ellipse',\n triangle: 'Triangle',\n pitchfork: \"Andrews' Pitchfork\",\n elliottWave: 'Elliott Wave',\n priceRange: 'Price Range',\n dateRange: 'Date Range',\n measure: 'Measure',\n textTool: 'Text',\n arrow: 'Arrow',\n clearAll: 'Clear All',\n\n // Trading\n buy: 'Buy',\n sell: 'Sell',\n buyLimit: 'Buy Limit',\n sellLimit: 'Sell Limit',\n buyStop: 'Buy Stop',\n sellStop: 'Sell Stop',\n stopLoss: 'Stop Loss',\n takeProfit: 'Take Profit',\n market: 'Market',\n limit: 'Limit',\n stop: 'Stop',\n cancel: 'Cancel',\n modify: 'Modify',\n quantity: 'Qty',\n pnl: 'P&L',\n activeOrders: 'Active Orders',\n positions: 'Positions',\n noOrders: 'No active orders',\n noPositions: 'No open positions',\n placeOrder: 'Place Order',\n rightClickToTrade: 'Right-click chart to place orders',\n\n // Market\n ceiling: 'Ceiling',\n floor: 'Floor',\n reference: 'Reference',\n session: 'Session',\n preOpen: 'Pre-Open',\n continuous: 'Continuous',\n preClose: 'Pre-Close',\n closed: 'Closed',\n\n // UI\n settings: 'Settings',\n theme: 'Theme',\n darkTheme: 'Dark',\n lightTheme: 'Light',\n tools: 'Tools',\n indicators: 'Indicators',\n overlays: 'Overlays',\n panels: 'Panels',\n orders: 'Orders',\n autoScale: 'Auto Scale',\n crosshair: 'Crosshair',\n grid: 'Grid',\n loading: 'Loading...',\n error: 'Error',\n\n numberDecimalSeparator: '.',\n numberGroupSeparator: ',',\n};\n","import type { LocaleStrings } from './types.js';\n\nexport const vi: LocaleStrings = {\n // Chart types\n candlestick: 'Nến',\n line: 'Đường',\n area: 'Vùng',\n bar: 'Thanh OHLC',\n\n // Axes\n price: 'Giá',\n volume: 'Khối lượng',\n time: 'Thời gian',\n open: 'Mở',\n high: 'Cao',\n low: 'Thấp',\n close: 'Đóng',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Dải Bollinger',\n vwap: 'VWAP',\n ichimoku: 'Mây Ichimoku',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Kênh Keltner',\n donchianChannel: 'Kênh Donchian',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Độ lệch chuẩn',\n volumeProfile: 'Phân bổ KL',\n accumulationDistribution: 'Tích lũy/Phân phối',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Đường xu hướng',\n horizontalLine: 'Đường ngang',\n verticalLine: 'Đường dọc',\n ray: 'Tia',\n extendedLine: 'Đường kéo dài',\n parallelChannel: 'Kênh song song',\n regressionChannel: 'Kênh hồi quy',\n fibRetracement: 'Fibonacci thoái lui',\n fibExtension: 'Fibonacci mở rộng',\n rectangle: 'Hình chữ nhật',\n ellipse: 'Hình elip',\n triangle: 'Tam giác',\n pitchfork: 'Chĩa ba Andrews',\n elliottWave: 'Sóng Elliott',\n priceRange: 'Khoảng giá',\n dateRange: 'Khoảng thời gian',\n measure: 'Đo lường',\n textTool: 'Chữ',\n arrow: 'Mũi tên',\n clearAll: 'Xóa tất cả',\n\n // Trading\n buy: 'Mua',\n sell: 'Bán',\n buyLimit: 'Mua giới hạn',\n sellLimit: 'Bán giới hạn',\n buyStop: 'Mua chặn',\n sellStop: 'Bán chặn',\n stopLoss: 'Cắt lỗ',\n takeProfit: 'Chốt lời',\n market: 'Thị trường',\n limit: 'Giới hạn',\n stop: 'Dừng',\n cancel: 'Hủy',\n modify: 'Sửa',\n quantity: 'KL',\n pnl: 'Lãi/Lỗ',\n activeOrders: 'Lệnh chờ',\n positions: 'Vị thế',\n noOrders: 'Không có lệnh chờ',\n noPositions: 'Không có vị thế mở',\n placeOrder: 'Đặt lệnh',\n rightClickToTrade: 'Nhấp chuột phải để đặt lệnh',\n\n // Market\n ceiling: 'Trần',\n floor: 'Sàn',\n reference: 'Tham chiếu',\n session: 'Phiên',\n preOpen: 'Trước giờ mở',\n continuous: 'Liên tục',\n preClose: 'Trước giờ đóng',\n closed: 'Đóng cửa',\n\n // UI\n settings: 'Cài đặt',\n theme: 'Giao diện',\n darkTheme: 'Tối',\n lightTheme: 'Sáng',\n tools: 'Công cụ',\n indicators: 'Chỉ báo',\n overlays: 'Phủ lên',\n panels: 'Bảng',\n orders: 'Lệnh',\n autoScale: 'Tự co giãn',\n crosshair: 'Chữ thập',\n grid: 'Lưới',\n loading: 'Đang tải...',\n error: 'Lỗi',\n\n numberDecimalSeparator: ',',\n numberGroupSeparator: '.',\n};\n","export type { Locale, LocaleStrings, NumberFormatConfig, DateFormatConfig } from './types.js';\nexport { en } from './en.js';\nexport { vi } from './vi.js';\n\nimport type { Locale, LocaleStrings } from './types.js';\nimport { en } from './en.js';\nimport { vi } from './vi.js';\nimport { formatPrice } from '../utils/precision.js';\n\nconst locales = new Map<string, LocaleStrings>([\n ['en', en],\n ['vi', vi],\n]);\n\nlet currentLocale: Locale = 'en';\nlet currentStrings: LocaleStrings = en;\n\nexport function setLocale(locale: Locale): void {\n currentLocale = locale;\n currentStrings = locales.get(locale) ?? en;\n}\n\nexport function getLocale(): Locale {\n return currentLocale;\n}\n\nexport function t(key: keyof LocaleStrings): string {\n return currentStrings[key] ?? (en as any)[key] ?? key;\n}\n\nexport function registerLocale(locale: string, strings: LocaleStrings): void {\n locales.set(locale, strings);\n}\n\nexport function getLocaleStrings(locale?: string): LocaleStrings {\n return locales.get(locale ?? currentLocale) ?? en;\n}\n\n// Number formatting\nexport function formatNumber(value: number, precision = 2, locale?: string): string {\n const strings = locales.get(locale ?? currentLocale) ?? en;\n const dec = strings.numberDecimalSeparator;\n const grp = strings.numberGroupSeparator;\n\n const fixed = value.toFixed(precision);\n const [intPart, decPart] = fixed.split('.');\n\n // Group integer part\n const negative = intPart.startsWith('-');\n const digits = negative ? intPart.slice(1) : intPart;\n let grouped = '';\n for (let i = digits.length - 1, count = 0; i >= 0; i--, count++) {\n if (count > 0 && count % 3 === 0) grouped = grp + grouped;\n grouped = digits[i] + grouped;\n }\n if (negative) grouped = '-' + grouped;\n\n return decPart ? grouped + dec + decPart : grouped;\n}\n\nexport function formatVND(value: number): string {\n return formatNumber(value, 0, 'vi');\n}\n\n/** Korean counts in ten-thousands: 만 (10⁴), 억 (10⁸), 조 (10¹²). */\nconst KO_UNITS: readonly [number, string][] = [[1e12, '조'], [1e8, '억'], [1e4, '만']];\n\n/** Whether `locale` writes large counts in 만, 억 and 조 (Korean) rather than K, M and B. */\nexport function usesKoreanUnits(locale: string): boolean {\n return /^ko([-_]|$)/i.test(locale);\n}\n\n/** A figure as Intl writes it in `locale`; in English when Intl does not know the locale. */\nfunction intlFigure(value: number, decimals: number, locale: string): string {\n try {\n return formatPrice(value, decimals, locale);\n } catch {\n return formatNumber(value, decimals, 'en');\n }\n}\n\n/** A volume shortened for `locale`: 1.23K, 4.50M; in Korean 1.23만, 3.45억, 1.82조. */\nexport function formatVolumeLoc(value: number, locale?: string): string {\n const loc = locale ?? currentLocale;\n if (!Number.isFinite(value)) return String(value);\n if (usesKoreanUnits(loc)) {\n // By the value as printed, so 99,999,999 reads 1.00억 rather than 10,000.00만.\n for (const [size, unit] of KO_UNITS) if (Math.round((value / size) * 100) >= 100) return formatNumber(value / size, 2, loc) + unit;\n return formatNumber(value, 0, loc);\n }\n // A locale with a table here keeps its marks; any other is written as Intl writes it.\n const figure = locales.has(loc) ? (v: number, d: number) => formatNumber(v, d, loc) : (v: number, d: number) => intlFigure(v, d, loc);\n if (value >= 1e9) return figure(value / 1e9, 2) + 'B';\n if (value >= 1e6) return figure(value / 1e6, 2) + 'M';\n if (value >= 1e3) return figure(value / 1e3, 2) + 'K';\n return figure(value, 0);\n}\n","import type { MarketConfig, MarketColorScheme, PriceStepBand, TradingSession, VN30FContract } from './types.js';\nimport type { Theme } from '../types/theme.js';\nimport { stepDecimals } from '../utils/symbols.js';\nimport { isValidTimeZone, zoneOffsetMinutes } from '../utils/timezone.js';\n\n/**\n * Vietnamese price boards: green up, red down, purple at the ceiling (trần),\n * cyan at the floor (sàn), yellow at the reference price (tham chiếu).\n */\nexport const VN_COLORS: MarketColorScheme = {\n up: '#22C55E',\n down: '#EF4444',\n unchanged: '#EAB308',\n ceiling: '#D946EF',\n floor: '#06B6D4',\n reference: '#EAB308',\n};\n\nconst VN_TIME_ZONE = 'Asia/Ho_Chi_Minh';\n\n/**\n * Korean trading apps: red up, blue down, against the previous close; the\n * upper limit (상한가) a deeper red, the lower (하한가) a deeper blue.\n */\nexport const KR_COLORS: MarketColorScheme = {\n up: '#E8313F',\n down: '#2F6FEB',\n unchanged: '#8B8F99',\n ceiling: '#C2121F',\n floor: '#1E4FC2',\n reference: '#8B8F99',\n};\n\nconst KR_TIME_ZONE = 'Asia/Seoul';\n\n// Session times and rules: the exchanges' trading rules as of May 2025 (the\n// HOSE KRX system went live on 5 May 2025).\nexport const HOSE_SESSIONS: TradingSession[] = [\n { name: 'ATO', startTime: '09:00', endTime: '09:15', type: 'preOpen' },\n { name: 'Phiên 1', startTime: '09:15', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\nexport const HNX_SESSIONS: TradingSession[] = [\n { name: 'Phiên 1', startTime: '09:15', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n { name: 'PLO', startTime: '14:45', endTime: '15:00', type: 'postClose' },\n];\n\nexport const UPCOM_SESSIONS: TradingSession[] = [\n { name: 'Phiên 1', startTime: '09:15', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n];\n\nexport const VN30F_SESSIONS: TradingSession[] = [\n { name: 'ATO', startTime: '08:45', endTime: '09:00', type: 'preOpen' },\n { name: 'Phiên 1', startTime: '09:00', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\n// KRX's sessions as of 14 September 2026, when the After-Market (16:00–20:00,\n// continuous, within the day's limits) replaced the after-hours single-price\n// session. The pre-hours closing-price trade (08:30–08:40) runs inside the\n// opening call and is left out.\nexport const KRX_SESSIONS: TradingSession[] = [\n { name: '장전 동시호가', startTime: '08:30', endTime: '09:00', type: 'preOpen' },\n { name: '정규장', startTime: '09:00', endTime: '15:20', type: 'continuous' },\n { name: '장마감 동시호가', startTime: '15:20', endTime: '15:30', type: 'preClose' },\n { name: '장후 시간외', startTime: '15:40', endTime: '16:00', type: 'postClose' },\n { name: '애프터마켓', startTime: '16:00', endTime: '20:00', type: 'postClose' },\n];\n\n// Nextrade, the alternative exchange (since March 2025): its main market\n// stops for KRX's closing call. It opens at 09:00:30; sessions are by the minute.\nexport const NXT_SESSIONS: TradingSession[] = [\n { name: '프리마켓', startTime: '08:00', endTime: '08:50', type: 'preOpen' },\n { name: '메인마켓', startTime: '09:00', endTime: '15:20', type: 'continuous' },\n { name: '애프터마켓', startTime: '15:40', endTime: '20:00', type: 'postClose' },\n];\n\n/** KOSPI, KOSDAQ and KONEX shares, in won (one table since 25 January 2023). */\nconst KRX_STEPS: readonly PriceStepBand[] = [\n { from: 0, step: 1 },\n { from: 2_000, step: 5 },\n { from: 5_000, step: 10 },\n { from: 20_000, step: 50 },\n { from: 50_000, step: 100 },\n { from: 200_000, step: 500 },\n { from: 500_000, step: 1_000 },\n];\n\n/** Upbit's KRW market, in won (since 31 July 2025). */\nconst UPBIT_KRW_STEPS: readonly PriceStepBand[] = [\n { from: 0, step: 0.00000001 },\n { from: 0.00001, step: 0.0000001 },\n { from: 0.0001, step: 0.000001 },\n { from: 0.001, step: 0.00001 },\n { from: 0.01, step: 0.0001 },\n { from: 0.1, step: 0.001 },\n { from: 1, step: 0.01 },\n { from: 10, step: 0.1 },\n { from: 100, step: 1 },\n { from: 5_000, step: 5 },\n { from: 10_000, step: 10 },\n { from: 50_000, step: 50 },\n { from: 100_000, step: 100 },\n { from: 500_000, step: 500 },\n { from: 1_000_000, step: 1_000 },\n];\n\n/** HOSE shares and closed funds, in thousands of dong: 10, 50 and 100 dong steps. */\nconst HOSE_STEPS: readonly PriceStepBand[] = [\n { from: 0, step: 0.01 },\n { from: 10, step: 0.05 },\n { from: 50, step: 0.1 },\n];\n\n// Market presets. Vietnamese prices are in thousands of dong (25.35 is 25,350\n// dong), as price boards show them; scaleMarketPrices(preset, 1000) for dong.\n\n/**\n * HOSE shares (Ho Chi Minh City), in thousands of dong: steps of 0.01 below\n * 10, 0.05 from 10, 0.1 from 50; 2 decimals; lots of 100; limits of ±7%\n * from the reference; zone Asia/Ho_Chi_Minh; the price board's colours\n * (`VN_COLORS`); the ATO, two continuous sessions and ATC (`HOSE_SESSIONS`).\n * With `chart.setMarket`: `setPriceLimits(reference)` for the day's ceiling\n * and floor, `setTimeZone('exchange')` for the axis in Vietnam's time.\n */\nexport const MARKET_HOSE: MarketConfig = {\n type: 'stock',\n exchange: 'HOSE',\n currency: 'VND',\n pricePrecision: 2,\n volumeUnit: 100,\n priceStep: 0.01,\n priceSteps: HOSE_STEPS,\n timeZone: VN_TIME_ZONE,\n priceLimits: { enabled: true, ceilingPercent: 7, floorPercent: 7 },\n sessions: HOSE_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\n/** HOSE ETFs and covered warrants: 10 dong at every price. */\nexport const MARKET_HOSE_ETF: MarketConfig = {\n ...MARKET_HOSE,\n priceSteps: undefined,\n};\n\n/** HNX shares (Hanoi), in thousands of dong: 0.1 a step, limits of ±10%, zone Asia/Ho_Chi_Minh, lots of 100, `HNX_SESSIONS`. */\nexport const MARKET_HNX: MarketConfig = {\n type: 'stock',\n exchange: 'HNX',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n timeZone: VN_TIME_ZONE,\n priceLimits: { enabled: true, ceilingPercent: 10, floorPercent: 10 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\n/** UPCoM shares, in thousands of dong: 0.1 a step, limits of ±15%, zone Asia/Ho_Chi_Minh, lots of 100, `UPCOM_SESSIONS`. */\nexport const MARKET_UPCOM: MarketConfig = {\n type: 'stock',\n exchange: 'UPCOM',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n timeZone: VN_TIME_ZONE,\n priceLimits: { enabled: true, ceilingPercent: 15, floorPercent: 15 },\n sessions: UPCOM_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\n/** VN30 index futures on HNX: index points, 0.1 a step, 100,000 dong a point, limits of ±7%, zone Asia/Ho_Chi_Minh, `VN30F_SESSIONS`. */\nexport const MARKET_VN30F: MarketConfig = {\n type: 'futures',\n exchange: 'HNX',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 1,\n priceStep: 0.1,\n contractMultiplier: 100_000,\n timeZone: VN_TIME_ZONE,\n priceLimits: { enabled: true, ceilingPercent: 7, floorPercent: 7 },\n sessions: VN30F_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\n/**\n * KOSPI and KOSDAQ shares on KRX, in won: steps from 1 won below 2,000 to\n * 1,000 from 500,000 (`priceSteps`); whole won; limits of ±30% from the\n * reference, the move rounded first as KRX does (`roundMove`); zone\n * Asia/Seoul; red up and blue down (`KR_COLORS`); the opening and closing\n * calls, the regular session and the After-Market (`KRX_SESSIONS`). ETFs\n * and ETNs step differently and are not in the After-Market.\n */\nexport const MARKET_KRX: MarketConfig = {\n type: 'stock',\n exchange: 'KRX',\n currency: 'KRW',\n pricePrecision: 0,\n volumeUnit: 1,\n priceStep: 1,\n priceSteps: KRX_STEPS,\n timeZone: KR_TIME_ZONE,\n priceLimits: { enabled: true, ceilingPercent: 30, floorPercent: 30, roundMove: true },\n sessions: KRX_SESSIONS,\n colorScheme: KR_COLORS,\n};\n\n/** Shares on Nextrade: KRX's steps and limits (from KRX's reference price), `NXT_SESSIONS`. */\nexport const MARKET_NXT: MarketConfig = {\n ...MARKET_KRX,\n exchange: 'NXT',\n sessions: NXT_SESSIONS,\n};\n\n/**\n * Upbit's KRW market (`KRW-BTC`): steps from 1,000 won at a million down to\n * a hundred-millionth of a won (`priceSteps`), the decimals following the\n * symbol's data; no limits; red up and blue down. It trades around the clock.\n */\nexport const MARKET_UPBIT_KRW: MarketConfig = {\n type: 'crypto',\n exchange: 'UPBIT',\n currency: 'KRW',\n priceStep: 0.00000001,\n priceSteps: UPBIT_KRW_STEPS,\n timeZone: KR_TIME_ZONE,\n priceLimits: { enabled: false },\n colorScheme: KR_COLORS,\n};\n\n/** Crypto: 2 decimals, no limits, no zone or sessions (it trades around the clock). */\nexport const MARKET_CRYPTO: MarketConfig = {\n type: 'crypto',\n currency: 'USDT',\n pricePrecision: 2,\n priceLimits: { enabled: false },\n};\n\n/** NYSE shares, in dollars: 0.01 a step, no limits, zone America/New_York, pre-market, regular and after-hours sessions. */\nexport const MARKET_NYSE: MarketConfig = {\n type: 'stock',\n exchange: 'NYSE',\n currency: 'USD',\n pricePrecision: 2,\n priceStep: 0.01,\n timeZone: 'America/New_York',\n priceLimits: { enabled: false },\n sessions: [\n { name: 'Pre-Market', startTime: '04:00', endTime: '09:30', type: 'preOpen' },\n { name: 'Regular', startTime: '09:30', endTime: '16:00', type: 'continuous' },\n { name: 'After-Hours', startTime: '16:00', endTime: '20:00', type: 'postClose' },\n ],\n};\n\n/**\n * A theme variant for the Vietnamese stock market: its candle colours. Volume\n * keeps the theme's own (neutral in the built-in themes; a candle-coloured\n * preset's follows the new candles).\n */\nexport function createVNTheme(base: Theme): Theme {\n return createMarketTheme(base, VN_COLORS);\n}\n\n/**\n * A theme variant with a market's candle colours: `createMarketTheme(DARK_THEME,\n * KR_COLORS)` draws rising candles red and falling ones blue. Volume keeps\n * the theme's own.\n */\nexport function createMarketTheme(base: Theme, colors: Pick<MarketColorScheme, 'up' | 'down'>): Theme {\n return {\n ...base,\n candleUp: colors.up,\n candleDown: colors.down,\n candleUpWick: colors.up,\n candleDownWick: colors.down,\n };\n}\n\n/** Rounding slack, so 27.1 / 0.05 (541.999…) still counts as 542 steps. */\nconst STEP_EPSILON = 1e-9;\n\n/**\n * The price step at `price`: the band it falls in, else the market's\n * `priceStep`; undefined when the market names no step.\n */\nexport function priceStepAt(price: number, config: MarketConfig): number | undefined {\n let step = config.priceStep;\n for (const band of config.priceSteps ?? []) {\n if (price + STEP_EPSILON >= band.from) step = band.step;\n }\n return step !== undefined && step > 0 ? step : undefined;\n}\n\n/** The step of the band just below `price`, for one step down from it. */\nfunction stepBelow(price: number, config: MarketConfig): number | undefined {\n let step = config.priceStep;\n for (const band of config.priceSteps ?? []) {\n if (price - STEP_EPSILON > band.from) step = band.step;\n }\n return step !== undefined && step > 0 ? step : undefined;\n}\n\n/**\n * `price` on the step of its band: to the nearest step, or `'down'` / `'up'`.\n * A market without a step leaves it as it is.\n */\nexport function roundToPriceStep(price: number, config: MarketConfig, mode: 'nearest' | 'down' | 'up' = 'nearest'): number {\n const step = priceStepAt(price, config);\n if (step === undefined || !Number.isFinite(price)) return price;\n const steps = price / step;\n const count = mode === 'down'\n ? Math.floor(steps + STEP_EPSILON)\n : mode === 'up'\n ? Math.ceil(steps - STEP_EPSILON)\n : Math.round(steps);\n return Number((count * step).toFixed(stepDecimals(step)));\n}\n\n/**\n * The day's ceiling, floor and reference prices. With a price step, the\n * ceiling rounds down and the floor up to a valid price; when one would land\n * back on the reference it moves a step off it, and a reference of one step\n * keeps the floor at the reference (the exchanges' rules).\n */\nexport function computePriceLimits(referencePrice: number, config: MarketConfig): { ceiling: number; floor: number; reference: number } | null {\n if (!config.priceLimits?.enabled || !config.priceLimits.ceilingPercent) return null;\n const ceilPct = config.priceLimits.ceilingPercent / 100;\n const floorPct = (config.priceLimits.floorPercent ?? config.priceLimits.ceilingPercent) / 100;\n const reference = referencePrice;\n const rawCeiling = reference * (1 + ceilPct);\n const rawFloor = reference * (1 - floorPct);\n const refStep = priceStepAt(reference, config);\n if (refStep === undefined) return { ceiling: rawCeiling, floor: rawFloor, reference };\n\n const oneUp = roundToPriceStep(reference + refStep, config);\n if (Math.abs(reference - refStep) < STEP_EPSILON) return { ceiling: oneUp, floor: reference, reference };\n\n let ceiling: number;\n let floor: number;\n if (config.priceLimits.roundMove) {\n // KRX: the move rounded down to the reference's step, then each limit down to its own.\n const atRefStep: MarketConfig = { ...config, priceStep: refStep, priceSteps: undefined };\n ceiling = roundToPriceStep(reference + roundToPriceStep(reference * ceilPct, atRefStep, 'down'), config, 'down');\n floor = roundToPriceStep(reference - roundToPriceStep(reference * floorPct, atRefStep, 'down'), config, 'down');\n } else {\n ceiling = roundToPriceStep(rawCeiling, config, 'down');\n floor = roundToPriceStep(rawFloor, config, 'up');\n }\n if (ceiling <= reference) ceiling = oneUp;\n if (floor >= reference) floor = roundToPriceStep(reference - (stepBelow(reference, config) ?? refStep), config);\n if (floor <= 0) floor = reference;\n return { ceiling, floor, reference };\n}\n\n/** `value * factor` without float dust (0.05 * 1000 is 50, not 50.00000000000001). */\nconst scaled = (value: number, factor: number) => Math.round(value * factor * 1e9) / 1e9;\n\n/**\n * A copy of `config` for prices `factor` times larger (a power of ten):\n * steps, bands, the reference price and the decimals follow; a contract's\n * multiplier stays. `scaleMarketPrices(MARKET_HOSE, 1000)` reads prices in\n * dong (25350) instead of thousands (25.35).\n */\nexport function scaleMarketPrices(config: MarketConfig, factor: number): MarketConfig {\n const decimalsLess = Math.round(Math.log10(factor));\n return {\n ...config,\n pricePrecision: config.pricePrecision === undefined ? undefined : Math.max(0, config.pricePrecision - decimalsLess),\n priceStep: config.priceStep === undefined ? undefined : scaled(config.priceStep, factor),\n priceSteps: config.priceSteps?.map((band) => ({ from: scaled(band.from, factor), step: scaled(band.step, factor) })),\n priceLimits: config.priceLimits && {\n ...config.priceLimits,\n referencePrice: config.priceLimits.referencePrice === undefined ? undefined : scaled(config.priceLimits.referencePrice, factor),\n },\n };\n}\n\nconst MINUTE_MS = 60_000;\nconst DAY_MS = 86_400_000;\n\n/** `HH:mm` of `now` in `timeZone`, or on this computer's clock without one. */\nfunction wallClock(now: number, timeZone?: string): string {\n let hours: number;\n let minutes: number;\n if (timeZone) {\n const local = new Date(now + zoneOffsetMinutes(timeZone, now) * MINUTE_MS);\n hours = local.getUTCHours();\n minutes = local.getUTCMinutes();\n } else {\n const local = new Date(now);\n hours = local.getHours();\n minutes = local.getMinutes();\n }\n return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`;\n}\n\n/**\n * The session `now` falls in: by the clock of `timeZone` (a market's\n * `timeZone`), or of this computer without one. Null outside them all, and\n * for a time zone it doesn't know. By the time of day only: weekends and\n * holidays are yours to tell.\n */\nexport function getCurrentSession(sessions: TradingSession[], now: number = Date.now(), timeZone?: string): TradingSession | null {\n if (timeZone !== undefined && !isValidTimeZone(timeZone)) return null;\n const hhmm = wallClock(now, timeZone);\n for (const session of sessions) {\n if (hhmm >= session.startTime && hhmm < session.endTime) return session;\n }\n return null;\n}\n\nconst pad2 = (n: number) => String(n).padStart(2, '0');\nconst isoDay = (ms: number) => {\n const d = new Date(ms);\n return `${d.getUTCFullYear()}-${pad2(d.getUTCMonth() + 1)}-${pad2(d.getUTCDate())}`;\n};\nconst THURSDAY = 4;\n/** Vietnam is UTC+7 all year. */\nconst VN_OFFSET_MS = 7 * 3_600_000;\n\n/**\n * The last trading day of the VN30 futures contract of `month` (1–12): the\n * third Thursday, or the trading day before it when that is a holiday\n * (`isHoliday` gets `YYYY-MM-DD`). As `YYYY-MM-DD`.\n */\nexport function vn30fLastTradingDay(year: number, month: number, isHoliday?: (day: string) => boolean): string {\n const first = Date.UTC(year, month - 1, 1);\n const firstThursday = 1 + ((THURSDAY - new Date(first).getUTCDay() + 7) % 7);\n let day = Date.UTC(year, month - 1, firstThursday + 14);\n const closed = (ms: number) => {\n const weekday = new Date(ms).getUTCDay();\n return weekday === 0 || weekday === 6 || (isHoliday?.(isoDay(ms)) ?? false);\n };\n while (closed(day)) day -= DAY_MS;\n return isoDay(day);\n}\n\n/**\n * The VN30 futures contracts listed at `now`: this month's (until its last\n * trading day), the next month's, and the last months of the two quarters\n * after that.\n */\nexport function vn30fContracts(now: number, isHoliday?: (day: string) => boolean): VN30FContract[] {\n const today = isoDay(now + VN_OFFSET_MS);\n const contract = (year: number, month: number): VN30FContract => ({\n symbol: `VN30F${pad2(year % 100)}${pad2(month)}`,\n year,\n month,\n lastTradingDay: vn30fLastTradingDay(year, month, isHoliday),\n });\n const next = (c: VN30FContract) => (c.month === 12 ? contract(c.year + 1, 1) : contract(c.year, c.month + 1));\n\n const vnNow = new Date(now + VN_OFFSET_MS);\n let front = contract(vnNow.getUTCFullYear(), vnNow.getUTCMonth() + 1);\n if (today > front.lastTradingDay) front = next(front);\n const listed = [front, next(front)];\n let candidate = next(listed[1]);\n while (listed.length < 4) {\n if (candidate.month % 3 === 0) listed.push(candidate);\n candidate = next(candidate);\n }\n return listed;\n}\n","/**\n * The TradeCanvas icon set, as in the \"TradeCanvas Icons\" Figma file: a 24 px\n * grid with 2 px padding, 1.75 px strokes with round caps and joins. Drawing\n * tools mark their anchor points (where you click to draw) with filled dots.\n */\nexport interface IconDef {\n /** Stroked path data. */\n d?: string;\n /** Dashed stroke, for guides. */\n dash?: string;\n /** Solid shapes, such as filled candle bodies. */\n fills?: readonly string[];\n /** An area filled at 22%. */\n soft?: string;\n /** Filled dots: [cx, cy, r = 1.75]. */\n dots?: readonly (readonly number[])[];\n}\n\n/** Toolbar, sidebar and panel glyphs. */\nexport const UI_ICONS: Readonly<Record<string, IconDef>> = {\n cursor: { d: 'M6 3.5L18.5 12.5L12.6 13.6L9.7 19.4z' }, // Cursor\n trendingUp: { d: 'M3 17L9 11L13 14.5L21 6.5M15 6.5H21V12.5' }, // Indicators / Long\n trendingDown: { d: 'M3 7L9 13L13 9.5L21 17.5M15 17.5H21V11.5' }, // Short\n minus: { d: 'M5 12H19' }, // Minus\n plus: { d: 'M12 5V19M5 12H19' }, // Plus\n penLine: { d: 'M14.5 5.5L18.5 9.5M4 20L5 15.5L15.8 4.7a2 2 0 0 1 2.83 0l.67.67a2 2 0 0 1 0 2.83L8.5 19z' }, // Draw\n zigzag: { d: 'M3 17L8 9L13 15L21 6' }, // Patterns\n hash: { d: 'M5 9H19M5 15H19M10 4L8.5 20M15.5 4L14 20' }, // Grid\n square: { d: 'M6.5 4.5h11a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2h-11a2 2 0 0 1-2-2v-11a2 2 0 0 1 2-2z' }, // Shape\n gitBranch: { d: 'M6 3V15M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM18 9a9 9 0 0 1-9 9' }, // Branch\n ruler: { d: 'M3.5 16.5L16.5 3.5L20.5 7.5L7.5 20.5zM6.5 13.5L8 15M9.5 10.5L11.5 12.5M12.5 7.5L14 9' }, // Measure\n type: { d: 'M6 6V4.5H18V6M12 4.5V19.5M9.5 19.5H14.5' }, // Text\n magnet: { d: 'M6 4V11a6 6 0 0 0 12 0V4M6 4h3.5v7a2.5 2.5 0 0 0 5 0V4H18M6 8h3.5M14.5 8H18' }, // Magnet\n magnetStrong: { d: 'M6 4V11a6 6 0 0 0 12 0V4M6 4h3.5v7a2.5 2.5 0 0 0 5 0V4H18', fills: ['M6 4h3.5v4H6z', 'M14.5 4H18v4h-3.5z'] }, // Strong magnet\n eraser: { d: 'M8.5 19.5L3.9 14.9a1.5 1.5 0 0 1 0-2.1l8.5-8.5a1.5 1.5 0 0 1 2.1 0l5.2 5.2a1.5 1.5 0 0 1 0 2.1L12 19.5zM8 9l7 7M12 19.5H20' }, // Eraser\n zoomIn: { d: 'M16.5 10.5a6 6 0 1 1-12 0 6 6 0 0 1 12 0zM15 15L20.5 20.5M10.5 7.5V13.5M7.5 10.5H13.5' }, // Zoom area\n undo: { d: 'M9 14L4 9L9 4M4 9H14.5a5.5 5.5 0 0 1 0 11H11' }, // Undo\n redo: { d: 'M15 14L20 9L15 4M20 9H9.5a5.5 5.5 0 0 0 0 11H13' }, // Redo\n trash: { d: 'M4 7H20M9.5 7V4.5h5V7M6.5 7l.8 12.2A1.5 1.5 0 0 0 8.8 20.6h6.4a1.5 1.5 0 0 0 1.5-1.4L17.5 7M10 11v6M14 11v6' }, // Delete\n camera: { d: 'M4.5 7.5h3L9 5h6l1.5 2.5h3A1.5 1.5 0 0 1 21 9v9.5a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 3 18.5V9a1.5 1.5 0 0 1 1.5-1.5zM15.5 13.5a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0z' }, // Screenshot\n settings: { d: 'M4 7H14M18 7H20M4 17H8M12 17H20M18 7a2 2 0 1 1-4 0 2 2 0 0 1 4 0zM12 17a2 2 0 1 1-4 0 2 2 0 0 1 4 0z' }, // Settings\n moon: { d: 'M20 14.5A8 8 0 1 1 9.5 4a6.5 6.5 0 0 0 10.5 10.5z' }, // Dark theme\n sun: { d: 'M16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0zM12 2.5v2M12 19.5v2M4.6 4.6l1.4 1.4M18 18l1.4 1.4M2.5 12h2M19.5 12h2M4.6 19.4L6 18M18 6l1.4-1.4' }, // Light theme\n chevronDown: { d: 'M6 9L12 15L18 9' }, // Expand\n chevronUp: { d: 'M6 15L12 9L18 15' }, // Collapse\n barChart: { d: 'M5 20V13M12 20V5M19 20V10' }, // Chart type\n x: { d: 'M6 6L18 18M18 6L6 18' }, // Close\n play: { d: 'M7 4.5v15L19.5 12z' }, // Play\n pause: { d: 'M8 5V19M16 5V19' }, // Pause\n stop: { d: 'M7.5 6h9A1.5 1.5 0 0 1 18 7.5v9a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 6 16.5v-9A1.5 1.5 0 0 1 7.5 6z' }, // Stop\n receipt: { d: 'M6 3.5h12v17l-2-1.25-2 1.25-2-1.25-2 1.25-2-1.25-2 1.25zM9 8h6M9 12h6M9 16h3' }, // Orders\n bell: { d: 'M6 16.5V11a6 6 0 0 1 12 0v5.5l1.5 2H4.5zM10 20.5a2.2 2.2 0 0 0 4 0' }, // Alerts\n layers: { d: 'M12 3.5L21 8.5L12 13.5L3 8.5zM3 12.5L12 17.5L21 12.5M3 16.5L12 21.5L21 16.5' }, // Objects\n list: { d: 'M9 6.5H20M9 12H20M9 17.5H20', dots: [[4.75, 6.5, 1.25], [4.75, 12, 1.25], [4.75, 17.5, 1.25]] }, // Watchlist\n table: { d: 'M5.5 4.5h13a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2v-11a2 2 0 0 1 2-2zM3.5 9.5H20.5M3.5 14.5H20.5M10 9.5V19.5' }, // Data window\n eye: { d: 'M2.5 12S6 5.5 12 5.5 21.5 12 21.5 12 18 18.5 12 18.5 2.5 12 2.5 12zM15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0z' }, // Show\n eyeOff: { d: 'M4 4L20 20M9.9 5.8A9.6 9.6 0 0 1 12 5.5c6 0 9.5 6.5 9.5 6.5a16 16 0 0 1-2.3 3.1M6.6 7.1C3.9 8.9 2.5 12 2.5 12S6 18.5 12 18.5a9.3 9.3 0 0 0 4.7-1.3M10 10.1a3 3 0 0 0 4 4' }, // Hide\n lock: { d: 'M7 10.5h10a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-6a2 2 0 0 1 2-2zM8 10.5V7.5a4 4 0 0 1 8 0v3' }, // Lock\n unlock: { d: 'M7 10.5h10a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-6a2 2 0 0 1 2-2zM8 10.5V7.5a4 4 0 0 1 7.7-1.5' }, // Unlock\n palette: { d: 'M12 3.5a8.5 8.5 0 0 0 0 17c1.1 0 1.6-.8 1.6-1.6 0-.5-.2-.9-.5-1.2a1.6 1.6 0 0 1 1.2-2.7h1.9a4.3 4.3 0 0 0 4.3-4.3C20.5 6.9 16.7 3.5 12 3.5z', dots: [[7.5, 11.5, 1.25], [9.5, 7.75, 1.25], [14, 7.25, 1.25]] }, // Style\n check: { d: 'M5 12.5L10 17.5L19 7' }, // Done\n maximize: { d: 'M8 4H5a1 1 0 0 0-1 1v3M16 4h3a1 1 0 0 1 1 1v3M20 16v3a1 1 0 0 1-1 1h-3M8 20H5a1 1 0 0 1-1-1v-3' }, // Fullscreen\n minimize: { d: 'M4 8h3a1 1 0 0 0 1-1V4M16 4v3a1 1 0 0 0 1 1h3M20 16h-3a1 1 0 0 0-1 1v3M8 20v-3a1 1 0 0 0-1-1H4' }, // Exit fullscreen\n repeat: { d: 'M17 3.5L20.5 7L17 10.5M3.5 11.5V10a3 3 0 0 1 3-3h14M7 20.5L3.5 17L7 13.5M20.5 12.5V14a3 3 0 0 1-3 3h-14' }, // Stay in drawing mode\n info: { d: 'M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0zM12 11V16.5', dots: [[12, 7.75, 1.25]] }, // Symbol info\n chevronLeft: { d: 'M15 5L8 12L15 19' }, // Scroll left\n chevronRight: { d: 'M9 5L16 12L9 19' }, // Scroll right\n reset: { d: 'M4.5 12a7.5 7.5 0 1 0 2.2-5.3M4.5 4v4.5H9' }, // Reset the view\n calendar: { d: 'M5.5 5h13a2 2 0 0 1 2 2v11.5a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2zM3.5 10H20.5M8 3V7M16 3V7' }, // Go to date\n star: { d: 'M12 3.5L14.6 9L20.5 9.6L16 13.6L17.3 19.5L12 16.5L6.7 19.5L8 13.6L3.5 9.6L9.4 9z' }, // Favourite\n pin: { d: 'M8 3.5h8M9.5 3.5v5.5L5.5 14h13l-4-5v-5.5M12 14v6.5' }, // Pinned\n search: { d: 'M16.5 10.5a6 6 0 1 1-12 0 6 6 0 0 1 12 0zM15 15L20.5 20.5' }, // Search\n enter: { d: 'M19 5v6.5a3 3 0 0 1-3 3H5.5M9.5 10L5 14.5L9.5 19' }, // Enter (select)\n stepBack: { d: 'M6 5v14M18.5 5.5v13L8.5 12z' }, // Replay: one bar back\n stepForward: { d: 'M18 5v14M5.5 5.5v13l10-6.5z' }, // Replay: one bar on\n replayPick: { d: 'M7.5 3.5V7M7.5 17V20.5M6 7h3a1.5 1.5 0 0 1 1.5 1.5v7A1.5 1.5 0 0 1 9 17H6a1.5 1.5 0 0 1-1.5-1.5v-7A1.5 1.5 0 0 1 6 7z', dash: 'M15 3V21', soft: 'M15 4h4.5a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H15z' }, // Replay: pick the start bar (a candle, the cut, the hidden bars)\n ladder: { d: 'M4 6H11M13 6H17M6 10H11M13 10H20M8 14H11M13 14H15M5 18H11M13 18H19' }, // Depth ladder\n save: { d: 'M5.5 3.5h10.5l4.5 4.5v10.5a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2v-13a2 2 0 0 1 2-2zM8 3.5v5h7v-5M7.5 20.5v-6h9v6' }, // Save layout\n folder: { d: 'M3.5 7a2 2 0 0 1 2-2h4l2 2.5h7a2 2 0 0 1 2 2V17a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2z' }, // Open layout\n link: { d: 'M10 14a4 4 0 0 0 5.66 0l3-3a4 4 0 0 0-5.66-5.66l-1.2 1.2M14 10a4 4 0 0 0-5.66 0l-3 3a4 4 0 0 0 5.66 5.66l1.2-1.2' }, // Sync\n arrowUp: { d: 'M12 19V5M6 11L12 5L18 11' }, // Move pane up\n arrowDown: { d: 'M12 5V19M6 13L12 19L18 13' }, // Move pane down\n arrowUpDown: { d: 'M8.5 19V5M5 8.5L8.5 5L12 8.5M15.5 5V19M12 15.5L15.5 19L19 15.5' }, // Reverse a position\n more: { dots: [[6, 12, 1.6], [12, 12, 1.6], [18, 12, 1.6]] }, // More\n copy: { d: 'M9.5 8.5h9a1 1 0 0 1 1 1v9a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1zM15.5 8.5v-3a1 1 0 0 0-1-1h-9a1 1 0 0 0-1 1v9a1 1 0 0 0 1 1h3' }, // Clone\n grip: { dots: [[9, 6, 1.4], [15, 6, 1.4], [9, 12, 1.4], [15, 12, 1.4], [9, 18, 1.4], [15, 18, 1.4]] }, // Drag to reorder\n layoutGrid: { d: 'M5 4.5h4.5a.5.5 0 0 1 .5.5v4.5a.5.5 0 0 1-.5.5H5a.5.5 0 0 1-.5-.5V5a.5.5 0 0 1 .5-.5zM14.5 4.5H19a.5.5 0 0 1 .5.5v4.5a.5.5 0 0 1-.5.5h-4.5a.5.5 0 0 1-.5-.5V5a.5.5 0 0 1 .5-.5zM5 14h4.5a.5.5 0 0 1 .5.5V19a.5.5 0 0 1-.5.5H5a.5.5 0 0 1-.5-.5v-4.5A.5.5 0 0 1 5 14zM14.5 14H19a.5.5 0 0 1 .5.5V19a.5.5 0 0 1-.5.5h-4.5a.5.5 0 0 1-.5-.5v-4.5a.5.5 0 0 1 .5-.5z' }, // Chart layout\n};\n\n/** One per drawing tool, keyed by tool type. */\nexport const DRAWING_TOOL_ICONS: Readonly<Record<string, IconDef>> = {\n trendLine: { d: 'M5 18L19 6', dots: [[5, 18], [19, 6]] }, // Trend Line\n ray: { d: 'M5 17L21 5M17.5 4.81L21 5L20.2 8.41', dots: [[5, 17], [11, 12.5]] }, // Ray\n extendedLine: { d: 'M3 18.5L21 5M17.5 4.81L21 5L20.2 8.41M6.5 18.69L3 18.5L3.8 15.09', dots: [[9, 14], [15, 9.5]] }, // Extended Line\n infoLine: { d: 'M5 20L19 10M4.5 3.5h9a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1zM6.5 6.5h5', dots: [[5, 20], [19, 10]] }, // Info Line\n trendAngle: { d: 'M5 18L19 7M5 18H20M11 18A6 6 0 0 0 9.71 14.29', dots: [[5, 18], [19, 7]] }, // Trend Angle\n horizontalLine: { d: 'M3 12H21', dots: [[12, 12]] }, // Horizontal Line\n horizontalRay: { d: 'M7 12H21M18.5 9.5L21 12L18.5 14.5', dots: [[7, 12]] }, // Horizontal Ray\n verticalLine: { d: 'M12 3V21', dots: [[12, 12]] }, // Vertical Line\n crossLine: { d: 'M3 12H21M12 3V21', dots: [[12, 12]] }, // Cross Line\n parallelChannel: { d: 'M3 15L15 5M9 19L21 9', dots: [[3, 15], [15, 5], [9, 19]] }, // Parallel Channel\n regressionChannel: { d: 'M3 12L21 4M3 20L21 12', dash: 'M3 16L21 8', dots: [[3, 16], [21, 8]] }, // Regression Channel\n fibRetracement: { d: 'M3 4H21M3 9H21M3 13H21M3 20H21', dots: [[5, 20], [19, 4]] }, // Fib Retracement\n fibExtension: { d: 'M3 20L8 10L12 16M14 4H21M14 8H21M14 12H21', dots: [[3, 20], [8, 10], [12, 16]] }, // Fib Extension\n fibChannel: { d: 'M3 9L21 3M3 13L21 7M3 16L21 10M3 21L21 15', dots: [[3, 21], [21, 15], [3, 9]] }, // Fib Channel\n fibTimeZones: { d: 'M3 4V20M6 4V20M9.5 4V20M14 4V20M20.5 4V20', dots: [[3, 20], [6, 20]] }, // Fib Time Zones\n fibSpeedResistanceFan: { d: 'M4 20L20 4M4 20L20 11M4 20L20 16M4 20L11 4', dash: 'M4 4H20V20', dots: [[4, 20], [20, 4]] }, // Fib Speed Resistance Fan\n rectangle: { d: 'M5.5 6h13A1.5 1.5 0 0 1 20 7.5v9a1.5 1.5 0 0 1-1.5 1.5h-13A1.5 1.5 0 0 1 4 16.5v-9A1.5 1.5 0 0 1 5.5 6z', dots: [[4, 6], [20, 18]] }, // Rectangle\n circle: { d: 'M19.5 12a7.5 7.5 0 1 1-15 0 7.5 7.5 0 0 1 15 0z', dots: [[12, 12], [19.5, 12]] }, // Circle\n ellipse: { d: 'M20.5 12c0 3-3.8 5.5-8.5 5.5S3.5 15 3.5 12 7.3 6.5 12 6.5s8.5 2.5 8.5 5.5z', dots: [[3.5, 12], [20.5, 12]] }, // Ellipse\n triangle: { d: 'M12 4.5L20 19H4z', dots: [[12, 4.5], [20, 19], [4, 19]] }, // Triangle\n pitchfork: { d: 'M4 20L16.75 3M7 9L11.5 3M13 15L21 4.33M7 9L13 15', dots: [[4, 20], [7, 9], [13, 15]] }, // Pitchfork\n schiffPitchfork: { d: 'M4 14.5L21 7.42M7 9L21 3.17M13 15L21 11.67M7 9L13 15', dash: 'M4 20V14.5', dots: [[4, 14.5], [7, 9], [13, 15]] }, // Schiff Pitchfork\n modifiedSchiffPitchfork: { d: 'M5.5 14.5L21 5.89M7 9L17.8 3M13 15L21 10.56M7 9L13 15', dash: 'M4 20L5.5 14.5', dots: [[5.5, 14.5], [7, 9], [13, 15]] }, // Modified Schiff Pitchfork\n gannFan: { d: 'M4 20L20 4M4 20L20 12M4 20L12 4M4 20L20 16.5M4 20L7.5 4', dots: [[4, 20], [20, 4]] }, // Gann Fan\n gannBox: { d: 'M4 4H20V20H4zM4 20L20 4M4 4L20 20M12 4V20', dots: [[4, 20], [20, 4]] }, // Gann Box\n cyclicLines: { d: 'M4 4V20M9 4V20M14 4V20M19 4V20', dots: [[4, 20], [9, 20]] }, // Cyclic Lines\n xabcdPattern: { d: 'M3 18L7 6L11 13L15 8L21 19', dash: 'M3 18L11 13L21 19', dots: [[3, 18], [7, 6], [11, 13], [15, 8], [21, 19]] }, // XABCD Pattern\n abcdPattern: { d: 'M4 19L9 8L13 14L20 4', dots: [[4, 19], [9, 8], [13, 14], [20, 4]] }, // ABCD Pattern\n headAndShoulders: { d: 'M3 19L6 11L8.5 15L12 5L15.5 15L18 11L21 19', dash: 'M4.5 15H19.5', dots: [[6, 11], [12, 5], [18, 11]] }, // Head and Shoulders\n elliottWave: { d: 'M3 19L6 13L8.5 16L14 6L16 10L21 4', dots: [[3, 19], [21, 4]] }, // Elliott Wave\n priceRange: { d: 'M5 4H19M5 20H19M12 6.5V17.5M9 9.5L12 6.5L15 9.5M9 14.5L12 17.5L15 14.5' }, // Price Range\n dateRange: { d: 'M4 5V19M20 5V19M6.5 12H17.5M9.5 9L6.5 12L9.5 15M14.5 9L17.5 12L14.5 15' }, // Date Range\n dateAndPriceRange: { d: 'M6 18V4M3 7L6 4L9 7M6 18H20M17 15L20 18L17 21', dash: 'M6 4H20V18' }, // Date and Price Range\n measure: { d: 'M3.5 16.5L16.5 3.5L20.5 7.5L7.5 20.5zM6.5 13.5L8 15M9.5 10.5L11.5 12.5M12.5 7.5L14 9' }, // Measure\n text: { d: 'M6 6V4.5H18V6M12 4.5V19.5M9.5 19.5H14.5' }, // Text\n priceLabel: { d: 'M9 5H19a1.5 1.5 0 0 1 1.5 1.5v11A1.5 1.5 0 0 1 19 19H9L3.5 12zM11 12H17' }, // Price Label\n arrow: { d: 'M5 19L19 5M10 5H19V14' }, // Arrow\n riskReward: { d: 'M5 12V4H19V12M3 12H21', dash: 'M5 12V18H19V12', dots: [[5, 12]] }, // Long/Short Position\n anchoredVWAP: { d: 'M4 18C9 17 12 10 20 7M4 20.5V18', dots: [[4, 18]] }, // Anchored VWAP\n volumeProfileRange: { d: 'M6 7H12M6 10.5H17M6 14H15M6 17.5H10', dash: 'M3.5 4V20M20.5 4V20', dots: [[3.5, 20], [20.5, 20]] }, // Fixed Range Volume Profile\n note: { d: 'M5.5 4.5h13v9l-5 5h-8zM13.5 18.5v-5h5M8.5 8.5h7M8.5 11.5h4' }, // Note\n callout: { d: 'M10.5 4h9a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1zM12 12L5 19M12.5 8h5', dots: [[5, 19]] }, // Callout\n flag: { d: 'M6 21V4M6 4.5h11l-2.5 3.75L17 12H6', soft: 'M6 4.5h11l-2.5 3.75L17 12H6z', dots: [[6, 21]] }, // Flag Mark\n arrowMark: { d: 'M12 4L18 11H14.5V20H9.5V11H6z' }, // Arrow Mark\n icon: { d: 'M12 3.5l2.6 5.3 5.9.85-4.25 4.15 1 5.85L12 16.9l-5.25 2.75 1-5.85L3.5 9.65l5.9-.85z' }, // Icon\n brush: { d: 'M3.5 17c2.5 0 3-5 6-5s2.5 5 5.5 5 3.5-6 5.5-9' }, // Brush\n highlighter: { d: 'M14.5 4.5l5 5L11 18H6v-5zM12 7l5 5M4 21h8' }, // Highlighter\n path: { d: 'M4 18L9 10L14 14L20 6M16.2 6.6L20 6L19.6 9.8', dots: [[4, 18], [9, 10], [14, 14]] }, // Path\n polyline: { d: 'M5 17L8 6L16 4L20 14L12 20z', soft: 'M5 17L8 6L16 4L20 14L12 20z', dots: [[5, 17], [8, 6], [16, 4], [20, 14], [12, 20]] }, // Polyline\n curve: { d: 'M4 18C8 4 16 4 20 18', dots: [[4, 18], [20, 18], [12, 7.5]] }, // Curve\n arc: { d: 'M4 17a8 8 0 0 1 16 0', dots: [[4, 17], [20, 17], [12, 9]] }, // Arc\n fibCircles: { d: 'M14 12a2 2 0 1 1-4 0 2 2 0 0 1 4 0zM16.5 12a4.5 4.5 0 1 1-9 0 4.5 4.5 0 0 1 9 0zM20 12a8 8 0 1 1-16 0 8 8 0 0 1 16 0z', dots: [[12, 12], [20, 12]] }, // Fib Circles\n fibSpiral: { d: 'M12 12a1.5 1.5 0 0 1 1.5 1.5 3 3 0 0 1-3 3A4.5 4.5 0 0 1 6 12a6 6 0 0 1 6-6 8 8 0 0 1 8 8', dots: [[12, 12]] }, // Fib Spiral\n fibArcs: { d: 'M10 20a6 6 0 0 0-6-6M14 20a10 10 0 0 0-10-10M18 20a14 14 0 0 0-14-14', dash: 'M4 20L18 6', dots: [[4, 20], [18, 6]] }, // Fib Speed Resistance Arcs\n fibWedge: { d: 'M4 19L20 7M4 19L20 16M10.4 14.2A8 8 0 0 1 11.86 17.53M14.4 11.2A13 13 0 0 1 16.78 16.6', dots: [[4, 19], [20, 7], [20, 16]] }, // Fib Wedge\n pitchfan: { d: 'M4 20L14 4M4 20L20 14M4 20L17 9', dash: 'M14 4L20 14', dots: [[4, 20], [14, 4], [20, 14]] }, // Pitchfan\n gannSquare: { d: 'M4 4H20V20H4zM4 20L20 4M4 12H20M12 4V20M4 12a8 8 0 0 1 8 8', dots: [[4, 20], [20, 4]] }, // Gann Square\n elliottImpulse: { d: 'M3 19L7 12L10 15L15 5L17.5 9L21 3', dots: [[3, 19], [21, 3]] }, // Elliott Impulse Wave\n elliottCorrection: { d: 'M4 5L10 17L14 11L20 20', dots: [[4, 5], [20, 20]] }, // Elliott Correction Wave\n elliottTriangle: { d: 'M3 6L7 17L11 9L15 15L18 11L21 13', dots: [[3, 6], [21, 13]] }, // Elliott Triangle Wave\n elliottDoubleCombo: { d: 'M4 5L9 14L13 9L20 19', dots: [[4, 5], [9, 14], [13, 9], [20, 19]] }, // Elliott Double Combo Wave\n elliottTripleCombo: { d: 'M3 5L7 13L10 9L14 16L17 12L21 20', dots: [[3, 5], [21, 20]] }, // Elliott Triple Combo Wave\n threeDrives: { d: 'M3 20L7 12L9.5 15L14 7L16.5 10L21 3', dash: 'M7 12L14 7L21 3', dots: [[7, 12], [14, 7], [21, 3]] }, // Three Drives Pattern\n cypherPattern: { d: 'M3 19L7 9L10 14L15 5L20 16', dash: 'M3 19L10 14L20 16', dots: [[3, 19], [7, 9], [10, 14], [15, 5], [20, 16]] }, // Cypher Pattern\n timeCycles: { d: 'M3 18a4.5 4.5 0 0 1 9 0a4.5 4.5 0 0 1 9 0', dots: [[3, 18], [12, 18]] }, // Time Cycles\n sineLine: { d: 'M3 12C5 5 7.5 5 9 12S13 19 15 12 19.5 5 21 12', dots: [[6, 6.75], [12, 17.25]] }, // Sine Line\n forecast: { d: 'M4 18L15.2 7.8M19.5 6a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0z', dots: [[4, 18]] }, // Forecast\n projection: { d: 'M12 19L18 11M15.2 11.3L18 11L17.8 13.8', dash: 'M3 17L9 9', dots: [[3, 17], [9, 9], [12, 19]] }, // Projection\n barsPattern: { d: 'M5 6V14M9 9V18M15 4V12M19 7V16', fills: ['M4 8h2v4H4z', 'M8 11h2v5H8z', 'M14 6h2v4h-2z', 'M18 9h2v5h-2z'], dash: 'M12 3V21' }, // Bars Pattern\n};\n\n/** One per chart type, keyed by chart type. */\nexport const CHART_TYPE_ICONS: Readonly<Record<string, IconDef>> = {\n candlestick: { d: 'M8 3.5V7M8 16V20.5M16 5V8.5M16 15.5V19', fills: ['M6.5 7h3a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1z', 'M14.5 8.5h3a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1z'] }, // Candlestick\n hollowCandle: { d: 'M8 3.5V7M8 16V20.5M16 5V8.5M16 15.5V19M6.5 7h3a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1zM14.5 8.5h3a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1z' }, // Hollow Candle\n heikinAshi: { d: 'M5.5 9.5V12M5.5 18V20M12 5.5V8M12 14V16M18.5 3V4.5M18.5 10.5V12.5', fills: ['M4 12h3a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5H4a.5.5 0 0 1-.5-.5v-5A.5.5 0 0 1 4 12z', 'M10.5 8h3a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-5a.5.5 0 0 1 .5-.5z', 'M17 4.5h3a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5V5a.5.5 0 0 1 .5-.5z'] }, // Heikin-Ashi\n bar: { d: 'M8 4V20M5 8H8M8 16H11M16 6V18M13 15H16M16 9H19' }, // Bar (OHLC)\n volumeCandles: { d: 'M6.5 5V8M6.5 16V19M15.5 3.5V6M15.5 16V20', fills: ['M5.5 8h2a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-7a.5.5 0 0 1 .5-.5z', 'M11.5 6h8a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-8a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5z'] }, // Volume Candles\n equivolume: { d: 'M4.5 10h2a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-6a1 1 0 0 1 1-1zM10 6h5a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zM18.5 4h1a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-1a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z' }, // Equivolume\n line: { d: 'M3 17L8 11L12 14L21 5' }, // Line\n area: { d: 'M3 17L8 11L12 14L21 5', soft: 'M3 17L8 11L12 14L21 5V20H3z' }, // Area\n baseline: { d: 'M3 16L7 9L11 14L15 7L21 15', dash: 'M3 12H21' }, // Baseline\n hlcArea: { d: 'M3 9L8 6L13 9L21 4M3 15L8 13L13 16L21 11', dash: 'M3 12L8 9.5L13 12.5L21 7.5', soft: 'M3 9L8 6L13 9L21 4V11L13 16L8 13L3 15z' }, // HLC Area\n stepLine: { d: 'M3 18H8V12H12V15H16V7H21' }, // Step Line\n lineWithMarkers: { d: 'M4 17L9 10L14 14L20 6', dots: [[4, 17], [9, 10], [14, 14], [20, 6]] }, // Line with Markers\n hiLo: { d: 'M6 7V17M12 4V14M18 9V20', fills: ['M5 7h2v10H5z', 'M11 4h2v10h-2z', 'M17 9h2v11h-2z'] }, // High-Low\n renko: { d: 'M3.5 15.5h4v4h-4zM7.5 11.5h4v4h-4zM11.5 7.5h4v4h-4zM15.5 11.5h4v4h-4z' }, // Renko\n lineBreak: { d: 'M4 14h4v5H4zM8 10h4v4H8zM16 9h4v8h-4z', fills: ['M12 5h4v5h-4z'] }, // Line Break\n kagi: { d: 'M4 19V11H9V16H14V5H20V13' }, // Kagi\n pointAndFigure: { d: 'M5.5 5.5l3 3M8.5 5.5l-3 3M5.5 10.5l3 3M8.5 10.5l-3 3M5.5 15.5l3 3M8.5 15.5l-3 3M14.5 9a1.5 1.5 0 1 0 3 0a1.5 1.5 0 1 0-3 0M14.5 14a1.5 1.5 0 1 0 3 0a1.5 1.5 0 1 0-3 0' }, // Point & Figure\n rangeBars: { d: 'M6.5 11V12M6.5 18V19M12 7V8M12 14V15M17.5 3.5V4.5M17.5 10.5V11.5', fills: ['M5 12h3v6H5z', 'M10.5 8h3v6h-3z', 'M16 4.5h3v6h-3z'] }, // Range Bars\n};\n\nexport const ICON_DOT_RADIUS = 1.75;\nexport const ICON_SOFT_OPACITY = 0.22;\nconst markupCache = new WeakMap<IconDef, string>();\n\n/** The icon's SVG elements, drawn in `currentColor`. */\nfunction markup(icon: IconDef): string {\n const cached = markupCache.get(icon);\n if (cached) return cached;\n let s = '';\n if (icon.soft) s += `<path d=\"${icon.soft}\" fill=\"currentColor\" fill-opacity=\"${ICON_SOFT_OPACITY}\" stroke=\"none\"/>`;\n for (const f of icon.fills ?? []) s += `<path d=\"${f}\" fill=\"currentColor\" stroke=\"none\"/>`;\n if (icon.d) s += `<path d=\"${icon.d}\"/>`;\n if (icon.dash) s += `<path d=\"${icon.dash}\" stroke-dasharray=\"2 2.5\"/>`;\n for (const [cx, cy, r = ICON_DOT_RADIUS] of icon.dots ?? []) s += `<circle cx=\"${cx}\" cy=\"${cy}\" r=\"${r}\" fill=\"currentColor\" stroke=\"none\"/>`;\n markupCache.set(icon, s);\n return s;\n}\n\n/** The icon as an inline SVG string at `size` px, coloured by `currentColor`. */\nexport function iconSvg(icon: IconDef, size: number): string {\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${size}\" height=\"${size}\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.75\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\">${markup(icon)}</svg>`;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/types/rendering.ts","../src/types/style.ts","../src/types/drawing.ts","../src/types/trading.ts","../src/types/signal.ts","../src/types/realtime.ts","../src/types/quote.ts","../src/types/news.ts","../src/utils/math.ts","../src/utils/data.ts","../src/utils/color.ts","../src/utils/timezone.ts","../src/utils/time.ts","../src/utils/precision.ts","../src/utils/priceSource.ts","../src/utils/resample.ts","../src/utils/symbols.ts","../src/utils/marketStatus.ts","../src/utils/drawingOptions.ts","../src/utils/drawingStyle.ts","../src/utils/chartTypeOptions.ts","../src/constants/themes.ts","../src/utils/chartStyle.ts","../src/constants/defaults.ts","../src/constants/golden.ts","../src/i18n/en.ts","../src/i18n/vi.ts","../src/i18n/index.ts","../src/market/presets.ts","../src/icons/iconSet.ts"],"sourcesContent":["export interface Point {\n x: number;\n y: number;\n}\n\nexport interface Size {\n width: number;\n height: number;\n}\n\nexport interface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport type PriceScaleMode = 'regular' | 'logarithmic' | 'percentage' | 'indexedTo100';\n\nexport interface ViewportState {\n visibleRange: { from: number; to: number };\n priceRange: { min: number; max: number };\n barWidth: number;\n barSpacing: number;\n offset: number;\n chartRect: Rect;\n /**\n * Logarithmic price geometry. Kept for back-compat; mirrors\n * `scaleMode === 'logarithmic'`. Prefer reading `scaleMode`.\n */\n logScale?: boolean;\n /**\n * Price-scale presentation. `regular`, `percentage`, and `indexedTo100` share\n * the same linear geometry — only the axis labels differ (rebased to\n * `scaleBaseline`). `logarithmic` changes the geometry. Defaults to\n * `regular` when unset.\n */\n scaleMode?: PriceScaleMode;\n /**\n * Reference price for `percentage` / `indexedTo100` axis labels — usually the\n * close of the first visible bar. Set by the chart each frame.\n */\n scaleBaseline?: number;\n /** Upside down: higher prices lower on screen. */\n invertScale?: boolean;\n /**\n * How prices on this scale read, when the chart has a price format of its\n * own (`ChartOptions.priceFormat`). Unset: decimals. Indicator panes leave\n * it unset.\n */\n formatPrice?: (price: number) => string;\n /** The number locale prices on this scale are grouped in (`'vi-VN'`: 72.202,13). Unset: en-US. */\n numberLocale?: string;\n /**\n * A bar's time as the chart writes it under the crosshair (its time zone,\n * its time formatter): a vertical line's time label. Unset: drawings show\n * no time.\n */\n formatTime?: (time: number) => string;\n /**\n * Decimals prices on this scale show, when the market or the symbol sets\n * them (`setMarket`, `SymbolInfo.pricePrecision`): drawing labels, price\n * limits and the tags beside the axis use them. Unset: each label keeps its\n * own decimals. Indicator panes and the left scale leave it unset.\n */\n pricePrecision?: number;\n /**\n * The step prices move in under that format (a 32nd): the axis puts its\n * ticks on whole numbers of it.\n */\n priceUnit?: number;\n /**\n * Optional reference to the current bar series. When set, drawings/indicators\n * treat `anchor.time` as a real timestamp and convert to bar index via\n * `timestampToBarIndex(time, data)` at render/hit-test time. This lets\n * anchors survive timeframe / symbol switches. When unset,\n * `anchor.time` is treated as a raw bar index (legacy behavior).\n */\n data?: ReadonlyArray<{ time: number }>;\n /**\n * Width of the price axis strip right of `chartRect`, in CSS pixels. The\n * chart widens it to fit long labels (sub-cent prices); renderers drawing\n * badges on the axis size them to it. Defaults to `PRICE_AXIS_WIDTH`.\n */\n priceAxisWidth?: number;\n}\n\n/**\n * What changed, for `requestRender()`. The chart paints two canvases: a scene\n * (everything that follows data, viewport and chart objects) and a thin top\n * canvas for pointer-tied visuals. Any type except `Hover` redraws both;\n * `Hover` redraws only the top canvas (crosshair, its axis pills, legend,\n * bar countdown, measure ruler, selection box).\n */\nexport enum LayerType {\n Background = 0,\n Main = 1,\n Panel = 2,\n Overlay = 3,\n UI = 4,\n Hover = 5,\n}\n","import type { LineStyle } from './chart.js';\n\n/** The kind of value a style key takes. */\nexport type StyleValueKind = 'color' | 'lineStyle' | 'width' | 'boolean';\n\n/**\n * Every key `chart.applyOverrides()` takes, and the kind of its value.\n *\n * - `series.<chartType>.*` style the main series while it is drawn as that\n * type. A candle's wick takes its body's colour (`upColor`, `downColor`)\n * unless `wickUpColor` / `wickDownColor` set one of its own. Up and down\n * colours fall back to `series.candlestick.*`, line\n * colours and widths to `series.line.*`, area fills to `series.area.*`,\n * then to the theme.\n * - The rest style one part of the chart each, falling back to the theme's\n * tokens: with no overrides the chart looks as its theme makes it.\n */\nexport const CHART_STYLE_KEYS = {\n 'background.color': 'color',\n\n 'panes.background': 'color',\n 'panes.separatorColor': 'color',\n 'panes.titleColor': 'color',\n\n 'grid.horizontal.visible': 'boolean',\n 'grid.horizontal.color': 'color',\n 'grid.horizontal.style': 'lineStyle',\n 'grid.horizontal.width': 'width',\n 'grid.vertical.visible': 'boolean',\n 'grid.vertical.color': 'color',\n 'grid.vertical.style': 'lineStyle',\n 'grid.vertical.width': 'width',\n\n 'crosshair.horizontal.visible': 'boolean',\n 'crosshair.horizontal.color': 'color',\n 'crosshair.horizontal.style': 'lineStyle',\n 'crosshair.horizontal.width': 'width',\n 'crosshair.vertical.visible': 'boolean',\n 'crosshair.vertical.color': 'color',\n 'crosshair.vertical.style': 'lineStyle',\n 'crosshair.vertical.width': 'width',\n 'crosshair.labelBackground': 'color',\n 'crosshair.labelTextColor': 'color',\n\n 'axis.price.lineColor': 'color',\n 'axis.price.textColor': 'color',\n 'axis.time.lineColor': 'color',\n 'axis.time.textColor': 'color',\n\n 'legend.textColor': 'color',\n 'legend.labelColor': 'color',\n\n 'watermark.color': 'color',\n\n 'lastPrice.visible': 'boolean',\n 'lastPrice.upColor': 'color',\n 'lastPrice.downColor': 'color',\n 'lastPrice.style': 'lineStyle',\n 'lastPrice.width': 'width',\n\n 'volume.upColor': 'color',\n 'volume.downColor': 'color',\n\n 'sessionBreaks.color': 'color',\n 'sessionBreaks.style': 'lineStyle',\n 'sessionBreaks.width': 'width',\n\n 'highLow.color': 'color',\n\n 'trading.buyColor': 'color',\n 'trading.sellColor': 'color',\n 'trading.profitColor': 'color',\n 'trading.lossColor': 'color',\n 'trading.entryColor': 'color',\n\n 'markers.longColor': 'color',\n 'markers.shortColor': 'color',\n 'markers.neutralColor': 'color',\n\n 'tradeZones.profitColor': 'color',\n 'tradeZones.lossColor': 'color',\n 'tradeZones.activeColor': 'color',\n\n 'drawings.handleColor': 'color',\n\n 'series.candlestick.upColor': 'color',\n 'series.candlestick.downColor': 'color',\n 'series.candlestick.wickUpColor': 'color',\n 'series.candlestick.wickDownColor': 'color',\n 'series.heikinAshi.upColor': 'color',\n 'series.heikinAshi.downColor': 'color',\n 'series.heikinAshi.wickUpColor': 'color',\n 'series.heikinAshi.wickDownColor': 'color',\n 'series.hollowCandle.upColor': 'color',\n 'series.hollowCandle.downColor': 'color',\n 'series.volumeCandles.upColor': 'color',\n 'series.volumeCandles.downColor': 'color',\n 'series.volumeCandles.wickUpColor': 'color',\n 'series.volumeCandles.wickDownColor': 'color',\n 'series.equivolume.upColor': 'color',\n 'series.equivolume.downColor': 'color',\n 'series.equivolume.wickUpColor': 'color',\n 'series.equivolume.wickDownColor': 'color',\n 'series.bar.upColor': 'color',\n 'series.bar.downColor': 'color',\n 'series.hiLo.upColor': 'color',\n 'series.hiLo.downColor': 'color',\n 'series.renko.upColor': 'color',\n 'series.renko.downColor': 'color',\n 'series.lineBreak.upColor': 'color',\n 'series.lineBreak.downColor': 'color',\n 'series.rangeBars.upColor': 'color',\n 'series.rangeBars.downColor': 'color',\n 'series.kagi.upColor': 'color',\n 'series.kagi.downColor': 'color',\n 'series.pointAndFigure.upColor': 'color',\n 'series.pointAndFigure.downColor': 'color',\n 'series.baseline.upColor': 'color',\n 'series.baseline.downColor': 'color',\n 'series.baseline.lineWidth': 'width',\n 'series.line.color': 'color',\n 'series.line.lineWidth': 'width',\n 'series.stepLine.color': 'color',\n 'series.stepLine.lineWidth': 'width',\n 'series.lineWithMarkers.color': 'color',\n 'series.lineWithMarkers.lineWidth': 'width',\n 'series.area.lineColor': 'color',\n 'series.area.lineWidth': 'width',\n 'series.area.topColor': 'color',\n 'series.area.bottomColor': 'color',\n 'series.hlcArea.lineColor': 'color',\n 'series.hlcArea.lineWidth': 'width',\n 'series.hlcArea.topColor': 'color',\n 'series.hlcArea.bottomColor': 'color',\n} as const satisfies Record<string, StyleValueKind>;\n\nexport type ChartStyleKey = keyof typeof CHART_STYLE_KEYS;\n\n/** The value a key of `kind` takes. */\nexport type StyleValue<K extends StyleValueKind> = K extends 'color'\n ? string\n : K extends 'lineStyle'\n ? LineStyle\n : K extends 'width'\n ? number\n : boolean;\n\n/** Style overrides, by key. */\nexport type ChartStyleOverrides = {\n [K in ChartStyleKey]?: StyleValue<(typeof CHART_STYLE_KEYS)[K]>;\n};\n\n/** A change to overrides: a value sets a key, `null` takes it away. */\nexport type ChartStyleOverridesPatch = {\n [K in ChartStyleKey]?: StyleValue<(typeof CHART_STYLE_KEYS)[K]> | null;\n};\n\n/**\n * Where an override goes. `'host'`: your app's, kept through theme changes\n * and never saved. `'user'`: what the person using the chart chose (the\n * widget's Settings write here), kept per theme and saved with `saveState`.\n */\nexport type StyleLayer = 'host' | 'user';\n\n/** One indicator pane's own look, over the panes' (`chart.setPaneStyle`). */\nexport interface PaneStyle {\n background?: string;\n separator?: string;\n}\n\n/** A line's look, as resolved. */\nexport interface ResolvedLineLook {\n visible: boolean;\n color: string;\n style: LineStyle;\n width: number;\n}\n\n/**\n * The chart's finer looks, worked out from the theme and its overrides once\n * per change. Renderers read it from `theme.style`; a theme without one (a\n * plugin's own) draws as before.\n */\nexport interface ResolvedChartStyle {\n panes: { background: string; separator: string; title: string };\n grid: { horizontal: ResolvedLineLook; vertical: ResolvedLineLook };\n crosshair: {\n horizontal: ResolvedLineLook;\n vertical: ResolvedLineLook;\n labelBackground: string;\n labelText: string;\n };\n axis: { price: { line: string; text: string }; time: { line: string; text: string } };\n legend: { text: string; label: string };\n /** Null: the watermark's own colour, or the theme's. */\n watermark: { color: string | null };\n lastPrice: { visible: boolean; up: string; down: string; style: LineStyle; width: number };\n /** Null: the session breaks' own settings, or the theme's. */\n sessionBreaks: { color: string | null; style: LineStyle | null; width: number | null };\n /** Null: the high and low lines' own colour. */\n highLow: { color: string | null };\n /** Orders (buy, sell) and positions (profit, loss, entry). Null: the trading config's colours. */\n trading: { buy: string | null; sell: string | null; profit: string | null; loss: string | null; entry: string | null };\n /** Signal markers. Null: their own style's colours. */\n markers: { long: string | null; short: string | null; neutral: string | null };\n /** Trade zones. Null: their own style's colours. */\n tradeZones: { profit: string | null; loss: string | null; active: string | null };\n /** A selected drawing's handles. Null: white. */\n drawings: { handle: string | null };\n /** The main series' line width, for the chart types drawn as a line. */\n series: { lineWidth: number };\n}\n","import type { Point, ViewportState } from './rendering.js';\nimport type { OHLCBar } from './ohlc.js';\nimport type { IndicatorIntervals } from './indicator.js';\n\n/** The drawing tools TradeCanvas ships. */\nexport type BuiltInDrawingToolType =\n | 'trendLine' | 'horizontalLine' | 'horizontalRay' | 'verticalLine' | 'ray' | 'extendedLine'\n | 'crossLine' | 'trendAngle' | 'infoLine'\n | 'parallelChannel' | 'regressionChannel'\n | 'fibRetracement' | 'fibExtension' | 'fibTimeZones' | 'fibChannel' | 'fibSpeedResistanceFan'\n | 'rectangle' | 'ellipse' | 'triangle' | 'circle'\n | 'pitchfork' | 'schiffPitchfork' | 'modifiedSchiffPitchfork' | 'elliottWave'\n | 'xabcdPattern' | 'abcdPattern' | 'headAndShoulders'\n | 'priceRange' | 'dateRange' | 'dateAndPriceRange' | 'measure'\n | 'text' | 'arrow' | 'priceLabel'\n | 'gannFan' | 'gannBox' | 'cyclicLines'\n | 'anchoredVWAP'\n | 'volumeProfileRange'\n | 'riskReward'\n | 'note' | 'callout' | 'flag' | 'arrowMark' | 'icon'\n | 'signpost' | 'balloon' | 'anchoredText' | 'anchoredNote'\n | 'brush' | 'highlighter' | 'path' | 'polyline' | 'curve' | 'arc'\n | 'fibCircles' | 'fibSpiral' | 'fibArcs' | 'fibWedge' | 'pitchfan' | 'gannSquare'\n | 'elliottImpulse' | 'elliottCorrection' | 'elliottTriangle' | 'elliottDoubleCombo' | 'elliottTripleCombo'\n | 'threeDrives' | 'cypherPattern'\n | 'timeCycles' | 'sineLine'\n | 'forecast' | 'projection' | 'barsPattern';\n\n/**\n * A drawing tool's name: a built-in one, or the name a plugin registered\n * (`DrawingPlugin.descriptor.type`). Built-in names still complete in an editor.\n */\nexport type DrawingToolType = BuiltInDrawingToolType | (string & {});\n\nexport interface AnchorPoint {\n time: number;\n price: number;\n}\n\nexport interface DrawingStyle {\n color: string;\n lineWidth: number;\n lineStyle: 'solid' | 'dashed' | 'dotted';\n fillColor?: string;\n fillOpacity?: number;\n fontSize?: number;\n text?: string;\n /** The text in bold. */\n bold?: boolean;\n /** The text in italics. */\n italic?: boolean;\n /**\n * Where each line of the text lines up in its box. On a line or a box (a\n * trend line, a rectangle): at which end of it the text sits, the middle\n * when left out.\n */\n textAlign?: 'left' | 'center' | 'right';\n /**\n * On a line: above it, on it, or under it. In a box: at its top, its\n * middle or its bottom. Left out: the top.\n */\n textVAlign?: 'top' | 'middle' | 'bottom';\n /** The text's colour; `color` when left out (a note keeps `color` for its pin). */\n textColor?: string;\n /**\n * A box behind the text, in `fillColor` at `fillOpacity`. Left out: as the\n * tool draws it (a note and a callout have one, a text has none).\n */\n textBackground?: boolean;\n /** A border round the text's box, in `borderColor` (`color` when left out). Left out: as the tool draws it. */\n textBorder?: boolean;\n borderColor?: string;\n /** Widest a line of the text gets before it wraps, px; 0: it breaks only where the text does. Left out: the tool's own width. */\n textWrap?: number;\n}\n\nexport interface DrawingState {\n id: string;\n type: DrawingToolType;\n anchors: AnchorPoint[];\n style: DrawingStyle;\n visible: boolean;\n locked: boolean;\n /** The tool's own settings (levels, extend left/right…); see `DrawingDescriptor.options`. */\n options?: DrawingOptions;\n /** The group it belongs to: drawings selected, hidden and locked together. */\n group?: { id: string; name: string };\n /** Its own name, as the object tree lists it (at most 80 characters); unset: its tool's name. */\n name?: string;\n /**\n * The intervals it shows on, as an indicator's are (`{ minutes: false }`:\n * not on minute charts); unset: all of them.\n */\n intervals?: IndicatorIntervals;\n /**\n * The indicator pane it is drawn on: the pane's id, as `getIndicatorPanes()`\n * lists them, and its anchors' prices are that pane's values. Unset: the\n * price pane.\n */\n paneId?: string;\n meta?: Record<string, unknown>;\n}\n\n/** One level of a Fibonacci or Gann tool: a ratio, shown or not, in its own colour. */\nexport interface DrawingLevel {\n value: number;\n visible: boolean;\n /** CSS colour; the drawing's colour when left out. */\n color?: string;\n}\n\nexport type DrawingOptionValue = boolean | number | string | DrawingLevel[];\n\n/** A drawing's settings beyond the shared style, by key. Missing keys take the tool's defaults. */\nexport type DrawingOptions = Record<string, DrawingOptionValue>;\n\n/** A setting a drawing tool offers beyond the shared style, with its default. */\nexport type DrawingOptionDef =\n | { kind: 'boolean'; label: string; default: boolean }\n | { kind: 'number'; label: string; default: number; min?: number; max?: number; step?: number }\n | { kind: 'choice'; label: string; default: string; choices: readonly { value: string; label: string }[] }\n | { kind: 'levels'; label: string; default: readonly DrawingLevel[] }\n | { kind: 'text'; label: string; default: string };\n\nexport type DrawingOptionDefs = Readonly<Record<string, DrawingOptionDef>>;\n\nexport interface DrawingDescriptor {\n type: DrawingToolType;\n name: string;\n requiredAnchors: number;\n singleClick?: boolean;\n /** Settings the tool offers beyond the shared style; a settings dialog is built from them. */\n options?: DrawingOptionDefs;\n /** It fills an area with `style.fillColor` (a settings dialog offers the fill). */\n fill?: boolean;\n /** It draws `style.text` (a settings dialog offers the text and its size). */\n text?: boolean;\n /**\n * How it is drawn with the pointer. 'clicks' (the default): a click per\n * anchor up to `requiredAnchors`. 'freehand': press and drag, a point every\n * few pixels, release to finish. 'path': a click per point, at least\n * `requiredAnchors` and at most `maxAnchors`; a double-click, Enter or a\n * click on the last point finishes it.\n */\n creation?: 'clicks' | 'freehand' | 'path';\n /** Most points a 'path' takes (100 when left out). */\n maxAnchors?: number;\n /**\n * What its points are kept to. 'chart' (the default): a bar's time and a\n * price, so it moves with the chart. 'screen': a place on the plot, each\n * point's `time` its share across from the left edge and `price` its\n * share down from the top (0 to 1), so it stays put as the chart scrolls,\n * zooms or changes symbol.\n */\n anchoring?: 'chart' | 'screen';\n /**\n * It reads the bars' prices or volumes (an anchored VWAP, a volume profile,\n * a position): drawn on the price pane only, never on an indicator pane.\n */\n priceOnly?: boolean;\n}\n\nexport interface DrawingPlugin {\n descriptor: DrawingDescriptor;\n render(\n ctx: CanvasRenderingContext2D,\n state: DrawingState,\n viewport: ViewportState,\n selected: boolean,\n ): void;\n hitTest(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): boolean;\n hitTestAnchor(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): number;\n /**\n * The drawing after handle `index` (from `hitTestAnchor`) is dragged to\n * `anchor`. Without it, the handle is anchor `index` and moves there. A\n * tool with handles that are not anchors (a position's target, say)\n * changes its options instead.\n */\n moveHandle?(state: DrawingState, index: number, anchor: AnchorPoint): DrawingState;\n /**\n * The prices of the drawing's lines at `time` (what an alert on it\n * crosses), or null where it doesn't reach. Tools without it take no alerts.\n * With `viewport` the lines follow the chart as drawn: straight across bars\n * (not clock time, so a weekend gap doesn't bend them) and on a log scale\n * straight in log price.\n */\n priceAt?(state: DrawingState, time: number, viewport?: ViewportState): number[] | null;\n /**\n * For a tool drawn from the chart's bars (an anchored VWAP, a volume\n * profile): the chart hands it a getter for them when it is registered,\n * and `revision`, whose number moves when a bar was replaced in the same\n * array (`updateBar`): a tool that keeps what it computed from the bars,\n * by the array and its length, computes it again then.\n */\n setDataGetter?(getter: () => readonly OHLCBar[], revision?: () => number): void;\n}\n\nexport const DEFAULT_DRAWING_STYLE: DrawingStyle = {\n color: '#4c8dff',\n lineWidth: 1,\n lineStyle: 'solid',\n fillColor: 'rgba(76, 141, 255, 0.1)',\n fillOpacity: 0.1,\n fontSize: 12,\n};\n","export type OrderSide = 'buy' | 'sell';\nexport type OrderType = 'market' | 'limit' | 'stop' | 'stopLimit';\nexport type OrderStatus = 'pending' | 'filled' | 'cancelled' | 'rejected';\nexport type OrderLabel = 'LIMIT' | 'STOP' | 'SL' | 'TP' | 'STOP LIMIT';\n\n/** How long an order works: good till cancelled, or for the day. */\nexport type TimeInForce = 'gtc' | 'day';\n\nexport interface TradingOrder {\n id: string;\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity: number;\n label?: OrderLabel;\n draggable?: boolean;\n /** Stop-loss and take-profit the position gets when the order fills. */\n stopLoss?: number;\n takeProfit?: number;\n timeInForce?: TimeInForce;\n meta?: Record<string, unknown>;\n}\n\nexport interface TradingPosition {\n id: string;\n side: OrderSide;\n entryPrice: number;\n quantity: number;\n /** Quantity already closed (for partial-close visualization). 0 ≤ closedQuantity ≤ quantity. */\n closedQuantity?: number;\n stopLoss?: number;\n takeProfit?: number;\n meta?: Record<string, unknown>;\n}\n\n/** Threshold-based P&L color stop. Sorted ascending by `pnl` is recommended. */\nexport interface PnLThreshold {\n /** Inclusive lower bound. Use -Infinity for the bottom-most stop. */\n pnl: number;\n color: string;\n}\n\n/** Tokens passed to position label templates. */\nexport interface PositionLabelContext {\n side: OrderSide;\n quantity: number;\n closedQuantity: number;\n openQuantity: number;\n entryPrice: number;\n currentPrice: number;\n pnl: number;\n pnlPct: number;\n precision: number;\n /** The chart's price format, for `{entry}` and `{price}` (decimals at `precision` without one). */\n formatPrice?: (price: number) => string;\n /** The number locale `{pnl}` (and prices without a format) are grouped in. Unset: en-US. */\n locale?: string;\n}\n\nexport interface DepthLevel {\n price: number;\n volume: number;\n}\n\nexport interface DepthData {\n bids: DepthLevel[];\n asks: DepthLevel[];\n}\n\nexport interface TradingConfig {\n enabled: boolean;\n orderColors?: { buy?: string; sell?: string };\n positionColors?: { profit?: string; loss?: string; entry?: string };\n /**\n * Optional gradient of colors keyed to P&L value. When provided, the rendered\n * position zone uses the color of the highest threshold whose `pnl` ≤ live P&L.\n * Falls back to `positionColors.profit`/`.loss` when unset.\n */\n pnlThresholds?: PnLThreshold[];\n /**\n * The words on a position's tag after its open quantity, in place of its\n * side and its open profit. A template with the tokens {side} {qty}\n * {closedQty} {openQty} {entry} {price} {pnl} {pnlPct} {pnlSign}, or a\n * function for full control. Unset: the side (\"Long\", \"Short\") and the\n * profit in the profit or loss colour.\n */\n positionLabel?: string | ((ctx: PositionLabelContext) => string);\n depthOverlay?: {\n enabled?: boolean;\n bidColor?: string;\n askColor?: string;\n maxWidth?: number;\n };\n contextMenu?: { enabled?: boolean };\n /**\n * Buttons on the lines: × on an order cancels it, × on a position closes it\n * and ⇅ reverses it, × on a stop-loss or take-profit removes it. All on by\n * default.\n */\n lineButtons?: { cancel?: boolean; close?: boolean; reverse?: boolean; removeStops?: boolean };\n /** Marks where orders filled (from the execution adapter's fills). On by default. */\n fillMarks?: boolean;\n /** Decimals of the prices on the trading tags; unset, the price axis's (the market's or the range's). */\n pricePrecision?: number;\n dragThreshold?: number;\n}\n\nexport interface OrderPlaceIntent {\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity?: number;\n /** Stop-loss and take-profit for the position the order opens. */\n stopLoss?: number;\n takeProfit?: number;\n timeInForce?: TimeInForce;\n}\n\nexport interface OrderModifyIntent {\n orderId: string;\n newPrice: number;\n /** The price before the change, when known (e.g. from a drag). Optional so\n * the chart's `orderModify` event payload routes straight to an adapter. */\n previousPrice?: number;\n}\n\nexport interface OrderCancelIntent {\n orderId: string;\n}\n\nexport interface PositionModifyIntent {\n positionId: string;\n /** A new stop-loss; null removes it, left out keeps it. */\n stopLoss?: number | null;\n /** A new take-profit; null removes it, left out keeps it. */\n takeProfit?: number | null;\n}\n\nexport interface PositionCloseIntent {\n positionId: string;\n}\n\n/** Close a position and open the same size the other way. */\nexport interface PositionReverseIntent {\n positionId: string;\n}\n\nexport const DEFAULT_TRADING_CONFIG: TradingConfig = {\n enabled: true,\n orderColors: { buy: '#1fa874', sell: '#e8505b' },\n positionColors: { profit: '#1fa874', loss: '#e8505b', entry: '#4c8dff' },\n depthOverlay: { enabled: false, bidColor: 'rgba(31, 168, 116,0.15)', askColor: 'rgba(232, 80, 91,0.15)', maxWidth: 100 },\n contextMenu: { enabled: true },\n lineButtons: { cancel: true, close: true, reverse: true, removeStops: true },\n fillMarks: true,\n dragThreshold: 3,\n};\n","export type SignalDirection = 'long' | 'short' | 'neutral';\n\nexport interface SignalMarker {\n id: string;\n time: number;\n price: number;\n direction: SignalDirection;\n confidence: number;\n source: string;\n label?: string;\n color?: string;\n meta?: Record<string, unknown>;\n}\n\nexport interface SignalMarkerStyle {\n longColor?: string;\n shortColor?: string;\n neutralColor?: string;\n arrowSize?: number;\n showLabel?: boolean;\n showConfidence?: boolean;\n sourceColors?: Record<string, string>;\n}\n\nexport const DEFAULT_SIGNAL_STYLE: SignalMarkerStyle = {\n longColor: '#1fa874',\n shortColor: '#e8505b',\n neutralColor: '#9E9E9E',\n arrowSize: 12,\n showLabel: true,\n showConfidence: true,\n};\n\nexport type TradeZoneDirection = 'long' | 'short';\n\nexport interface TradeZone {\n id: string;\n entryTime: number;\n entryPrice: number;\n exitTime?: number;\n exitPrice?: number;\n direction: TradeZoneDirection;\n pnl?: number;\n pnlPercent?: number;\n label?: string;\n meta?: Record<string, unknown>;\n}\n\nexport interface TradeZoneStyle {\n profitColor?: string;\n lossColor?: string;\n activeColor?: string;\n fillOpacity?: number;\n borderWidth?: number;\n showLabel?: boolean;\n showPnl?: boolean;\n}\n\nexport const DEFAULT_TRADE_ZONE_STYLE: TradeZoneStyle = {\n profitColor: '#1fa874',\n lossColor: '#e8505b',\n activeColor: '#4c8dff',\n fillOpacity: 0.12,\n borderWidth: 1,\n showLabel: true,\n showPnl: true,\n};\n","import type { OHLCBar, TimeFrame } from './ohlc.js';\nimport type { SymbolInfo, SymbolSearchOptions } from './symbol.js';\nimport type { Quote } from './quote.js';\nimport type { NewsItem } from './news.js';\n\n/** One trade: when (ms), at what price, how much. */\nexport interface Trade {\n time: number;\n price: number;\n volume: number;\n}\n\n// --- Connection ---\n\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';\n\nexport interface ConnectionInfo {\n state: ConnectionState;\n latency?: number;\n reconnectAttempt?: number;\n lastMessageTime?: number;\n error?: string;\n}\n\n// --- Ticks & Trades ---\n\nexport interface RawTick {\n time: number;\n price: number;\n volume: number;\n side?: 'buy' | 'sell';\n /** The best bid and ask with it, when the feed has them (the chart marks them). */\n bid?: number;\n ask?: number;\n}\n\nexport interface AggregatedBar extends OHLCBar {\n /** True once the bar's interval is over and it no longer changes. */\n closed: boolean;\n /** How many ticks made the bar. */\n tickCount: number;\n}\n\n// --- Data Adapter (Strategy Pattern) ---\n\n/**\n * What `adapter.connect(config)` is given. The chart's stream\n * (`connectStream`) passes `symbol` and `timeframe` only; the other fields\n * are for an adapter you connect yourself, and none of the built-in\n * adapters reads them. The stream reconnects by `StreamConfig.reconnect`.\n */\nexport interface DataAdapterConfig {\n symbol: string;\n timeframe: TimeFrame;\n /** Connect again when the connection drops. Not passed by the stream. */\n reconnect?: boolean;\n /** Tries before giving up. Not passed by the stream. */\n reconnectMaxRetries?: number;\n /** The wait before the first try, ms. Not passed by the stream. */\n reconnectBaseDelay?: number;\n /** The longest wait between tries, ms. Not passed by the stream. */\n reconnectMaxDelay?: number;\n /** How often to check the connection is alive, ms. Not passed by the stream. */\n heartbeatInterval?: number;\n /** The most ticks to keep while they can't be delivered. Not passed by the stream. */\n bufferSize?: number;\n}\n\nexport type DataAdapterEventType =\n | 'tick'\n | 'bar'\n | 'barClose'\n /** The first bars, loaded at the start. */\n | 'snapshot'\n | 'connectionChange'\n | 'error'\n /**\n * The feed learned about the connected symbol after the chart asked\n * (`resolveSymbol`), for instance on its first message: `data` is the\n * `SymbolInfo`. The chart applies it (precision, price step, hours).\n */\n | 'symbolInfo';\n\nexport interface DataAdapterEvent<T = unknown> {\n type: DataAdapterEventType;\n data: T;\n timestamp: number;\n}\n\nexport type DataAdapterListener<T = unknown> = (event: DataAdapterEvent<T>) => void;\n\n/**\n * Data adapter interface. Implements the observer pattern:\n * - connect() to start receiving data\n * - on('bar'|'tick'|'connectionChange', handler) to receive events\n * - disconnect() to stop, then connect() again to switch symbols/timeframes\n * - No separate subscribe/unsubscribe — reconnect is the intended pattern\n *\n * Strategy pattern for pluggable data sources.\n * Implementations handle the specifics of each data source (WebSocket, REST,\n * SSE, etc.) while the StreamManager orchestrates lifecycle and aggregation.\n *\n * Built-in: BinanceAdapter\n * Implement this for: custom exchange APIs, broker feeds, mock data\n */\nexport interface DataAdapter {\n readonly name: string;\n\n /**\n * Optional: the timeframes the feed serves. Charts build any other\n * timeframe (7m, 90m, 2d…) from the coarsest of these that divides it.\n * Days, weeks, months and the hour frames that divide a day (2h to 12h)\n * they build start at the midnight of the symbol's `timeZone`\n * (`resolveSymbol`), else at UTC's; daily bars stamped at 00:00 UTC are\n * read as their dates. Leave it out when the feed serves every timeframe.\n */\n readonly supportedTimeframes?: readonly TimeFrame[];\n\n connect(config: DataAdapterConfig): void;\n disconnect(): void;\n getConnectionState(): ConnectionState;\n\n /**\n * Load historical bars. Called once on connect, before streaming starts.\n * Returns bars sorted by time ascending.\n */\n fetchHistory(symbol: string, timeframe: TimeFrame, limit?: number): Promise<OHLCBar[]>;\n\n /**\n * Optional: load up to `limit` bars older than `before` (the oldest loaded\n * bar's time, in the bars' own unit), sorted by time ascending. Return an\n * empty array when no older data exists. A chart connected to an adapter\n * with this method loads older bars as the user scrolls back in time.\n */\n fetchHistoryBefore?(symbol: string, timeframe: TimeFrame, before: number, limit: number): Promise<OHLCBar[]>;\n\n /** Optional: symbols matching `query`, best first — for a symbol search box. */\n searchSymbols?(query: string, options?: SymbolSearchOptions): Promise<SymbolInfo[]>;\n\n /**\n * Optional: what the feed knows about `symbol` (name, price step, the\n * exchange's `timeZone` and hours), or null when it doesn't know it. A\n * connected chart asks for it and applies it.\n */\n resolveSymbol?(symbol: string): Promise<SymbolInfo | null>;\n\n /**\n * Optional: live quotes (last price, the day's change, high, low, volume)\n * for many symbols at once, until the function it returns is called. A\n * widget's watchlist fills its rows from it.\n */\n subscribeQuotes?(symbols: readonly string[], onQuotes: (quotes: Quote[]) => void): () => void;\n\n /** Optional: recent headlines about `symbol`, newest first. */\n fetchNews?(symbol: string, limit?: number): Promise<NewsItem[]>;\n\n /**\n * Optional, with `subscribeTrades`: up to `limit` recent trades, oldest\n * first. A chart builds tick timeframes (`'100T'`) from a feed's trades.\n */\n fetchTrades?(symbol: string, limit?: number): Promise<Trade[]>;\n\n /** Optional, with `fetchTrades`: live trades of `symbol` until the function it returns is called. */\n subscribeTrades?(symbol: string, onTrades: (trades: Trade[]) => void): () => void;\n\n on<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n off<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n\n dispose(): void;\n}\n\n// --- Stream Manager Config ---\n\nexport interface StreamConfig {\n adapter: DataAdapter;\n symbol: string;\n timeframe: TimeFrame;\n /** Bars to load at the start. Default 500. */\n historyLimit?: number;\n /** Bars per request when scrolling back for older bars (needs `adapter.fetchHistoryBefore`), default: 500. */\n historyPageSize?: number;\n /**\n * Follow a new bar while the view is at the newest one (a view scrolled\n * back stays). Sets `chart.setAutoScroll`. Default `true`.\n */\n autoScroll?: boolean;\n /** Not read: the stream leaves the last price's line as the chart shows it. */\n showCurrentPriceLine?: boolean;\n /** Build the bars from the feed's ticks instead of taking its bars. Default `false`. */\n aggregateTicks?: boolean;\n reconnect?: ReconnectConfig;\n}\n\nexport interface ReconnectConfig {\n /** Connect again when the connection drops. Default `true`. */\n enabled: boolean;\n /** Tries before giving up. Default `Infinity`. */\n maxRetries: number;\n /** The wait before the first try, ms. Default 1000. */\n baseDelay: number;\n /** The longest wait between tries, ms, before a jitter of up to 25% either way. Default 30000. */\n maxDelay: number;\n /** Each wait is the last times this. Default 2. */\n backoffMultiplier: number;\n}\n\nexport const DEFAULT_RECONNECT: ReconnectConfig = {\n enabled: true,\n maxRetries: Infinity,\n baseDelay: 1000,\n maxDelay: 30000,\n backoffMultiplier: 2,\n};\n\nexport const DEFAULT_STREAM_CONFIG: Partial<StreamConfig> = {\n historyLimit: 500,\n autoScroll: true,\n showCurrentPriceLine: true,\n aggregateTicks: false,\n};\n","/**\n * A symbol's latest quote: its price and the day's move, for a watchlist row\n * or a symbol's details. Prices are in the symbol's quote currency.\n */\nexport interface Quote {\n symbol: string;\n /** The last traded price. */\n last: number;\n /** The move from the reference price (the prior close; 24 h ago for crypto). */\n change?: number;\n /** The same move, in percent. */\n changePercent?: number;\n open?: number;\n high?: number;\n low?: number;\n /** The prior session's close. */\n prevClose?: number;\n /** Volume over the same period, in the base unit. */\n volume?: number;\n bid?: number;\n ask?: number;\n /** When the quote was made, in ms since the epoch. */\n time?: number;\n}\n\n/** Live quotes for many symbols at once. */\nexport interface QuoteSource {\n /**\n * Send quotes for `symbols` to `onQuotes` as they change (any number per\n * call) until the function it returns is called.\n */\n subscribeQuotes(symbols: readonly string[], onQuotes: (quotes: Quote[]) => void): () => void;\n}\n\nconst QUOTE_NUMBERS = ['change', 'changePercent', 'open', 'high', 'low', 'prevClose', 'volume', 'bid', 'ask', 'time'] as const;\n\n/**\n * A quote from untrusted input (a host's push, a feed's frame): its symbol\n * and last price must be usable; any other field that isn't a finite number\n * is left out. The change is worked out from the prior close or the open when\n * the input has none. Null when it isn't a quote.\n */\nexport function readQuote(raw: unknown): Quote | null {\n if (!raw || typeof raw !== 'object') return null;\n const r = raw as Record<string, unknown>;\n const symbol = typeof r.symbol === 'string' ? r.symbol.trim() : '';\n if (!symbol || symbol.length > 64 || !isFiniteNumber(r.last)) return null;\n const quote: Quote = { symbol, last: r.last };\n for (const key of QUOTE_NUMBERS) {\n const v = r[key];\n if (isFiniteNumber(v)) quote[key] = v;\n }\n const ref = quote.prevClose ?? quote.open;\n if (quote.change === undefined && ref !== undefined) quote.change = quote.last - ref;\n if (quote.changePercent === undefined && quote.change !== undefined) {\n const base = quote.last - quote.change;\n if (base !== 0) quote.changePercent = (quote.change / base) * 100;\n }\n return quote;\n}\n\nfunction isFiniteNumber(v: unknown): v is number {\n return typeof v === 'number' && Number.isFinite(v);\n}\n","/** A news headline about a symbol. */\nexport interface NewsItem {\n title: string;\n /** When it was published, in ms since the epoch. */\n time: number;\n /** The article; only http(s) links are kept. */\n url?: string;\n source?: string;\n summary?: string;\n id?: string;\n}\n\nconst MAX_TITLE = 300;\nconst MAX_TEXT = 1000;\n\nconst text = (v: unknown, max: number): string | undefined => {\n if (typeof v !== 'string') return undefined;\n const t = v.trim();\n return t ? t.slice(0, max) : undefined;\n};\n\nconst webUrl = (v: unknown): string | undefined => {\n if (typeof v !== 'string') return undefined;\n try {\n const url = new URL(v);\n return url.protocol === 'https:' || url.protocol === 'http:' ? url.href : undefined;\n } catch {\n return undefined;\n }\n};\n\n/**\n * Headlines from untrusted input (a feed, a host): each needs a title and a\n * time; links that aren't web pages are dropped. Newest first, at most\n * `limit`.\n */\nexport function readNews(raw: unknown, limit = 20): NewsItem[] {\n if (!Array.isArray(raw)) return [];\n const items: NewsItem[] = [];\n for (const entry of raw) {\n if (!entry || typeof entry !== 'object') continue;\n const r = entry as Record<string, unknown>;\n const title = text(r.title, MAX_TITLE);\n if (!title || typeof r.time !== 'number' || !Number.isFinite(r.time)) continue;\n const item: NewsItem = { title, time: r.time };\n const url = webUrl(r.url);\n if (url) item.url = url;\n const source = text(r.source, MAX_TITLE);\n if (source) item.source = source;\n const summary = text(r.summary, MAX_TEXT);\n if (summary) item.summary = summary;\n const id = text(r.id, MAX_TITLE);\n if (id) item.id = id;\n items.push(item);\n }\n return items.sort((a, b) => b.time - a.time).slice(0, Math.max(0, limit));\n}\n","export function clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nexport function inverseLerp(a: number, b: number, value: number): number {\n if (a === b) return 0;\n return (value - a) / (b - a);\n}\n\nexport function roundToStep(value: number, step: number): number {\n return Math.round(value / step) * step;\n}\n\nexport function niceNumber(value: number, round: boolean): number {\n const exp = Math.floor(Math.log10(value));\n const frac = value / Math.pow(10, exp);\n let nice: number;\n if (round) {\n if (frac < 1.5) nice = 1;\n else if (frac < 3) nice = 2;\n else if (frac < 7) nice = 5;\n else nice = 10;\n } else {\n if (frac <= 1) nice = 1;\n else if (frac <= 2) nice = 2;\n else if (frac <= 5) nice = 5;\n else nice = 10;\n }\n return nice * Math.pow(10, exp);\n}\n\nexport function computeTickStep(min: number, max: number, maxTicks: number): number {\n const range = niceNumber(max - min, false);\n return niceNumber(range / (maxTicks - 1), true);\n}\n","import type { OHLCBar, DataSeries } from '../types/ohlc.js';\n\n/**\n * Bar times at or above this are milliseconds (from March 1973 on), below it\n * seconds (up to the year 5138).\n */\nexport const MS_TIME_THRESHOLD = 1e11;\n\n/** Milliseconds in one unit of a series' bar times: 1 for milliseconds, 1000 for seconds. */\nexport type BarTimeUnit = 1 | 1000;\n\n/**\n * The unit of a series' bar times, decided once from its newest bar, so its\n * old bars keep the series' unit: a millisecond bar from 2000 is below 1e12\n * and would pass for seconds on its own. Milliseconds when there are no bars.\n */\nexport function barTimeUnit(data: ArrayLike<{ time: number }>): BarTimeUnit {\n const last = data.length > 0 ? data[data.length - 1].time : NaN;\n if (!Number.isFinite(last)) return 1;\n return Math.abs(last) >= MS_TIME_THRESHOLD ? 1 : 1000;\n}\n\n/**\n * Normalize bar timestamp to milliseconds. Pass the series' unit\n * (`barTimeUnit(data)`) when there is one; on its own a time is taken as\n * milliseconds from `MS_TIME_THRESHOLD` (1973) up, seconds below.\n */\nexport function normalizeBarTime(time: number, unit?: BarTimeUnit): number {\n if (unit !== undefined) return time * unit;\n return Math.abs(time) >= MS_TIME_THRESHOLD ? time : time * 1000;\n}\n\n/**\n * Normalize a bar's timestamp field to milliseconds.\n * Accepts either { time } (ms or s) or { t, o, h, l, c, v } wire format.\n */\nexport function normalizeBar(raw: Record<string, number>): OHLCBar {\n const time = normalizeBarTime(raw.time ?? raw.t ?? 0);\n return {\n time,\n open: raw.open ?? raw.o ?? 0,\n high: raw.high ?? raw.h ?? 0,\n low: raw.low ?? raw.l ?? 0,\n close: raw.close ?? raw.c ?? 0,\n volume: raw.volume ?? raw.v ?? 0,\n };\n}\n\nexport function sliceVisibleData(\n data: DataSeries,\n from: number,\n to: number,\n): DataSeries {\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length, to + 1);\n return data.slice(startIdx, endIdx);\n}\n\nexport function findBarIndex(data: DataSeries, timestamp: number): number {\n let lo = 0;\n let hi = data.length - 1;\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n if (data[mid].time < timestamp) lo = mid + 1;\n else if (data[mid].time > timestamp) hi = mid - 1;\n else return mid;\n }\n return lo;\n}\n\n/**\n * `min`..`max` with room above and below: `padding` of the span on each side,\n * or on a log scale the same share of its log span, so the range stays above\n * zero and the room looks the same top and bottom.\n */\nexport function padPriceRange(min: number, max: number, padding: number, log = false): { min: number; max: number } {\n const logSpan = log && min > 0 && max > 0 ? Math.log(max / min) : Number.NaN;\n if (Number.isFinite(logSpan)) {\n const span = logSpan || Math.log(1 + 2 * padding);\n const factor = Math.exp(span * padding);\n return { min: min / factor, max: max * factor };\n }\n const range = max - min || 1;\n return { min: min - range * padding, max: max + range * padding };\n}\n\n/** Room above and below the prices on a scale, as shares of its height (0.1: a tenth). */\nexport interface ScaleMargins {\n top: number;\n bottom: number;\n}\n\n/**\n * The range that shows `min`..`max` with `margins` of the scale's height\n * above and below them; on a log scale, shares of its log span. A flat price\n * gets a span of 1 (a hundredth of itself on a log scale) to sit in.\n */\nexport function fitPriceRange(min: number, max: number, margins: ScaleMargins, log = false): { min: number; max: number } {\n const share = Math.max(1 - margins.top - margins.bottom, Number.EPSILON);\n const logSpan = log && min > 0 && max > 0 ? Math.log(max / min) : Number.NaN;\n if (Number.isFinite(logSpan)) {\n const total = (logSpan || Math.log(1.01)) / share;\n return { min: min / Math.exp(total * margins.bottom), max: max * Math.exp(total * margins.top) };\n }\n const total = (max - min || 1) / share;\n return { min: min - total * margins.bottom, max: max + total * margins.top };\n}\n\nexport function computePriceRange(\n data: DataSeries,\n from: number,\n to: number,\n padding = 0.05,\n /** Pad as a log scale shows it (`padPriceRange`). */\n log = false,\n): { min: number; max: number } {\n if (data.length === 0) return { min: 0, max: 1 };\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length - 1, to);\n let min = Infinity;\n let max = -Infinity;\n for (let i = startIdx; i <= endIdx; i++) {\n if (data[i].low < min) min = data[i].low;\n if (data[i].high > max) max = data[i].high;\n }\n if (min === Infinity) return { min: 0, max: 1 };\n return padPriceRange(min, max, padding, log);\n}\n\n/**\n * A trade into the bar it falls in: its high, low, close and volume. The bar\n * keeps its own time, where its interval opens; a trade later in it moving\n * the time made the next update for that bar look older than the bar.\n */\nexport function mergeBar(existing: OHLCBar, tick: { price: number; volume?: number; time: number }): OHLCBar {\n return {\n ...existing,\n high: Math.max(existing.high, tick.price),\n low: Math.min(existing.low, tick.price),\n close: tick.price,\n volume: existing.volume + (tick.volume ?? 0),\n };\n}\n","export function hexToRgba(hex: string, alpha = 1): string {\n // #rgb and #rgba are short for #rrggbb and #rrggbbaa; a hex alpha gives way to `alpha`.\n let h = hex.slice(1);\n if (h.length === 3 || h.length === 4) h = [...h.slice(0, 3)].map((c) => c + c).join('');\n const r = parseInt(h.slice(0, 2), 16);\n const g = parseInt(h.slice(2, 4), 16);\n const b = parseInt(h.slice(4, 6), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\n/**\n * `color` at `alpha`: hex (#rgb, #rgba, #rrggbb, #rrggbbaa) and rgb()/rgba()\n * with commas or spaces. Any other colour (a name, hsl()) comes back as it is.\n */\nexport function withAlpha(color: string, alpha: number): string {\n const c = color.trim();\n if (/^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(c)) {\n return hexToRgba(c, alpha);\n }\n const rgb = c.match(/^rgba?\\(\\s*(\\d+(?:\\.\\d+)?)[\\s,]+(\\d+(?:\\.\\d+)?)[\\s,]+(\\d+(?:\\.\\d+)?)/i);\n if (rgb) {\n return `rgba(${rgb[1]}, ${rgb[2]}, ${rgb[3]}, ${alpha})`;\n }\n return color;\n}\n\n/** A colour's channels (0-255) and alpha (0-1). */\ninterface Rgba {\n r: number;\n g: number;\n b: number;\n a: number;\n}\n\n/** Decimals an alpha is written with: finer than a screen's 8 bits. */\nconst ALPHA_DECIMALS = 3;\n\n/** Hex (#rgb, #rgba, #rrggbb, #rrggbbaa) or rgb()/rgba() with commas or spaces; null for any other colour. */\nfunction parseColor(color: string): Rgba | null {\n const c = color.trim();\n const hex = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.exec(c);\n if (hex) {\n let h = hex[1];\n if (h.length <= 4) h = [...h].map((d) => d + d).join('');\n const at = (i: number) => parseInt(h.slice(i, i + 2), 16);\n return { r: at(0), g: at(2), b: at(4), a: h.length === 8 ? at(6) / 255 : 1 };\n }\n const rgb = /^rgba?\\(\\s*([\\d.]+)[\\s,]+([\\d.]+)[\\s,]+([\\d.]+)(?:\\s*[,/]\\s*([\\d.]+)(%)?)?\\s*\\)$/i.exec(c);\n if (!rgb) return null;\n const alpha = rgb[4] === undefined ? 1 : Number(rgb[4]) / (rgb[5] ? 100 : 1);\n return { r: Number(rgb[1]), g: Number(rgb[2]), b: Number(rgb[3]), a: Math.min(1, Math.max(0, alpha)) };\n}\n\n/**\n * The colour `t` of the way from `colorA` to `colorB` (0 to 1), each hex or\n * rgb()/rgba(): `rgb(r,g,b)`, or `rgba(…)` when either is see-through. The\n * alpha is mixed as `color-mix` mixes it, weighting each colour by its own,\n * so a fade toward a see-through colour (a panel's faint surface) keeps the\n * hue of the other instead of washing toward the surface's. A colour it can't\n * read (a name, hsl()) comes back as it is, from the end `t` is nearer.\n */\nexport function lerpColor(colorA: string, colorB: string, t: number): string {\n const a = parseColor(colorA);\n const b = parseColor(colorB);\n if (!a || !b) return t < 0.5 ? colorA : colorB;\n const alpha = a.a + (b.a - a.a) * t;\n // Each channel weighted by its colour's alpha, then the mix's taken out again.\n const channel = (x: number, y: number) => (alpha === 0 ? 0 : Math.round((x * a.a + (y * b.a - x * a.a) * t) / alpha));\n const rgb = `${channel(a.r, b.r)},${channel(a.g, b.g)},${channel(a.b, b.b)}`;\n return alpha >= 1 ? `rgb(${rgb})` : `rgba(${rgb},${Number(alpha.toFixed(ALPHA_DECIMALS))})`;\n}\n\n/** A colour's WCAG relative luminance, 0 (black) to 1 (white); null for a colour it can't read. */\nfunction relativeLuminance(color: string): number | null {\n const c = parseColor(color);\n if (!c) return null;\n const linear = (v: number) => {\n const s = v / 255;\n return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;\n };\n return 0.2126 * linear(c.r) + 0.7152 * linear(c.g) + 0.0722 * linear(c.b);\n}\n\n/** WCAG contrast of two opaque colours, 1 to 21; null when either can't be read. */\nexport function contrastRatio(a: string, b: string): number | null {\n const la = relativeLuminance(a);\n const lb = relativeLuminance(b);\n if (la === null || lb === null) return null;\n return (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05);\n}\n\n/** Steps a colour takes toward the ink while it looks for enough contrast. */\nconst READABLE_STEPS = 20;\n\n/**\n * `color`, or the nearest mix of it toward `ink` that reads at `minRatio` on\n * `background`: a hue kept, only deepened (or lightened) as far as it must\n * be. `color` as it is when it already reads, or when a colour can't be read.\n */\nexport function readableOn(color: string, background: string, ink: string, minRatio: number): string {\n const ratio = contrastRatio(color, background);\n if (ratio === null || ratio >= minRatio) return color;\n for (let step = 1; step <= READABLE_STEPS; step++) {\n const mixed = lerpColor(color, ink, step / READABLE_STEPS);\n if ((contrastRatio(mixed, background) ?? 0) >= minRatio) return mixed;\n }\n return ink;\n}\n\n/** Of `a` and `b`, the one that reads better on `fill`: the text for a tag of that colour. */\nexport function inkOn(fill: string, a: string, b: string): string {\n return (contrastRatio(fill, a) ?? 0) >= (contrastRatio(fill, b) ?? 0) ? a : b;\n}\n","/**\n * The display timezone: an IANA name (`'America/New_York'`, `'UTC'`), a fixed\n * offset in minutes east of UTC (`-300`), or null for the browser's own zone.\n */\nexport type TimeZoneSetting = string | number | null;\n\nconst MINUTE_MS = 60_000;\nconst DAY_MS = 24 * 60 * MINUTE_MS;\n/** Zones change their offset on quarter hours, so it holds for each 15 minutes. */\nconst OFFSET_BUCKET_MS = 15 * MINUTE_MS;\nconst OFFSET_CACHE_MAX = 8192;\n/**\n * Clocks change months apart, so a week whose offset is the same at both\n * ends holds it throughout: one lookup serves a week of bars.\n */\nconst WEEK_MS = 7 * DAY_MS;\nconst WEEK_CACHE_MAX = 4096;\n/** Names of UTC itself: no lookup needed. */\nconst UTC_ZONES = new Set(['UTC', 'Etc/UTC', 'GMT', 'Etc/GMT', 'UCT', 'Etc/UCT', 'Universal', 'Etc/Universal', 'Zulu', 'Etc/Zulu']);\n\nconst zoneFormats = new Map<string, Intl.DateTimeFormat>();\nconst offsetCache = new Map<string, number>();\n/** A week's offsets: `before` until the clocks change at `change`, then `after`. */\ninterface WeekOffsets {\n before: number;\n change: number;\n after: number;\n}\n/** Per zone, the offsets of each week looked at. */\nconst weekOffsets = new Map<string, Map<number, WeekOffsets>>();\n\nfunction zoneFormat(zone: string): Intl.DateTimeFormat {\n let format = zoneFormats.get(zone);\n if (!format) {\n format = new Intl.DateTimeFormat('en-US', {\n timeZone: zone,\n hourCycle: 'h23',\n year: 'numeric',\n month: 'numeric',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n second: 'numeric',\n });\n zoneFormats.set(zone, format);\n }\n return format;\n}\n\n/** Whether `zone` is a time zone this browser knows (an IANA name such as `'Europe/London'`). */\nexport function isValidTimeZone(zone: string): boolean {\n if (!zone) return false;\n try {\n zoneFormat(zone);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * The zone's offset from UTC, in minutes east, at `timeMs` — daylight saving\n * time included. Throws a RangeError for a zone the browser doesn't know.\n */\nexport function zoneOffsetMinutes(zone: string, timeMs: number): number {\n if (!Number.isFinite(timeMs) || UTC_ZONES.has(zone)) return 0;\n let weeks = weekOffsets.get(zone);\n if (!weeks) {\n weeks = new Map();\n weekOffsets.set(zone, weeks);\n }\n const week = Math.floor(timeMs / WEEK_MS);\n let offsets = weeks.get(week);\n if (!offsets) {\n offsets = readWeek(zone, week * WEEK_MS);\n if (weeks.size >= WEEK_CACHE_MAX) weeks.clear();\n weeks.set(week, offsets);\n }\n return timeMs < offsets.change ? offsets.before : offsets.after;\n}\n\n/** The offsets of the week from `start`, and the quarter hour the clocks change in it, if they do. */\nfunction readWeek(zone: string, start: number): WeekOffsets {\n const before = bucketOffset(zone, start);\n let last = start + WEEK_MS - OFFSET_BUCKET_MS;\n const after = bucketOffset(zone, last);\n if (after === before) return { before, change: Infinity, after };\n // Halve the week down to the first quarter hour on the new offset.\n let first = start;\n while (last - first > OFFSET_BUCKET_MS) {\n const mid = first + Math.floor((last - first) / OFFSET_BUCKET_MS / 2) * OFFSET_BUCKET_MS;\n if (bucketOffset(zone, mid) === before) first = mid;\n else last = mid;\n }\n return { before, change: last, after };\n}\n\n/** The zone's offset over the quarter hour holding `timeMs`. */\nfunction bucketOffset(zone: string, timeMs: number): number {\n const bucket = Math.floor(timeMs / OFFSET_BUCKET_MS);\n const key = `${zone}|${bucket}`;\n const cached = offsetCache.get(key);\n if (cached !== undefined) return cached;\n\n const at = bucket * OFFSET_BUCKET_MS;\n let year = 1970, month = 1, day = 1, hour = 0, minute = 0, second = 0;\n for (const part of zoneFormat(zone).formatToParts(new Date(at))) {\n const value = Number(part.value);\n switch (part.type) {\n case 'year': year = value; break;\n case 'month': month = value; break;\n case 'day': day = value; break;\n case 'hour': hour = value % 24; break;\n case 'minute': minute = value; break;\n case 'second': second = value; break;\n }\n }\n const offset = Math.round((Date.UTC(year, month - 1, day, hour, minute, second) - at) / MINUTE_MS);\n if (offsetCache.size >= OFFSET_CACHE_MAX) offsetCache.clear();\n offsetCache.set(key, offset);\n return offset;\n}\n\n/** Whether `tz` keeps UTC's clock all year: a name of UTC itself, or an offset of 0. */\nexport function isUtcTimeZone(tz: TimeZoneSetting): boolean {\n return tz === 0 || (typeof tz === 'string' && UTC_ZONES.has(tz));\n}\n\n/** Minutes east of UTC at `timeMs` for any display timezone. */\nexport function offsetAt(tz: TimeZoneSetting, timeMs: number): number {\n if (tz === null) return -new Date(timeMs).getTimezoneOffset();\n if (typeof tz === 'number') return tz;\n return zoneOffsetMinutes(tz, timeMs);\n}\n\n/**\n * The instant whose wall clock in `tz` reads `wallMs` (a wall-clock time\n * written as if it were UTC, e.g. `Date.UTC(2026, 0, 15, 9, 30)`). A time\n * that occurs twice (clocks going back) is its first occurrence; a time a\n * spring-forward skips moves forward by the jump (02:30 → 03:30).\n */\nexport function wallToUtc(wallMs: number, tz: TimeZoneSetting): number {\n // The instant is within 14 hours of `wallMs`, so the offsets a day either\n // side bracket any clock change near it.\n const early = wallMs - offsetAt(tz, wallMs - DAY_MS) * MINUTE_MS;\n if (early + offsetAt(tz, early) * MINUTE_MS === wallMs) return early;\n const late = wallMs - offsetAt(tz, wallMs + DAY_MS) * MINUTE_MS;\n if (late + offsetAt(tz, late) * MINUTE_MS === wallMs) return late;\n return early; // skipped: read with the offset from before the jump\n}\n\nconst dateFormatters = new Map<string, (ms: number) => string>();\n\n/**\n * `Intl.DateTimeFormat#format` for dates in a display timezone, cached per\n * locale, options and zone (building a format costs ~40µs). A fixed offset\n * is applied by shifting the instant and formatting it as UTC.\n */\nexport function zonedDateFormatter(\n locale: string,\n options: Intl.DateTimeFormatOptions,\n tz: TimeZoneSetting,\n): (ms: number) => string {\n const key = `${locale}|${JSON.stringify(options)}|${tz === null ? 'local' : typeof tz === 'number' ? `fixed:${tz}` : tz}`;\n let formatter = dateFormatters.get(key);\n if (formatter) return formatter;\n\n const timeZone = tz === null ? undefined : typeof tz === 'number' ? 'UTC' : tz;\n let format: Intl.DateTimeFormat;\n try {\n format = new Intl.DateTimeFormat(locale, { ...options, timeZone });\n } catch {\n format = new Intl.DateTimeFormat('en-US', { ...options, timeZone }); // unknown locale tag\n }\n const shift = typeof tz === 'number' ? tz * MINUTE_MS : 0;\n formatter = (ms) => format.format(new Date(ms + shift));\n dateFormatters.set(key, formatter);\n return formatter;\n}\n","import type { KnownTimeFrame, TimeFrame, TimeFrameUnit } from '../types/ohlc.js';\nimport { isUtcTimeZone, offsetAt, wallToUtc, type TimeZoneSetting } from './timezone.js';\nimport { barTimeUnit } from './data.js';\n\nconst TIMEFRAME_MS: Record<KnownTimeFrame, number> = {\n '1s': 1_000,\n '5s': 5_000,\n '15s': 15_000,\n '30s': 30_000,\n '1m': 60_000,\n '3m': 180_000,\n '5m': 300_000,\n '15m': 900_000,\n '30m': 1_800_000,\n '45m': 2_700_000,\n '1h': 3_600_000,\n '2h': 7_200_000,\n '3h': 10_800_000,\n '4h': 14_400_000,\n '6h': 21_600_000,\n '8h': 28_800_000,\n '12h': 43_200_000,\n '1d': 86_400_000,\n '2d': 172_800_000,\n '3d': 259_200_000,\n '1w': 604_800_000,\n '2w': 1_209_600_000,\n '1M': 2_592_000_000,\n '3M': 7_776_000_000,\n '6M': 15_552_000_000,\n '12M': 31_536_000_000,\n};\n\n/** Milliseconds per unit; a month counts 30 days (a 12-month frame, 365). */\nconst UNIT_MS: Record<TimeFrameUnit, number> = {\n s: 1_000,\n m: 60_000,\n h: 3_600_000,\n d: 86_400_000,\n w: 604_800_000,\n M: 2_592_000_000,\n};\n\nconst TIMEFRAME_PATTERN = /^([1-9]\\d*)([smhdwM])$/;\n\n/** A timeframe's count and unit, or null when `value` isn't one (`'7m'` → 7 minutes). */\nexport function parseTimeframe(value: string): { count: number; unit: TimeFrameUnit } | null {\n const match = TIMEFRAME_PATTERN.exec(value);\n if (!match) return null;\n const count = Number(match[1]);\n return Number.isSafeInteger(count) ? { count, unit: match[2] as TimeFrameUnit } : null;\n}\n\n/** Most trades a tick bar may hold. */\nconst MAX_TICKS_PER_BAR = 1_000_000;\n\n/** The trades per bar of a tick timeframe (`'100T'` → 100), or null for any other. */\nexport function tickBarCount(timeframe: string): number | null {\n const match = /^([1-9]\\d*)T$/.exec(timeframe);\n if (!match) return null;\n const count = Number(match[1]);\n return Number.isSafeInteger(count) && count <= MAX_TICKS_PER_BAR ? count : null;\n}\n\nexport function isTimeFrame(value: string): value is TimeFrame {\n return parseTimeframe(value) !== null;\n}\n\n/** Length of a timeframe in milliseconds (approximate for months); NaN for a non-timeframe. */\nexport function timeframeToMs(tf: TimeFrame): number {\n const known = TIMEFRAME_MS[tf as KnownTimeFrame];\n if (known !== undefined) return known;\n const parsed = parseTimeframe(tf);\n return parsed ? parsed.count * UNIT_MS[parsed.unit] : Number.NaN;\n}\n\nexport function formatTimestamp(timestamp: number, tf: TimeFrame): string {\n const d = new Date(timestamp);\n const ms = timeframeToMs(tf);\n if (ms >= 86_400_000) {\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }\n if (ms >= 3_600_000) {\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\n }\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\nexport function alignToTimeframe(timestamp: number, tf: TimeFrame): number {\n const ms = timeframeToMs(tf);\n return Math.floor(timestamp / ms) * ms;\n}\n\nexport interface TimeParts {\n year: number;\n /** 1 to 12. */\n month: number;\n day: number;\n hours: number;\n minutes: number;\n}\n\n/**\n * Calendar parts of a timestamp in a display timezone: an IANA zone\n * (`'America/New_York'`, daylight saving time included), a fixed UTC offset in\n * minutes (e.g. -300 for EST) or the browser's zone (`null`).\n */\nexport function timeParts(timeMs: number, tz: TimeZoneSetting): TimeParts {\n if (tz === null) {\n const d = new Date(timeMs);\n return {\n year: d.getFullYear(),\n month: d.getMonth() + 1,\n day: d.getDate(),\n hours: d.getHours(),\n minutes: d.getMinutes(),\n };\n }\n const d = new Date(timeMs + offsetAt(tz, timeMs) * 60_000);\n return {\n year: d.getUTCFullYear(),\n month: d.getUTCMonth() + 1,\n day: d.getUTCDate(),\n hours: d.getUTCHours(),\n minutes: d.getUTCMinutes(),\n };\n}\n\n/**\n * A bar with no time-of-day component (a daily, weekly, monthly or yearly candle — always anchored\n * to a calendar-day boundary, so hours/minutes read 00:00) needs the YEAR in its label instead: a\n * bare `month/day` is ambiguous across years, and `00:00` tells a trader nothing. Detected from the\n * parts themselves rather than a separate timeframe parameter, so every caller that formats a bar's\n * time gets the same rule for free. It can't tell an hourly bar at midnight from a daily one:\n * callers that have the series ask `barsAreDaily` first and fall back to this.\n */\nexport function isDateOnly(parts: Pick<TimeParts, 'hours' | 'minutes'>): boolean {\n return parts.hours === 0 && parts.minutes === 0;\n}\n\n/** Gaps this long or longer (a day with a daylight-saving change is 23 h) mean daily-or-larger bars. */\nconst DAILY_GAP_MS = 20 * 3_600_000;\n\n/**\n * Whether bars are a day apart or more (daily, weekly, monthly): their labels\n * then carry a date and no time of day, while an hourly bar at midnight keeps\n * its time. Read from the smallest gap among the first bars, so a weekend or\n * a missing session doesn't make an intraday series look daily. Undefined for\n * fewer than two bars.\n */\nexport function barsAreDaily(data: ArrayLike<{ time: number }>): boolean | undefined {\n const n = Math.min(data.length, 64);\n if (n < 2) return undefined;\n const unit = barTimeUnit(data);\n let gap = Infinity;\n for (let i = 1; i < n; i++) {\n const d = Math.abs(data[i].time - data[i - 1].time) * unit;\n if (d > 0 && d < gap) gap = d;\n }\n return gap === Infinity ? undefined : gap >= DAILY_GAP_MS;\n}\n\n/** A short label like `UTC-5` or `UTC+5:30` for the offset in force at `atMs` (default: now). */\nexport function tzLabel(tz: TimeZoneSetting, atMs: number = Date.now()): string {\n const min = offsetAt(tz, atMs);\n const sign = min >= 0 ? '+' : '-';\n const abs = Math.abs(min);\n const h = Math.floor(abs / 60);\n const m = abs % 60;\n return m === 0 ? `UTC${sign}${h}` : `UTC${sign}${h}:${String(m).padStart(2, '0')}`;\n}\n\n/** Day-of-week for a Monday-anchored reference week (1970-01-05 was a Monday, UTC). */\nconst WEEK_ANCHOR_MS = Date.UTC(1970, 0, 5);\nconst MINUTE_MS = UNIT_MS.m;\nconst DAY_MS = UNIT_MS.d;\nconst HOURS_PER_DAY = 24;\n\n/** Where the buckets of `timeframeBucketStart` (and `resampleBars`) start. */\nexport interface BucketOptions {\n /** The day weeks start on: 0 Sunday, 1 Monday (the default). */\n weekStartsOn?: 0 | 1;\n /**\n * The zone whose midnight days start at: an IANA name such as\n * `'Asia/Ho_Chi_Minh'` (daylight saving time included), or minutes east of\n * UTC. Days, weeks, months and the hour frames that divide a day (2h, 3h,\n * 4h, 6h, 8h, 12h) follow it; 1h and shorter frames keep their epoch floor,\n * so the hour a fall-back night repeats stays two bars. Left out, UTC's.\n */\n timeZone?: string | number;\n /**\n * The times are bars a day long or more: one stamped at 00:00 UTC is the\n * date it names, and keeps that date's UTC bucket and stamp. Other times\n * are instants in `timeZone`.\n */\n dates?: boolean;\n}\n\ntype ParsedFrame = { count: number; unit: TimeFrameUnit };\n/** A frame that isn't one buckets as a minute, as it always has. */\nconst MINUTE_FRAME: ParsedFrame = { count: 1, unit: 'm' };\nconst PARSED_FRAMES_MAX = 256;\n/** Bars are bucketed one by one: read each timeframe's text once, not once a bar. */\nconst parsedFrames = new Map<string, ParsedFrame>();\n\nfunction parsedFrame(tf: TimeFrame): ParsedFrame {\n let frame = parsedFrames.get(tf);\n if (!frame) {\n frame = parseTimeframe(tf) ?? MINUTE_FRAME;\n if (parsedFrames.size >= PARSED_FRAMES_MAX) parsedFrames.clear();\n parsedFrames.set(tf, frame);\n }\n return frame;\n}\n\n/** Whether a frame's bars are a day long or more: days, weeks, months. */\nfunction spansDays({ unit }: ParsedFrame): boolean {\n return unit === 'd' || unit === 'w' || unit === 'M';\n}\n\n/** Whether a frame's buckets start at a day's midnight: days, weeks, months, and hours that divide a day. */\nfunction followsDays(frame: ParsedFrame): boolean {\n if (frame.unit === 'h') return frame.count > 1 && HOURS_PER_DAY % frame.count === 0;\n return spansDays(frame);\n}\n\n/** Whether `timeframeBucketStart` starts the buckets of `tf` at a zone's midnight when given one. */\nexport function timeframeFollowsDays(tf: TimeFrame): boolean {\n return followsDays(parsedFrame(tf));\n}\n\n/** Whether bars of `tf` are a day long or more (days, weeks, months), which feeds often stamp by date. */\nexport function timeframeSpansDays(tf: TimeFrame): boolean {\n return spansDays(parsedFrame(tf));\n}\n\n/** Whether `timeZone` moves a day's midnight away from UTC's. */\nfunction isZoned(timeZone: string | number | undefined): timeZone is string | number {\n return timeZone !== undefined && !isUtcTimeZone(timeZone);\n}\n\n/**\n * Start of the bucket a timestamp falls into for a given timeframe.\n *\n * Minutes and hours floor to multiples of the frame since the Unix epoch.\n * Days, weeks (from Monday, or `weekStartsOn`), months, quarters and years\n * start at midnight, and the hour frames that divide a day (2h to 12h) count\n * from it: UTC's, or `timeZone`'s when given (a day the clocks change is 23\n * or 25 hours long, its 4h bucket 3 or 5). A 3M frame starts on quarters, a\n * 12M one on 1 January. The third argument may also be the day weeks start\n * on alone. Throws a RangeError for a zone the browser doesn't know.\n */\nexport function timeframeBucketStart(\n timestamp: number,\n tf: TimeFrame,\n options: 0 | 1 | BucketOptions = 1,\n): number {\n const frame = parsedFrame(tf);\n const weekStartsOn = typeof options === 'number' ? options : options.weekStartsOn ?? 1;\n const timeZone = typeof options === 'number' ? undefined : options.timeZone;\n if (!isZoned(timeZone) || !followsDays(frame)) return utcBucketStart(timestamp, frame, weekStartsOn);\n // A date keeps the bucket of the day it names; only instants follow the zone.\n if (typeof options === 'object' && options.dates && timestamp % DAY_MS === 0) {\n return utcBucketStart(timestamp, frame, weekStartsOn);\n }\n // Bucket the zone's wall clock as if it were UTC, then find when that wall time happens there.\n const wall = timestamp + offsetAt(timeZone, timestamp) * MINUTE_MS;\n return wallToUtc(utcBucketStart(wall, frame, weekStartsOn), timeZone);\n}\n\n/** The bucket of `timestamp` on UTC's clock and calendar. */\nfunction utcBucketStart(timestamp: number, { count, unit }: ParsedFrame, weekStartsOn: 0 | 1): number {\n if (unit === 's' || unit === 'm' || unit === 'h' || unit === 'd') {\n const ms = count * UNIT_MS[unit];\n return Math.floor(timestamp / ms) * ms;\n }\n\n const d = new Date(timestamp);\n\n if (unit === 'w') {\n const dow = d.getUTCDay();\n const shift = (dow - weekStartsOn + 7) % 7;\n const weekStart = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate() - shift);\n if (count <= 1) return weekStart;\n const weekIndex = Math.floor((weekStart - WEEK_ANCHOR_MS) / (7 * DAY_MS));\n const grouped = Math.floor(weekIndex / count) * count;\n return WEEK_ANCHOR_MS + grouped * 7 * DAY_MS;\n }\n\n // months / quarters / years\n const totalMonths = d.getUTCFullYear() * 12 + d.getUTCMonth();\n const grouped = Math.floor(totalMonths / count) * count;\n return Date.UTC(Math.floor(grouped / 12), grouped % 12, 1);\n}\n\n/**\n * The zone a bar a day long or more is dated in, whatever zone the chart\n * shows (`tz`): UTC for one stamped at 00:00 UTC, the date it names; its\n * exchange's zone (`exchangeZone`) for one stamped at the exchange's\n * midnight, as the days a chart builds are; else `tz`, so a bar stamped at\n * the browser's midnight still reads its own date there.\n */\nexport function barDateZone(timeMs: number, tz: TimeZoneSetting, exchangeZone?: string | null): TimeZoneSetting {\n if (timeMs % DAY_MS === 0) return 0;\n if (exchangeZone && timeframeBucketStart(timeMs, '1d', { timeZone: exchangeZone }) === timeMs) return exchangeZone;\n return tz;\n}\n\n/** The calendar parts a bar a day long or more is labelled with: its date, in the zone `barDateZone` gives. */\nexport function barDateParts(timeMs: number, tz: TimeZoneSetting, exchangeZone?: string | null): TimeParts {\n return timeParts(timeMs, barDateZone(timeMs, tz, exchangeZone));\n}\n","const NUMBER_FORMAT_CACHE_LIMIT = 64;\nconst numberFormatCache = new Map<string, Intl.NumberFormat>();\n\n/**\n * `Number#toLocaleString(locale, options)` constructs a fresh\n * `Intl.NumberFormat` on every call — ~20µs in V8 versus ~0.4µs to reuse one.\n * Axis labels, the legend, crosshair pills and panel axes format dozens of\n * numbers per frame, so formatters are cached per (locale, precision). The\n * output is identical: per spec, `toLocaleString` is defined as exactly this.\n */\nfunction numberFormat(locale: string, precision: number): Intl.NumberFormat {\n const key = `${locale}|${precision}`;\n let nf = numberFormatCache.get(key);\n if (!nf) {\n if (numberFormatCache.size >= NUMBER_FORMAT_CACHE_LIMIT) numberFormatCache.clear();\n nf = new Intl.NumberFormat(locale, {\n minimumFractionDigits: precision,\n maximumFractionDigits: precision,\n });\n numberFormatCache.set(key, nf);\n }\n return nf;\n}\n\n/**\n * A price on a tag beside the axis (an order, a position, an alert) as the\n * axis writes one: the chart's price format when it has one, else grouped in\n * its number locale at `precision` decimals, or the market's or the symbol's\n * (`viewport.pricePrecision`), or the axis's own for the range on view when\n * neither is given.\n */\nexport function priceTagText(\n price: number,\n viewport: Pick<ViewportState, 'formatPrice' | 'numberLocale' | 'priceRange' | 'pricePrecision'>,\n precision?: number,\n): string {\n if (viewport.formatPrice) return viewport.formatPrice(price);\n const decimals = precision ?? viewport.pricePrecision ?? autoPricePrecision(viewport.priceRange.min, viewport.priceRange.max);\n return formatPrice(price, decimals, viewport.numberLocale ?? 'en-US');\n}\n\nexport function formatPrice(value: number, precision = 2, locale = 'en-US'): string {\n return numberFormat(locale, precision).format(value);\n}\n\n/**\n * Decimals the price axis uses for a visible price range: one more than its\n * tick step needs, 2 at minimum. Everything that prints a price next to the\n * axis (legend, crosshair pill, last-price tag) shares it, so a sub-cent\n * asset reads \"0.000004349\" everywhere instead of \"0.00\" off the axis.\n */\nexport function autoPricePrecision(min: number, max: number): number {\n if (!(max > min) || !Number.isFinite(min) || !Number.isFinite(max)) return 2;\n const step = computeTickStep(min, max, 8);\n return step > 0 && step < 1 ? Math.ceil(-Math.log10(step)) + 1 : 2;\n}\n\nimport type { PriceScaleMode, ViewportState } from '../types/rendering.js';\nimport type { PriceFormatter, PriceFraction } from '../types/chart.js';\nimport { computeTickStep } from './math.js';\n\n/** Decimals a percentage on the price scale shows. */\nconst PERCENT_DECIMALS = 2;\n\n/**\n * Format a price-axis label for a given scale mode, in the number locale.\n *\n * - `regular` / `logarithmic`: the raw price.\n * - `percentage`: change from `baseline`, e.g. `+12.34%` (`+12,34%` in\n * `de-DE`); one that reads as nothing has no sign.\n * - `indexedTo100`: the price rebased so `baseline` reads as 100.\n *\n * Falls back to a plain price when a baseline is required but missing/zero.\n */\nexport function formatPriceScaleLabel(\n price: number,\n mode: PriceScaleMode,\n baseline: number | undefined,\n precision = 2,\n locale = 'en-US',\n): string {\n if ((mode === 'percentage' || mode === 'indexedTo100') && baseline && baseline !== 0) {\n if (mode === 'percentage') {\n const pct = (price / baseline - 1) * 100;\n const text = formatPrice(Math.abs(pct), PERCENT_DECIMALS, locale);\n const sign = text === formatPrice(0, PERCENT_DECIMALS, locale) ? '' : pct > 0 ? '+' : '-';\n return `${sign}${text}%`;\n }\n const indexed = (price / baseline) * 100;\n return formatPrice(indexed, 2, locale);\n }\n return formatPrice(price, precision, locale);\n}\n\n/**\n * `value` in fractions of a point: whole points, an apostrophe, then the\n * fraction's numerator padded to the denominator's digits (`101'16` for\n * 101.5 in 32nds). A `subDenominator` of 2 or 4 adds the half or quarter of\n * that fraction as one more digit, as futures quote it (`101'165`, `110'162`,\n * `110'167`). Rounds to the nearest step. A denominator that isn't a whole\n * number above 1 gives plain digits.\n */\nexport function formatFraction(value: number, denominator: number, subDenominator = 1): string {\n const sub = Number.isInteger(subDenominator) && subDenominator > 1 ? subDenominator : 1;\n if (!Number.isFinite(value) || !Number.isInteger(denominator) || denominator < 2) return String(value);\n const steps = denominator * sub;\n const total = Math.round(Math.abs(value) * steps);\n const whole = Math.floor(total / steps);\n const rest = total - whole * steps;\n const numerator = Math.floor(rest / sub);\n const width = String(denominator - 1).length;\n const tail = sub > 1 ? String(Math.floor(((rest - numerator * sub) / sub) * 10)) : '';\n const sign = value < 0 && total > 0 ? '-' : '';\n return `${sign}${whole}'${String(numerator).padStart(width, '0')}${tail}`;\n}\n\n/**\n * The smallest step a fraction format prints (a 32nd; a quarter of one with\n * `subDenominator` 4), or null for a denominator it can't print (it falls\n * back to plain digits then).\n */\nexport function fractionTick(fraction: PriceFraction): number | null {\n if (!Number.isInteger(fraction.denominator) || fraction.denominator < 2) return null;\n const sub = Number.isInteger(fraction.subDenominator) && (fraction.subDenominator ?? 0) > 1 ? fraction.subDenominator as number : 1;\n return 1 / (fraction.denominator * sub);\n}\n\n/** The formatter a `priceFormat` option stands for: its function, its fraction's, or null for decimals. */\nexport function priceFormatterFor(format: PriceFormatter | PriceFraction | null | undefined): PriceFormatter | null {\n if (!format) return null;\n if (typeof format === 'function') return format;\n // A denominator it can't print leaves the chart's decimals.\n if (fractionTick(format) === null) return null;\n return (price) => formatFraction(price, format.denominator, format.subDenominator);\n}\n\nexport function formatVolume(value: number): string {\n if (value >= 1_000_000_000) return (value / 1_000_000_000).toFixed(2) + 'B';\n if (value >= 1_000_000) return (value / 1_000_000).toFixed(2) + 'M';\n if (value >= 1_000) return (value / 1_000).toFixed(2) + 'K';\n return value.toFixed(0);\n}\n\nexport function detectPrecision(values: number[]): number {\n let maxDecimals = 0;\n for (const v of values) {\n const str = v.toString();\n const dot = str.indexOf('.');\n if (dot >= 0) {\n maxDecimals = Math.max(maxDecimals, str.length - dot - 1);\n }\n }\n return Math.min(maxDecimals, 8);\n}\n","import type { OHLCBar } from '../types/ohlc.js';\n\n/** The price an indicator can be computed from. */\nexport const PRICE_SOURCES = ['close', 'open', 'high', 'low', 'hl2', 'hlc3', 'ohlc4', 'hlcc4'] as const;\n\nexport type PriceSource = (typeof PRICE_SOURCES)[number];\n\nexport function isPriceSource(value: unknown): value is PriceSource {\n return typeof value === 'string' && (PRICE_SOURCES as readonly string[]).includes(value);\n}\n\n/** A bar's price by source: `hl2` = (high + low) / 2, `hlc3`, `ohlc4`, `hlcc4` = (h + l + 2c) / 4. */\nexport function sourcePrice(bar: OHLCBar, source: PriceSource): number {\n switch (source) {\n case 'open': return bar.open;\n case 'high': return bar.high;\n case 'low': return bar.low;\n case 'hl2': return (bar.high + bar.low) / 2;\n case 'hlc3': return (bar.high + bar.low + bar.close) / 3;\n case 'ohlc4': return (bar.open + bar.high + bar.low + bar.close) / 4;\n case 'hlcc4': return (bar.high + bar.low + 2 * bar.close) / 4;\n default: return bar.close;\n }\n}\n\nconst INDICATOR_SOURCE = /^ind:([^:]+):(.+)$/;\n\n/** A source that is another indicator's line: `ind:<instanceId>:<key>`. */\nexport function indicatorSource(instanceId: string, key: string): string {\n return `ind:${instanceId}:${key}`;\n}\n\n/** The indicator line a source refers to, or null for a price source or anything else. */\nexport function parseIndicatorSource(value: unknown): { instanceId: string; key: string } | null {\n if (typeof value !== 'string') return null;\n const m = INDICATOR_SOURCE.exec(value);\n return m ? { instanceId: m[1], key: m[2] } : null;\n}\n","import type { OHLCBar, TimeFrame, TimeFrameUnit } from '../types/ohlc.js';\nimport { barsAreDaily, parseTimeframe, timeframeBucketStart, timeframeFollowsDays, timeframeToMs, type BucketOptions } from './time.js';\nimport { isUtcTimeZone, offsetAt } from './timezone.js';\n\nconst DAY_MS = 86_400_000;\nconst MINUTE_MS = 60_000;\n\n/**\n * Aggregate bars (ascending, times in ms) into a coarser timeframe: per\n * bucket (see `timeframeBucketStart`) the first open, the extremes, the last\n * close and the summed volume. The input bars are not changed.\n *\n * With a `timeZone`, days, weeks, months and the hour frames that divide a\n * day start at its midnight. Daily-or-longer bars stamped at 00:00 UTC are\n * read as the dates they name (unless `dates` says otherwise), so a Monday\n * stays in its own week west of UTC, and the weeks keep 00:00 UTC stamps.\n */\nexport function resampleBars(bars: readonly OHLCBar[], target: TimeFrame, options: 0 | 1 | BucketOptions = 1): OHLCBar[] {\n const bucket = bucketOptionsFor(bars, target, options);\n const out: OHLCBar[] = [];\n let current: OHLCBar | null = null;\n for (const bar of bars) {\n const key = timeframeBucketStart(bar.time, target, bucket);\n if (current === null || key !== current.time) {\n current = { time: key, open: bar.open, high: bar.high, low: bar.low, close: bar.close, volume: bar.volume };\n out.push(current);\n } else {\n if (bar.high > current.high) current.high = bar.high;\n if (bar.low < current.low) current.low = bar.low;\n current.close = bar.close;\n current.volume += bar.volume;\n }\n }\n return out;\n}\n\n/** The options as `timeframeBucketStart` takes them, with `dates` read from the bars when a zone needs it. */\nfunction bucketOptionsFor(bars: readonly OHLCBar[], target: TimeFrame, options: 0 | 1 | BucketOptions): 0 | 1 | BucketOptions {\n if (typeof options === 'number' || options.timeZone === undefined || options.dates !== undefined) return options;\n if (isUtcTimeZone(options.timeZone) || !timeframeFollowsDays(target)) return options;\n return { ...options, dates: barsAreDaily(bars) === true };\n}\n\nconst isFixedLength = (unit: TimeFrameUnit): boolean => unit === 's' || unit === 'm' || unit === 'h' || unit === 'd';\n\n/** Whether whole bars of `base` fill every bucket of `target` exactly. */\nfunction buildsInto(base: TimeFrame, target: TimeFrame): boolean {\n const b = parseTimeframe(base);\n const t = parseTimeframe(target);\n if (!b || !t) return false;\n const baseMs = timeframeToMs(base);\n // Feeds disagree on where a 3-day bar starts: only build from whole days.\n if (b.unit === 'd' && b.count > 1) return false;\n if (isFixedLength(t.unit)) {\n return isFixedLength(b.unit) && timeframeToMs(target) % baseMs === 0;\n }\n if (b.unit === t.unit) return t.count % b.count === 0;\n // Weeks and months start at midnight: build them from bars that never\n // cross one.\n return isFixedLength(b.unit) && DAY_MS % baseMs === 0;\n}\n\n/**\n * Whether bars of `base`, which feeds start on UTC's clock, also start on\n * every midnight of `timeZone`: its offset, in winter and in summer, is a\n * whole number of them. Bars of a day or more line up as dates.\n */\nfunction linesUpWith(base: TimeFrame, timeZone: string | number): boolean {\n const baseMs = timeframeToMs(base);\n if (!(baseMs < DAY_MS)) return true;\n const year = new Date().getUTCFullYear();\n return [Date.UTC(year, 0, 1), Date.UTC(year, 6, 1)].every((at) => (offsetAt(timeZone, at) * MINUTE_MS) % baseMs === 0);\n}\n\n/**\n * The coarsest of `supported` that builds `target` from whole bars (e.g. 7m\n * from 1m, 90m from 30m, a quarter from months), or null when none does.\n * With a `timeZone`, a target whose buckets start at its midnight (days,\n * weeks, months, 2h to 12h) takes only bars that line up with it: 1h for\n * Ho Chi Minh City's days, not 4h.\n */\nexport function pickBaseTimeframe(\n target: TimeFrame,\n supported: readonly TimeFrame[],\n options: Pick<BucketOptions, 'timeZone'> = {},\n): TimeFrame | null {\n const { timeZone } = options;\n const zone = timeZone !== undefined && !isUtcTimeZone(timeZone) && timeframeFollowsDays(target) ? timeZone : undefined;\n let best: TimeFrame | null = null;\n let bestMs = 0;\n for (const tf of supported) {\n if (!buildsInto(tf, target)) continue;\n if (zone !== undefined && !linesUpWith(tf, zone)) continue;\n const ms = timeframeToMs(tf);\n if (ms > bestMs) {\n best = tf;\n bestMs = ms;\n }\n }\n return best;\n}\n","import type { SymbolInfo } from '../types/symbol.js';\n\n/** How well `query` (upper case) matches `text` (upper case): 0 when it doesn't. */\nfunction score(text: string, query: string): number {\n if (!text) return 0;\n if (text === query) return 1000;\n if (text.startsWith(query)) return 600 - Math.min(100, text.length - query.length);\n const at = text.indexOf(query);\n return at >= 0 ? 300 - Math.min(100, at) : 0;\n}\n\n/**\n * Symbols matching `query`, best first: an exact ticker, then tickers that\n * start with it, then names that contain it. `boost` adds to a match's score\n * (say, for the quote currencies most traded). An empty query keeps the order\n * given. At most `limit` results.\n */\nexport function rankSymbols(\n symbols: readonly SymbolInfo[],\n query: string,\n limit = 50,\n boost?: (info: SymbolInfo) => number,\n): SymbolInfo[] {\n const q = query.trim().toUpperCase();\n if (!q) return symbols.slice(0, limit);\n const scored: { info: SymbolInfo; score: number }[] = [];\n for (const info of symbols) {\n const s = Math.max(\n score(info.symbol.toUpperCase(), q),\n score((info.description ?? '').toUpperCase(), q) * 0.8,\n );\n if (s > 0) scored.push({ info, score: s + (boost?.(info) ?? 0) });\n }\n scored.sort((a, b) => b.score - a.score || a.info.symbol.localeCompare(b.info.symbol));\n return scored.slice(0, limit).map((s) => s.info);\n}\n\n/** Decimals in a price step: `'0.01000000'` → 2, `'1'` → 0, `1e-8` → 8. */\nexport function stepDecimals(step: number | string): number {\n const value = typeof step === 'number' ? step : Number(step);\n if (!Number.isFinite(value) || value <= 0) return 0;\n for (let decimals = 0; decimals <= 12; decimals++) {\n const scaled = value * 10 ** decimals;\n if (Math.abs(scaled - Math.round(scaled)) < 1e-9 * Math.max(1, scaled)) return decimals;\n }\n return 12;\n}\n\n/** The zone a symbol keeps its hours in: its `timeZone`, else the older `timezone`. */\nexport function symbolTimeZone(info: Pick<SymbolInfo, 'timeZone' | 'timezone'> | null | undefined): string | undefined {\n return info?.timeZone ?? info?.timezone;\n}\n\n/** `'09:30'` → 570 (`'24:00'`, a day's end, → 1440), or null for anything that isn't a time of day. */\nexport function sessionMinute(time: string): number | null {\n const match = /^(\\d{1,2}):(\\d{2})$/.exec(time.trim());\n if (!match) return null;\n const hours = Number(match[1]);\n const minutes = Number(match[2]);\n if (hours === 24 && minutes === 0) return 1440;\n return hours < 24 && minutes < 60 ? hours * 60 + minutes : null;\n}\n","import type { SymbolInfo } from '../types/symbol.js';\nimport { sessionMinute, symbolTimeZone } from './symbols.js';\nimport { isValidTimeZone, zoneOffsetMinutes } from './timezone.js';\n\n/** Whether a symbol's market is trading now, and when that changes. */\nexport interface MarketStatus {\n /** `'always'`: no hours known (24/7, such as crypto). */\n state: 'open' | 'closed' | 'always';\n /** When it next closes (open) or opens (closed), in ms; null when unknown. */\n next: number | null;\n}\n\nconst DAY_MS = 86_400_000;\nconst MINUTE_MS = 60_000;\n/** Days looked ahead for the next open (a long weekend, a week of holidays). */\nconst LOOK_AHEAD_DAYS = 8;\n\n/**\n * The market status of `info` at `now`: in a session of its hours (in its\n * exchange's time zone, clocks changes included) or not, and when that\n * changes. Sessions that meet count as one; a session past midnight belongs\n * to the day it starts. Without hours or a zone it knows: `'always'`.\n */\nexport function marketStatus(info: SymbolInfo | null | undefined, now: number): MarketStatus {\n const zone = symbolTimeZone(info);\n const sessions = (info?.sessions ?? []).flatMap((s) => {\n const start = sessionMinute(s.start);\n const end = sessionMinute(s.end);\n if (start === null || end === null || start === end) return [];\n return [{ start, end, days: Array.isArray(s.days) ? s.days : null }];\n });\n if (!zone || !isValidTimeZone(zone) || sessions.length === 0 || !Number.isFinite(now)) {\n return { state: 'always', next: null };\n }\n\n const offset = zoneOffsetMinutes(zone, now) * MINUTE_MS;\n const today = Math.floor((now + offset) / DAY_MS) * DAY_MS;\n // A wall-clock time in the zone, back to UTC with the offset that holds then\n // (asked twice, so a time beside a clock change settles on its side).\n const toUtc = (local: number) => {\n const guess = local - zoneOffsetMinutes(zone, local - offset) * MINUTE_MS;\n return local - zoneOffsetMinutes(zone, guess) * MINUTE_MS;\n };\n\n const spans: [number, number][] = [];\n for (let d = -1; d <= LOOK_AHEAD_DAYS; d++) {\n const dayStart = today + d * DAY_MS;\n const weekday = (Math.floor(dayStart / DAY_MS) + 4) % 7; // 1 Jan 1970 was a Thursday\n for (const s of sessions) {\n if (s.days && !s.days.includes(weekday)) continue;\n const start = dayStart + s.start * MINUTE_MS;\n const end = (s.end > s.start ? dayStart : dayStart + DAY_MS) + s.end * MINUTE_MS;\n spans.push([toUtc(start), toUtc(end)]);\n }\n }\n spans.sort((a, b) => a[0] - b[0]);\n const merged: [number, number][] = [];\n for (const [start, end] of spans) {\n const last = merged[merged.length - 1];\n if (last && start <= last[1]) merged[merged.length - 1] = [last[0], Math.max(last[1], end)];\n else merged.push([start, end]);\n }\n\n const current = merged.find(([start, end]) => start <= now && now < end);\n if (current) return { state: 'open', next: current[1] };\n const upcoming = merged.find(([start]) => start > now);\n return { state: 'closed', next: upcoming ? upcoming[0] : null };\n}\n","import type { DrawingLevel, DrawingOptionDef, DrawingOptionDefs, DrawingOptionValue, DrawingOptions } from '../types/drawing.js';\n\n/** Most levels a drawing keeps; more is a pasted or hand-edited state, not a chart. */\nconst MAX_LEVELS = 48;\nconst MAX_TEXT = 2000;\n/** Largest level ratio kept (a Fibonacci level of 4.236, a time zone of 89 bars). */\nconst MAX_LEVEL_VALUE = 10_000;\n\nfunction sanitizeLevels(raw: unknown): DrawingLevel[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const levels: DrawingLevel[] = [];\n for (const item of raw) {\n if (levels.length >= MAX_LEVELS) break;\n if (typeof item !== 'object' || item === null) continue;\n const { value, visible, color } = item as Record<string, unknown>;\n if (typeof value !== 'number' || !Number.isFinite(value) || Math.abs(value) > MAX_LEVEL_VALUE) continue;\n if (visible !== undefined && typeof visible !== 'boolean') continue;\n const level: DrawingLevel = { value, visible: visible ?? true };\n if (typeof color === 'string' && color) level.color = color;\n levels.push(level);\n }\n return levels;\n}\n\n/** `raw` as a value for `def`, or undefined when it isn't one. */\nfunction sanitizeValue(def: DrawingOptionDef, raw: unknown): DrawingOptionValue | undefined {\n switch (def.kind) {\n case 'boolean':\n return typeof raw === 'boolean' ? raw : undefined;\n case 'number': {\n if (typeof raw !== 'number' || !Number.isFinite(raw)) return undefined;\n return Math.min(def.max ?? Infinity, Math.max(def.min ?? -Infinity, raw));\n }\n case 'choice':\n return typeof raw === 'string' && def.choices.some((c) => c.value === raw) ? raw : undefined;\n case 'levels':\n return sanitizeLevels(raw);\n case 'text':\n return typeof raw === 'string' ? raw.slice(0, MAX_TEXT) : undefined;\n }\n}\n\n/** The valid entries of `raw` for a tool's options: unknown keys and wrong values are dropped, numbers clamped. */\nexport function sanitizeDrawingOptions(defs: DrawingOptionDefs | undefined, raw: unknown): DrawingOptions {\n if (!defs || typeof raw !== 'object' || raw === null) return {};\n const out: DrawingOptions = {};\n for (const [key, value] of Object.entries(raw)) {\n const def = defs[key];\n if (!def) continue;\n const clean = sanitizeValue(def, value);\n if (clean !== undefined) out[key] = clean;\n }\n return out;\n}\n\nfunction copyValue(value: DrawingOptionValue | readonly DrawingLevel[]): DrawingOptionValue {\n return Array.isArray(value) ? value.map((level) => ({ ...level })) : (value as DrawingOptionValue);\n}\n\n/** One option of a drawing: its own value when valid, else the tool's default. */\nexport function drawingOption<T extends DrawingOptionValue = DrawingOptionValue>(\n defs: DrawingOptionDefs | undefined,\n options: DrawingOptions | undefined,\n key: string,\n): T {\n const def = defs?.[key];\n if (!def) return options?.[key] as T;\n const own = options && key in options ? sanitizeValue(def, options[key]) : undefined;\n return copyValue(own ?? def.default) as T;\n}\n\n/** Every option of a tool for a drawing, defaults filled in. */\nexport function resolveDrawingOptions(defs: DrawingOptionDefs | undefined, options: DrawingOptions | undefined): DrawingOptions {\n const out: DrawingOptions = {};\n for (const key of Object.keys(defs ?? {})) out[key] = drawingOption(defs, options, key);\n return out;\n}\n","import type { DrawingStyle } from '../types/drawing.js';\n\nconst LINE_STYLES: readonly DrawingStyle['lineStyle'][] = ['solid', 'dashed', 'dotted'];\nconst MAX_COLOR = 64;\nconst MAX_TEXT = 2000;\nconst MAX_LINE_WIDTH = 20;\nconst MAX_FONT_SIZE = 200;\n/** Widest a text may be set to run before it wraps, px. */\nconst MAX_TEXT_WRAP = 4000;\n/** Narrowest a wrap width may be, px: room for a short word. */\nconst MIN_TEXT_WRAP = 20;\nconst TEXT_ALIGNS: readonly NonNullable<DrawingStyle['textAlign']>[] = ['left', 'center', 'right'];\nconst TEXT_VALIGNS: readonly NonNullable<DrawingStyle['textVAlign']>[] = ['top', 'middle', 'bottom'];\n\nfunction finiteIn(value: unknown, min: number, max: number): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? Math.min(max, Math.max(min, value)) : undefined;\n}\n\nfunction colorValue(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 && value.length <= MAX_COLOR ? value : undefined;\n}\n\n/**\n * The valid fields of a drawing style from untrusted data (a saved layout, a\n * template): colours as short strings, a known line style, widths, opacity\n * and font size as finite numbers in range, text cut to length. Anything\n * else is dropped.\n */\nexport function sanitizeDrawingStyle(raw: unknown): Partial<DrawingStyle> {\n if (typeof raw !== 'object' || raw === null) return {};\n const obj = raw as Record<string, unknown>;\n const out: Partial<DrawingStyle> = {};\n const color = colorValue(obj.color);\n if (color !== undefined) out.color = color;\n const lineWidth = finiteIn(obj.lineWidth, 0.5, MAX_LINE_WIDTH);\n if (lineWidth !== undefined) out.lineWidth = lineWidth;\n if (LINE_STYLES.includes(obj.lineStyle as DrawingStyle['lineStyle'])) out.lineStyle = obj.lineStyle as DrawingStyle['lineStyle'];\n const fillColor = colorValue(obj.fillColor);\n if (fillColor !== undefined) out.fillColor = fillColor;\n const fillOpacity = finiteIn(obj.fillOpacity, 0, 1);\n if (fillOpacity !== undefined) out.fillOpacity = fillOpacity;\n const fontSize = finiteIn(obj.fontSize, 6, MAX_FONT_SIZE);\n if (fontSize !== undefined) out.fontSize = fontSize;\n if (typeof obj.text === 'string') out.text = obj.text.slice(0, MAX_TEXT);\n for (const key of ['bold', 'italic', 'textBackground', 'textBorder'] as const) {\n if (typeof obj[key] === 'boolean') out[key] = obj[key] as boolean;\n }\n if (TEXT_ALIGNS.includes(obj.textAlign as NonNullable<DrawingStyle['textAlign']>)) out.textAlign = obj.textAlign as DrawingStyle['textAlign'];\n if (TEXT_VALIGNS.includes(obj.textVAlign as NonNullable<DrawingStyle['textVAlign']>)) out.textVAlign = obj.textVAlign as DrawingStyle['textVAlign'];\n const textColor = colorValue(obj.textColor);\n if (textColor !== undefined) out.textColor = textColor;\n const borderColor = colorValue(obj.borderColor);\n if (borderColor !== undefined) out.borderColor = borderColor;\n // 0 wraps only where the text breaks; any other width is kept to what a word fits in and a screen could use.\n if (typeof obj.textWrap === 'number' && Number.isFinite(obj.textWrap) && obj.textWrap >= 0) {\n out.textWrap = obj.textWrap === 0 ? 0 : Math.min(MAX_TEXT_WRAP, Math.max(MIN_TEXT_WRAP, obj.textWrap));\n }\n return out;\n}\n","import type { ChartTypeOptions } from '../types/chart.js';\n\nconst positive = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v) && v > 0;\nconst wholeIn = (v: unknown, lo: number, hi: number): v is number =>\n typeof v === 'number' && Number.isInteger(v) && v >= lo && v <= hi;\nconst isObject = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null && !Array.isArray(v);\n\n/**\n * The chart type settings in `raw` the chart can use: boxes, ranges and\n * reversals above 0, whole line and box counts in range. A type given at\n * all is in the result (empty when none of its settings were usable), so\n * a type's settings can be put back to their defaults.\n */\nexport function readChartTypeOptions(raw: unknown): ChartTypeOptions {\n if (!isObject(raw)) return {};\n const out: ChartTypeOptions = {};\n if (isObject(raw.renko)) {\n const { boxSize, atrPeriod } = raw.renko;\n out.renko = {\n ...(positive(boxSize) || boxSize === 'atr' ? { boxSize } : {}),\n ...(wholeIn(atrPeriod, 1, 500) ? { atrPeriod } : {}),\n };\n }\n if (isObject(raw.lineBreak)) {\n const { lines } = raw.lineBreak;\n out.lineBreak = wholeIn(lines, 1, 10) ? { lines } : {};\n }\n if (isObject(raw.kagi)) {\n const { reversal, reversalType } = raw.kagi;\n out.kagi = {\n ...(positive(reversal) ? { reversal } : {}),\n ...(reversalType === 'percent' || reversalType === 'price' ? { reversalType } : {}),\n };\n }\n if (isObject(raw.pointAndFigure)) {\n const { boxSize, reversal } = raw.pointAndFigure;\n out.pointAndFigure = {\n ...(positive(boxSize) || boxSize === 'auto' ? { boxSize } : {}),\n ...(wholeIn(reversal, 1, 10) ? { reversal } : {}),\n };\n }\n if (isObject(raw.rangeBars)) {\n const { range } = raw.rangeBars;\n out.rangeBars = positive(range) || range === 'auto' ? { range } : {};\n }\n return out;\n}\n","import type { PriceLimitColors, Theme } from '../types/theme.js';\nimport { withAlpha } from '../utils/color.js';\n\n/**\n * The chart's own type: a monospaced face, so the figures on the axes, in the\n * legend and on the tags line up in columns, as in a printed price table.\n */\nexport const DEFAULT_FONT_FAMILY = \"'Cascadia Mono', 'SF Mono', ui-monospace, Menlo, Consolas, monospace\";\n\n/**\n * A proportional face every system has, for figures that read lighter: the\n * airy look's axes and legend (`chart.setFont({ family: SANS_FONT_FAMILY })`).\n * Each axis label stands alone, so proportional digits read well there; the\n * widget's columns of figures keep them one width with `tabular-nums`.\n */\nexport const SANS_FONT_FAMILY = \"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif\";\n\n/** Three sizes a third of φ apart (11, 13, 15), as the widget's type scale climbs. */\nconst DEFAULT_FONT = {\n family: DEFAULT_FONT_FAMILY,\n sizeSmall: 11,\n sizeMedium: 13,\n sizeLarge: 15,\n};\n\n/**\n * TradeCanvas palette. Themes pick their own candle colours for their\n * background; everything drawn on top of either theme (indicators, orders,\n * signals, drawings) uses the theme-neutral values below, which keep at\n * least 3:1 contrast on both the dark ink and the light paper. `amber` is\n * the brand accent for dark surfaces (2:1 on paper); light surfaces use\n * `ochre` instead.\n */\nexport const TC_PALETTE = {\n /** Brand amber, for marks on dark surfaces. */\n amber: '#f2a93b',\n /** Rising / bullish, legible on dark and light. */\n up: '#1c9e6d',\n /** Falling / bearish, legible on dark and light. */\n down: '#e8505b',\n /** Amber deep enough for white backgrounds; auto-coloured series use it. */\n ochre: '#c07c12',\n /** Secondary series, signal lines. */\n blue: '#4688fa',\n violet: '#9c73f8',\n cyan: '#1398a8',\n rose: '#e25592',\n /** Zero lines, neutral guides. */\n neutral: '#7d8696',\n /** Ink ground of the dark theme. */\n ink: '#131416',\n} as const;\n\n/**\n * How strongly volume bars show: the candle colour at this opacity, so they\n * read as a backdrop under the candles rather than a second chart.\n */\nexport const VOLUME_ALPHA = 0.22;\n\n/** The volume bar colour for a candle colour. */\nexport function volumeColor(candleColor: string): string {\n return withAlpha(candleColor, VOLUME_ALPHA);\n}\n\n/**\n * The built-in themes are paper and ink: an off-white and an off-black, never\n * pure, so text doesn't glare; grey for everything that is normal; colour\n * only where it means something (up, down, your orders). Volume is the ink at\n * low strength, lighter under falling bars: the candles above already say\n * which way the price went.\n */\nconst PAPER = '#fbfaf6';\nconst PAPER_INK = '#1b1d21';\nconst NIGHT = '#131416';\nconst NIGHT_INK = '#e6e3dc';\nconst LIGHT_UP = '#1f7a5c';\nconst LIGHT_DOWN = '#b8423f';\nconst DARK_UP = '#4fae8a';\nconst DARK_DOWN = '#e2706b';\n/**\n * The crosshair is the ink faded into the ground, mixed rather than\n * translucent: bar tints and guides drawn in it at their own opacity keep\n * their strength. 3:1 on the ground, quiet beside the data.\n */\nconst NIGHT_CROSSHAIR = '#6a6966';\nconst PAPER_CROSSHAIR = '#8d8a84';\n\n/**\n * The price limits on ink: bright magenta, cyan and gold, the colours a\n * price board marks the ceiling, floor and reference with; each reads at 5:1\n * or more there. Themes without limit colours of their own take these.\n */\nexport const DARK_PRICE_LIMITS: PriceLimitColors = { ceiling: '#FF00FF', floor: '#00FFFF', reference: '#FFD700' };\n\n/** The same hues deep enough for paper: 4.5:1 or more on it, as text needs. */\nexport const LIGHT_PRICE_LIMITS: PriceLimitColors = { ceiling: '#a21caf', floor: '#0e7490', reference: '#8a6a00' };\n\n/** Order in which overlay indicators are coloured when no colour is given. */\nexport const TC_SERIES_COLORS: readonly string[] = [\n TC_PALETTE.blue,\n TC_PALETTE.ochre,\n TC_PALETTE.violet,\n TC_PALETTE.cyan,\n TC_PALETTE.rose,\n];\n\nexport const DARK_THEME: Theme = {\n name: 'dark',\n background: NIGHT,\n text: NIGHT_INK,\n textSecondary: '#8d8b86',\n grid: '#1d1e21',\n crosshair: NIGHT_CROSSHAIR,\n candleUp: DARK_UP,\n candleDown: DARK_DOWN,\n candleUpWick: DARK_UP,\n candleDownWick: DARK_DOWN,\n lineColor: NIGHT_INK,\n areaTopColor: withAlpha(NIGHT_INK, 0.14),\n areaBottomColor: withAlpha(NIGHT_INK, 0),\n volumeUp: withAlpha(NIGHT_INK, 0.14),\n volumeDown: withAlpha(NIGHT_INK, 0.08),\n axisLine: '#2a2b2f',\n axisLabel: '#a9a6a0',\n axisLabelBackground: '#232427',\n font: DEFAULT_FONT,\n priceLimits: DARK_PRICE_LIMITS,\n};\n\nexport const LIGHT_THEME: Theme = {\n name: 'light',\n background: PAPER,\n text: PAPER_INK,\n textSecondary: '#6b6f76',\n grid: '#ece8df',\n crosshair: PAPER_CROSSHAIR,\n candleUp: LIGHT_UP,\n candleDown: LIGHT_DOWN,\n candleUpWick: LIGHT_UP,\n candleDownWick: LIGHT_DOWN,\n lineColor: PAPER_INK,\n areaTopColor: withAlpha(PAPER_INK, 0.12),\n areaBottomColor: withAlpha(PAPER_INK, 0),\n volumeUp: withAlpha(PAPER_INK, 0.13),\n volumeDown: withAlpha(PAPER_INK, 0.08),\n axisLine: '#cfcac0',\n axisLabel: '#4a4e57',\n axisLabelBackground: '#eeebe3',\n font: DEFAULT_FONT,\n priceLimits: LIGHT_PRICE_LIMITS,\n};\n\nexport const DARK_TERMINAL: Theme = {\n name: 'terminal',\n background: '#0E0E0E',\n text: '#C0C0C0',\n textSecondary: '#8A8A8A',\n grid: '#1A1A1A',\n crosshair: '#666666',\n candleUp: '#00FF87',\n candleDown: '#FF3B4D',\n candleUpWick: '#00FF87',\n candleDownWick: '#FF3B4D',\n lineColor: '#3D8BFD',\n areaTopColor: 'rgba(61, 139, 253, 0.3)',\n areaBottomColor: 'rgba(61, 139, 253, 0.0)',\n volumeUp: volumeColor('#00FF87'),\n volumeDown: volumeColor('#FF3B4D'),\n axisLine: '#1A1A1A',\n axisLabel: '#8A8A8A',\n axisLabelBackground: '#1A1A1A',\n font: {\n family: \"'Roboto Mono', 'JetBrains Mono', 'SF Mono', Consolas, monospace\",\n sizeSmall: 10,\n sizeMedium: 12,\n sizeLarge: 14,\n },\n};\n\n/** The volume colours of the presets that draw volume in their candles' colours. */\nconst PRESET_VOLUME = new Set([DARK_TERMINAL.volumeUp, DARK_TERMINAL.volumeDown]);\n\n/**\n * The volume bars' colours for `theme`: its own `volumeUp` / `volumeDown`,\n * except that a theme spread from a candle-coloured preset with new candle\n * colours (and the preset's volume left in place) gets volume in its new\n * candles' colours. Neutral volume stays neutral whatever the candles.\n */\nexport function resolveVolumeColors(theme: Pick<Theme, 'candleUp' | 'candleDown' | 'volumeUp' | 'volumeDown'>): { up: string; down: string } {\n const pick = (volume: string, candle: string): string => {\n if (!PRESET_VOLUME.has(volume)) return volume;\n const derived = volumeColor(candle);\n return derived === candle ? volume : derived;\n };\n return { up: pick(theme.volumeUp, theme.candleUp), down: pick(theme.volumeDown, theme.candleDown) };\n}\n","import type { ChartType, LineStyle } from '../types/chart.js';\nimport type { Theme } from '../types/theme.js';\nimport type { IndicatorPlotStyle } from '../types/indicator.js';\nimport {\n CHART_STYLE_KEYS,\n type ChartStyleKey,\n type ChartStyleOverrides,\n type ChartStyleOverridesPatch,\n type PaneStyle,\n type ResolvedChartStyle,\n type ResolvedLineLook,\n type StyleValueKind,\n} from '../types/style.js';\nimport { resolveVolumeColors } from '../constants/themes.js';\n\nconst LINE_STYLES: readonly LineStyle[] = ['solid', 'dashed', 'dotted'];\n/** Widths past this are a mistake, not a look. */\nconst MAX_WIDTH = 20;\n/** Long enough for any colour CSS writes, short enough to keep anything else out. */\nconst MAX_COLOR_LENGTH = 64;\n/** The main series' line width when nothing sets it. */\nconst DEFAULT_LINE_WIDTH = 2;\n\n/**\n * A colour as CSS writes one, and only that: hex, a name, or a colour\n * function (`rgb()`, `hsl()`, `oklch()`, `color()`…) of numbers, units and\n * words. Anything else is refused, so a value read from a saved layout can't\n * carry markup or script into a style or an attribute.\n */\nconst COLOR_PATTERNS = [\n /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i,\n /^[a-z]{3,30}$/i,\n /^(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch|color)\\([0-9a-z.,%/\\s-]*\\)$/i,\n];\n\nfunction isColor(value: unknown): value is string {\n return typeof value === 'string' && value.length <= MAX_COLOR_LENGTH && COLOR_PATTERNS.some((pattern) => pattern.test(value.trim()));\n}\n\nfunction isValue(kind: StyleValueKind, value: unknown): boolean {\n switch (kind) {\n case 'color': return isColor(value);\n case 'lineStyle': return LINE_STYLES.includes(value as LineStyle);\n case 'width': return typeof value === 'number' && Number.isFinite(value) && value > 0 && value <= MAX_WIDTH;\n case 'boolean': return typeof value === 'boolean';\n }\n}\n\nfunction isStyleKey(key: string): key is ChartStyleKey {\n return Object.prototype.hasOwnProperty.call(CHART_STYLE_KEYS, key);\n}\n\n/**\n * Overrides read from anywhere (your options, a saved layout): the keys it\n * knows with values of their kind, `null` taking a key away. `rejected`\n * names what was left out.\n */\nexport function readChartStyleOverrides(raw: unknown): { overrides: ChartStyleOverridesPatch; rejected: string[] } {\n const overrides: Record<string, unknown> = {};\n const rejected: string[] = [];\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) return { overrides: {}, rejected };\n for (const [key, value] of Object.entries(raw)) {\n if (!isStyleKey(key)) rejected.push(key);\n else if (value === null) overrides[key] = null;\n else if (isValue(CHART_STYLE_KEYS[key], value)) overrides[key] = value;\n else rejected.push(key);\n }\n return { overrides: overrides as ChartStyleOverridesPatch, rejected };\n}\n\n/** A pane's own style: the colours it can use, or null when it has none. */\nexport function readPaneStyle(raw: unknown): PaneStyle | null {\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) return null;\n const { background, separator } = raw as Record<string, unknown>;\n const style: PaneStyle = {\n ...(isColor(background) ? { background } : {}),\n ...(isColor(separator) ? { separator } : {}),\n };\n return Object.keys(style).length > 0 ? style : null;\n}\n\n/** A plot key as indicators name them: short, nothing odd in it. */\nconst PLOT_KEY = /^[A-Za-z0-9_]{1,32}$/;\n\n/** Plot styles read from anywhere: by plot key, a dash style and whether it shows; undefined when none. */\nexport function readIndicatorPlotStyles(raw: unknown): Record<string, IndicatorPlotStyle> | undefined {\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) return undefined;\n const out: Record<string, IndicatorPlotStyle> = {};\n for (const [key, value] of Object.entries(raw)) {\n if (!PLOT_KEY.test(key) || typeof value !== 'object' || value === null) continue;\n const { lineStyle, visible } = value as Record<string, unknown>;\n const plot: IndicatorPlotStyle = {\n ...(LINE_STYLES.includes(lineStyle as LineStyle) ? { lineStyle: lineStyle as LineStyle } : {}),\n ...(typeof visible === 'boolean' ? { visible } : {}),\n };\n if (Object.keys(plot).length > 0) out[key] = plot;\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\n/** A dash pattern for a line style: `dashed` its own, `dotted` dots as wide as the line. */\nexport function lineDash(style: LineStyle, dashed: readonly number[], width = 1): number[] {\n if (style === 'solid') return [];\n if (style === 'dotted') return [width, width * 2];\n return [...dashed];\n}\n\ntype Lookup = (key: string) => unknown;\n\n/** The main series' colours and widths, as the chart type `type` takes them. */\nfunction seriesLooks(base: Theme, o: Lookup, type: ChartType) {\n const own = (prop: string) => o(`series.${type}.${prop}`);\n const upSet = own('upColor') ?? o('series.candlestick.upColor');\n const downSet = own('downColor') ?? o('series.candlestick.downColor');\n const up = (upSet as string | undefined) ?? base.candleUp;\n const down = (downSet as string | undefined) ?? base.candleDown;\n return {\n up,\n down,\n // A wick takes its body's colour once that is set, as the theme's own do.\n wickUp: ((own('wickUpColor') ?? o('series.candlestick.wickUpColor')) as string | undefined) ?? (upSet !== undefined ? up : base.candleUpWick),\n wickDown: ((own('wickDownColor') ?? o('series.candlestick.wickDownColor')) as string | undefined) ?? (downSet !== undefined ? down : base.candleDownWick),\n line: ((own('color') ?? own('lineColor') ?? o('series.line.color')) as string | undefined) ?? base.lineColor,\n lineWidth: ((own('lineWidth') ?? o('series.line.lineWidth')) as number | undefined) ?? DEFAULT_LINE_WIDTH,\n top: ((own('topColor') ?? o('series.area.topColor')) as string | undefined) ?? base.areaTopColor,\n bottom: ((own('bottomColor') ?? o('series.area.bottomColor')) as string | undefined) ?? base.areaBottomColor,\n };\n}\n\nfunction lineLook(o: Lookup, prefix: string, fallback: ResolvedLineLook): ResolvedLineLook {\n return {\n visible: (o(`${prefix}.visible`) as boolean | undefined) ?? fallback.visible,\n color: (o(`${prefix}.color`) as string | undefined) ?? fallback.color,\n style: (o(`${prefix}.style`) as LineStyle | undefined) ?? fallback.style,\n width: (o(`${prefix}.width`) as number | undefined) ?? fallback.width,\n };\n}\n\n/**\n * The theme the chart draws with: `base` with `overrides` on its tokens (the\n * main series' as `chartType` takes them) and the finer looks in `style`.\n * `base` is left as it was.\n */\nexport function resolveChartTheme(base: Theme, chartType: ChartType, overrides: ChartStyleOverrides): Theme {\n const { style: _ignored, ...plain } = base;\n const map = overrides as Record<string, unknown>;\n const o: Lookup = (key) => map[key];\n const series = seriesLooks(plain, o, chartType);\n const background = (o('background.color') as string | undefined) ?? plain.background;\n const str = (key: ChartStyleKey, fallback: string) => (o(key) as string | undefined) ?? fallback;\n /** A colour of a part with its own settings: the override, or null to keep to them. */\n const ownColor = (key: ChartStyleKey): string | null => (o(key) as string | undefined) ?? null;\n\n const style: ResolvedChartStyle = {\n panes: {\n background: str('panes.background', background),\n separator: str('panes.separatorColor', plain.axisLine),\n title: str('panes.titleColor', plain.textSecondary),\n },\n grid: {\n horizontal: lineLook(o, 'grid.horizontal', { visible: true, color: plain.grid, style: 'solid', width: 1 }),\n vertical: lineLook(o, 'grid.vertical', { visible: true, color: plain.grid, style: 'solid', width: 1 }),\n },\n // Hairlines, solid: a dash pattern is noise the eye has to read past.\n crosshair: {\n horizontal: lineLook(o, 'crosshair.horizontal', { visible: true, color: plain.crosshair, style: 'solid', width: 1 }),\n vertical: lineLook(o, 'crosshair.vertical', { visible: true, color: plain.crosshair, style: 'solid', width: 1 }),\n labelBackground: str('crosshair.labelBackground', plain.text),\n labelText: str('crosshair.labelTextColor', background),\n },\n axis: {\n price: { line: str('axis.price.lineColor', plain.axisLine), text: str('axis.price.textColor', plain.axisLabel) },\n time: { line: str('axis.time.lineColor', plain.axisLine), text: str('axis.time.textColor', plain.axisLabel) },\n },\n legend: { text: str('legend.textColor', plain.text), label: str('legend.labelColor', plain.textSecondary) },\n watermark: { color: (o('watermark.color') as string | undefined) ?? null },\n lastPrice: {\n visible: (o('lastPrice.visible') as boolean | undefined) ?? true,\n up: str('lastPrice.upColor', series.up),\n down: str('lastPrice.downColor', series.down),\n style: (o('lastPrice.style') as LineStyle | undefined) ?? 'solid',\n width: (o('lastPrice.width') as number | undefined) ?? 1,\n },\n sessionBreaks: {\n color: (o('sessionBreaks.color') as string | undefined) ?? null,\n style: (o('sessionBreaks.style') as LineStyle | undefined) ?? null,\n width: (o('sessionBreaks.width') as number | undefined) ?? null,\n },\n highLow: { color: (o('highLow.color') as string | undefined) ?? null },\n series: { lineWidth: series.lineWidth },\n trading: {\n buy: ownColor('trading.buyColor'),\n sell: ownColor('trading.sellColor'),\n profit: ownColor('trading.profitColor'),\n loss: ownColor('trading.lossColor'),\n entry: ownColor('trading.entryColor'),\n },\n markers: { long: ownColor('markers.longColor'), short: ownColor('markers.shortColor'), neutral: ownColor('markers.neutralColor') },\n tradeZones: { profit: ownColor('tradeZones.profitColor'), loss: ownColor('tradeZones.lossColor'), active: ownColor('tradeZones.activeColor') },\n drawings: { handle: ownColor('drawings.handleColor') },\n };\n\n return {\n ...plain,\n background,\n candleUp: series.up,\n candleDown: series.down,\n candleUpWick: series.wickUp,\n candleDownWick: series.wickDown,\n lineColor: series.line,\n areaTopColor: series.top,\n areaBottomColor: series.bottom,\n volumeUp: str('volume.upColor', plain.volumeUp),\n volumeDown: str('volume.downColor', plain.volumeDown),\n style,\n };\n}\n\n/** How each key that isn't the series' reads back from the resolved theme. */\nconst READ_BACK: { [K in ChartStyleKey]?: (t: Theme, s: ResolvedChartStyle) => unknown } = {\n 'background.color': (t) => t.background,\n 'panes.background': (_t, s) => s.panes.background,\n 'panes.separatorColor': (_t, s) => s.panes.separator,\n 'panes.titleColor': (_t, s) => s.panes.title,\n 'crosshair.labelBackground': (_t, s) => s.crosshair.labelBackground,\n 'crosshair.labelTextColor': (_t, s) => s.crosshair.labelText,\n 'axis.price.lineColor': (_t, s) => s.axis.price.line,\n 'axis.price.textColor': (_t, s) => s.axis.price.text,\n 'axis.time.lineColor': (_t, s) => s.axis.time.line,\n 'axis.time.textColor': (_t, s) => s.axis.time.text,\n 'legend.textColor': (_t, s) => s.legend.text,\n 'legend.labelColor': (_t, s) => s.legend.label,\n 'watermark.color': (_t, s) => s.watermark.color,\n 'lastPrice.visible': (_t, s) => s.lastPrice.visible,\n 'lastPrice.upColor': (_t, s) => s.lastPrice.up,\n 'lastPrice.downColor': (_t, s) => s.lastPrice.down,\n 'lastPrice.style': (_t, s) => s.lastPrice.style,\n 'lastPrice.width': (_t, s) => s.lastPrice.width,\n // As drawn: a theme that sets only candle colours gets volume in those colours.\n 'volume.upColor': (t) => resolveVolumeColors(t).up,\n 'volume.downColor': (t) => resolveVolumeColors(t).down,\n 'sessionBreaks.color': (_t, s) => s.sessionBreaks.color,\n 'sessionBreaks.style': (_t, s) => s.sessionBreaks.style,\n 'sessionBreaks.width': (_t, s) => s.sessionBreaks.width,\n 'highLow.color': (_t, s) => s.highLow.color,\n 'trading.buyColor': (_t, s) => s.trading.buy,\n 'trading.sellColor': (_t, s) => s.trading.sell,\n 'trading.profitColor': (_t, s) => s.trading.profit,\n 'trading.lossColor': (_t, s) => s.trading.loss,\n 'trading.entryColor': (_t, s) => s.trading.entry,\n 'markers.longColor': (_t, s) => s.markers.long,\n 'markers.shortColor': (_t, s) => s.markers.short,\n 'markers.neutralColor': (_t, s) => s.markers.neutral,\n 'tradeZones.profitColor': (_t, s) => s.tradeZones.profit,\n 'tradeZones.lossColor': (_t, s) => s.tradeZones.loss,\n 'tradeZones.activeColor': (_t, s) => s.tradeZones.active,\n 'drawings.handleColor': (_t, s) => s.drawings.handle,\n};\n\nconst LINE_PROPS: Record<string, keyof ResolvedLineLook> = { visible: 'visible', color: 'color', style: 'style', width: 'width' };\n\n/**\n * What `key` resolves to: its override, or what it falls back to. A\n * `series.<type>.*` key resolves as that type would draw; the last price\n * follows `chartType`'s colours. Null for the parts that keep to their own\n * settings when not overridden (the watermark, session breaks, high/low).\n */\nexport function chartStyleValue(\n base: Theme,\n overrides: ChartStyleOverrides,\n key: ChartStyleKey,\n chartType: ChartType = 'candlestick',\n): string | number | boolean | null {\n const parts = key.split('.');\n if (parts[0] === 'series') {\n const looks = seriesLooks(base, (k) => (overrides as Record<string, unknown>)[k], parts[1] as ChartType);\n switch (parts[2]) {\n case 'upColor': return looks.up;\n case 'downColor': return looks.down;\n case 'wickUpColor': return looks.wickUp;\n case 'wickDownColor': return looks.wickDown;\n case 'color':\n case 'lineColor': return looks.line;\n case 'lineWidth': return looks.lineWidth;\n case 'topColor': return looks.top;\n case 'bottomColor': return looks.bottom;\n }\n }\n const theme = resolveChartTheme(base, chartType, overrides);\n const style = theme.style!;\n if (parts[0] === 'grid' || (parts[0] === 'crosshair' && (parts[1] === 'horizontal' || parts[1] === 'vertical'))) {\n const group = parts[0] === 'grid' ? style.grid : style.crosshair;\n return group[parts[1] as 'horizontal' | 'vertical'][LINE_PROPS[parts[2]]];\n }\n return (READ_BACK[key]?.(theme, style) ?? null) as string | number | boolean | null;\n}\n","import type { ChartOptions } from '../types/chart.js';\n\nexport const DEFAULT_CHART_OPTIONS: Required<Pick<ChartOptions, 'autoScale' | 'rightMargin' | 'minBarSpacing' | 'maxBarSpacing'>> & Pick<ChartOptions, 'grid' | 'crosshair'> = {\n autoScale: true,\n rightMargin: 5,\n minBarSpacing: 2,\n maxBarSpacing: 30,\n grid: {\n visible: true,\n hLineStyle: 'solid',\n vLineStyle: 'solid',\n },\n crosshair: {\n mode: 'magnet',\n },\n};\n\n// Standard timeframe presets for different market types\nimport type { TimeFrame } from '../types/ohlc.js';\n\n/** Crypto: all timeframes including seconds */\nexport const TIMEFRAMES_CRYPTO: TimeFrame[] = [\n '1s', '1m', '3m', '5m', '15m', '30m',\n '1h', '2h', '4h', '6h', '8h', '12h',\n '1d', '3d', '1w', '1M',\n];\n\n/** Stocks: minute-level and above (no seconds) */\nexport const TIMEFRAMES_STOCK: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '2h', '4h',\n '1d', '1w', '1M', '3M', '6M', '12M',\n];\n\n/** Forex: common forex timeframes */\nexport const TIMEFRAMES_FOREX: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '4h',\n '1d', '1w', '1M',\n];\n\n/** Default favorites shown in quick-access bar */\nexport const DEFAULT_TIMEFRAME_FAVORITES: TimeFrame[] = [\n '1m', '5m', '15m', '1h', '4h', '1d', '1w',\n];\n\nexport const DEFAULT_BAR_WIDTH = 8;\nexport const DEFAULT_BAR_SPACING = 2;\nexport const PRICE_AXIS_WIDTH = 70;\nexport const TIME_AXIS_HEIGHT = 30;\nexport const MIN_PANEL_HEIGHT = 60;\nexport const DEFAULT_PANEL_HEIGHT = 120;\n","/**\n * The golden ratio, which the built-in look keeps to. Sizes that sit together\n * stand in it (an icon, its button, the bar it sits in), spacing and corners\n * are Fibonacci numbers, whose neighbours approach it, and type climbs by its\n * cube root, so every third size is φ larger.\n */\nexport const PHI = (1 + Math.sqrt(5)) / 2;\n\n/** Spacing and corners, px: each the sum of the two before, so neighbours stand near φ. */\nexport const FIBONACCI = [1, 2, 3, 5, 8, 13, 21, 34, 55, 89] as const;\n\n/**\n * `base` moved `steps` along a scale that reaches φ in `perPhi` steps, in\n * whole pixels: `phiStep(16, 2, 2)` is 26, `phiStep(13, 3, 3)` is 21.\n */\nexport function phiStep(base: number, steps: number, perPhi = 1): number {\n return Math.round(base * PHI ** (steps / perPhi));\n}\n","import type { LocaleStrings } from './types.js';\n\nexport const en: LocaleStrings = {\n // Chart types\n candlestick: 'Candlestick',\n line: 'Line',\n area: 'Area',\n bar: 'OHLC Bar',\n\n // Axes\n price: 'Price',\n volume: 'Volume',\n time: 'Time',\n open: 'Open',\n high: 'High',\n low: 'Low',\n close: 'Close',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Bollinger Bands',\n vwap: 'VWAP',\n ichimoku: 'Ichimoku Cloud',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Keltner Channel',\n donchianChannel: 'Donchian Channel',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Std Dev',\n volumeProfile: 'Volume Profile',\n accumulationDistribution: 'A/D Line',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Trend Line',\n horizontalLine: 'Horizontal Line',\n verticalLine: 'Vertical Line',\n ray: 'Ray',\n extendedLine: 'Extended Line',\n parallelChannel: 'Parallel Channel',\n regressionChannel: 'Regression Channel',\n fibRetracement: 'Fibonacci Retracement',\n fibExtension: 'Fibonacci Extension',\n rectangle: 'Rectangle',\n ellipse: 'Ellipse',\n triangle: 'Triangle',\n pitchfork: \"Andrews' Pitchfork\",\n elliottWave: 'Elliott Wave',\n priceRange: 'Price Range',\n dateRange: 'Date Range',\n measure: 'Measure',\n textTool: 'Text',\n arrow: 'Arrow',\n clearAll: 'Clear All',\n\n // Trading\n buy: 'Buy',\n sell: 'Sell',\n buyLimit: 'Buy Limit',\n sellLimit: 'Sell Limit',\n buyStop: 'Buy Stop',\n sellStop: 'Sell Stop',\n stopLoss: 'Stop Loss',\n takeProfit: 'Take Profit',\n market: 'Market',\n limit: 'Limit',\n stop: 'Stop',\n cancel: 'Cancel',\n modify: 'Modify',\n quantity: 'Qty',\n pnl: 'P&L',\n activeOrders: 'Active Orders',\n positions: 'Positions',\n noOrders: 'No active orders',\n noPositions: 'No open positions',\n placeOrder: 'Place Order',\n rightClickToTrade: 'Right-click chart to place orders',\n\n // Market\n ceiling: 'Ceiling',\n floor: 'Floor',\n reference: 'Reference',\n session: 'Session',\n preOpen: 'Pre-Open',\n continuous: 'Continuous',\n preClose: 'Pre-Close',\n closed: 'Closed',\n\n // UI\n settings: 'Settings',\n theme: 'Theme',\n darkTheme: 'Dark',\n lightTheme: 'Light',\n tools: 'Tools',\n indicators: 'Indicators',\n overlays: 'Overlays',\n panels: 'Panels',\n orders: 'Orders',\n autoScale: 'Auto Scale',\n crosshair: 'Crosshair',\n grid: 'Grid',\n loading: 'Loading...',\n error: 'Error',\n\n numberDecimalSeparator: '.',\n numberGroupSeparator: ',',\n};\n","import type { LocaleStrings } from './types.js';\n\nexport const vi: LocaleStrings = {\n // Chart types\n candlestick: 'Nến',\n line: 'Đường',\n area: 'Vùng',\n bar: 'Thanh OHLC',\n\n // Axes\n price: 'Giá',\n volume: 'Khối lượng',\n time: 'Thời gian',\n open: 'Mở',\n high: 'Cao',\n low: 'Thấp',\n close: 'Đóng',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Dải Bollinger',\n vwap: 'VWAP',\n ichimoku: 'Mây Ichimoku',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Kênh Keltner',\n donchianChannel: 'Kênh Donchian',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Độ lệch chuẩn',\n volumeProfile: 'Phân bổ KL',\n accumulationDistribution: 'Tích lũy/Phân phối',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Đường xu hướng',\n horizontalLine: 'Đường ngang',\n verticalLine: 'Đường dọc',\n ray: 'Tia',\n extendedLine: 'Đường kéo dài',\n parallelChannel: 'Kênh song song',\n regressionChannel: 'Kênh hồi quy',\n fibRetracement: 'Fibonacci thoái lui',\n fibExtension: 'Fibonacci mở rộng',\n rectangle: 'Hình chữ nhật',\n ellipse: 'Hình elip',\n triangle: 'Tam giác',\n pitchfork: 'Chĩa ba Andrews',\n elliottWave: 'Sóng Elliott',\n priceRange: 'Khoảng giá',\n dateRange: 'Khoảng thời gian',\n measure: 'Đo lường',\n textTool: 'Chữ',\n arrow: 'Mũi tên',\n clearAll: 'Xóa tất cả',\n\n // Trading\n buy: 'Mua',\n sell: 'Bán',\n buyLimit: 'Mua giới hạn',\n sellLimit: 'Bán giới hạn',\n buyStop: 'Mua chặn',\n sellStop: 'Bán chặn',\n stopLoss: 'Cắt lỗ',\n takeProfit: 'Chốt lời',\n market: 'Thị trường',\n limit: 'Giới hạn',\n stop: 'Dừng',\n cancel: 'Hủy',\n modify: 'Sửa',\n quantity: 'KL',\n pnl: 'Lãi/Lỗ',\n activeOrders: 'Lệnh chờ',\n positions: 'Vị thế',\n noOrders: 'Không có lệnh chờ',\n noPositions: 'Không có vị thế mở',\n placeOrder: 'Đặt lệnh',\n rightClickToTrade: 'Nhấp chuột phải để đặt lệnh',\n\n // Market\n ceiling: 'Trần',\n floor: 'Sàn',\n reference: 'Tham chiếu',\n session: 'Phiên',\n preOpen: 'Trước giờ mở',\n continuous: 'Liên tục',\n preClose: 'Trước giờ đóng',\n closed: 'Đóng cửa',\n\n // UI\n settings: 'Cài đặt',\n theme: 'Giao diện',\n darkTheme: 'Tối',\n lightTheme: 'Sáng',\n tools: 'Công cụ',\n indicators: 'Chỉ báo',\n overlays: 'Phủ lên',\n panels: 'Bảng',\n orders: 'Lệnh',\n autoScale: 'Tự co giãn',\n crosshair: 'Chữ thập',\n grid: 'Lưới',\n loading: 'Đang tải...',\n error: 'Lỗi',\n\n numberDecimalSeparator: ',',\n numberGroupSeparator: '.',\n};\n","export type { Locale, LocaleStrings, NumberFormatConfig, DateFormatConfig } from './types.js';\nexport { en } from './en.js';\nexport { vi } from './vi.js';\n\nimport type { Locale, LocaleStrings } from './types.js';\nimport { en } from './en.js';\nimport { vi } from './vi.js';\nimport { formatPrice } from '../utils/precision.js';\n\nconst locales = new Map<string, LocaleStrings>([\n ['en', en],\n ['vi', vi],\n]);\n\nlet currentLocale: Locale = 'en';\nlet currentStrings: LocaleStrings = en;\n\nexport function setLocale(locale: Locale): void {\n currentLocale = locale;\n currentStrings = locales.get(locale) ?? en;\n}\n\nexport function getLocale(): Locale {\n return currentLocale;\n}\n\nexport function t(key: keyof LocaleStrings): string {\n return currentStrings[key] ?? (en as any)[key] ?? key;\n}\n\nexport function registerLocale(locale: string, strings: LocaleStrings): void {\n locales.set(locale, strings);\n}\n\nexport function getLocaleStrings(locale?: string): LocaleStrings {\n return locales.get(locale ?? currentLocale) ?? en;\n}\n\n// Number formatting\nexport function formatNumber(value: number, precision = 2, locale?: string): string {\n const strings = locales.get(locale ?? currentLocale) ?? en;\n const dec = strings.numberDecimalSeparator;\n const grp = strings.numberGroupSeparator;\n\n const fixed = value.toFixed(precision);\n const [intPart, decPart] = fixed.split('.');\n\n // Group integer part\n const negative = intPart.startsWith('-');\n const digits = negative ? intPart.slice(1) : intPart;\n let grouped = '';\n for (let i = digits.length - 1, count = 0; i >= 0; i--, count++) {\n if (count > 0 && count % 3 === 0) grouped = grp + grouped;\n grouped = digits[i] + grouped;\n }\n if (negative) grouped = '-' + grouped;\n\n return decPart ? grouped + dec + decPart : grouped;\n}\n\nexport function formatVND(value: number): string {\n return formatNumber(value, 0, 'vi');\n}\n\n/** Korean counts in ten-thousands: 만 (10⁴), 억 (10⁸), 조 (10¹²). */\nconst KO_UNITS: readonly [number, string][] = [[1e12, '조'], [1e8, '억'], [1e4, '만']];\n\n/** Whether `locale` writes large counts in 만, 억 and 조 (Korean) rather than K, M and B. */\nexport function usesKoreanUnits(locale: string): boolean {\n return /^ko([-_]|$)/i.test(locale);\n}\n\n/** A figure as Intl writes it in `locale`; in English when Intl does not know the locale. */\nfunction intlFigure(value: number, decimals: number, locale: string): string {\n try {\n return formatPrice(value, decimals, locale);\n } catch {\n return formatNumber(value, decimals, 'en');\n }\n}\n\n/** A volume shortened for `locale`: 1.23K, 4.50M; in Korean 1.23만, 3.45억, 1.82조. */\nexport function formatVolumeLoc(value: number, locale?: string): string {\n const loc = locale ?? currentLocale;\n if (!Number.isFinite(value)) return String(value);\n if (usesKoreanUnits(loc)) {\n // By the value as printed, so 99,999,999 reads 1.00억 rather than 10,000.00만.\n for (const [size, unit] of KO_UNITS) if (Math.round((value / size) * 100) >= 100) return formatNumber(value / size, 2, loc) + unit;\n return formatNumber(value, 0, loc);\n }\n // A locale with a table here keeps its marks; any other is written as Intl writes it.\n const figure = locales.has(loc) ? (v: number, d: number) => formatNumber(v, d, loc) : (v: number, d: number) => intlFigure(v, d, loc);\n if (value >= 1e9) return figure(value / 1e9, 2) + 'B';\n if (value >= 1e6) return figure(value / 1e6, 2) + 'M';\n if (value >= 1e3) return figure(value / 1e3, 2) + 'K';\n return figure(value, 0);\n}\n","import type { MarketConfig, MarketColorScheme, PriceStepBand, TradingSession, VN30FContract } from './types.js';\nimport type { Theme } from '../types/theme.js';\nimport { stepDecimals } from '../utils/symbols.js';\nimport { isValidTimeZone, zoneOffsetMinutes } from '../utils/timezone.js';\n\n/**\n * Vietnamese price boards: green up, red down, purple at the ceiling (trần),\n * cyan at the floor (sàn), yellow at the reference price (tham chiếu).\n */\nexport const VN_COLORS: MarketColorScheme = {\n up: '#22C55E',\n down: '#EF4444',\n unchanged: '#EAB308',\n ceiling: '#D946EF',\n floor: '#06B6D4',\n reference: '#EAB308',\n};\n\nconst VN_TIME_ZONE = 'Asia/Ho_Chi_Minh';\n\n/**\n * Korean trading apps: red up, blue down, against the previous close; the\n * upper limit (상한가) a deeper red, the lower (하한가) a deeper blue.\n */\nexport const KR_COLORS: MarketColorScheme = {\n up: '#E8313F',\n down: '#2F6FEB',\n unchanged: '#8B8F99',\n ceiling: '#C2121F',\n floor: '#1E4FC2',\n reference: '#8B8F99',\n};\n\nconst KR_TIME_ZONE = 'Asia/Seoul';\n\n// Session times and rules: the exchanges' trading rules as of May 2025 (the\n// HOSE KRX system went live on 5 May 2025).\nexport const HOSE_SESSIONS: TradingSession[] = [\n { name: 'ATO', startTime: '09:00', endTime: '09:15', type: 'preOpen' },\n { name: 'Phiên 1', startTime: '09:15', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\nexport const HNX_SESSIONS: TradingSession[] = [\n { name: 'Phiên 1', startTime: '09:15', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n { name: 'PLO', startTime: '14:45', endTime: '15:00', type: 'postClose' },\n];\n\nexport const UPCOM_SESSIONS: TradingSession[] = [\n { name: 'Phiên 1', startTime: '09:15', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n];\n\nexport const VN30F_SESSIONS: TradingSession[] = [\n { name: 'ATO', startTime: '08:45', endTime: '09:00', type: 'preOpen' },\n { name: 'Phiên 1', startTime: '09:00', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\n// KRX's sessions as of 14 September 2026, when the After-Market (16:00–20:00,\n// continuous, within the day's limits) replaced the after-hours single-price\n// session. The pre-hours closing-price trade (08:30–08:40) runs inside the\n// opening call and is left out.\nexport const KRX_SESSIONS: TradingSession[] = [\n { name: '장전 동시호가', startTime: '08:30', endTime: '09:00', type: 'preOpen' },\n { name: '정규장', startTime: '09:00', endTime: '15:20', type: 'continuous' },\n { name: '장마감 동시호가', startTime: '15:20', endTime: '15:30', type: 'preClose' },\n { name: '장후 시간외', startTime: '15:40', endTime: '16:00', type: 'postClose' },\n { name: '애프터마켓', startTime: '16:00', endTime: '20:00', type: 'postClose' },\n];\n\n// Nextrade, the alternative exchange (since March 2025): its main market\n// stops for KRX's closing call. It opens at 09:00:30; sessions are by the minute.\nexport const NXT_SESSIONS: TradingSession[] = [\n { name: '프리마켓', startTime: '08:00', endTime: '08:50', type: 'preOpen' },\n { name: '메인마켓', startTime: '09:00', endTime: '15:20', type: 'continuous' },\n { name: '애프터마켓', startTime: '15:40', endTime: '20:00', type: 'postClose' },\n];\n\n/** KOSPI, KOSDAQ and KONEX shares, in won (one table since 25 January 2023). */\nconst KRX_STEPS: readonly PriceStepBand[] = [\n { from: 0, step: 1 },\n { from: 2_000, step: 5 },\n { from: 5_000, step: 10 },\n { from: 20_000, step: 50 },\n { from: 50_000, step: 100 },\n { from: 200_000, step: 500 },\n { from: 500_000, step: 1_000 },\n];\n\n/** Upbit's KRW market, in won (since 31 July 2025). */\nconst UPBIT_KRW_STEPS: readonly PriceStepBand[] = [\n { from: 0, step: 0.00000001 },\n { from: 0.00001, step: 0.0000001 },\n { from: 0.0001, step: 0.000001 },\n { from: 0.001, step: 0.00001 },\n { from: 0.01, step: 0.0001 },\n { from: 0.1, step: 0.001 },\n { from: 1, step: 0.01 },\n { from: 10, step: 0.1 },\n { from: 100, step: 1 },\n { from: 5_000, step: 5 },\n { from: 10_000, step: 10 },\n { from: 50_000, step: 50 },\n { from: 100_000, step: 100 },\n { from: 500_000, step: 500 },\n { from: 1_000_000, step: 1_000 },\n];\n\n/** HOSE shares and closed funds, in thousands of dong: 10, 50 and 100 dong steps. */\nconst HOSE_STEPS: readonly PriceStepBand[] = [\n { from: 0, step: 0.01 },\n { from: 10, step: 0.05 },\n { from: 50, step: 0.1 },\n];\n\n// Market presets. Vietnamese prices are in thousands of dong (25.35 is 25,350\n// dong), as price boards show them; scaleMarketPrices(preset, 1000) for dong.\n\n/**\n * HOSE shares (Ho Chi Minh City), in thousands of dong: steps of 0.01 below\n * 10, 0.05 from 10, 0.1 from 50; 2 decimals; lots of 100; limits of ±7%\n * from the reference; zone Asia/Ho_Chi_Minh; the price board's colours\n * (`VN_COLORS`); the ATO, two continuous sessions and ATC (`HOSE_SESSIONS`).\n * With `chart.setMarket`: `setPriceLimits(reference)` for the day's ceiling\n * and floor, `setTimeZone('exchange')` for the axis in Vietnam's time.\n */\nexport const MARKET_HOSE: MarketConfig = {\n type: 'stock',\n exchange: 'HOSE',\n currency: 'VND',\n pricePrecision: 2,\n volumeUnit: 100,\n priceStep: 0.01,\n priceSteps: HOSE_STEPS,\n timeZone: VN_TIME_ZONE,\n priceLimits: { enabled: true, ceilingPercent: 7, floorPercent: 7 },\n sessions: HOSE_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\n/** HOSE ETFs and covered warrants: 10 dong at every price. */\nexport const MARKET_HOSE_ETF: MarketConfig = {\n ...MARKET_HOSE,\n priceSteps: undefined,\n};\n\n/** HNX shares (Hanoi), in thousands of dong: 0.1 a step, limits of ±10%, zone Asia/Ho_Chi_Minh, lots of 100, `HNX_SESSIONS`. */\nexport const MARKET_HNX: MarketConfig = {\n type: 'stock',\n exchange: 'HNX',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n timeZone: VN_TIME_ZONE,\n priceLimits: { enabled: true, ceilingPercent: 10, floorPercent: 10 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\n/** UPCoM shares, in thousands of dong: 0.1 a step, limits of ±15%, zone Asia/Ho_Chi_Minh, lots of 100, `UPCOM_SESSIONS`. */\nexport const MARKET_UPCOM: MarketConfig = {\n type: 'stock',\n exchange: 'UPCOM',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n timeZone: VN_TIME_ZONE,\n priceLimits: { enabled: true, ceilingPercent: 15, floorPercent: 15 },\n sessions: UPCOM_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\n/** VN30 index futures on HNX: index points, 0.1 a step, 100,000 dong a point, limits of ±7%, zone Asia/Ho_Chi_Minh, `VN30F_SESSIONS`. */\nexport const MARKET_VN30F: MarketConfig = {\n type: 'futures',\n exchange: 'HNX',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 1,\n priceStep: 0.1,\n contractMultiplier: 100_000,\n timeZone: VN_TIME_ZONE,\n priceLimits: { enabled: true, ceilingPercent: 7, floorPercent: 7 },\n sessions: VN30F_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\n/**\n * KOSPI and KOSDAQ shares on KRX, in won: steps from 1 won below 2,000 to\n * 1,000 from 500,000 (`priceSteps`); whole won; limits of ±30% from the\n * reference, the move rounded first as KRX does (`roundMove`); zone\n * Asia/Seoul; red up and blue down (`KR_COLORS`); the opening and closing\n * calls, the regular session and the After-Market (`KRX_SESSIONS`). ETFs\n * and ETNs step differently and are not in the After-Market.\n */\nexport const MARKET_KRX: MarketConfig = {\n type: 'stock',\n exchange: 'KRX',\n currency: 'KRW',\n pricePrecision: 0,\n volumeUnit: 1,\n priceStep: 1,\n priceSteps: KRX_STEPS,\n timeZone: KR_TIME_ZONE,\n priceLimits: { enabled: true, ceilingPercent: 30, floorPercent: 30, roundMove: true },\n sessions: KRX_SESSIONS,\n colorScheme: KR_COLORS,\n};\n\n/** Shares on Nextrade: KRX's steps and limits (from KRX's reference price), `NXT_SESSIONS`. */\nexport const MARKET_NXT: MarketConfig = {\n ...MARKET_KRX,\n exchange: 'NXT',\n sessions: NXT_SESSIONS,\n};\n\n/**\n * Upbit's KRW market (`KRW-BTC`): steps from 1,000 won at a million down to\n * a hundred-millionth of a won (`priceSteps`), the decimals following the\n * symbol's data; no limits; red up and blue down. It trades around the clock.\n */\nexport const MARKET_UPBIT_KRW: MarketConfig = {\n type: 'crypto',\n exchange: 'UPBIT',\n currency: 'KRW',\n priceStep: 0.00000001,\n priceSteps: UPBIT_KRW_STEPS,\n timeZone: KR_TIME_ZONE,\n priceLimits: { enabled: false },\n colorScheme: KR_COLORS,\n};\n\n/** Crypto: 2 decimals, no limits, no zone or sessions (it trades around the clock). */\nexport const MARKET_CRYPTO: MarketConfig = {\n type: 'crypto',\n currency: 'USDT',\n pricePrecision: 2,\n priceLimits: { enabled: false },\n};\n\n/** NYSE shares, in dollars: 0.01 a step, no limits, zone America/New_York, pre-market, regular and after-hours sessions. */\nexport const MARKET_NYSE: MarketConfig = {\n type: 'stock',\n exchange: 'NYSE',\n currency: 'USD',\n pricePrecision: 2,\n priceStep: 0.01,\n timeZone: 'America/New_York',\n priceLimits: { enabled: false },\n sessions: [\n { name: 'Pre-Market', startTime: '04:00', endTime: '09:30', type: 'preOpen' },\n { name: 'Regular', startTime: '09:30', endTime: '16:00', type: 'continuous' },\n { name: 'After-Hours', startTime: '16:00', endTime: '20:00', type: 'postClose' },\n ],\n};\n\n/**\n * A theme variant for the Vietnamese stock market: its candle colours. Volume\n * keeps the theme's own (neutral in the built-in themes; a candle-coloured\n * preset's follows the new candles).\n */\nexport function createVNTheme(base: Theme): Theme {\n return createMarketTheme(base, VN_COLORS);\n}\n\n/**\n * A theme variant with a market's candle colours: `createMarketTheme(DARK_THEME,\n * KR_COLORS)` draws rising candles red and falling ones blue. Volume keeps\n * the theme's own.\n */\nexport function createMarketTheme(base: Theme, colors: Pick<MarketColorScheme, 'up' | 'down'>): Theme {\n return {\n ...base,\n candleUp: colors.up,\n candleDown: colors.down,\n candleUpWick: colors.up,\n candleDownWick: colors.down,\n };\n}\n\n/** Rounding slack, so 27.1 / 0.05 (541.999…) still counts as 542 steps. */\nconst STEP_EPSILON = 1e-9;\n\n/**\n * The price step at `price`: the band it falls in, else the market's\n * `priceStep`; undefined when the market names no step.\n */\nexport function priceStepAt(price: number, config: MarketConfig): number | undefined {\n let step = config.priceStep;\n for (const band of config.priceSteps ?? []) {\n if (price + STEP_EPSILON >= band.from) step = band.step;\n }\n return step !== undefined && step > 0 ? step : undefined;\n}\n\n/** The step of the band just below `price`, for one step down from it. */\nfunction stepBelow(price: number, config: MarketConfig): number | undefined {\n let step = config.priceStep;\n for (const band of config.priceSteps ?? []) {\n if (price - STEP_EPSILON > band.from) step = band.step;\n }\n return step !== undefined && step > 0 ? step : undefined;\n}\n\n/**\n * `price` on the step of its band: to the nearest step, or `'down'` / `'up'`.\n * A market without a step leaves it as it is.\n */\nexport function roundToPriceStep(price: number, config: MarketConfig, mode: 'nearest' | 'down' | 'up' = 'nearest'): number {\n const step = priceStepAt(price, config);\n if (step === undefined || !Number.isFinite(price)) return price;\n const steps = price / step;\n const count = mode === 'down'\n ? Math.floor(steps + STEP_EPSILON)\n : mode === 'up'\n ? Math.ceil(steps - STEP_EPSILON)\n : Math.round(steps);\n return Number((count * step).toFixed(stepDecimals(step)));\n}\n\n/**\n * The day's ceiling, floor and reference prices. With a price step, the\n * ceiling rounds down and the floor up to a valid price; when one would land\n * back on the reference it moves a step off it, and a reference of one step\n * keeps the floor at the reference (the exchanges' rules).\n */\nexport function computePriceLimits(referencePrice: number, config: MarketConfig): { ceiling: number; floor: number; reference: number } | null {\n if (!config.priceLimits?.enabled || !config.priceLimits.ceilingPercent) return null;\n const ceilPct = config.priceLimits.ceilingPercent / 100;\n const floorPct = (config.priceLimits.floorPercent ?? config.priceLimits.ceilingPercent) / 100;\n const reference = referencePrice;\n const rawCeiling = reference * (1 + ceilPct);\n const rawFloor = reference * (1 - floorPct);\n const refStep = priceStepAt(reference, config);\n if (refStep === undefined) return { ceiling: rawCeiling, floor: rawFloor, reference };\n\n const oneUp = roundToPriceStep(reference + refStep, config);\n if (Math.abs(reference - refStep) < STEP_EPSILON) return { ceiling: oneUp, floor: reference, reference };\n\n let ceiling: number;\n let floor: number;\n if (config.priceLimits.roundMove) {\n // KRX: the move rounded down to the reference's step, then each limit down to its own.\n const atRefStep: MarketConfig = { ...config, priceStep: refStep, priceSteps: undefined };\n ceiling = roundToPriceStep(reference + roundToPriceStep(reference * ceilPct, atRefStep, 'down'), config, 'down');\n floor = roundToPriceStep(reference - roundToPriceStep(reference * floorPct, atRefStep, 'down'), config, 'down');\n } else {\n ceiling = roundToPriceStep(rawCeiling, config, 'down');\n floor = roundToPriceStep(rawFloor, config, 'up');\n }\n if (ceiling <= reference) ceiling = oneUp;\n if (floor >= reference) floor = roundToPriceStep(reference - (stepBelow(reference, config) ?? refStep), config);\n if (floor <= 0) floor = reference;\n return { ceiling, floor, reference };\n}\n\n/** `value * factor` without float dust (0.05 * 1000 is 50, not 50.00000000000001). */\nconst scaled = (value: number, factor: number) => Math.round(value * factor * 1e9) / 1e9;\n\n/**\n * A copy of `config` for prices `factor` times larger (a power of ten):\n * steps, bands, the reference price and the decimals follow; a contract's\n * multiplier stays. `scaleMarketPrices(MARKET_HOSE, 1000)` reads prices in\n * dong (25350) instead of thousands (25.35).\n */\nexport function scaleMarketPrices(config: MarketConfig, factor: number): MarketConfig {\n const decimalsLess = Math.round(Math.log10(factor));\n return {\n ...config,\n pricePrecision: config.pricePrecision === undefined ? undefined : Math.max(0, config.pricePrecision - decimalsLess),\n priceStep: config.priceStep === undefined ? undefined : scaled(config.priceStep, factor),\n priceSteps: config.priceSteps?.map((band) => ({ from: scaled(band.from, factor), step: scaled(band.step, factor) })),\n priceLimits: config.priceLimits && {\n ...config.priceLimits,\n referencePrice: config.priceLimits.referencePrice === undefined ? undefined : scaled(config.priceLimits.referencePrice, factor),\n },\n };\n}\n\nconst MINUTE_MS = 60_000;\nconst DAY_MS = 86_400_000;\n\n/** `HH:mm` of `now` in `timeZone`, or on this computer's clock without one. */\nfunction wallClock(now: number, timeZone?: string): string {\n let hours: number;\n let minutes: number;\n if (timeZone) {\n const local = new Date(now + zoneOffsetMinutes(timeZone, now) * MINUTE_MS);\n hours = local.getUTCHours();\n minutes = local.getUTCMinutes();\n } else {\n const local = new Date(now);\n hours = local.getHours();\n minutes = local.getMinutes();\n }\n return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`;\n}\n\n/**\n * The session `now` falls in: by the clock of `timeZone` (a market's\n * `timeZone`), or of this computer without one. Null outside them all, and\n * for a time zone it doesn't know. By the time of day only: weekends and\n * holidays are yours to tell.\n */\nexport function getCurrentSession(sessions: TradingSession[], now: number = Date.now(), timeZone?: string): TradingSession | null {\n if (timeZone !== undefined && !isValidTimeZone(timeZone)) return null;\n const hhmm = wallClock(now, timeZone);\n for (const session of sessions) {\n if (hhmm >= session.startTime && hhmm < session.endTime) return session;\n }\n return null;\n}\n\nconst pad2 = (n: number) => String(n).padStart(2, '0');\nconst isoDay = (ms: number) => {\n const d = new Date(ms);\n return `${d.getUTCFullYear()}-${pad2(d.getUTCMonth() + 1)}-${pad2(d.getUTCDate())}`;\n};\nconst THURSDAY = 4;\n/** Vietnam is UTC+7 all year. */\nconst VN_OFFSET_MS = 7 * 3_600_000;\n\n/**\n * The last trading day of the VN30 futures contract of `month` (1–12): the\n * third Thursday, or the trading day before it when that is a holiday\n * (`isHoliday` gets `YYYY-MM-DD`). As `YYYY-MM-DD`.\n */\nexport function vn30fLastTradingDay(year: number, month: number, isHoliday?: (day: string) => boolean): string {\n const first = Date.UTC(year, month - 1, 1);\n const firstThursday = 1 + ((THURSDAY - new Date(first).getUTCDay() + 7) % 7);\n let day = Date.UTC(year, month - 1, firstThursday + 14);\n const closed = (ms: number) => {\n const weekday = new Date(ms).getUTCDay();\n return weekday === 0 || weekday === 6 || (isHoliday?.(isoDay(ms)) ?? false);\n };\n while (closed(day)) day -= DAY_MS;\n return isoDay(day);\n}\n\n/**\n * The VN30 futures contracts listed at `now`: this month's (until its last\n * trading day), the next month's, and the last months of the two quarters\n * after that.\n */\nexport function vn30fContracts(now: number, isHoliday?: (day: string) => boolean): VN30FContract[] {\n const today = isoDay(now + VN_OFFSET_MS);\n const contract = (year: number, month: number): VN30FContract => ({\n symbol: `VN30F${pad2(year % 100)}${pad2(month)}`,\n year,\n month,\n lastTradingDay: vn30fLastTradingDay(year, month, isHoliday),\n });\n const next = (c: VN30FContract) => (c.month === 12 ? contract(c.year + 1, 1) : contract(c.year, c.month + 1));\n\n const vnNow = new Date(now + VN_OFFSET_MS);\n let front = contract(vnNow.getUTCFullYear(), vnNow.getUTCMonth() + 1);\n if (today > front.lastTradingDay) front = next(front);\n const listed = [front, next(front)];\n let candidate = next(listed[1]);\n while (listed.length < 4) {\n if (candidate.month % 3 === 0) listed.push(candidate);\n candidate = next(candidate);\n }\n return listed;\n}\n","/**\n * The TradeCanvas icon set, as in the \"TradeCanvas Icons\" Figma file: a 24 px\n * grid with 2 px padding, 1.75 px strokes with round caps and joins. Drawing\n * tools mark their anchor points (where you click to draw) with filled dots.\n */\nexport interface IconDef {\n /** Stroked path data. */\n d?: string;\n /** Dashed stroke, for guides. */\n dash?: string;\n /** Solid shapes, such as filled candle bodies. */\n fills?: readonly string[];\n /** An area filled at 22%. */\n soft?: string;\n /** Filled dots: [cx, cy, r = 1.75]. */\n dots?: readonly (readonly number[])[];\n}\n\n/** Toolbar, sidebar and panel glyphs. */\nexport const UI_ICONS: Readonly<Record<string, IconDef>> = {\n cursor: { d: 'M6 3.5L18.5 12.5L12.6 13.6L9.7 19.4z' }, // Cursor\n trendingUp: { d: 'M3 17L9 11L13 14.5L21 6.5M15 6.5H21V12.5' }, // Indicators / Long\n trendingDown: { d: 'M3 7L9 13L13 9.5L21 17.5M15 17.5H21V11.5' }, // Short\n minus: { d: 'M5 12H19' }, // Minus\n plus: { d: 'M12 5V19M5 12H19' }, // Plus\n penLine: { d: 'M14.5 5.5L18.5 9.5M4 20L5 15.5L15.8 4.7a2 2 0 0 1 2.83 0l.67.67a2 2 0 0 1 0 2.83L8.5 19z' }, // Draw\n zigzag: { d: 'M3 17L8 9L13 15L21 6' }, // Patterns\n hash: { d: 'M5 9H19M5 15H19M10 4L8.5 20M15.5 4L14 20' }, // Grid\n square: { d: 'M6.5 4.5h11a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2h-11a2 2 0 0 1-2-2v-11a2 2 0 0 1 2-2z' }, // Shape\n gitBranch: { d: 'M6 3V15M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM18 9a9 9 0 0 1-9 9' }, // Branch\n ruler: { d: 'M3.5 16.5L16.5 3.5L20.5 7.5L7.5 20.5zM6.5 13.5L8 15M9.5 10.5L11.5 12.5M12.5 7.5L14 9' }, // Measure\n type: { d: 'M6 6V4.5H18V6M12 4.5V19.5M9.5 19.5H14.5' }, // Text\n magnet: { d: 'M6 4V11a6 6 0 0 0 12 0V4M6 4h3.5v7a2.5 2.5 0 0 0 5 0V4H18M6 8h3.5M14.5 8H18' }, // Magnet\n magnetStrong: { d: 'M6 4V11a6 6 0 0 0 12 0V4M6 4h3.5v7a2.5 2.5 0 0 0 5 0V4H18', fills: ['M6 4h3.5v4H6z', 'M14.5 4H18v4h-3.5z'] }, // Strong magnet\n eraser: { d: 'M8.5 19.5L3.9 14.9a1.5 1.5 0 0 1 0-2.1l8.5-8.5a1.5 1.5 0 0 1 2.1 0l5.2 5.2a1.5 1.5 0 0 1 0 2.1L12 19.5zM8 9l7 7M12 19.5H20' }, // Eraser\n zoomIn: { d: 'M16.5 10.5a6 6 0 1 1-12 0 6 6 0 0 1 12 0zM15 15L20.5 20.5M10.5 7.5V13.5M7.5 10.5H13.5' }, // Zoom area\n undo: { d: 'M9 14L4 9L9 4M4 9H14.5a5.5 5.5 0 0 1 0 11H11' }, // Undo\n redo: { d: 'M15 14L20 9L15 4M20 9H9.5a5.5 5.5 0 0 0 0 11H13' }, // Redo\n trash: { d: 'M4 7H20M9.5 7V4.5h5V7M6.5 7l.8 12.2A1.5 1.5 0 0 0 8.8 20.6h6.4a1.5 1.5 0 0 0 1.5-1.4L17.5 7M10 11v6M14 11v6' }, // Delete\n camera: { d: 'M4.5 7.5h3L9 5h6l1.5 2.5h3A1.5 1.5 0 0 1 21 9v9.5a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 3 18.5V9a1.5 1.5 0 0 1 1.5-1.5zM15.5 13.5a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0z' }, // Screenshot\n settings: { d: 'M4 7H14M18 7H20M4 17H8M12 17H20M18 7a2 2 0 1 1-4 0 2 2 0 0 1 4 0zM12 17a2 2 0 1 1-4 0 2 2 0 0 1 4 0z' }, // Settings\n moon: { d: 'M20 14.5A8 8 0 1 1 9.5 4a6.5 6.5 0 0 0 10.5 10.5z' }, // Dark theme\n sun: { d: 'M16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0zM12 2.5v2M12 19.5v2M4.6 4.6l1.4 1.4M18 18l1.4 1.4M2.5 12h2M19.5 12h2M4.6 19.4L6 18M18 6l1.4-1.4' }, // Light theme\n chevronDown: { d: 'M6 9L12 15L18 9' }, // Expand\n chevronUp: { d: 'M6 15L12 9L18 15' }, // Collapse\n barChart: { d: 'M5 20V13M12 20V5M19 20V10' }, // Chart type\n x: { d: 'M6 6L18 18M18 6L6 18' }, // Close\n play: { d: 'M7 4.5v15L19.5 12z' }, // Play\n pause: { d: 'M8 5V19M16 5V19' }, // Pause\n stop: { d: 'M7.5 6h9A1.5 1.5 0 0 1 18 7.5v9a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 6 16.5v-9A1.5 1.5 0 0 1 7.5 6z' }, // Stop\n receipt: { d: 'M6 3.5h12v17l-2-1.25-2 1.25-2-1.25-2 1.25-2-1.25-2 1.25zM9 8h6M9 12h6M9 16h3' }, // Orders\n bell: { d: 'M6 16.5V11a6 6 0 0 1 12 0v5.5l1.5 2H4.5zM10 20.5a2.2 2.2 0 0 0 4 0' }, // Alerts\n layers: { d: 'M12 3.5L21 8.5L12 13.5L3 8.5zM3 12.5L12 17.5L21 12.5M3 16.5L12 21.5L21 16.5' }, // Objects\n list: { d: 'M9 6.5H20M9 12H20M9 17.5H20', dots: [[4.75, 6.5, 1.25], [4.75, 12, 1.25], [4.75, 17.5, 1.25]] }, // Watchlist\n table: { d: 'M5.5 4.5h13a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2v-11a2 2 0 0 1 2-2zM3.5 9.5H20.5M3.5 14.5H20.5M10 9.5V19.5' }, // Data window\n eye: { d: 'M2.5 12S6 5.5 12 5.5 21.5 12 21.5 12 18 18.5 12 18.5 2.5 12 2.5 12zM15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0z' }, // Show\n eyeOff: { d: 'M4 4L20 20M9.9 5.8A9.6 9.6 0 0 1 12 5.5c6 0 9.5 6.5 9.5 6.5a16 16 0 0 1-2.3 3.1M6.6 7.1C3.9 8.9 2.5 12 2.5 12S6 18.5 12 18.5a9.3 9.3 0 0 0 4.7-1.3M10 10.1a3 3 0 0 0 4 4' }, // Hide\n lock: { d: 'M7 10.5h10a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-6a2 2 0 0 1 2-2zM8 10.5V7.5a4 4 0 0 1 8 0v3' }, // Lock\n unlock: { d: 'M7 10.5h10a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-6a2 2 0 0 1 2-2zM8 10.5V7.5a4 4 0 0 1 7.7-1.5' }, // Unlock\n palette: { d: 'M12 3.5a8.5 8.5 0 0 0 0 17c1.1 0 1.6-.8 1.6-1.6 0-.5-.2-.9-.5-1.2a1.6 1.6 0 0 1 1.2-2.7h1.9a4.3 4.3 0 0 0 4.3-4.3C20.5 6.9 16.7 3.5 12 3.5z', dots: [[7.5, 11.5, 1.25], [9.5, 7.75, 1.25], [14, 7.25, 1.25]] }, // Style\n check: { d: 'M5 12.5L10 17.5L19 7' }, // Done\n maximize: { d: 'M8 4H5a1 1 0 0 0-1 1v3M16 4h3a1 1 0 0 1 1 1v3M20 16v3a1 1 0 0 1-1 1h-3M8 20H5a1 1 0 0 1-1-1v-3' }, // Fullscreen\n minimize: { d: 'M4 8h3a1 1 0 0 0 1-1V4M16 4v3a1 1 0 0 0 1 1h3M20 16h-3a1 1 0 0 0-1 1v3M8 20v-3a1 1 0 0 0-1-1H4' }, // Exit fullscreen\n repeat: { d: 'M17 3.5L20.5 7L17 10.5M3.5 11.5V10a3 3 0 0 1 3-3h14M7 20.5L3.5 17L7 13.5M20.5 12.5V14a3 3 0 0 1-3 3h-14' }, // Stay in drawing mode\n info: { d: 'M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0zM12 11V16.5', dots: [[12, 7.75, 1.25]] }, // Symbol info\n chevronLeft: { d: 'M15 5L8 12L15 19' }, // Scroll left\n chevronRight: { d: 'M9 5L16 12L9 19' }, // Scroll right\n reset: { d: 'M4.5 12a7.5 7.5 0 1 0 2.2-5.3M4.5 4v4.5H9' }, // Reset the view\n calendar: { d: 'M5.5 5h13a2 2 0 0 1 2 2v11.5a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2zM3.5 10H20.5M8 3V7M16 3V7' }, // Go to date\n star: { d: 'M12 3.5L14.6 9L20.5 9.6L16 13.6L17.3 19.5L12 16.5L6.7 19.5L8 13.6L3.5 9.6L9.4 9z' }, // Favourite\n pin: { d: 'M8 3.5h8M9.5 3.5v5.5L5.5 14h13l-4-5v-5.5M12 14v6.5' }, // Pinned\n search: { d: 'M16.5 10.5a6 6 0 1 1-12 0 6 6 0 0 1 12 0zM15 15L20.5 20.5' }, // Search\n enter: { d: 'M19 5v6.5a3 3 0 0 1-3 3H5.5M9.5 10L5 14.5L9.5 19' }, // Enter (select)\n stepBack: { d: 'M6 5v14M18.5 5.5v13L8.5 12z' }, // Replay: one bar back\n stepForward: { d: 'M18 5v14M5.5 5.5v13l10-6.5z' }, // Replay: one bar on\n replayPick: { d: 'M7.5 3.5V7M7.5 17V20.5M6 7h3a1.5 1.5 0 0 1 1.5 1.5v7A1.5 1.5 0 0 1 9 17H6a1.5 1.5 0 0 1-1.5-1.5v-7A1.5 1.5 0 0 1 6 7z', dash: 'M15 3V21', soft: 'M15 4h4.5a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H15z' }, // Replay: pick the start bar (a candle, the cut, the hidden bars)\n ladder: { d: 'M4 6H11M13 6H17M6 10H11M13 10H20M8 14H11M13 14H15M5 18H11M13 18H19' }, // Depth ladder\n save: { d: 'M5.5 3.5h10.5l4.5 4.5v10.5a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2v-13a2 2 0 0 1 2-2zM8 3.5v5h7v-5M7.5 20.5v-6h9v6' }, // Save layout\n folder: { d: 'M3.5 7a2 2 0 0 1 2-2h4l2 2.5h7a2 2 0 0 1 2 2V17a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2z' }, // Open layout\n link: { d: 'M10 14a4 4 0 0 0 5.66 0l3-3a4 4 0 0 0-5.66-5.66l-1.2 1.2M14 10a4 4 0 0 0-5.66 0l-3 3a4 4 0 0 0 5.66 5.66l1.2-1.2' }, // Sync\n arrowUp: { d: 'M12 19V5M6 11L12 5L18 11' }, // Move pane up\n arrowDown: { d: 'M12 5V19M6 13L12 19L18 13' }, // Move pane down\n arrowUpDown: { d: 'M8.5 19V5M5 8.5L8.5 5L12 8.5M15.5 5V19M12 15.5L15.5 19L19 15.5' }, // Reverse a position\n more: { dots: [[6, 12, 1.6], [12, 12, 1.6], [18, 12, 1.6]] }, // More\n copy: { d: 'M9.5 8.5h9a1 1 0 0 1 1 1v9a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1zM15.5 8.5v-3a1 1 0 0 0-1-1h-9a1 1 0 0 0-1 1v9a1 1 0 0 0 1 1h3' }, // Clone\n grip: { dots: [[9, 6, 1.4], [15, 6, 1.4], [9, 12, 1.4], [15, 12, 1.4], [9, 18, 1.4], [15, 18, 1.4]] }, // Drag to reorder\n layoutGrid: { d: 'M5 4.5h4.5a.5.5 0 0 1 .5.5v4.5a.5.5 0 0 1-.5.5H5a.5.5 0 0 1-.5-.5V5a.5.5 0 0 1 .5-.5zM14.5 4.5H19a.5.5 0 0 1 .5.5v4.5a.5.5 0 0 1-.5.5h-4.5a.5.5 0 0 1-.5-.5V5a.5.5 0 0 1 .5-.5zM5 14h4.5a.5.5 0 0 1 .5.5V19a.5.5 0 0 1-.5.5H5a.5.5 0 0 1-.5-.5v-4.5A.5.5 0 0 1 5 14zM14.5 14H19a.5.5 0 0 1 .5.5V19a.5.5 0 0 1-.5.5h-4.5a.5.5 0 0 1-.5-.5v-4.5a.5.5 0 0 1 .5-.5z' }, // Chart layout\n};\n\n/** One per drawing tool, keyed by tool type. */\nexport const DRAWING_TOOL_ICONS: Readonly<Record<string, IconDef>> = {\n trendLine: { d: 'M5 18L19 6', dots: [[5, 18], [19, 6]] }, // Trend Line\n ray: { d: 'M5 17L21 5M17.5 4.81L21 5L20.2 8.41', dots: [[5, 17], [11, 12.5]] }, // Ray\n extendedLine: { d: 'M3 18.5L21 5M17.5 4.81L21 5L20.2 8.41M6.5 18.69L3 18.5L3.8 15.09', dots: [[9, 14], [15, 9.5]] }, // Extended Line\n infoLine: { d: 'M5 20L19 10M4.5 3.5h9a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1zM6.5 6.5h5', dots: [[5, 20], [19, 10]] }, // Info Line\n trendAngle: { d: 'M5 18L19 7M5 18H20M11 18A6 6 0 0 0 9.71 14.29', dots: [[5, 18], [19, 7]] }, // Trend Angle\n horizontalLine: { d: 'M3 12H21', dots: [[12, 12]] }, // Horizontal Line\n horizontalRay: { d: 'M7 12H21M18.5 9.5L21 12L18.5 14.5', dots: [[7, 12]] }, // Horizontal Ray\n verticalLine: { d: 'M12 3V21', dots: [[12, 12]] }, // Vertical Line\n crossLine: { d: 'M3 12H21M12 3V21', dots: [[12, 12]] }, // Cross Line\n parallelChannel: { d: 'M3 15L15 5M9 19L21 9', dots: [[3, 15], [15, 5], [9, 19]] }, // Parallel Channel\n regressionChannel: { d: 'M3 12L21 4M3 20L21 12', dash: 'M3 16L21 8', dots: [[3, 16], [21, 8]] }, // Regression Channel\n fibRetracement: { d: 'M3 4H21M3 9H21M3 13H21M3 20H21', dots: [[5, 20], [19, 4]] }, // Fib Retracement\n fibExtension: { d: 'M3 20L8 10L12 16M14 4H21M14 8H21M14 12H21', dots: [[3, 20], [8, 10], [12, 16]] }, // Fib Extension\n fibChannel: { d: 'M3 9L21 3M3 13L21 7M3 16L21 10M3 21L21 15', dots: [[3, 21], [21, 15], [3, 9]] }, // Fib Channel\n fibTimeZones: { d: 'M3 4V20M6 4V20M9.5 4V20M14 4V20M20.5 4V20', dots: [[3, 20], [6, 20]] }, // Fib Time Zones\n fibSpeedResistanceFan: { d: 'M4 20L20 4M4 20L20 11M4 20L20 16M4 20L11 4', dash: 'M4 4H20V20', dots: [[4, 20], [20, 4]] }, // Fib Speed Resistance Fan\n rectangle: { d: 'M5.5 6h13A1.5 1.5 0 0 1 20 7.5v9a1.5 1.5 0 0 1-1.5 1.5h-13A1.5 1.5 0 0 1 4 16.5v-9A1.5 1.5 0 0 1 5.5 6z', dots: [[4, 6], [20, 18]] }, // Rectangle\n circle: { d: 'M19.5 12a7.5 7.5 0 1 1-15 0 7.5 7.5 0 0 1 15 0z', dots: [[12, 12], [19.5, 12]] }, // Circle\n ellipse: { d: 'M20.5 12c0 3-3.8 5.5-8.5 5.5S3.5 15 3.5 12 7.3 6.5 12 6.5s8.5 2.5 8.5 5.5z', dots: [[3.5, 12], [20.5, 12]] }, // Ellipse\n triangle: { d: 'M12 4.5L20 19H4z', dots: [[12, 4.5], [20, 19], [4, 19]] }, // Triangle\n pitchfork: { d: 'M4 20L16.75 3M7 9L11.5 3M13 15L21 4.33M7 9L13 15', dots: [[4, 20], [7, 9], [13, 15]] }, // Pitchfork\n schiffPitchfork: { d: 'M4 14.5L21 7.42M7 9L21 3.17M13 15L21 11.67M7 9L13 15', dash: 'M4 20V14.5', dots: [[4, 14.5], [7, 9], [13, 15]] }, // Schiff Pitchfork\n modifiedSchiffPitchfork: { d: 'M5.5 14.5L21 5.89M7 9L17.8 3M13 15L21 10.56M7 9L13 15', dash: 'M4 20L5.5 14.5', dots: [[5.5, 14.5], [7, 9], [13, 15]] }, // Modified Schiff Pitchfork\n gannFan: { d: 'M4 20L20 4M4 20L20 12M4 20L12 4M4 20L20 16.5M4 20L7.5 4', dots: [[4, 20], [20, 4]] }, // Gann Fan\n gannBox: { d: 'M4 4H20V20H4zM4 20L20 4M4 4L20 20M12 4V20', dots: [[4, 20], [20, 4]] }, // Gann Box\n cyclicLines: { d: 'M4 4V20M9 4V20M14 4V20M19 4V20', dots: [[4, 20], [9, 20]] }, // Cyclic Lines\n xabcdPattern: { d: 'M3 18L7 6L11 13L15 8L21 19', dash: 'M3 18L11 13L21 19', dots: [[3, 18], [7, 6], [11, 13], [15, 8], [21, 19]] }, // XABCD Pattern\n abcdPattern: { d: 'M4 19L9 8L13 14L20 4', dots: [[4, 19], [9, 8], [13, 14], [20, 4]] }, // ABCD Pattern\n headAndShoulders: { d: 'M3 19L6 11L8.5 15L12 5L15.5 15L18 11L21 19', dash: 'M4.5 15H19.5', dots: [[6, 11], [12, 5], [18, 11]] }, // Head and Shoulders\n elliottWave: { d: 'M3 19L6 13L8.5 16L14 6L16 10L21 4', dots: [[3, 19], [21, 4]] }, // Elliott Wave\n priceRange: { d: 'M5 4H19M5 20H19M12 6.5V17.5M9 9.5L12 6.5L15 9.5M9 14.5L12 17.5L15 14.5' }, // Price Range\n dateRange: { d: 'M4 5V19M20 5V19M6.5 12H17.5M9.5 9L6.5 12L9.5 15M14.5 9L17.5 12L14.5 15' }, // Date Range\n dateAndPriceRange: { d: 'M6 18V4M3 7L6 4L9 7M6 18H20M17 15L20 18L17 21', dash: 'M6 4H20V18' }, // Date and Price Range\n measure: { d: 'M3.5 16.5L16.5 3.5L20.5 7.5L7.5 20.5zM6.5 13.5L8 15M9.5 10.5L11.5 12.5M12.5 7.5L14 9' }, // Measure\n text: { d: 'M6 6V4.5H18V6M12 4.5V19.5M9.5 19.5H14.5' }, // Text\n priceLabel: { d: 'M9 5H19a1.5 1.5 0 0 1 1.5 1.5v11A1.5 1.5 0 0 1 19 19H9L3.5 12zM11 12H17' }, // Price Label\n arrow: { d: 'M5 19L19 5M10 5H19V14' }, // Arrow\n riskReward: { d: 'M5 12V4H19V12M3 12H21', dash: 'M5 12V18H19V12', dots: [[5, 12]] }, // Long/Short Position\n anchoredVWAP: { d: 'M4 18C9 17 12 10 20 7M4 20.5V18', dots: [[4, 18]] }, // Anchored VWAP\n volumeProfileRange: { d: 'M6 7H12M6 10.5H17M6 14H15M6 17.5H10', dash: 'M3.5 4V20M20.5 4V20', dots: [[3.5, 20], [20.5, 20]] }, // Fixed Range Volume Profile\n note: { d: 'M5.5 4.5h13v9l-5 5h-8zM13.5 18.5v-5h5M8.5 8.5h7M8.5 11.5h4' }, // Note\n callout: { d: 'M10.5 4h9a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1zM12 12L5 19M12.5 8h5', dots: [[5, 19]] }, // Callout\n flag: { d: 'M6 21V4M6 4.5h11l-2.5 3.75L17 12H6', soft: 'M6 4.5h11l-2.5 3.75L17 12H6z', dots: [[6, 21]] }, // Flag Mark\n arrowMark: { d: 'M12 4L18 11H14.5V20H9.5V11H6z' }, // Arrow Mark\n icon: { d: 'M12 3.5l2.6 5.3 5.9.85-4.25 4.15 1 5.85L12 16.9l-5.25 2.75 1-5.85L3.5 9.65l5.9-.85z' }, // Icon\n signpost: { d: 'M12 20.5V11M5.5 4.5h13v6.5h-13zM8.5 7.75h7', dots: [[12, 20.5]] }, // Signpost\n balloon: { d: 'M5 4.5h14a1.5 1.5 0 0 1 1.5 1.5v8a1.5 1.5 0 0 1-1.5 1.5h-5.5L12 20l-1.5-4.5H5A1.5 1.5 0 0 1 3.5 14V6A1.5 1.5 0 0 1 5 4.5zM8 9h8M8 12h5' }, // Balloon\n anchoredText: { d: 'M8 8.5h8M12 8.5v8M3.5 7.5v-4h4M20.5 16.5v4h-4' }, // Anchored Text\n anchoredNote: { d: 'M7 7h10v6.5l-3.5 3.5H7zM13.5 17v-3.5H17M3.5 7.5v-4h4M20.5 16.5v4h-4' }, // Anchored Note\n brush: { d: 'M3.5 17c2.5 0 3-5 6-5s2.5 5 5.5 5 3.5-6 5.5-9' }, // Brush\n highlighter: { d: 'M14.5 4.5l5 5L11 18H6v-5zM12 7l5 5M4 21h8' }, // Highlighter\n path: { d: 'M4 18L9 10L14 14L20 6M16.2 6.6L20 6L19.6 9.8', dots: [[4, 18], [9, 10], [14, 14]] }, // Path\n polyline: { d: 'M5 17L8 6L16 4L20 14L12 20z', soft: 'M5 17L8 6L16 4L20 14L12 20z', dots: [[5, 17], [8, 6], [16, 4], [20, 14], [12, 20]] }, // Polyline\n curve: { d: 'M4 18C8 4 16 4 20 18', dots: [[4, 18], [20, 18], [12, 7.5]] }, // Curve\n arc: { d: 'M4 17a8 8 0 0 1 16 0', dots: [[4, 17], [20, 17], [12, 9]] }, // Arc\n fibCircles: { d: 'M14 12a2 2 0 1 1-4 0 2 2 0 0 1 4 0zM16.5 12a4.5 4.5 0 1 1-9 0 4.5 4.5 0 0 1 9 0zM20 12a8 8 0 1 1-16 0 8 8 0 0 1 16 0z', dots: [[12, 12], [20, 12]] }, // Fib Circles\n fibSpiral: { d: 'M12 12a1.5 1.5 0 0 1 1.5 1.5 3 3 0 0 1-3 3A4.5 4.5 0 0 1 6 12a6 6 0 0 1 6-6 8 8 0 0 1 8 8', dots: [[12, 12]] }, // Fib Spiral\n fibArcs: { d: 'M10 20a6 6 0 0 0-6-6M14 20a10 10 0 0 0-10-10M18 20a14 14 0 0 0-14-14', dash: 'M4 20L18 6', dots: [[4, 20], [18, 6]] }, // Fib Speed Resistance Arcs\n fibWedge: { d: 'M4 19L20 7M4 19L20 16M10.4 14.2A8 8 0 0 1 11.86 17.53M14.4 11.2A13 13 0 0 1 16.78 16.6', dots: [[4, 19], [20, 7], [20, 16]] }, // Fib Wedge\n pitchfan: { d: 'M4 20L14 4M4 20L20 14M4 20L17 9', dash: 'M14 4L20 14', dots: [[4, 20], [14, 4], [20, 14]] }, // Pitchfan\n gannSquare: { d: 'M4 4H20V20H4zM4 20L20 4M4 12H20M12 4V20M4 12a8 8 0 0 1 8 8', dots: [[4, 20], [20, 4]] }, // Gann Square\n elliottImpulse: { d: 'M3 19L7 12L10 15L15 5L17.5 9L21 3', dots: [[3, 19], [21, 3]] }, // Elliott Impulse Wave\n elliottCorrection: { d: 'M4 5L10 17L14 11L20 20', dots: [[4, 5], [20, 20]] }, // Elliott Correction Wave\n elliottTriangle: { d: 'M3 6L7 17L11 9L15 15L18 11L21 13', dots: [[3, 6], [21, 13]] }, // Elliott Triangle Wave\n elliottDoubleCombo: { d: 'M4 5L9 14L13 9L20 19', dots: [[4, 5], [9, 14], [13, 9], [20, 19]] }, // Elliott Double Combo Wave\n elliottTripleCombo: { d: 'M3 5L7 13L10 9L14 16L17 12L21 20', dots: [[3, 5], [21, 20]] }, // Elliott Triple Combo Wave\n threeDrives: { d: 'M3 20L7 12L9.5 15L14 7L16.5 10L21 3', dash: 'M7 12L14 7L21 3', dots: [[7, 12], [14, 7], [21, 3]] }, // Three Drives Pattern\n cypherPattern: { d: 'M3 19L7 9L10 14L15 5L20 16', dash: 'M3 19L10 14L20 16', dots: [[3, 19], [7, 9], [10, 14], [15, 5], [20, 16]] }, // Cypher Pattern\n timeCycles: { d: 'M3 18a4.5 4.5 0 0 1 9 0a4.5 4.5 0 0 1 9 0', dots: [[3, 18], [12, 18]] }, // Time Cycles\n sineLine: { d: 'M3 12C5 5 7.5 5 9 12S13 19 15 12 19.5 5 21 12', dots: [[6, 6.75], [12, 17.25]] }, // Sine Line\n forecast: { d: 'M4 18L15.2 7.8M19.5 6a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0z', dots: [[4, 18]] }, // Forecast\n projection: { d: 'M12 19L18 11M15.2 11.3L18 11L17.8 13.8', dash: 'M3 17L9 9', dots: [[3, 17], [9, 9], [12, 19]] }, // Projection\n barsPattern: { d: 'M5 6V14M9 9V18M15 4V12M19 7V16', fills: ['M4 8h2v4H4z', 'M8 11h2v5H8z', 'M14 6h2v4h-2z', 'M18 9h2v5h-2z'], dash: 'M12 3V21' }, // Bars Pattern\n};\n\n/** One per chart type, keyed by chart type. */\nexport const CHART_TYPE_ICONS: Readonly<Record<string, IconDef>> = {\n candlestick: { d: 'M8 3.5V7M8 16V20.5M16 5V8.5M16 15.5V19', fills: ['M6.5 7h3a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1z', 'M14.5 8.5h3a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1z'] }, // Candlestick\n hollowCandle: { d: 'M8 3.5V7M8 16V20.5M16 5V8.5M16 15.5V19M6.5 7h3a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1zM14.5 8.5h3a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1z' }, // Hollow Candle\n heikinAshi: { d: 'M5.5 9.5V12M5.5 18V20M12 5.5V8M12 14V16M18.5 3V4.5M18.5 10.5V12.5', fills: ['M4 12h3a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5H4a.5.5 0 0 1-.5-.5v-5A.5.5 0 0 1 4 12z', 'M10.5 8h3a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-5a.5.5 0 0 1 .5-.5z', 'M17 4.5h3a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5V5a.5.5 0 0 1 .5-.5z'] }, // Heikin-Ashi\n bar: { d: 'M8 4V20M5 8H8M8 16H11M16 6V18M13 15H16M16 9H19' }, // Bar (OHLC)\n volumeCandles: { d: 'M6.5 5V8M6.5 16V19M15.5 3.5V6M15.5 16V20', fills: ['M5.5 8h2a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-7a.5.5 0 0 1 .5-.5z', 'M11.5 6h8a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-8a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5z'] }, // Volume Candles\n equivolume: { d: 'M4.5 10h2a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-6a1 1 0 0 1 1-1zM10 6h5a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zM18.5 4h1a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-1a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z' }, // Equivolume\n line: { d: 'M3 17L8 11L12 14L21 5' }, // Line\n area: { d: 'M3 17L8 11L12 14L21 5', soft: 'M3 17L8 11L12 14L21 5V20H3z' }, // Area\n baseline: { d: 'M3 16L7 9L11 14L15 7L21 15', dash: 'M3 12H21' }, // Baseline\n hlcArea: { d: 'M3 9L8 6L13 9L21 4M3 15L8 13L13 16L21 11', dash: 'M3 12L8 9.5L13 12.5L21 7.5', soft: 'M3 9L8 6L13 9L21 4V11L13 16L8 13L3 15z' }, // HLC Area\n stepLine: { d: 'M3 18H8V12H12V15H16V7H21' }, // Step Line\n lineWithMarkers: { d: 'M4 17L9 10L14 14L20 6', dots: [[4, 17], [9, 10], [14, 14], [20, 6]] }, // Line with Markers\n hiLo: { d: 'M6 7V17M12 4V14M18 9V20', fills: ['M5 7h2v10H5z', 'M11 4h2v10h-2z', 'M17 9h2v11h-2z'] }, // High-Low\n renko: { d: 'M3.5 15.5h4v4h-4zM7.5 11.5h4v4h-4zM11.5 7.5h4v4h-4zM15.5 11.5h4v4h-4z' }, // Renko\n lineBreak: { d: 'M4 14h4v5H4zM8 10h4v4H8zM16 9h4v8h-4z', fills: ['M12 5h4v5h-4z'] }, // Line Break\n kagi: { d: 'M4 19V11H9V16H14V5H20V13' }, // Kagi\n pointAndFigure: { d: 'M5.5 5.5l3 3M8.5 5.5l-3 3M5.5 10.5l3 3M8.5 10.5l-3 3M5.5 15.5l3 3M8.5 15.5l-3 3M14.5 9a1.5 1.5 0 1 0 3 0a1.5 1.5 0 1 0-3 0M14.5 14a1.5 1.5 0 1 0 3 0a1.5 1.5 0 1 0-3 0' }, // Point & Figure\n rangeBars: { d: 'M6.5 11V12M6.5 18V19M12 7V8M12 14V15M17.5 3.5V4.5M17.5 10.5V11.5', fills: ['M5 12h3v6H5z', 'M10.5 8h3v6h-3z', 'M16 4.5h3v6h-3z'] }, // Range Bars\n};\n\nexport const ICON_DOT_RADIUS = 1.75;\nexport const ICON_SOFT_OPACITY = 0.22;\nconst markupCache = new WeakMap<IconDef, string>();\n\n/** The icon's SVG elements, drawn in `currentColor`. */\nfunction markup(icon: IconDef): string {\n const cached = markupCache.get(icon);\n if (cached) return cached;\n let s = '';\n if (icon.soft) s += `<path d=\"${icon.soft}\" fill=\"currentColor\" fill-opacity=\"${ICON_SOFT_OPACITY}\" stroke=\"none\"/>`;\n for (const f of icon.fills ?? []) s += `<path d=\"${f}\" fill=\"currentColor\" stroke=\"none\"/>`;\n if (icon.d) s += `<path d=\"${icon.d}\"/>`;\n if (icon.dash) s += `<path d=\"${icon.dash}\" stroke-dasharray=\"2 2.5\"/>`;\n for (const [cx, cy, r = ICON_DOT_RADIUS] of icon.dots ?? []) s += `<circle cx=\"${cx}\" cy=\"${cy}\" r=\"${r}\" fill=\"currentColor\" stroke=\"none\"/>`;\n markupCache.set(icon, s);\n return s;\n}\n\n/** The icon as an inline SVG string at `size` px, coloured by `currentColor`. */\nexport function iconSvg(icon: IconDef, size: number): string {\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${size}\" height=\"${size}\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.75\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\">${markup(icon)}</svg>`;\n}\n"],"mappings":"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"}
|