@tradecanvas/commons 1.2.0 → 1.4.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/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/types/rendering.ts","../src/types/drawing.ts","../src/types/trading.ts","../src/types/signal.ts","../src/types/realtime.ts","../src/utils/math.ts","../src/utils/data.ts","../src/utils/color.ts","../src/utils/time.ts","../src/utils/precision.ts","../src/constants/defaults.ts","../src/constants/themes.ts","../src/i18n/en.ts","../src/i18n/vi.ts","../src/i18n/index.ts","../src/market/presets.ts"],"sourcesContent":["export interface Point {\r\n x: number;\r\n y: number;\r\n}\r\n\r\nexport interface Size {\r\n width: number;\r\n height: number;\r\n}\r\n\r\nexport interface Rect {\r\n x: number;\r\n y: number;\r\n width: number;\r\n height: number;\r\n}\r\n\r\nexport type PriceScaleMode = 'regular' | 'logarithmic' | 'percentage' | 'indexedTo100';\r\n\r\nexport interface ViewportState {\r\n visibleRange: { from: number; to: number };\r\n priceRange: { min: number; max: number };\r\n barWidth: number;\r\n barSpacing: number;\r\n offset: number;\r\n chartRect: Rect;\r\n /**\r\n * Logarithmic price geometry. Kept for back-compat; mirrors\r\n * `scaleMode === 'logarithmic'`. Prefer reading `scaleMode`.\r\n */\r\n logScale?: boolean;\r\n /**\r\n * Price-scale presentation. `regular`, `percentage`, and `indexedTo100` share\r\n * the same linear geometry — only the axis labels differ (rebased to\r\n * `scaleBaseline`). `logarithmic` changes the geometry. Defaults to\r\n * `regular` when unset.\r\n */\r\n scaleMode?: PriceScaleMode;\r\n /**\r\n * Reference price for `percentage` / `indexedTo100` axis labels — usually the\r\n * close of the first visible bar. Set by the chart each frame.\r\n */\r\n scaleBaseline?: number;\r\n /**\r\n * Optional reference to the current bar series. When set, drawings/indicators\r\n * treat `anchor.time` as a real timestamp and convert to bar index via\r\n * `timestampToBarIndex(time, data)` at render/hit-test time. This lets\r\n * anchors survive timeframe / symbol switches like TradingView. When unset,\r\n * `anchor.time` is treated as a raw bar index (legacy behavior).\r\n */\r\n data?: ReadonlyArray<{ time: number }>;\r\n /**\r\n * Width of the price axis strip right of `chartRect`, in CSS pixels. The\r\n * chart widens it to fit long labels (sub-cent prices); renderers drawing\r\n * badges on the axis size them to it. Defaults to `PRICE_AXIS_WIDTH`.\r\n */\r\n priceAxisWidth?: number;\r\n}\r\n\r\nexport enum LayerType {\r\n Background = 0,\r\n Main = 1,\r\n Panel = 2,\r\n Overlay = 3,\r\n UI = 4,\r\n}\r\n","import type { Point, ViewportState } from './rendering.js';\r\n\r\nexport type DrawingToolType =\r\n | 'trendLine' | 'horizontalLine' | 'horizontalRay' | 'verticalLine' | 'ray' | 'extendedLine'\r\n | 'crossLine' | 'trendAngle' | 'infoLine'\r\n | 'parallelChannel' | 'regressionChannel'\r\n | 'fibRetracement' | 'fibExtension' | 'fibTimeZones' | 'fibChannel' | 'fibSpeedResistanceFan'\r\n | 'rectangle' | 'ellipse' | 'triangle' | 'circle'\r\n | 'pitchfork' | 'schiffPitchfork' | 'modifiedSchiffPitchfork' | 'elliottWave'\r\n | 'xabcdPattern' | 'abcdPattern' | 'headAndShoulders'\r\n | 'priceRange' | 'dateRange' | 'dateAndPriceRange' | 'measure'\r\n | 'text' | 'arrow' | 'priceLabel'\r\n | 'gannFan' | 'gannBox' | 'cyclicLines'\r\n | 'anchoredVWAP'\r\n | 'volumeProfileRange'\r\n | 'riskReward';\r\n\r\nexport interface AnchorPoint {\r\n time: number;\r\n price: number;\r\n}\r\n\r\nexport interface DrawingStyle {\r\n color: string;\r\n lineWidth: number;\r\n lineStyle: 'solid' | 'dashed' | 'dotted';\r\n fillColor?: string;\r\n fillOpacity?: number;\r\n fontSize?: number;\r\n text?: string;\r\n}\r\n\r\nexport interface DrawingState {\r\n id: string;\r\n type: DrawingToolType;\r\n anchors: AnchorPoint[];\r\n style: DrawingStyle;\r\n visible: boolean;\r\n locked: boolean;\r\n meta?: Record<string, unknown>;\r\n}\r\n\r\nexport interface DrawingDescriptor {\r\n type: DrawingToolType;\r\n name: string;\r\n requiredAnchors: number;\r\n singleClick?: boolean;\r\n}\r\n\r\nexport interface DrawingPlugin {\r\n descriptor: DrawingDescriptor;\r\n render(\r\n ctx: CanvasRenderingContext2D,\r\n state: DrawingState,\r\n viewport: ViewportState,\r\n selected: boolean,\r\n ): void;\r\n hitTest(\r\n point: Point,\r\n state: DrawingState,\r\n viewport: ViewportState,\r\n tolerance: number,\r\n ): boolean;\r\n hitTestAnchor(\r\n point: Point,\r\n state: DrawingState,\r\n viewport: ViewportState,\r\n tolerance: number,\r\n ): number;\r\n}\r\n\r\nexport const DEFAULT_DRAWING_STYLE: DrawingStyle = {\r\n color: '#2196F3',\r\n lineWidth: 1,\r\n lineStyle: 'solid',\r\n fillColor: 'rgba(33, 150, 243, 0.1)',\r\n fillOpacity: 0.1,\r\n fontSize: 12,\r\n};\r\n","export type OrderSide = 'buy' | 'sell';\r\nexport type OrderType = 'market' | 'limit' | 'stop' | 'stopLimit';\r\nexport type OrderStatus = 'pending' | 'filled' | 'cancelled' | 'rejected';\r\nexport type OrderLabel = 'LIMIT' | 'STOP' | 'SL' | 'TP' | 'STOP LIMIT';\r\n\r\nexport interface TradingOrder {\r\n id: string;\r\n side: OrderSide;\r\n type: OrderType;\r\n price: number;\r\n stopPrice?: number;\r\n quantity: number;\r\n label?: OrderLabel;\r\n draggable?: boolean;\r\n meta?: Record<string, unknown>;\r\n}\r\n\r\nexport interface TradingPosition {\r\n id: string;\r\n side: OrderSide;\r\n entryPrice: number;\r\n quantity: number;\r\n /** Quantity already closed (for partial-close visualization). 0 ≤ closedQuantity ≤ quantity. */\r\n closedQuantity?: number;\r\n stopLoss?: number;\r\n takeProfit?: number;\r\n meta?: Record<string, unknown>;\r\n}\r\n\r\n/** Threshold-based P&L color stop. Sorted ascending by `pnl` is recommended. */\r\nexport interface PnLThreshold {\r\n /** Inclusive lower bound. Use -Infinity for the bottom-most stop. */\r\n pnl: number;\r\n color: string;\r\n}\r\n\r\n/** Tokens passed to position label templates. */\r\nexport interface PositionLabelContext {\r\n side: OrderSide;\r\n quantity: number;\r\n closedQuantity: number;\r\n openQuantity: number;\r\n entryPrice: number;\r\n currentPrice: number;\r\n pnl: number;\r\n pnlPct: number;\r\n precision: number;\r\n}\r\n\r\nexport interface DepthLevel {\r\n price: number;\r\n volume: number;\r\n}\r\n\r\nexport interface DepthData {\r\n bids: DepthLevel[];\r\n asks: DepthLevel[];\r\n}\r\n\r\nexport interface TradingConfig {\r\n enabled: boolean;\r\n orderColors?: { buy?: string; sell?: string };\r\n positionColors?: { profit?: string; loss?: string; entry?: string };\r\n /**\r\n * Optional gradient of colors keyed to P&L value. When provided, the rendered\r\n * position zone uses the color of the highest threshold whose `pnl` ≤ live P&L.\r\n * Falls back to `positionColors.profit`/`.loss` when unset.\r\n */\r\n pnlThresholds?: PnLThreshold[];\r\n /**\r\n * Position P&L label template. Supports tokens: {side} {qty} {closedQty}\r\n * {openQty} {entry} {price} {pnl} {pnlPct} {pnlSign}. Pass a function for\r\n * full control. Default: `{side} {qty} | P&L: {pnlSign}{pnl}`.\r\n */\r\n positionLabel?: string | ((ctx: PositionLabelContext) => string);\r\n depthOverlay?: {\r\n enabled?: boolean;\r\n bidColor?: string;\r\n askColor?: string;\r\n maxWidth?: number;\r\n };\r\n contextMenu?: { enabled?: boolean };\r\n pricePrecision?: number;\r\n dragThreshold?: number;\r\n}\r\n\r\nexport interface OrderPlaceIntent {\r\n side: OrderSide;\r\n type: OrderType;\r\n price: number;\r\n stopPrice?: number;\r\n quantity?: number;\r\n}\r\n\r\nexport interface OrderModifyIntent {\r\n orderId: string;\r\n newPrice: number;\r\n /** The price before the change, when known (e.g. from a drag). Optional so\r\n * the chart's `orderModify` event payload routes straight to an adapter. */\r\n previousPrice?: number;\r\n}\r\n\r\nexport interface OrderCancelIntent {\r\n orderId: string;\r\n}\r\n\r\nexport interface PositionModifyIntent {\r\n positionId: string;\r\n stopLoss?: number;\r\n takeProfit?: number;\r\n}\r\n\r\nexport interface PositionCloseIntent {\r\n positionId: string;\r\n}\r\n\r\nexport const DEFAULT_TRADING_CONFIG: TradingConfig = {\r\n enabled: true,\r\n orderColors: { buy: '#26A69A', sell: '#EF5350' },\r\n positionColors: { profit: '#26A69A', loss: '#EF5350', entry: '#2196F3' },\r\n depthOverlay: { enabled: false, bidColor: 'rgba(38,166,154,0.15)', askColor: 'rgba(239,83,80,0.15)', maxWidth: 100 },\r\n contextMenu: { enabled: true },\r\n pricePrecision: 2,\r\n dragThreshold: 3,\r\n};\r\n","export type SignalDirection = 'long' | 'short' | 'neutral';\r\n\r\nexport interface SignalMarker {\r\n id: string;\r\n time: number;\r\n price: number;\r\n direction: SignalDirection;\r\n confidence: number;\r\n source: string;\r\n label?: string;\r\n color?: string;\r\n meta?: Record<string, unknown>;\r\n}\r\n\r\nexport interface SignalMarkerStyle {\r\n longColor?: string;\r\n shortColor?: string;\r\n neutralColor?: string;\r\n arrowSize?: number;\r\n showLabel?: boolean;\r\n showConfidence?: boolean;\r\n sourceColors?: Record<string, string>;\r\n}\r\n\r\nexport const DEFAULT_SIGNAL_STYLE: SignalMarkerStyle = {\r\n longColor: '#26A69A',\r\n shortColor: '#EF5350',\r\n neutralColor: '#9E9E9E',\r\n arrowSize: 12,\r\n showLabel: true,\r\n showConfidence: true,\r\n};\r\n\r\nexport type TradeZoneDirection = 'long' | 'short';\r\n\r\nexport interface TradeZone {\r\n id: string;\r\n entryTime: number;\r\n entryPrice: number;\r\n exitTime?: number;\r\n exitPrice?: number;\r\n direction: TradeZoneDirection;\r\n pnl?: number;\r\n pnlPercent?: number;\r\n label?: string;\r\n meta?: Record<string, unknown>;\r\n}\r\n\r\nexport interface TradeZoneStyle {\r\n profitColor?: string;\r\n lossColor?: string;\r\n activeColor?: string;\r\n fillOpacity?: number;\r\n borderWidth?: number;\r\n showLabel?: boolean;\r\n showPnl?: boolean;\r\n}\r\n\r\nexport const DEFAULT_TRADE_ZONE_STYLE: TradeZoneStyle = {\r\n profitColor: '#26A69A',\r\n lossColor: '#EF5350',\r\n activeColor: '#2196F3',\r\n fillOpacity: 0.12,\r\n borderWidth: 1,\r\n showLabel: true,\r\n showPnl: true,\r\n};\r\n","import type { OHLCBar, TimeFrame } from './ohlc.js';\r\n\r\n// --- Connection ---\r\n\r\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';\r\n\r\nexport interface ConnectionInfo {\r\n state: ConnectionState;\r\n latency?: number;\r\n reconnectAttempt?: number;\r\n lastMessageTime?: number;\r\n error?: string;\r\n}\r\n\r\n// --- Ticks & Trades ---\r\n\r\nexport interface RawTick {\r\n time: number;\r\n price: number;\r\n volume: number;\r\n side?: 'buy' | 'sell';\r\n}\r\n\r\nexport interface AggregatedBar extends OHLCBar {\r\n closed: boolean; // true when bar is finalized\r\n tickCount: number; // number of ticks in this bar\r\n}\r\n\r\n// --- Data Adapter (Strategy Pattern) ---\r\n\r\nexport interface DataAdapterConfig {\r\n symbol: string;\r\n timeframe: TimeFrame;\r\n reconnect?: boolean; // default: true\r\n reconnectMaxRetries?: number; // default: Infinity\r\n reconnectBaseDelay?: number; // ms, default: 1000\r\n reconnectMaxDelay?: number; // ms, default: 30000\r\n heartbeatInterval?: number; // ms, default: 30000\r\n bufferSize?: number; // max ticks to buffer, default: 1000\r\n}\r\n\r\nexport type DataAdapterEventType =\r\n | 'tick'\r\n | 'bar'\r\n | 'barClose'\r\n | 'snapshot' // initial historical data loaded\r\n | 'connectionChange'\r\n | 'error';\r\n\r\nexport interface DataAdapterEvent<T = unknown> {\r\n type: DataAdapterEventType;\r\n data: T;\r\n timestamp: number;\r\n}\r\n\r\nexport type DataAdapterListener<T = unknown> = (event: DataAdapterEvent<T>) => void;\r\n\r\n/**\r\n * Data adapter interface. Implements the observer pattern:\r\n * - connect() to start receiving data\r\n * - on('bar'|'tick'|'connectionChange', handler) to receive events\r\n * - disconnect() to stop, then connect() again to switch symbols/timeframes\r\n * - No separate subscribe/unsubscribe — reconnect is the intended pattern\r\n *\r\n * Strategy pattern for pluggable data sources.\r\n * Implementations handle the specifics of each data source (WebSocket, REST,\r\n * SSE, etc.) while the StreamManager orchestrates lifecycle and aggregation.\r\n *\r\n * Built-in: BinanceAdapter\r\n * Implement this for: custom exchange APIs, broker feeds, mock data\r\n */\r\nexport interface DataAdapter {\r\n readonly name: string;\r\n\r\n connect(config: DataAdapterConfig): void;\r\n disconnect(): void;\r\n getConnectionState(): ConnectionState;\r\n\r\n /**\r\n * Load historical bars. Called once on connect, before streaming starts.\r\n * Returns bars sorted by time ascending.\r\n */\r\n fetchHistory(symbol: string, timeframe: TimeFrame, limit?: number): Promise<OHLCBar[]>;\r\n\r\n on<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\r\n off<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\r\n\r\n dispose(): void;\r\n}\r\n\r\n// --- Stream Manager Config ---\r\n\r\nexport interface StreamConfig {\r\n adapter: DataAdapter;\r\n symbol: string;\r\n timeframe: TimeFrame;\r\n historyLimit?: number; // bars to load initially, default: 500\r\n autoScroll?: boolean; // scroll to end on new bar, default: true\r\n showCurrentPriceLine?: boolean; // default: true\r\n aggregateTicks?: boolean; // build bars from ticks, default: false\r\n reconnect?: ReconnectConfig;\r\n}\r\n\r\nexport interface ReconnectConfig {\r\n enabled: boolean; // default: true\r\n maxRetries: number; // default: Infinity\r\n baseDelay: number; // ms, default: 1000\r\n maxDelay: number; // ms, default: 30000\r\n backoffMultiplier: number; // default: 2\r\n}\r\n\r\nexport const DEFAULT_RECONNECT: ReconnectConfig = {\r\n enabled: true,\r\n maxRetries: Infinity,\r\n baseDelay: 1000,\r\n maxDelay: 30000,\r\n backoffMultiplier: 2,\r\n};\r\n\r\nexport const DEFAULT_STREAM_CONFIG: Partial<StreamConfig> = {\r\n historyLimit: 500,\r\n autoScroll: true,\r\n showCurrentPriceLine: true,\r\n aggregateTicks: false,\r\n};\r\n","export function clamp(value: number, min: number, max: number): number {\r\n return Math.max(min, Math.min(max, value));\r\n}\r\n\r\nexport function lerp(a: number, b: number, t: number): number {\r\n return a + (b - a) * t;\r\n}\r\n\r\nexport function inverseLerp(a: number, b: number, value: number): number {\r\n if (a === b) return 0;\r\n return (value - a) / (b - a);\r\n}\r\n\r\nexport function roundToStep(value: number, step: number): number {\r\n return Math.round(value / step) * step;\r\n}\r\n\r\nexport function niceNumber(value: number, round: boolean): number {\r\n const exp = Math.floor(Math.log10(value));\r\n const frac = value / Math.pow(10, exp);\r\n let nice: number;\r\n if (round) {\r\n if (frac < 1.5) nice = 1;\r\n else if (frac < 3) nice = 2;\r\n else if (frac < 7) nice = 5;\r\n else nice = 10;\r\n } else {\r\n if (frac <= 1) nice = 1;\r\n else if (frac <= 2) nice = 2;\r\n else if (frac <= 5) nice = 5;\r\n else nice = 10;\r\n }\r\n return nice * Math.pow(10, exp);\r\n}\r\n\r\nexport function computeTickStep(min: number, max: number, maxTicks: number): number {\r\n const range = niceNumber(max - min, false);\r\n return niceNumber(range / (maxTicks - 1), true);\r\n}\r\n","import type { OHLCBar, DataSeries } from '../types/ohlc.js';\r\n\r\n/**\r\n * Normalize bar timestamp to milliseconds.\r\n * Auto-detects: time > 1e12 is already ms, otherwise treats as seconds.\r\n */\r\nexport function normalizeBarTime(time: number): number {\r\n return time > 1e12 ? time : time * 1000;\r\n}\r\n\r\n/**\r\n * Normalize a bar's timestamp field to milliseconds.\r\n * Accepts either { time } (ms or s) or { t, o, h, l, c, v } wire format.\r\n */\r\nexport function normalizeBar(raw: Record<string, number>): OHLCBar {\r\n const time = normalizeBarTime(raw.time ?? raw.t ?? 0);\r\n return {\r\n time,\r\n open: raw.open ?? raw.o ?? 0,\r\n high: raw.high ?? raw.h ?? 0,\r\n low: raw.low ?? raw.l ?? 0,\r\n close: raw.close ?? raw.c ?? 0,\r\n volume: raw.volume ?? raw.v ?? 0,\r\n };\r\n}\r\n\r\nexport function sliceVisibleData(\r\n data: DataSeries,\r\n from: number,\r\n to: number,\r\n): DataSeries {\r\n const startIdx = Math.max(0, from);\r\n const endIdx = Math.min(data.length, to + 1);\r\n return data.slice(startIdx, endIdx);\r\n}\r\n\r\nexport function findBarIndex(data: DataSeries, timestamp: number): number {\r\n let lo = 0;\r\n let hi = data.length - 1;\r\n while (lo <= hi) {\r\n const mid = (lo + hi) >>> 1;\r\n if (data[mid].time < timestamp) lo = mid + 1;\r\n else if (data[mid].time > timestamp) hi = mid - 1;\r\n else return mid;\r\n }\r\n return lo;\r\n}\r\n\r\nexport function computePriceRange(\r\n data: DataSeries,\r\n from: number,\r\n to: number,\r\n padding = 0.05,\r\n): { min: number; max: number } {\r\n if (data.length === 0) return { min: 0, max: 1 };\r\n const startIdx = Math.max(0, from);\r\n const endIdx = Math.min(data.length - 1, to);\r\n let min = Infinity;\r\n let max = -Infinity;\r\n for (let i = startIdx; i <= endIdx; i++) {\r\n if (data[i].low < min) min = data[i].low;\r\n if (data[i].high > max) max = data[i].high;\r\n }\r\n if (min === Infinity) return { min: 0, max: 1 };\r\n const range = max - min || 1;\r\n return {\r\n min: min - range * padding,\r\n max: max + range * padding,\r\n };\r\n}\r\n\r\nexport function mergeBar(existing: OHLCBar, tick: { price: number; volume?: number; time: number }): OHLCBar {\r\n return {\r\n ...existing,\r\n high: Math.max(existing.high, tick.price),\r\n low: Math.min(existing.low, tick.price),\r\n close: tick.price,\r\n volume: existing.volume + (tick.volume ?? 0),\r\n time: tick.time,\r\n };\r\n}\r\n","export function hexToRgba(hex: string, alpha = 1): string {\r\n const r = parseInt(hex.slice(1, 3), 16);\r\n const g = parseInt(hex.slice(3, 5), 16);\r\n const b = parseInt(hex.slice(5, 7), 16);\r\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\r\n}\r\n\r\nexport function withAlpha(color: string, alpha: number): string {\r\n if (color.startsWith('#')) {\r\n return hexToRgba(color, alpha);\r\n }\r\n const rgbaMatch = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\r\n if (rgbaMatch) {\r\n return `rgba(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]}, ${alpha})`;\r\n }\r\n return color;\r\n}\r\n\r\nexport function lerpColor(colorA: string, colorB: string, t: number): string {\r\n const parseHex = (hex: string) => {\r\n hex = hex.replace('#', '');\r\n if (hex.length === 3) hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];\r\n return {\r\n r: parseInt(hex.slice(0, 2), 16),\r\n g: parseInt(hex.slice(2, 4), 16),\r\n b: parseInt(hex.slice(4, 6), 16),\r\n };\r\n };\r\n const a = parseHex(colorA);\r\n const b = parseHex(colorB);\r\n const r = Math.round(a.r + (b.r - a.r) * t);\r\n const g = Math.round(a.g + (b.g - a.g) * t);\r\n const bl = Math.round(a.b + (b.b - a.b) * t);\r\n return `rgb(${r},${g},${bl})`;\r\n}\r\n","import type { TimeFrame } from '../types/ohlc.js';\r\n\r\nconst TIMEFRAME_MS: Record<TimeFrame, number> = {\r\n '1s': 1_000,\r\n '5s': 5_000,\r\n '15s': 15_000,\r\n '30s': 30_000,\r\n '1m': 60_000,\r\n '3m': 180_000,\r\n '5m': 300_000,\r\n '15m': 900_000,\r\n '30m': 1_800_000,\r\n '45m': 2_700_000,\r\n '1h': 3_600_000,\r\n '2h': 7_200_000,\r\n '3h': 10_800_000,\r\n '4h': 14_400_000,\r\n '6h': 21_600_000,\r\n '8h': 28_800_000,\r\n '12h': 43_200_000,\r\n '1d': 86_400_000,\r\n '2d': 172_800_000,\r\n '3d': 259_200_000,\r\n '1w': 604_800_000,\r\n '2w': 1_209_600_000,\r\n '1M': 2_592_000_000,\r\n '3M': 7_776_000_000,\r\n '6M': 15_552_000_000,\r\n '12M': 31_536_000_000,\r\n};\r\n\r\nexport function timeframeToMs(tf: TimeFrame): number {\r\n return TIMEFRAME_MS[tf];\r\n}\r\n\r\nexport function formatTimestamp(timestamp: number, tf: TimeFrame): string {\r\n const d = new Date(timestamp);\r\n const ms = TIMEFRAME_MS[tf];\r\n if (ms >= 86_400_000) {\r\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\r\n }\r\n if (ms >= 3_600_000) {\r\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\r\n }\r\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' });\r\n}\r\n\r\nexport function alignToTimeframe(timestamp: number, tf: TimeFrame): number {\r\n const ms = TIMEFRAME_MS[tf];\r\n return Math.floor(timestamp / ms) * ms;\r\n}\r\n\r\nexport interface TimeParts {\r\n year: number;\r\n month: number; // 1-12\r\n day: number;\r\n hours: number;\r\n minutes: number;\r\n}\r\n\r\n/**\r\n * Calendar parts of a timestamp in either the browser-local timezone\r\n * (`tzOffsetMinutes === null`) or a fixed UTC offset (e.g. -300 for EST).\r\n */\r\nexport function timeParts(timeMs: number, tzOffsetMinutes: number | null): TimeParts {\r\n if (tzOffsetMinutes === null) {\r\n const d = new Date(timeMs);\r\n return {\r\n year: d.getFullYear(),\r\n month: d.getMonth() + 1,\r\n day: d.getDate(),\r\n hours: d.getHours(),\r\n minutes: d.getMinutes(),\r\n };\r\n }\r\n const d = new Date(timeMs + tzOffsetMinutes * 60_000);\r\n return {\r\n year: d.getUTCFullYear(),\r\n month: d.getUTCMonth() + 1,\r\n day: d.getUTCDate(),\r\n hours: d.getUTCHours(),\r\n minutes: d.getUTCMinutes(),\r\n };\r\n}\r\n\r\n/**\r\n * A bar with no time-of-day component (a daily, weekly, monthly or yearly candle — always anchored\r\n * to a calendar-day boundary, so hours/minutes read 00:00) needs the YEAR in its label instead: a\r\n * bare `month/day` is ambiguous across years, and `00:00` tells a trader nothing. Detected from the\r\n * parts themselves rather than a separate timeframe parameter, so every caller that formats a bar's\r\n * time gets the same rule for free. The one false positive this accepts — a genuine intraday bar\r\n * landing exactly on midnight — is acceptable: real trade-driven timestamps essentially never do.\r\n */\r\nexport function isDateOnly(parts: Pick<TimeParts, 'hours' | 'minutes'>): boolean {\r\n return parts.hours === 0 && parts.minutes === 0;\r\n}\r\n\r\n/** A short timezone label like `UTC-5` or `UTC+5:30` (browser-local when null). */\r\nexport function tzLabel(tzOffsetMinutes: number | null): string {\r\n const min = tzOffsetMinutes === null ? -new Date().getTimezoneOffset() : tzOffsetMinutes;\r\n const sign = min >= 0 ? '+' : '-';\r\n const abs = Math.abs(min);\r\n const h = Math.floor(abs / 60);\r\n const m = abs % 60;\r\n return m === 0 ? `UTC${sign}${h}` : `UTC${sign}${h}:${String(m).padStart(2, '0')}`;\r\n}\r\n\r\n/** Day-of-week for a Monday-anchored reference week (1970-01-05 was a Monday, UTC). */\r\nconst WEEK_ANCHOR_MS = Date.UTC(1970, 0, 5);\r\n\r\nfunction parseTimeframe(tf: TimeFrame): { count: number; unit: 's' | 'm' | 'h' | 'd' | 'w' | 'M' } {\r\n const match = /^(\\d+)([smhdwM])$/.exec(tf);\r\n if (!match) return { count: 1, unit: 'm' };\r\n return { count: parseInt(match[1], 10), unit: match[2] as 's' | 'm' | 'h' | 'd' | 'w' | 'M' };\r\n}\r\n\r\n/**\r\n * Start of the bucket a timestamp falls into for a given timeframe.\r\n *\r\n * Intraday and daily frames are anchored to the Unix epoch (UTC) via fixed-ms\r\n * flooring. Weekly frames are anchored to Monday (or `weekStartsOn`), monthly\r\n * and yearly frames use calendar boundaries (1st of month, Jan for years) so\r\n * 3M aligns to quarters and 12M to calendar years.\r\n */\r\nexport function timeframeBucketStart(\r\n timestamp: number,\r\n tf: TimeFrame,\r\n weekStartsOn: 0 | 1 = 1,\r\n): number {\r\n const { count, unit } = parseTimeframe(tf);\r\n\r\n if (unit === 's' || unit === 'm' || unit === 'h' || unit === 'd') {\r\n const ms = TIMEFRAME_MS[tf];\r\n return Math.floor(timestamp / ms) * ms;\r\n }\r\n\r\n const d = new Date(timestamp);\r\n\r\n if (unit === 'w') {\r\n const dayMs = TIMEFRAME_MS['1d'];\r\n const dow = d.getUTCDay();\r\n const shift = (dow - weekStartsOn + 7) % 7;\r\n const weekStart = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate() - shift);\r\n if (count <= 1) return weekStart;\r\n const weekIndex = Math.floor((weekStart - WEEK_ANCHOR_MS) / (7 * dayMs));\r\n const grouped = Math.floor(weekIndex / count) * count;\r\n return WEEK_ANCHOR_MS + grouped * 7 * dayMs;\r\n }\r\n\r\n // months / quarters / years\r\n const totalMonths = d.getUTCFullYear() * 12 + d.getUTCMonth();\r\n const grouped = Math.floor(totalMonths / count) * count;\r\n return Date.UTC(Math.floor(grouped / 12), grouped % 12, 1);\r\n}\r\n","const NUMBER_FORMAT_CACHE_LIMIT = 64;\r\nconst numberFormatCache = new Map<string, Intl.NumberFormat>();\r\n\r\n/**\r\n * `Number#toLocaleString(locale, options)` constructs a fresh\r\n * `Intl.NumberFormat` on every call — ~20µs in V8 versus ~0.4µs to reuse one.\r\n * Axis labels, the legend, crosshair pills and panel axes format dozens of\r\n * numbers per frame, so formatters are cached per (locale, precision). The\r\n * output is identical: per spec, `toLocaleString` is defined as exactly this.\r\n */\r\nfunction numberFormat(locale: string, precision: number): Intl.NumberFormat {\r\n const key = `${locale}|${precision}`;\r\n let nf = numberFormatCache.get(key);\r\n if (!nf) {\r\n if (numberFormatCache.size >= NUMBER_FORMAT_CACHE_LIMIT) numberFormatCache.clear();\r\n nf = new Intl.NumberFormat(locale, {\r\n minimumFractionDigits: precision,\r\n maximumFractionDigits: precision,\r\n });\r\n numberFormatCache.set(key, nf);\r\n }\r\n return nf;\r\n}\r\n\r\nexport function formatPrice(value: number, precision = 2, locale = 'en-US'): string {\r\n return numberFormat(locale, precision).format(value);\r\n}\r\n\r\n/**\r\n * Decimals the price axis uses for a visible price range: one more than its\r\n * tick step needs, 2 at minimum. Everything that prints a price next to the\r\n * axis (legend, crosshair pill, last-price tag) shares it, so a sub-cent\r\n * asset reads \"0.000004349\" everywhere instead of \"0.00\" off the axis.\r\n */\r\nexport function autoPricePrecision(min: number, max: number): number {\r\n if (!(max > min) || !Number.isFinite(min) || !Number.isFinite(max)) return 2;\r\n const step = computeTickStep(min, max, 8);\r\n return step > 0 && step < 1 ? Math.ceil(-Math.log10(step)) + 1 : 2;\r\n}\r\n\r\nimport type { PriceScaleMode } from '../types/rendering.js';\r\nimport { computeTickStep } from './math.js';\r\n\r\n/**\r\n * Format a price-axis label for a given scale mode.\r\n *\r\n * - `regular` / `logarithmic`: the raw price.\r\n * - `percentage`: change from `baseline`, e.g. `+12.34%`.\r\n * - `indexedTo100`: the price rebased so `baseline` reads as 100.\r\n *\r\n * Falls back to a plain price when a baseline is required but missing/zero.\r\n */\r\nexport function formatPriceScaleLabel(\r\n price: number,\r\n mode: PriceScaleMode,\r\n baseline: number | undefined,\r\n precision = 2,\r\n locale = 'en-US',\r\n): string {\r\n if ((mode === 'percentage' || mode === 'indexedTo100') && baseline && baseline !== 0) {\r\n if (mode === 'percentage') {\r\n const pct = (price / baseline - 1) * 100;\r\n const sign = pct > 0 ? '+' : '';\r\n return `${sign}${pct.toFixed(2)}%`;\r\n }\r\n const indexed = (price / baseline) * 100;\r\n return formatPrice(indexed, 2, locale);\r\n }\r\n return formatPrice(price, precision, locale);\r\n}\r\n\r\nexport function formatVolume(value: number): string {\r\n if (value >= 1_000_000_000) return (value / 1_000_000_000).toFixed(2) + 'B';\r\n if (value >= 1_000_000) return (value / 1_000_000).toFixed(2) + 'M';\r\n if (value >= 1_000) return (value / 1_000).toFixed(2) + 'K';\r\n return value.toFixed(0);\r\n}\r\n\r\nexport function detectPrecision(values: number[]): number {\r\n let maxDecimals = 0;\r\n for (const v of values) {\r\n const str = v.toString();\r\n const dot = str.indexOf('.');\r\n if (dot >= 0) {\r\n maxDecimals = Math.max(maxDecimals, str.length - dot - 1);\r\n }\r\n }\r\n return Math.min(maxDecimals, 8);\r\n}\r\n","import type { ChartOptions } from '../types/chart.js';\r\n\r\nexport const DEFAULT_CHART_OPTIONS: Required<Pick<ChartOptions, 'autoScale' | 'rightMargin' | 'minBarSpacing' | 'maxBarSpacing'>> & Pick<ChartOptions, 'grid' | 'crosshair'> = {\r\n autoScale: true,\r\n rightMargin: 5,\r\n minBarSpacing: 2,\r\n maxBarSpacing: 30,\r\n grid: {\r\n visible: true,\r\n hLineStyle: 'solid',\r\n vLineStyle: 'solid',\r\n },\r\n crosshair: {\r\n mode: 'magnet',\r\n },\r\n};\r\n\r\n// Standard timeframe presets for different market types\r\nimport type { TimeFrame } from '../types/ohlc.js';\r\n\r\n/** Crypto: all timeframes including seconds */\r\nexport const TIMEFRAMES_CRYPTO: TimeFrame[] = [\r\n '1s', '1m', '3m', '5m', '15m', '30m',\r\n '1h', '2h', '4h', '6h', '8h', '12h',\r\n '1d', '3d', '1w', '1M',\r\n];\r\n\r\n/** Stocks: minute-level and above (no seconds) */\r\nexport const TIMEFRAMES_STOCK: TimeFrame[] = [\r\n '1m', '5m', '15m', '30m',\r\n '1h', '2h', '4h',\r\n '1d', '1w', '1M', '3M', '6M', '12M',\r\n];\r\n\r\n/** Forex: common forex timeframes */\r\nexport const TIMEFRAMES_FOREX: TimeFrame[] = [\r\n '1m', '5m', '15m', '30m',\r\n '1h', '4h',\r\n '1d', '1w', '1M',\r\n];\r\n\r\n/** Default favorites shown in quick-access bar */\r\nexport const DEFAULT_TIMEFRAME_FAVORITES: TimeFrame[] = [\r\n '1m', '5m', '15m', '1h', '4h', '1d', '1w',\r\n];\r\n\r\nexport const DEFAULT_BAR_WIDTH = 8;\r\nexport const DEFAULT_BAR_SPACING = 2;\r\nexport const PRICE_AXIS_WIDTH = 70;\r\nexport const TIME_AXIS_HEIGHT = 30;\r\nexport const MIN_PANEL_HEIGHT = 60;\r\nexport const DEFAULT_PANEL_HEIGHT = 120;\r\n","import type { Theme } from '../types/theme.js';\r\n\r\nconst DEFAULT_FONT = {\r\n family: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\r\n sizeSmall: 10,\r\n sizeMedium: 12,\r\n sizeLarge: 14,\r\n};\r\n\r\nexport const DARK_THEME: Theme = {\r\n name: 'dark',\r\n background: '#131722',\r\n text: '#D1D4DC',\r\n textSecondary: '#787B86',\r\n grid: '#1E222D',\r\n crosshair: '#9598A1',\r\n candleUp: '#26A69A',\r\n candleDown: '#EF5350',\r\n candleUpWick: '#26A69A',\r\n candleDownWick: '#EF5350',\r\n lineColor: '#2196F3',\r\n areaTopColor: 'rgba(33, 150, 243, 0.4)',\r\n areaBottomColor: 'rgba(33, 150, 243, 0.0)',\r\n volumeUp: 'rgba(38, 166, 154, 0.3)',\r\n volumeDown: 'rgba(239, 83, 80, 0.3)',\r\n axisLine: '#2A2E39',\r\n axisLabel: '#D1D4DC',\r\n axisLabelBackground: '#2A2E39',\r\n font: DEFAULT_FONT,\r\n};\r\n\r\nexport const LIGHT_THEME: Theme = {\r\n name: 'light',\r\n background: '#FFFFFF',\r\n text: '#131722',\r\n textSecondary: '#787B86',\r\n grid: '#F0F3FA',\r\n crosshair: '#9598A1',\r\n candleUp: '#26A69A',\r\n candleDown: '#EF5350',\r\n candleUpWick: '#26A69A',\r\n candleDownWick: '#EF5350',\r\n lineColor: '#2196F3',\r\n areaTopColor: 'rgba(33, 150, 243, 0.4)',\r\n areaBottomColor: 'rgba(33, 150, 243, 0.0)',\r\n volumeUp: 'rgba(38, 166, 154, 0.3)',\r\n volumeDown: 'rgba(239, 83, 80, 0.3)',\r\n axisLine: '#E0E3EB',\r\n axisLabel: '#131722',\r\n axisLabelBackground: '#F0F3FA',\r\n font: DEFAULT_FONT,\r\n};\r\n\r\nexport const DARK_TERMINAL: Theme = {\r\n name: 'terminal',\r\n background: '#0E0E0E',\r\n text: '#C0C0C0',\r\n textSecondary: '#8A8A8A',\r\n grid: '#1A1A1A',\r\n crosshair: '#666666',\r\n candleUp: '#00FF87',\r\n candleDown: '#FF3B4D',\r\n candleUpWick: '#00FF87',\r\n candleDownWick: '#FF3B4D',\r\n lineColor: '#3D8BFD',\r\n areaTopColor: 'rgba(61, 139, 253, 0.3)',\r\n areaBottomColor: 'rgba(61, 139, 253, 0.0)',\r\n volumeUp: 'rgba(0, 255, 135, 0.2)',\r\n volumeDown: 'rgba(255, 59, 77, 0.2)',\r\n axisLine: '#1A1A1A',\r\n axisLabel: '#8A8A8A',\r\n axisLabelBackground: '#1A1A1A',\r\n font: {\r\n family: \"'Roboto Mono', 'JetBrains Mono', 'SF Mono', Consolas, monospace\",\r\n sizeSmall: 10,\r\n sizeMedium: 12,\r\n sizeLarge: 14,\r\n },\r\n};\r\n","import type { LocaleStrings } from './types.js';\r\n\r\nexport const en: LocaleStrings = {\r\n // Chart types\r\n candlestick: 'Candlestick',\r\n line: 'Line',\r\n area: 'Area',\r\n bar: 'OHLC Bar',\r\n\r\n // Axes\r\n price: 'Price',\r\n volume: 'Volume',\r\n time: 'Time',\r\n open: 'Open',\r\n high: 'High',\r\n low: 'Low',\r\n close: 'Close',\r\n\r\n // Indicators - overlays\r\n sma: 'SMA',\r\n ema: 'EMA',\r\n bollingerBands: 'Bollinger Bands',\r\n vwap: 'VWAP',\r\n ichimoku: 'Ichimoku Cloud',\r\n parabolicSAR: 'Parabolic SAR',\r\n supertrend: 'Supertrend',\r\n keltnerChannel: 'Keltner Channel',\r\n donchianChannel: 'Donchian Channel',\r\n\r\n // Indicators - panels\r\n rsi: 'RSI',\r\n macd: 'MACD',\r\n stochastic: 'Stochastic',\r\n atr: 'ATR',\r\n adx: 'ADX',\r\n obv: 'OBV',\r\n williamsR: 'Williams %R',\r\n cci: 'CCI',\r\n mfi: 'MFI',\r\n aroon: 'Aroon',\r\n roc: 'ROC',\r\n tsi: 'TSI',\r\n cmf: 'CMF',\r\n stddev: 'Std Dev',\r\n volumeProfile: 'Volume Profile',\r\n accumulationDistribution: 'A/D Line',\r\n vroc: 'VROC',\r\n\r\n // Drawing tools\r\n trendLine: 'Trend Line',\r\n horizontalLine: 'Horizontal Line',\r\n verticalLine: 'Vertical Line',\r\n ray: 'Ray',\r\n extendedLine: 'Extended Line',\r\n parallelChannel: 'Parallel Channel',\r\n regressionChannel: 'Regression Channel',\r\n fibRetracement: 'Fibonacci Retracement',\r\n fibExtension: 'Fibonacci Extension',\r\n rectangle: 'Rectangle',\r\n ellipse: 'Ellipse',\r\n triangle: 'Triangle',\r\n pitchfork: \"Andrews' Pitchfork\",\r\n elliottWave: 'Elliott Wave',\r\n priceRange: 'Price Range',\r\n dateRange: 'Date Range',\r\n measure: 'Measure',\r\n textTool: 'Text',\r\n arrow: 'Arrow',\r\n clearAll: 'Clear All',\r\n\r\n // Trading\r\n buy: 'Buy',\r\n sell: 'Sell',\r\n buyLimit: 'Buy Limit',\r\n sellLimit: 'Sell Limit',\r\n buyStop: 'Buy Stop',\r\n sellStop: 'Sell Stop',\r\n stopLoss: 'Stop Loss',\r\n takeProfit: 'Take Profit',\r\n market: 'Market',\r\n limit: 'Limit',\r\n stop: 'Stop',\r\n cancel: 'Cancel',\r\n modify: 'Modify',\r\n quantity: 'Qty',\r\n pnl: 'P&L',\r\n activeOrders: 'Active Orders',\r\n positions: 'Positions',\r\n noOrders: 'No active orders',\r\n noPositions: 'No open positions',\r\n placeOrder: 'Place Order',\r\n rightClickToTrade: 'Right-click chart to place orders',\r\n\r\n // Market\r\n ceiling: 'Ceiling',\r\n floor: 'Floor',\r\n reference: 'Reference',\r\n session: 'Session',\r\n preOpen: 'Pre-Open',\r\n continuous: 'Continuous',\r\n preClose: 'Pre-Close',\r\n closed: 'Closed',\r\n\r\n // UI\r\n settings: 'Settings',\r\n theme: 'Theme',\r\n darkTheme: 'Dark',\r\n lightTheme: 'Light',\r\n tools: 'Tools',\r\n indicators: 'Indicators',\r\n overlays: 'Overlays',\r\n panels: 'Panels',\r\n orders: 'Orders',\r\n autoScale: 'Auto Scale',\r\n crosshair: 'Crosshair',\r\n grid: 'Grid',\r\n loading: 'Loading...',\r\n error: 'Error',\r\n\r\n numberDecimalSeparator: '.',\r\n numberGroupSeparator: ',',\r\n};\r\n","import type { LocaleStrings } from './types.js';\r\n\r\nexport const vi: LocaleStrings = {\r\n // Chart types\r\n candlestick: 'Nến',\r\n line: 'Đường',\r\n area: 'Vùng',\r\n bar: 'Thanh OHLC',\r\n\r\n // Axes\r\n price: 'Giá',\r\n volume: 'Khối lượng',\r\n time: 'Thời gian',\r\n open: 'Mở',\r\n high: 'Cao',\r\n low: 'Thấp',\r\n close: 'Đóng',\r\n\r\n // Indicators - overlays\r\n sma: 'SMA',\r\n ema: 'EMA',\r\n bollingerBands: 'Dải Bollinger',\r\n vwap: 'VWAP',\r\n ichimoku: 'Mây Ichimoku',\r\n parabolicSAR: 'Parabolic SAR',\r\n supertrend: 'Supertrend',\r\n keltnerChannel: 'Kênh Keltner',\r\n donchianChannel: 'Kênh Donchian',\r\n\r\n // Indicators - panels\r\n rsi: 'RSI',\r\n macd: 'MACD',\r\n stochastic: 'Stochastic',\r\n atr: 'ATR',\r\n adx: 'ADX',\r\n obv: 'OBV',\r\n williamsR: 'Williams %R',\r\n cci: 'CCI',\r\n mfi: 'MFI',\r\n aroon: 'Aroon',\r\n roc: 'ROC',\r\n tsi: 'TSI',\r\n cmf: 'CMF',\r\n stddev: 'Độ lệch chuẩn',\r\n volumeProfile: 'Phân bổ KL',\r\n accumulationDistribution: 'Tích lũy/Phân phối',\r\n vroc: 'VROC',\r\n\r\n // Drawing tools\r\n trendLine: 'Đường xu hướng',\r\n horizontalLine: 'Đường ngang',\r\n verticalLine: 'Đường dọc',\r\n ray: 'Tia',\r\n extendedLine: 'Đường kéo dài',\r\n parallelChannel: 'Kênh song song',\r\n regressionChannel: 'Kênh hồi quy',\r\n fibRetracement: 'Fibonacci thoái lui',\r\n fibExtension: 'Fibonacci mở rộng',\r\n rectangle: 'Hình chữ nhật',\r\n ellipse: 'Hình elip',\r\n triangle: 'Tam giác',\r\n pitchfork: 'Chĩa ba Andrews',\r\n elliottWave: 'Sóng Elliott',\r\n priceRange: 'Khoảng giá',\r\n dateRange: 'Khoảng thời gian',\r\n measure: 'Đo lường',\r\n textTool: 'Chữ',\r\n arrow: 'Mũi tên',\r\n clearAll: 'Xóa tất cả',\r\n\r\n // Trading\r\n buy: 'Mua',\r\n sell: 'Bán',\r\n buyLimit: 'Mua giới hạn',\r\n sellLimit: 'Bán giới hạn',\r\n buyStop: 'Mua chặn',\r\n sellStop: 'Bán chặn',\r\n stopLoss: 'Cắt lỗ',\r\n takeProfit: 'Chốt lời',\r\n market: 'Thị trường',\r\n limit: 'Giới hạn',\r\n stop: 'Dừng',\r\n cancel: 'Hủy',\r\n modify: 'Sửa',\r\n quantity: 'KL',\r\n pnl: 'Lãi/Lỗ',\r\n activeOrders: 'Lệnh chờ',\r\n positions: 'Vị thế',\r\n noOrders: 'Không có lệnh chờ',\r\n noPositions: 'Không có vị thế mở',\r\n placeOrder: 'Đặt lệnh',\r\n rightClickToTrade: 'Nhấp chuột phải để đặt lệnh',\r\n\r\n // Market\r\n ceiling: 'Trần',\r\n floor: 'Sàn',\r\n reference: 'Tham chiếu',\r\n session: 'Phiên',\r\n preOpen: 'Trước giờ mở',\r\n continuous: 'Liên tục',\r\n preClose: 'Trước giờ đóng',\r\n closed: 'Đóng cửa',\r\n\r\n // UI\r\n settings: 'Cài đặt',\r\n theme: 'Giao diện',\r\n darkTheme: 'Tối',\r\n lightTheme: 'Sáng',\r\n tools: 'Công cụ',\r\n indicators: 'Chỉ báo',\r\n overlays: 'Phủ lên',\r\n panels: 'Bảng',\r\n orders: 'Lệnh',\r\n autoScale: 'Tự co giãn',\r\n crosshair: 'Chữ thập',\r\n grid: 'Lưới',\r\n loading: 'Đang tải...',\r\n error: 'Lỗi',\r\n\r\n numberDecimalSeparator: ',',\r\n numberGroupSeparator: '.',\r\n};\r\n","export type { Locale, LocaleStrings, NumberFormatConfig, DateFormatConfig } from './types.js';\r\nexport { en } from './en.js';\r\nexport { vi } from './vi.js';\r\n\r\nimport type { Locale, LocaleStrings } from './types.js';\r\nimport { en } from './en.js';\r\nimport { vi } from './vi.js';\r\n\r\nconst locales = new Map<string, LocaleStrings>([\r\n ['en', en],\r\n ['vi', vi],\r\n]);\r\n\r\nlet currentLocale: Locale = 'en';\r\nlet currentStrings: LocaleStrings = en;\r\n\r\nexport function setLocale(locale: Locale): void {\r\n currentLocale = locale;\r\n currentStrings = locales.get(locale) ?? en;\r\n}\r\n\r\nexport function getLocale(): Locale {\r\n return currentLocale;\r\n}\r\n\r\nexport function t(key: keyof LocaleStrings): string {\r\n return currentStrings[key] ?? (en as any)[key] ?? key;\r\n}\r\n\r\nexport function registerLocale(locale: string, strings: LocaleStrings): void {\r\n locales.set(locale, strings);\r\n}\r\n\r\nexport function getLocaleStrings(locale?: string): LocaleStrings {\r\n return locales.get(locale ?? currentLocale) ?? en;\r\n}\r\n\r\n// Number formatting\r\nexport function formatNumber(value: number, precision = 2, locale?: string): string {\r\n const strings = locales.get(locale ?? currentLocale) ?? en;\r\n const dec = strings.numberDecimalSeparator;\r\n const grp = strings.numberGroupSeparator;\r\n\r\n const fixed = value.toFixed(precision);\r\n const [intPart, decPart] = fixed.split('.');\r\n\r\n // Group integer part\r\n const negative = intPart.startsWith('-');\r\n const digits = negative ? intPart.slice(1) : intPart;\r\n let grouped = '';\r\n for (let i = digits.length - 1, count = 0; i >= 0; i--, count++) {\r\n if (count > 0 && count % 3 === 0) grouped = grp + grouped;\r\n grouped = digits[i] + grouped;\r\n }\r\n if (negative) grouped = '-' + grouped;\r\n\r\n return decPart ? grouped + dec + decPart : grouped;\r\n}\r\n\r\nexport function formatVND(value: number): string {\r\n return formatNumber(value, 0, 'vi');\r\n}\r\n\r\nexport function formatVolumeLoc(value: number, locale?: string): string {\r\n if (value >= 1e9) return formatNumber(value / 1e9, 2, locale ?? currentLocale) + 'B';\r\n if (value >= 1e6) return formatNumber(value / 1e6, 2, locale ?? currentLocale) + 'M';\r\n if (value >= 1e3) return formatNumber(value / 1e3, 2, locale ?? currentLocale) + 'K';\r\n return formatNumber(value, 0, locale ?? currentLocale);\r\n}\r\n","import type { MarketConfig, MarketColorScheme, TradingSession } from './types.js';\r\nimport type { Theme } from '../types/theme.js';\r\n\r\n// Vietnam stock color convention:\r\n// Purple/Red = ceiling (trần) - max up\r\n// Green/Cyan = floor (sàn) - max down\r\n// Yellow = reference (tham chiếu)\r\n// Red = up, Blue = down (common VN convention)\r\nexport const VN_COLORS: MarketColorScheme = {\r\n up: '#FF0000', // Đỏ - tăng\r\n down: '#0000FF', // Xanh dương - giảm\r\n unchanged: '#FFD700', // Vàng - tham chiếu\r\n ceiling: '#FF00FF', // Tím - trần\r\n floor: '#00FFFF', // Xanh lam - sàn\r\n reference: '#FFD700', // Vàng - tham chiếu\r\n};\r\n\r\nexport const HOSE_SESSIONS: TradingSession[] = [\r\n { name: 'ATO', startTime: '09:00', endTime: '09:15', type: 'preOpen' },\r\n { name: 'Phiên 1', startTime: '09:15', endTime: '11:30', type: 'continuous' },\r\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\r\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\r\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\r\n];\r\n\r\nexport const HNX_SESSIONS: TradingSession[] = [\r\n { name: 'Phiên 1', startTime: '09:00', endTime: '11:30', type: 'continuous' },\r\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\r\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\r\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\r\n];\r\n\r\n// Market presets\r\nexport const MARKET_HOSE: MarketConfig = {\r\n type: 'stock',\r\n exchange: 'HOSE',\r\n currency: 'VND',\r\n pricePrecision: 2,\r\n volumeUnit: 10,\r\n priceStep: 0.05,\r\n priceLimits: { enabled: true, ceilingPercent: 7, floorPercent: 7 },\r\n sessions: HOSE_SESSIONS,\r\n colorScheme: VN_COLORS,\r\n};\r\n\r\nexport const MARKET_HNX: MarketConfig = {\r\n type: 'stock',\r\n exchange: 'HNX',\r\n currency: 'VND',\r\n pricePrecision: 1,\r\n volumeUnit: 100,\r\n priceStep: 0.1,\r\n priceLimits: { enabled: true, ceilingPercent: 10, floorPercent: 10 },\r\n sessions: HNX_SESSIONS,\r\n colorScheme: VN_COLORS,\r\n};\r\n\r\nexport const MARKET_UPCOM: MarketConfig = {\r\n type: 'stock',\r\n exchange: 'UPCOM',\r\n currency: 'VND',\r\n pricePrecision: 1,\r\n volumeUnit: 100,\r\n priceStep: 0.1,\r\n priceLimits: { enabled: true, ceilingPercent: 15, floorPercent: 15 },\r\n sessions: HNX_SESSIONS,\r\n colorScheme: VN_COLORS,\r\n};\r\n\r\nexport const MARKET_CRYPTO: MarketConfig = {\r\n type: 'crypto',\r\n currency: 'USDT',\r\n pricePrecision: 2,\r\n priceLimits: { enabled: false },\r\n};\r\n\r\nexport const MARKET_NYSE: MarketConfig = {\r\n type: 'stock',\r\n exchange: 'NYSE',\r\n currency: 'USD',\r\n pricePrecision: 2,\r\n priceStep: 0.01,\r\n priceLimits: { enabled: false },\r\n sessions: [\r\n { name: 'Pre-Market', startTime: '04:00', endTime: '09:30', type: 'preOpen' },\r\n { name: 'Regular', startTime: '09:30', endTime: '16:00', type: 'continuous' },\r\n { name: 'After-Hours', startTime: '16:00', endTime: '20:00', type: 'preClose' },\r\n ],\r\n};\r\n\r\n// Build a theme variant for VN stock market\r\nexport function createVNTheme(base: Theme): Theme {\r\n return {\r\n ...base,\r\n candleUp: VN_COLORS.up,\r\n candleDown: VN_COLORS.down,\r\n candleUpWick: VN_COLORS.up,\r\n candleDownWick: VN_COLORS.down,\r\n volumeUp: 'rgba(255, 0, 0, 0.3)',\r\n volumeDown: 'rgba(0, 0, 255, 0.3)',\r\n };\r\n}\r\n\r\nexport function computePriceLimits(referencePrice: number, config: MarketConfig): { ceiling: number; floor: number; reference: number } | null {\r\n if (!config.priceLimits?.enabled || !config.priceLimits.ceilingPercent) return null;\r\n const ceilPct = config.priceLimits.ceilingPercent / 100;\r\n const floorPct = (config.priceLimits.floorPercent ?? config.priceLimits.ceilingPercent) / 100;\r\n return {\r\n ceiling: referencePrice * (1 + ceilPct),\r\n floor: referencePrice * (1 - floorPct),\r\n reference: referencePrice,\r\n };\r\n}\r\n\r\nexport function getCurrentSession(sessions: TradingSession[]): TradingSession | null {\r\n const now = new Date();\r\n const hhmm = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;\r\n for (const session of sessions) {\r\n if (hhmm >= session.startTime && hhmm < session.endTime) return session;\r\n }\r\n return null;\r\n}\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/types/rendering.ts","../src/types/drawing.ts","../src/types/trading.ts","../src/types/signal.ts","../src/types/realtime.ts","../src/utils/math.ts","../src/utils/data.ts","../src/utils/color.ts","../src/utils/time.ts","../src/utils/precision.ts","../src/constants/defaults.ts","../src/constants/themes.ts","../src/i18n/en.ts","../src/i18n/vi.ts","../src/i18n/index.ts","../src/market/presets.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 * 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 { Point, ViewportState } from './rendering.js';\r\n\r\nexport type DrawingToolType =\r\n | 'trendLine' | 'horizontalLine' | 'horizontalRay' | 'verticalLine' | 'ray' | 'extendedLine'\r\n | 'crossLine' | 'trendAngle' | 'infoLine'\r\n | 'parallelChannel' | 'regressionChannel'\r\n | 'fibRetracement' | 'fibExtension' | 'fibTimeZones' | 'fibChannel' | 'fibSpeedResistanceFan'\r\n | 'rectangle' | 'ellipse' | 'triangle' | 'circle'\r\n | 'pitchfork' | 'schiffPitchfork' | 'modifiedSchiffPitchfork' | 'elliottWave'\r\n | 'xabcdPattern' | 'abcdPattern' | 'headAndShoulders'\r\n | 'priceRange' | 'dateRange' | 'dateAndPriceRange' | 'measure'\r\n | 'text' | 'arrow' | 'priceLabel'\r\n | 'gannFan' | 'gannBox' | 'cyclicLines'\r\n | 'anchoredVWAP'\r\n | 'volumeProfileRange'\r\n | 'riskReward';\r\n\r\nexport interface AnchorPoint {\r\n time: number;\r\n price: number;\r\n}\r\n\r\nexport interface DrawingStyle {\r\n color: string;\r\n lineWidth: number;\r\n lineStyle: 'solid' | 'dashed' | 'dotted';\r\n fillColor?: string;\r\n fillOpacity?: number;\r\n fontSize?: number;\r\n text?: string;\r\n}\r\n\r\nexport interface DrawingState {\r\n id: string;\r\n type: DrawingToolType;\r\n anchors: AnchorPoint[];\r\n style: DrawingStyle;\r\n visible: boolean;\r\n locked: boolean;\r\n meta?: Record<string, unknown>;\r\n}\r\n\r\nexport interface DrawingDescriptor {\r\n type: DrawingToolType;\r\n name: string;\r\n requiredAnchors: number;\r\n singleClick?: boolean;\r\n}\r\n\r\nexport interface DrawingPlugin {\r\n descriptor: DrawingDescriptor;\r\n render(\r\n ctx: CanvasRenderingContext2D,\r\n state: DrawingState,\r\n viewport: ViewportState,\r\n selected: boolean,\r\n ): void;\r\n hitTest(\r\n point: Point,\r\n state: DrawingState,\r\n viewport: ViewportState,\r\n tolerance: number,\r\n ): boolean;\r\n hitTestAnchor(\r\n point: Point,\r\n state: DrawingState,\r\n viewport: ViewportState,\r\n tolerance: number,\r\n ): number;\r\n}\r\n\r\nexport const DEFAULT_DRAWING_STYLE: DrawingStyle = {\r\n color: '#4c8dff',\r\n lineWidth: 1,\r\n lineStyle: 'solid',\r\n fillColor: 'rgba(76, 141, 255, 0.1)',\r\n fillOpacity: 0.1,\r\n fontSize: 12,\r\n};\r\n","export type OrderSide = 'buy' | 'sell';\r\nexport type OrderType = 'market' | 'limit' | 'stop' | 'stopLimit';\r\nexport type OrderStatus = 'pending' | 'filled' | 'cancelled' | 'rejected';\r\nexport type OrderLabel = 'LIMIT' | 'STOP' | 'SL' | 'TP' | 'STOP LIMIT';\r\n\r\nexport interface TradingOrder {\r\n id: string;\r\n side: OrderSide;\r\n type: OrderType;\r\n price: number;\r\n stopPrice?: number;\r\n quantity: number;\r\n label?: OrderLabel;\r\n draggable?: boolean;\r\n meta?: Record<string, unknown>;\r\n}\r\n\r\nexport interface TradingPosition {\r\n id: string;\r\n side: OrderSide;\r\n entryPrice: number;\r\n quantity: number;\r\n /** Quantity already closed (for partial-close visualization). 0 ≤ closedQuantity ≤ quantity. */\r\n closedQuantity?: number;\r\n stopLoss?: number;\r\n takeProfit?: number;\r\n meta?: Record<string, unknown>;\r\n}\r\n\r\n/** Threshold-based P&L color stop. Sorted ascending by `pnl` is recommended. */\r\nexport interface PnLThreshold {\r\n /** Inclusive lower bound. Use -Infinity for the bottom-most stop. */\r\n pnl: number;\r\n color: string;\r\n}\r\n\r\n/** Tokens passed to position label templates. */\r\nexport interface PositionLabelContext {\r\n side: OrderSide;\r\n quantity: number;\r\n closedQuantity: number;\r\n openQuantity: number;\r\n entryPrice: number;\r\n currentPrice: number;\r\n pnl: number;\r\n pnlPct: number;\r\n precision: number;\r\n}\r\n\r\nexport interface DepthLevel {\r\n price: number;\r\n volume: number;\r\n}\r\n\r\nexport interface DepthData {\r\n bids: DepthLevel[];\r\n asks: DepthLevel[];\r\n}\r\n\r\nexport interface TradingConfig {\r\n enabled: boolean;\r\n orderColors?: { buy?: string; sell?: string };\r\n positionColors?: { profit?: string; loss?: string; entry?: string };\r\n /**\r\n * Optional gradient of colors keyed to P&L value. When provided, the rendered\r\n * position zone uses the color of the highest threshold whose `pnl` ≤ live P&L.\r\n * Falls back to `positionColors.profit`/`.loss` when unset.\r\n */\r\n pnlThresholds?: PnLThreshold[];\r\n /**\r\n * Position P&L label template. Supports tokens: {side} {qty} {closedQty}\r\n * {openQty} {entry} {price} {pnl} {pnlPct} {pnlSign}. Pass a function for\r\n * full control. Default: `{side} {qty} | P&L: {pnlSign}{pnl}`.\r\n */\r\n positionLabel?: string | ((ctx: PositionLabelContext) => string);\r\n depthOverlay?: {\r\n enabled?: boolean;\r\n bidColor?: string;\r\n askColor?: string;\r\n maxWidth?: number;\r\n };\r\n contextMenu?: { enabled?: boolean };\r\n pricePrecision?: number;\r\n dragThreshold?: number;\r\n}\r\n\r\nexport interface OrderPlaceIntent {\r\n side: OrderSide;\r\n type: OrderType;\r\n price: number;\r\n stopPrice?: number;\r\n quantity?: number;\r\n}\r\n\r\nexport interface OrderModifyIntent {\r\n orderId: string;\r\n newPrice: number;\r\n /** The price before the change, when known (e.g. from a drag). Optional so\r\n * the chart's `orderModify` event payload routes straight to an adapter. */\r\n previousPrice?: number;\r\n}\r\n\r\nexport interface OrderCancelIntent {\r\n orderId: string;\r\n}\r\n\r\nexport interface PositionModifyIntent {\r\n positionId: string;\r\n stopLoss?: number;\r\n takeProfit?: number;\r\n}\r\n\r\nexport interface PositionCloseIntent {\r\n positionId: string;\r\n}\r\n\r\nexport const DEFAULT_TRADING_CONFIG: TradingConfig = {\r\n enabled: true,\r\n orderColors: { buy: '#1fa874', sell: '#e8505b' },\r\n positionColors: { profit: '#1fa874', loss: '#e8505b', entry: '#4c8dff' },\r\n depthOverlay: { enabled: false, bidColor: 'rgba(31, 168, 116,0.15)', askColor: 'rgba(232, 80, 91,0.15)', maxWidth: 100 },\r\n contextMenu: { enabled: true },\r\n pricePrecision: 2,\r\n dragThreshold: 3,\r\n};\r\n","export type SignalDirection = 'long' | 'short' | 'neutral';\r\n\r\nexport interface SignalMarker {\r\n id: string;\r\n time: number;\r\n price: number;\r\n direction: SignalDirection;\r\n confidence: number;\r\n source: string;\r\n label?: string;\r\n color?: string;\r\n meta?: Record<string, unknown>;\r\n}\r\n\r\nexport interface SignalMarkerStyle {\r\n longColor?: string;\r\n shortColor?: string;\r\n neutralColor?: string;\r\n arrowSize?: number;\r\n showLabel?: boolean;\r\n showConfidence?: boolean;\r\n sourceColors?: Record<string, string>;\r\n}\r\n\r\nexport const DEFAULT_SIGNAL_STYLE: SignalMarkerStyle = {\r\n longColor: '#1fa874',\r\n shortColor: '#e8505b',\r\n neutralColor: '#9E9E9E',\r\n arrowSize: 12,\r\n showLabel: true,\r\n showConfidence: true,\r\n};\r\n\r\nexport type TradeZoneDirection = 'long' | 'short';\r\n\r\nexport interface TradeZone {\r\n id: string;\r\n entryTime: number;\r\n entryPrice: number;\r\n exitTime?: number;\r\n exitPrice?: number;\r\n direction: TradeZoneDirection;\r\n pnl?: number;\r\n pnlPercent?: number;\r\n label?: string;\r\n meta?: Record<string, unknown>;\r\n}\r\n\r\nexport interface TradeZoneStyle {\r\n profitColor?: string;\r\n lossColor?: string;\r\n activeColor?: string;\r\n fillOpacity?: number;\r\n borderWidth?: number;\r\n showLabel?: boolean;\r\n showPnl?: boolean;\r\n}\r\n\r\nexport const DEFAULT_TRADE_ZONE_STYLE: TradeZoneStyle = {\r\n profitColor: '#1fa874',\r\n lossColor: '#e8505b',\r\n activeColor: '#4c8dff',\r\n fillOpacity: 0.12,\r\n borderWidth: 1,\r\n showLabel: true,\r\n showPnl: true,\r\n};\r\n","import type { OHLCBar, TimeFrame } from './ohlc.js';\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}\n\nexport interface AggregatedBar extends OHLCBar {\n closed: boolean; // true when bar is finalized\n tickCount: number; // number of ticks in this bar\n}\n\n// --- Data Adapter (Strategy Pattern) ---\n\nexport interface DataAdapterConfig {\n symbol: string;\n timeframe: TimeFrame;\n reconnect?: boolean; // default: true\n reconnectMaxRetries?: number; // default: Infinity\n reconnectBaseDelay?: number; // ms, default: 1000\n reconnectMaxDelay?: number; // ms, default: 30000\n heartbeatInterval?: number; // ms, default: 30000\n bufferSize?: number; // max ticks to buffer, default: 1000\n}\n\nexport type DataAdapterEventType =\n | 'tick'\n | 'bar'\n | 'barClose'\n | 'snapshot' // initial historical data loaded\n | 'connectionChange'\n | 'error';\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 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 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 historyLimit?: number; // bars to load initially, default: 500\n autoScroll?: boolean; // scroll to end on new bar, default: true\n showCurrentPriceLine?: boolean; // default: true\n aggregateTicks?: boolean; // build bars from ticks, default: false\n reconnect?: ReconnectConfig;\n}\n\nexport interface ReconnectConfig {\n enabled: boolean; // default: true\n maxRetries: number; // default: Infinity\n baseDelay: number; // ms, default: 1000\n maxDelay: number; // ms, default: 30000\n backoffMultiplier: number; // default: 2\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","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 * Normalize bar timestamp to milliseconds.\n * Auto-detects: time > 1e12 is already ms, otherwise treats as seconds.\n */\nexport function normalizeBarTime(time: number): number {\n return time > 1e12 ? 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\nexport function computePriceRange(\n data: DataSeries,\n from: number,\n to: number,\n padding = 0.05,\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 const range = max - min || 1;\n return {\n min: min - range * padding,\n max: max + range * padding,\n };\n}\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 time: tick.time,\n };\n}\n","export function hexToRgba(hex: string, alpha = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\nexport function withAlpha(color: string, alpha: number): string {\n if (color.startsWith('#')) {\n return hexToRgba(color, alpha);\n }\n const rgbaMatch = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (rgbaMatch) {\n return `rgba(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]}, ${alpha})`;\n }\n return color;\n}\n\nexport function lerpColor(colorA: string, colorB: string, t: number): string {\n const parseHex = (hex: string) => {\n hex = hex.replace('#', '');\n if (hex.length === 3) hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];\n return {\n r: parseInt(hex.slice(0, 2), 16),\n g: parseInt(hex.slice(2, 4), 16),\n b: parseInt(hex.slice(4, 6), 16),\n };\n };\n const a = parseHex(colorA);\n const b = parseHex(colorB);\n const r = Math.round(a.r + (b.r - a.r) * t);\n const g = Math.round(a.g + (b.g - a.g) * t);\n const bl = Math.round(a.b + (b.b - a.b) * t);\n return `rgb(${r},${g},${bl})`;\n}\n","import type { TimeFrame } from '../types/ohlc.js';\r\n\r\nconst TIMEFRAME_MS: Record<TimeFrame, number> = {\r\n '1s': 1_000,\r\n '5s': 5_000,\r\n '15s': 15_000,\r\n '30s': 30_000,\r\n '1m': 60_000,\r\n '3m': 180_000,\r\n '5m': 300_000,\r\n '15m': 900_000,\r\n '30m': 1_800_000,\r\n '45m': 2_700_000,\r\n '1h': 3_600_000,\r\n '2h': 7_200_000,\r\n '3h': 10_800_000,\r\n '4h': 14_400_000,\r\n '6h': 21_600_000,\r\n '8h': 28_800_000,\r\n '12h': 43_200_000,\r\n '1d': 86_400_000,\r\n '2d': 172_800_000,\r\n '3d': 259_200_000,\r\n '1w': 604_800_000,\r\n '2w': 1_209_600_000,\r\n '1M': 2_592_000_000,\r\n '3M': 7_776_000_000,\r\n '6M': 15_552_000_000,\r\n '12M': 31_536_000_000,\r\n};\r\n\r\nexport function timeframeToMs(tf: TimeFrame): number {\r\n return TIMEFRAME_MS[tf];\r\n}\r\n\r\nexport function formatTimestamp(timestamp: number, tf: TimeFrame): string {\r\n const d = new Date(timestamp);\r\n const ms = TIMEFRAME_MS[tf];\r\n if (ms >= 86_400_000) {\r\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\r\n }\r\n if (ms >= 3_600_000) {\r\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\r\n }\r\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' });\r\n}\r\n\r\nexport function alignToTimeframe(timestamp: number, tf: TimeFrame): number {\r\n const ms = TIMEFRAME_MS[tf];\r\n return Math.floor(timestamp / ms) * ms;\r\n}\r\n\r\nexport interface TimeParts {\r\n year: number;\r\n month: number; // 1-12\r\n day: number;\r\n hours: number;\r\n minutes: number;\r\n}\r\n\r\n/**\r\n * Calendar parts of a timestamp in either the browser-local timezone\r\n * (`tzOffsetMinutes === null`) or a fixed UTC offset (e.g. -300 for EST).\r\n */\r\nexport function timeParts(timeMs: number, tzOffsetMinutes: number | null): TimeParts {\r\n if (tzOffsetMinutes === null) {\r\n const d = new Date(timeMs);\r\n return {\r\n year: d.getFullYear(),\r\n month: d.getMonth() + 1,\r\n day: d.getDate(),\r\n hours: d.getHours(),\r\n minutes: d.getMinutes(),\r\n };\r\n }\r\n const d = new Date(timeMs + tzOffsetMinutes * 60_000);\r\n return {\r\n year: d.getUTCFullYear(),\r\n month: d.getUTCMonth() + 1,\r\n day: d.getUTCDate(),\r\n hours: d.getUTCHours(),\r\n minutes: d.getUTCMinutes(),\r\n };\r\n}\r\n\r\n/**\r\n * A bar with no time-of-day component (a daily, weekly, monthly or yearly candle — always anchored\r\n * to a calendar-day boundary, so hours/minutes read 00:00) needs the YEAR in its label instead: a\r\n * bare `month/day` is ambiguous across years, and `00:00` tells a trader nothing. Detected from the\r\n * parts themselves rather than a separate timeframe parameter, so every caller that formats a bar's\r\n * time gets the same rule for free. The one false positive this accepts — a genuine intraday bar\r\n * landing exactly on midnight — is acceptable: real trade-driven timestamps essentially never do.\r\n */\r\nexport function isDateOnly(parts: Pick<TimeParts, 'hours' | 'minutes'>): boolean {\r\n return parts.hours === 0 && parts.minutes === 0;\r\n}\r\n\r\n/** A short timezone label like `UTC-5` or `UTC+5:30` (browser-local when null). */\r\nexport function tzLabel(tzOffsetMinutes: number | null): string {\r\n const min = tzOffsetMinutes === null ? -new Date().getTimezoneOffset() : tzOffsetMinutes;\r\n const sign = min >= 0 ? '+' : '-';\r\n const abs = Math.abs(min);\r\n const h = Math.floor(abs / 60);\r\n const m = abs % 60;\r\n return m === 0 ? `UTC${sign}${h}` : `UTC${sign}${h}:${String(m).padStart(2, '0')}`;\r\n}\r\n\r\n/** Day-of-week for a Monday-anchored reference week (1970-01-05 was a Monday, UTC). */\r\nconst WEEK_ANCHOR_MS = Date.UTC(1970, 0, 5);\r\n\r\nfunction parseTimeframe(tf: TimeFrame): { count: number; unit: 's' | 'm' | 'h' | 'd' | 'w' | 'M' } {\r\n const match = /^(\\d+)([smhdwM])$/.exec(tf);\r\n if (!match) return { count: 1, unit: 'm' };\r\n return { count: parseInt(match[1], 10), unit: match[2] as 's' | 'm' | 'h' | 'd' | 'w' | 'M' };\r\n}\r\n\r\n/**\r\n * Start of the bucket a timestamp falls into for a given timeframe.\r\n *\r\n * Intraday and daily frames are anchored to the Unix epoch (UTC) via fixed-ms\r\n * flooring. Weekly frames are anchored to Monday (or `weekStartsOn`), monthly\r\n * and yearly frames use calendar boundaries (1st of month, Jan for years) so\r\n * 3M aligns to quarters and 12M to calendar years.\r\n */\r\nexport function timeframeBucketStart(\r\n timestamp: number,\r\n tf: TimeFrame,\r\n weekStartsOn: 0 | 1 = 1,\r\n): number {\r\n const { count, unit } = parseTimeframe(tf);\r\n\r\n if (unit === 's' || unit === 'm' || unit === 'h' || unit === 'd') {\r\n const ms = TIMEFRAME_MS[tf];\r\n return Math.floor(timestamp / ms) * ms;\r\n }\r\n\r\n const d = new Date(timestamp);\r\n\r\n if (unit === 'w') {\r\n const dayMs = TIMEFRAME_MS['1d'];\r\n const dow = d.getUTCDay();\r\n const shift = (dow - weekStartsOn + 7) % 7;\r\n const weekStart = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate() - shift);\r\n if (count <= 1) return weekStart;\r\n const weekIndex = Math.floor((weekStart - WEEK_ANCHOR_MS) / (7 * dayMs));\r\n const grouped = Math.floor(weekIndex / count) * count;\r\n return WEEK_ANCHOR_MS + grouped * 7 * dayMs;\r\n }\r\n\r\n // months / quarters / years\r\n const totalMonths = d.getUTCFullYear() * 12 + d.getUTCMonth();\r\n const grouped = Math.floor(totalMonths / count) * count;\r\n return Date.UTC(Math.floor(grouped / 12), grouped % 12, 1);\r\n}\r\n","const NUMBER_FORMAT_CACHE_LIMIT = 64;\r\nconst numberFormatCache = new Map<string, Intl.NumberFormat>();\r\n\r\n/**\r\n * `Number#toLocaleString(locale, options)` constructs a fresh\r\n * `Intl.NumberFormat` on every call — ~20µs in V8 versus ~0.4µs to reuse one.\r\n * Axis labels, the legend, crosshair pills and panel axes format dozens of\r\n * numbers per frame, so formatters are cached per (locale, precision). The\r\n * output is identical: per spec, `toLocaleString` is defined as exactly this.\r\n */\r\nfunction numberFormat(locale: string, precision: number): Intl.NumberFormat {\r\n const key = `${locale}|${precision}`;\r\n let nf = numberFormatCache.get(key);\r\n if (!nf) {\r\n if (numberFormatCache.size >= NUMBER_FORMAT_CACHE_LIMIT) numberFormatCache.clear();\r\n nf = new Intl.NumberFormat(locale, {\r\n minimumFractionDigits: precision,\r\n maximumFractionDigits: precision,\r\n });\r\n numberFormatCache.set(key, nf);\r\n }\r\n return nf;\r\n}\r\n\r\nexport function formatPrice(value: number, precision = 2, locale = 'en-US'): string {\r\n return numberFormat(locale, precision).format(value);\r\n}\r\n\r\n/**\r\n * Decimals the price axis uses for a visible price range: one more than its\r\n * tick step needs, 2 at minimum. Everything that prints a price next to the\r\n * axis (legend, crosshair pill, last-price tag) shares it, so a sub-cent\r\n * asset reads \"0.000004349\" everywhere instead of \"0.00\" off the axis.\r\n */\r\nexport function autoPricePrecision(min: number, max: number): number {\r\n if (!(max > min) || !Number.isFinite(min) || !Number.isFinite(max)) return 2;\r\n const step = computeTickStep(min, max, 8);\r\n return step > 0 && step < 1 ? Math.ceil(-Math.log10(step)) + 1 : 2;\r\n}\r\n\r\nimport type { PriceScaleMode } from '../types/rendering.js';\r\nimport { computeTickStep } from './math.js';\r\n\r\n/**\r\n * Format a price-axis label for a given scale mode.\r\n *\r\n * - `regular` / `logarithmic`: the raw price.\r\n * - `percentage`: change from `baseline`, e.g. `+12.34%`.\r\n * - `indexedTo100`: the price rebased so `baseline` reads as 100.\r\n *\r\n * Falls back to a plain price when a baseline is required but missing/zero.\r\n */\r\nexport function formatPriceScaleLabel(\r\n price: number,\r\n mode: PriceScaleMode,\r\n baseline: number | undefined,\r\n precision = 2,\r\n locale = 'en-US',\r\n): string {\r\n if ((mode === 'percentage' || mode === 'indexedTo100') && baseline && baseline !== 0) {\r\n if (mode === 'percentage') {\r\n const pct = (price / baseline - 1) * 100;\r\n const sign = pct > 0 ? '+' : '';\r\n return `${sign}${pct.toFixed(2)}%`;\r\n }\r\n const indexed = (price / baseline) * 100;\r\n return formatPrice(indexed, 2, locale);\r\n }\r\n return formatPrice(price, precision, locale);\r\n}\r\n\r\nexport function formatVolume(value: number): string {\r\n if (value >= 1_000_000_000) return (value / 1_000_000_000).toFixed(2) + 'B';\r\n if (value >= 1_000_000) return (value / 1_000_000).toFixed(2) + 'M';\r\n if (value >= 1_000) return (value / 1_000).toFixed(2) + 'K';\r\n return value.toFixed(0);\r\n}\r\n\r\nexport function detectPrecision(values: number[]): number {\r\n let maxDecimals = 0;\r\n for (const v of values) {\r\n const str = v.toString();\r\n const dot = str.indexOf('.');\r\n if (dot >= 0) {\r\n maxDecimals = Math.max(maxDecimals, str.length - dot - 1);\r\n }\r\n }\r\n return Math.min(maxDecimals, 8);\r\n}\r\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","import type { Theme } from '../types/theme.js';\r\n\r\nconst DEFAULT_FONT = {\r\n family: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\r\n sizeSmall: 10,\r\n sizeMedium: 12,\r\n sizeLarge: 14,\r\n};\r\n\r\n/**\r\n * TradeCanvas palette. Themes pick their own candle colours for their\r\n * background; everything drawn on top of either theme (indicators, orders,\r\n * signals, drawings) uses the theme-neutral values below, which keep at\r\n * least 3:1 contrast on both the dark ink and a white background. `amber` is\r\n * the brand accent for dark surfaces (2:1 on white); light surfaces use\r\n * `LIGHT_THEME.lineColor` / `ochre` instead.\r\n */\r\nexport const TC_PALETTE = {\r\n /** Brand amber — the default series line and the accent. */\r\n amber: '#f2a93b',\r\n /** Rising / bullish, legible on dark and light. */\r\n up: '#1fa874',\r\n /** Falling / bearish, legible on dark and light. */\r\n down: '#e8505b',\r\n /** Amber deep enough for white backgrounds; auto-coloured series use it. */\r\n ochre: '#c98316',\r\n /** Secondary series, signal lines. */\r\n blue: '#4c8dff',\r\n violet: '#a57cff',\r\n cyan: '#1398a8',\r\n rose: '#e25592',\r\n /** Zero lines, neutral guides. */\r\n neutral: '#7d8696',\r\n /** Ink ground of the dark theme. */\r\n ink: '#0c1016',\r\n} as const;\r\n\r\n/** Order in which overlay indicators are coloured when no colour is given. */\r\nexport const TC_SERIES_COLORS: readonly string[] = [\r\n TC_PALETTE.blue,\r\n TC_PALETTE.ochre,\r\n TC_PALETTE.violet,\r\n TC_PALETTE.cyan,\r\n TC_PALETTE.rose,\r\n];\r\n\r\nexport const DARK_THEME: Theme = {\r\n name: 'dark',\r\n background: TC_PALETTE.ink,\r\n text: '#d9dde4',\r\n textSecondary: '#7d8696',\r\n grid: '#161b23',\r\n crosshair: '#8a93a3',\r\n candleUp: '#3ccf91',\r\n candleDown: '#f0616d',\r\n candleUpWick: '#3ccf91',\r\n candleDownWick: '#f0616d',\r\n lineColor: TC_PALETTE.amber,\r\n areaTopColor: 'rgba(242, 169, 59, 0.32)',\r\n areaBottomColor: 'rgba(242, 169, 59, 0.0)',\r\n volumeUp: 'rgba(60, 207, 145, 0.28)',\r\n volumeDown: 'rgba(240, 97, 109, 0.28)',\r\n axisLine: '#1f2630',\r\n axisLabel: '#c3c9d3',\r\n axisLabelBackground: '#1f2630',\r\n font: DEFAULT_FONT,\r\n};\r\n\r\nexport const LIGHT_THEME: Theme = {\r\n name: 'light',\r\n background: '#ffffff',\r\n text: '#0f131a',\r\n textSecondary: '#6b7380',\r\n grid: '#eef0f3',\r\n crosshair: '#8a93a3',\r\n candleUp: '#16a36a',\r\n candleDown: '#d9414f',\r\n candleUpWick: '#16a36a',\r\n candleDownWick: '#d9414f',\r\n lineColor: '#c77a0a',\r\n areaTopColor: 'rgba(199, 122, 10, 0.24)',\r\n areaBottomColor: 'rgba(199, 122, 10, 0.0)',\r\n volumeUp: 'rgba(22, 163, 106, 0.25)',\r\n volumeDown: 'rgba(217, 65, 79, 0.25)',\r\n axisLine: '#dde1e7',\r\n axisLabel: '#3f4754',\r\n axisLabelBackground: '#eef0f3',\r\n font: DEFAULT_FONT,\r\n};\r\n\r\nexport const DARK_TERMINAL: Theme = {\r\n name: 'terminal',\r\n background: '#0E0E0E',\r\n text: '#C0C0C0',\r\n textSecondary: '#8A8A8A',\r\n grid: '#1A1A1A',\r\n crosshair: '#666666',\r\n candleUp: '#00FF87',\r\n candleDown: '#FF3B4D',\r\n candleUpWick: '#00FF87',\r\n candleDownWick: '#FF3B4D',\r\n lineColor: '#3D8BFD',\r\n areaTopColor: 'rgba(61, 139, 253, 0.3)',\r\n areaBottomColor: 'rgba(61, 139, 253, 0.0)',\r\n volumeUp: 'rgba(0, 255, 135, 0.2)',\r\n volumeDown: 'rgba(255, 59, 77, 0.2)',\r\n axisLine: '#1A1A1A',\r\n axisLabel: '#8A8A8A',\r\n axisLabelBackground: '#1A1A1A',\r\n font: {\r\n family: \"'Roboto Mono', 'JetBrains Mono', 'SF Mono', Consolas, monospace\",\r\n sizeSmall: 10,\r\n sizeMedium: 12,\r\n sizeLarge: 14,\r\n },\r\n};\r\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';\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\nexport function formatVolumeLoc(value: number, locale?: string): string {\n if (value >= 1e9) return formatNumber(value / 1e9, 2, locale ?? currentLocale) + 'B';\n if (value >= 1e6) return formatNumber(value / 1e6, 2, locale ?? currentLocale) + 'M';\n if (value >= 1e3) return formatNumber(value / 1e3, 2, locale ?? currentLocale) + 'K';\n return formatNumber(value, 0, locale ?? currentLocale);\n}\n","import type { MarketConfig, MarketColorScheme, TradingSession } from './types.js';\nimport type { Theme } from '../types/theme.js';\n\n// Vietnam stock color convention:\n// Purple/Red = ceiling (trần) - max up\n// Green/Cyan = floor (sàn) - max down\n// Yellow = reference (tham chiếu)\n// Red = up, Blue = down (common VN convention)\nexport const VN_COLORS: MarketColorScheme = {\n up: '#FF0000', // Đỏ - tăng\n down: '#0000FF', // Xanh dương - giảm\n unchanged: '#FFD700', // Vàng - tham chiếu\n ceiling: '#FF00FF', // Tím - trần\n floor: '#00FFFF', // Xanh lam - sàn\n reference: '#FFD700', // Vàng - tham chiếu\n};\n\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: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// Market presets\nexport const MARKET_HOSE: MarketConfig = {\n type: 'stock',\n exchange: 'HOSE',\n currency: 'VND',\n pricePrecision: 2,\n volumeUnit: 10,\n priceStep: 0.05,\n priceLimits: { enabled: true, ceilingPercent: 7, floorPercent: 7 },\n sessions: HOSE_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\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 priceLimits: { enabled: true, ceilingPercent: 10, floorPercent: 10 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\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 priceLimits: { enabled: true, ceilingPercent: 15, floorPercent: 15 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_CRYPTO: MarketConfig = {\n type: 'crypto',\n currency: 'USDT',\n pricePrecision: 2,\n priceLimits: { enabled: false },\n};\n\nexport const MARKET_NYSE: MarketConfig = {\n type: 'stock',\n exchange: 'NYSE',\n currency: 'USD',\n pricePrecision: 2,\n priceStep: 0.01,\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: 'preClose' },\n ],\n};\n\n// Build a theme variant for VN stock market\nexport function createVNTheme(base: Theme): Theme {\n return {\n ...base,\n candleUp: VN_COLORS.up,\n candleDown: VN_COLORS.down,\n candleUpWick: VN_COLORS.up,\n candleDownWick: VN_COLORS.down,\n volumeUp: 'rgba(255, 0, 0, 0.3)',\n volumeDown: 'rgba(0, 0, 255, 0.3)',\n };\n}\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 return {\n ceiling: referencePrice * (1 + ceilPct),\n floor: referencePrice * (1 - floorPct),\n reference: referencePrice,\n };\n}\n\nexport function getCurrentSession(sessions: TradingSession[]): TradingSession | null {\n const now = new Date();\n const hhmm = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;\n for (const session of sessions) {\n if (hhmm >= session.startTime && hhmm < session.endTime) return session;\n }\n return null;\n}\n"],"mappings":"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"}
@@ -13,13 +13,13 @@ export interface FeaturesConfig {
13
13
  drawings?: boolean;
14
14
  /** Whitelist of allowed drawing tool types. When set, only these tools are available. */
15
15
  drawingTools?: DrawingToolType[];
16
- /** Enable magnet/snap for drawing anchors */
16
+ /** Allow magnet/snap for drawing anchors. When false, `setDrawingMagnet(true)` is ignored. */
17
17
  drawingMagnet?: boolean;
18
18
  /** Enable undo/redo for drawings (Ctrl+Z / Ctrl+Y) */
19
19
  drawingUndoRedo?: boolean;
20
20
  /** Enable trading features (orders, positions, context menu) */
21
21
  trading?: boolean;
22
- /** Enable right-click context menu for placing orders */
22
+ /** Right-click menu for placing orders. Default `false` — opt in explicitly. */
23
23
  tradingContextMenu?: boolean;
24
24
  /** Enable indicator overlays and panels */
25
25
  indicators?: boolean;
@@ -33,7 +33,7 @@ export interface FeaturesConfig {
33
33
  crosshair?: boolean;
34
34
  /**
35
35
  * Show the floating OHLCV tooltip that follows the cursor on hover.
36
- * TradingView-style charts rely on the top-left legend (`legend`) instead
36
+ * Pro trading charts usually rely on the top-left legend (`legend`) instead
37
37
  * of a cursor-following popup — set this to `false` to match that and
38
38
  * keep only the legend updating on hover.
39
39
  */
@@ -62,17 +62,20 @@ export interface FeaturesConfig {
62
62
  replay?: boolean;
63
63
  /** Show session break lines (day separators) */
64
64
  sessionBreaks?: boolean;
65
- /** Show bar countdown timer (time until current candle closes) */
65
+ /** Show bar countdown timer (time until current candle closes). When false it stays hidden. */
66
66
  barCountdown?: boolean;
67
- /** Enable compare/overlay symbols */
67
+ /** Enable compare/overlay symbols. When false, `addCompareSymbol` does nothing. */
68
68
  compareSymbols?: boolean;
69
- /** Enable data export (CSV/JSON) */
69
+ /** Enable data export (CSV/JSON). When false, `exportVisibleData` / `exportAllData` do nothing. */
70
70
  dataExport?: boolean;
71
- /** Enable logarithmic price scale toggle */
71
+ /** Allow the logarithmic price scale. When false, switching to it is ignored. */
72
72
  logScale?: boolean;
73
- /** Whitelist of available timeframes. When set, only these are selectable. */
73
+ /**
74
+ * Whitelist of timeframes. When set, `setTimeframe` ignores any other, and
75
+ * ChartWidget offers only these.
76
+ */
74
77
  timeframes?: TimeFrame[];
75
- /** Default favorite timeframes shown in the quick-access bar */
78
+ /** ChartWidget: timeframes on the quick-access bar until the user changes them. */
76
79
  defaultTimeframeFavorites?: TimeFrame[];
77
80
  }
78
81
  export interface ChartOptions {
@@ -97,6 +100,17 @@ export interface ChartOptions {
97
100
  features?: FeaturesConfig;
98
101
  /** BCP 47 locale for number formatting (e.g. 'en-US', 'de-DE', 'vi-VN'). Defaults to 'en-US'. */
99
102
  numberLocale?: string;
103
+ /**
104
+ * Free panning (default `true`): drag past the newest bar
105
+ * into empty future space, or past the oldest bar, until `panLimits.minVisibleBars`
106
+ * bars remain. `false` restores the pre-1.3 clamp (newest bar stops at its
107
+ * resting position).
108
+ */
109
+ freePan?: boolean;
110
+ /** Bounds for free panning. */
111
+ panLimits?: {
112
+ minVisibleBars?: number;
113
+ };
100
114
  }
101
115
  export interface SessionBreakOptions {
102
116
  visible?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"chart.d.ts","sourceRoot":"","sources":["../../src/types/chart.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,MAAM,SAAS,GACjB,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GACvC,YAAY,GAAG,cAAc,GAAG,UAAU,GAC1C,OAAO,GAAG,WAAW,GAAG,MAAM,GAAG,gBAAgB,GACjD,WAAW,GACX,eAAe,GAAG,SAAS,GAAG,UAAU,GAAG,iBAAiB,GAC5D,YAAY,CAAC;AAEjB,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEtD;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAE7B,mFAAmF;IACnF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yFAAyF;IACzF,YAAY,CAAC,EAAE,eAAe,EAAE,CAAC;IACjC,6CAA6C;IAC7C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,sDAAsD;IACtD,eAAe,CAAC,EAAE,OAAO,CAAC;IAG1B,gEAAgE;IAChE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yDAAyD;IACzD,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAG7B,2CAA2C;IAC3C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAGxB,6BAA6B;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sCAAsC;IACtC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,uBAAuB;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,OAAO,CAAC;IAGnB,sBAAsB;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sBAAsB;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,gCAAgC;IAChC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,qCAAqC;IACrC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0BAA0B;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;IAGpB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gCAAgC;IAChC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,0BAA0B;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wBAAwB;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gDAAgD;IAChD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kEAAkE;IAClE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,qCAAqC;IACrC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,oCAAoC;IACpC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;IAGnB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC;IACzB,gEAAgE;IAChE,yBAAyB,CAAC,EAAE,SAAS,EAAE,CAAC;CACzC;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,yCAAyC;IACzC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,sDAAsD;IACtD,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,iGAAiG;IACjG,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACrC,KAAK,CAAC,EAAE,oBAAoB,CAAC;IAC7B,KAAK,CAAC,EAAE,oBAAoB,CAAC;CAC9B;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,SAAS,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,YAAY,CAAC;CAC7C;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
1
+ {"version":3,"file":"chart.d.ts","sourceRoot":"","sources":["../../src/types/chart.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,8 @@
1
1
  import { OHLCBar, DataSeries } from './ohlc.js';
2
2
  import { Point } from './rendering.js';
3
3
  import { IndicatorValue } from './indicator.js';
4
- export type ChartEventType = 'crosshairMove' | 'click' | 'barClick' | 'visibleRangeChange' | 'priceRangeChange' | 'zoomChange' | 'dataUpdate' | 'indicatorAdd' | 'indicatorRemove' | 'themeChange' | 'resize' | 'orderPlace' | 'orderModify' | 'orderCancel' | 'positionClose' | 'positionModify' | 'executionError' | 'bracketPlace' | 'drawingCreate' | 'drawingRemove' | 'signalMarkerAdd' | 'signalMarkerRemove' | 'tradeZoneAdd' | 'tradeZoneRemove' | 'alertAdd' | 'alertRemove' | 'alertTriggered' | 'alertUpdate';
4
+ import { DrawingToolType } from './drawing.js';
5
+ export type ChartEventType = 'crosshairMove' | 'crosshairLeave' | 'click' | 'barClick' | 'visibleRangeChange' | 'priceRangeChange' | 'zoomChange' | 'dataUpdate' | 'indicatorAdd' | 'indicatorRemove' | 'paneResize' | 'indicatorUpdate' | 'themeChange' | 'resize' | 'orderPlace' | 'orderModify' | 'orderCancel' | 'positionClose' | 'positionModify' | 'executionError' | 'bracketPlace' | 'drawingCreate' | 'drawingRemove' | 'drawingToolChange' | 'signalMarkerAdd' | 'signalMarkerRemove' | 'tradeZoneAdd' | 'tradeZoneRemove' | 'alertAdd' | 'alertRemove' | 'alertTriggered' | 'alertUpdate';
5
6
  export interface ChartEvent<T = unknown> {
6
7
  type: ChartEventType;
7
8
  timestamp: number;
@@ -130,6 +131,8 @@ export interface AlertPayload {
130
131
  }
131
132
  export interface ChartEventMap {
132
133
  crosshairMove: CrosshairMovePayload;
134
+ /** The pointer left the plot; the crosshair is gone. */
135
+ crosshairLeave: Record<string, never>;
133
136
  click: {
134
137
  x: number;
135
138
  y: number;
@@ -141,6 +144,15 @@ export interface ChartEventMap {
141
144
  dataUpdate: DataSeries;
142
145
  indicatorAdd: IndicatorChangePayload;
143
146
  indicatorRemove: IndicatorChangePayload;
147
+ /** An indicator pane was resized (by dragging its divider or `setPanelSize`). */
148
+ paneResize: {
149
+ instanceId: string;
150
+ size: number;
151
+ };
152
+ /** Indicator values were recomputed from bar index `from` on: new bars, a live tick, a replay step. */
153
+ indicatorUpdate: {
154
+ from: number;
155
+ };
144
156
  themeChange: ThemeChangePayload;
145
157
  resize: ResizePayload;
146
158
  orderPlace: OrderPlacePayload;
@@ -152,6 +164,10 @@ export interface ChartEventMap {
152
164
  executionError: ExecutionErrorPayload;
153
165
  drawingCreate: DrawingCreatePayload;
154
166
  drawingRemove: DrawingRemovePayload;
167
+ /** The active drawing tool changed — picked, finished, or cancelled (`tool: null`). */
168
+ drawingToolChange: {
169
+ tool: DrawingToolType | null;
170
+ };
155
171
  signalMarkerAdd: SignalMarkerAddPayload;
156
172
  signalMarkerRemove: SignalMarkerRemovePayload;
157
173
  tradeZoneAdd: TradeZoneAddPayload;
@@ -1 +1 @@
1
- {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/types/events.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/types/events.ts"],"names":[],"mappings":"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"}
@@ -104,14 +104,25 @@ export interface GaugeOptions extends BaseFinanceChartOptions {
104
104
  value: number;
105
105
  min?: number;
106
106
  max?: number;
107
+ /** Coloured bands; the part below the value is drawn bright, the rest dimmed. */
107
108
  zones?: GaugeZone[];
109
+ /** Ring width as a share of the radius. Default `0.14`. */
108
110
  thickness?: number;
111
+ /** Arc start in degrees, clockwise from 3 o'clock. Default `150` (a 240° sweep open at the bottom). */
109
112
  startAngle?: number;
113
+ /** Arc end in degrees. Default `390`. */
110
114
  endAngle?: number;
111
115
  showValue?: boolean;
112
116
  showZoneLabels?: boolean;
113
117
  label?: string;
114
118
  valueFormat?: (v: number) => string;
119
+ /**
120
+ * How the value is pointed at: `'marker'` (default) rides a knob on the
121
+ * ring and keeps the centre free for the number; `'needle'` draws a classic
122
+ * needle from a hub, with the number moved below it.
123
+ */
124
+ pointer?: 'marker' | 'needle';
125
+ /** Needle colour (`pointer: 'needle'`); without zones, also the progress colour. */
115
126
  needleColor?: string;
116
127
  trackColor?: string;
117
128
  animate?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"finance.d.ts","sourceRoot":"","sources":["../../src/types/finance.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"finance.d.ts","sourceRoot":"","sources":["../../src/types/finance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,WAAW,uBAAuB;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAiB,SAAQ,uBAAuB;IAC/D,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAkB,SAAQ,uBAAuB;IAChE,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;CACxC;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAmB,SAAQ,uBAAuB;IACjE,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,cAAe,SAAQ,uBAAuB;IAC7D,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;IACF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,MAAM,CAAC;IAC5C,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;IAC1C,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG,OAAO,GAAG,UAAU,CAAC;CACvD;AAED,MAAM,WAAW,gBAAiB,SAAQ,uBAAuB;IAC/D,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAa,SAAQ,uBAAuB;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;IACpB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uGAAuG;IACvG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC;;;;OAIG;IACH,OAAO,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC9B,oFAAoF;IACpF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B"}
@@ -43,11 +43,13 @@ export interface ViewportState {
43
43
  * close of the first visible bar. Set by the chart each frame.
44
44
  */
45
45
  scaleBaseline?: number;
46
+ /** Upside down: higher prices lower on screen. */
47
+ invertScale?: boolean;
46
48
  /**
47
49
  * Optional reference to the current bar series. When set, drawings/indicators
48
50
  * treat `anchor.time` as a real timestamp and convert to bar index via
49
51
  * `timestampToBarIndex(time, data)` at render/hit-test time. This lets
50
- * anchors survive timeframe / symbol switches like TradingView. When unset,
52
+ * anchors survive timeframe / symbol switches. When unset,
51
53
  * `anchor.time` is treated as a raw bar index (legacy behavior).
52
54
  */
53
55
  data?: ReadonlyArray<{
@@ -60,11 +62,19 @@ export interface ViewportState {
60
62
  */
61
63
  priceAxisWidth?: number;
62
64
  }
65
+ /**
66
+ * What changed, for `requestRender()`. The chart paints two canvases: a scene
67
+ * (everything that follows data, viewport and chart objects) and a thin top
68
+ * canvas for pointer-tied visuals. Any type except `Hover` redraws both;
69
+ * `Hover` redraws only the top canvas (crosshair, its axis pills, legend,
70
+ * bar countdown, measure ruler, selection box).
71
+ */
63
72
  export declare enum LayerType {
64
73
  Background = 0,
65
74
  Main = 1,
66
75
  Panel = 2,
67
76
  Overlay = 3,
68
- UI = 4
77
+ UI = 4,
78
+ Hover = 5
69
79
  }
70
80
  //# sourceMappingURL=rendering.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rendering.d.ts","sourceRoot":"","sources":["../../src/types/rendering.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,KAAK;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,IAAI;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,IAAI;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,aAAa,GAAG,YAAY,GAAG,cAAc,CAAC;AAEvF,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,UAAU,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvC;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,oBAAY,SAAS;IACnB,UAAU,IAAI;IACd,IAAI,IAAI;IACR,KAAK,IAAI;IACT,OAAO,IAAI;IACX,EAAE,IAAI;CACP"}
1
+ {"version":3,"file":"rendering.d.ts","sourceRoot":"","sources":["../../src/types/rendering.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,KAAK;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,IAAI;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,IAAI;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,aAAa,GAAG,YAAY,GAAG,cAAc,CAAC;AAEvF,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,UAAU,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kDAAkD;IAClD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvC;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;GAMG;AACH,oBAAY,SAAS;IACnB,UAAU,IAAI;IACd,IAAI,IAAI;IACR,KAAK,IAAI;IACT,OAAO,IAAI;IACX,EAAE,IAAI;IACN,KAAK,IAAI;CACV"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tradecanvas/commons",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "description": "Shared types and utilities for @tradecanvas/chart",
6
6
  "license": "MIT",