@tradecanvas/commons 1.2.0 → 1.3.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/constants/themes.d.ts +29 -0
- package/dist/constants/themes.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +139 -122
- package/dist/index.js.map +1 -1
- package/dist/types/chart.d.ts +13 -2
- package/dist/types/chart.d.ts.map +1 -1
- package/dist/types/finance.d.ts +11 -0
- package/dist/types/finance.d.ts.map +1 -1
- package/dist/types/rendering.d.ts +10 -2
- package/dist/types/rendering.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/types/rendering.ts","../src/types/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 {\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. 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\n/**\r\n * What changed, for `requestRender()`. The chart paints two canvases: a scene\r\n * (everything that follows data, viewport and chart objects) and a thin top\r\n * canvas for pointer-tied visuals. Any type except `Hover` redraws both;\r\n * `Hover` redraws only the top canvas (crosshair, its axis pills, legend,\r\n * bar countdown, measure ruler, selection box).\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 Hover = 5,\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: '#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';\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\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';\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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"}
|
package/dist/types/chart.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export interface FeaturesConfig {
|
|
|
19
19
|
drawingUndoRedo?: boolean;
|
|
20
20
|
/** Enable trading features (orders, positions, context menu) */
|
|
21
21
|
trading?: boolean;
|
|
22
|
-
/**
|
|
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
|
-
*
|
|
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
|
*/
|
|
@@ -97,6 +97,17 @@ export interface ChartOptions {
|
|
|
97
97
|
features?: FeaturesConfig;
|
|
98
98
|
/** BCP 47 locale for number formatting (e.g. 'en-US', 'de-DE', 'vi-VN'). Defaults to 'en-US'. */
|
|
99
99
|
numberLocale?: string;
|
|
100
|
+
/**
|
|
101
|
+
* Free panning (default `true`): drag past the newest bar
|
|
102
|
+
* into empty future space, or past the oldest bar, until `panLimits.minVisibleBars`
|
|
103
|
+
* bars remain. `false` restores the pre-1.3 clamp (newest bar stops at its
|
|
104
|
+
* resting position).
|
|
105
|
+
*/
|
|
106
|
+
freePan?: boolean;
|
|
107
|
+
/** Bounds for free panning. */
|
|
108
|
+
panLimits?: {
|
|
109
|
+
minVisibleBars?: number;
|
|
110
|
+
};
|
|
100
111
|
}
|
|
101
112
|
export interface SessionBreakOptions {
|
|
102
113
|
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,
|
|
1
|
+
{"version":3,"file":"chart.d.ts","sourceRoot":"","sources":["../../src/types/chart.ts"],"names":[],"mappings":"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"}
|
package/dist/types/finance.d.ts
CHANGED
|
@@ -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":"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"}
|
|
@@ -47,7 +47,7 @@ export interface ViewportState {
|
|
|
47
47
|
* Optional reference to the current bar series. When set, drawings/indicators
|
|
48
48
|
* treat `anchor.time` as a real timestamp and convert to bar index via
|
|
49
49
|
* `timestampToBarIndex(time, data)` at render/hit-test time. This lets
|
|
50
|
-
* anchors survive timeframe / symbol switches
|
|
50
|
+
* anchors survive timeframe / symbol switches. When unset,
|
|
51
51
|
* `anchor.time` is treated as a raw bar index (legacy behavior).
|
|
52
52
|
*/
|
|
53
53
|
data?: ReadonlyArray<{
|
|
@@ -60,11 +60,19 @@ export interface ViewportState {
|
|
|
60
60
|
*/
|
|
61
61
|
priceAxisWidth?: number;
|
|
62
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* What changed, for `requestRender()`. The chart paints two canvases: a scene
|
|
65
|
+
* (everything that follows data, viewport and chart objects) and a thin top
|
|
66
|
+
* canvas for pointer-tied visuals. Any type except `Hover` redraws both;
|
|
67
|
+
* `Hover` redraws only the top canvas (crosshair, its axis pills, legend,
|
|
68
|
+
* bar countdown, measure ruler, selection box).
|
|
69
|
+
*/
|
|
63
70
|
export declare enum LayerType {
|
|
64
71
|
Background = 0,
|
|
65
72
|
Main = 1,
|
|
66
73
|
Panel = 2,
|
|
67
74
|
Overlay = 3,
|
|
68
|
-
UI = 4
|
|
75
|
+
UI = 4,
|
|
76
|
+
Hover = 5
|
|
69
77
|
}
|
|
70
78
|
//# 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;
|
|
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;;;;;;GAMG;AACH,oBAAY,SAAS;IACnB,UAAU,IAAI;IACd,IAAI,IAAI;IACR,KAAK,IAAI;IACT,OAAO,IAAI;IACX,EAAE,IAAI;IACN,KAAK,IAAI;CACV"}
|