@tradecanvas/commons 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=function(e){return e[e.Background=0]=`Background`,e[e.Main=1]=`Main`,e[e.Panel=2]=`Panel`,e[e.Overlay=3]=`Overlay`,e[e.UI=4]=`UI`,e}({}),t={color:`#2196F3`,lineWidth:1,lineStyle:`solid`,fillColor:`rgba(33, 150, 243, 0.1)`,fillOpacity:.1,fontSize:12},n={enabled:!0,orderColors:{buy:`#26A69A`,sell:`#EF5350`},positionColors:{profit:`#26A69A`,loss:`#EF5350`,entry:`#2196F3`},depthOverlay:{enabled:!1,bidColor:`rgba(38,166,154,0.15)`,askColor:`rgba(239,83,80,0.15)`,maxWidth:100},contextMenu:{enabled:!0},pricePrecision:2,dragThreshold:3},r={enabled:!0,maxRetries:1/0,baseDelay:1e3,maxDelay:3e4,backoffMultiplier:2},i={historyLimit:500,autoScroll:!0,showCurrentPriceLine:!0,aggregateTicks:!1};function a(e,t,n){return Math.max(t,Math.min(n,e))}function o(e,t,n){return e+(t-e)*n}function s(e,t,n){return e===t?0:(n-e)/(t-e)}function c(e,t){return Math.round(e/t)*t}function l(e,t){let n=Math.floor(Math.log10(e)),r=e/10**n,i;return i=t?r<1.5?1:r<3?2:r<7?5:10:r<=1?1:r<=2?2:r<=5?5:10,i*10**n}function u(e,t,n){return l(l(t-e,!1)/(n-1),!0)}function d(e,t,n){let r=Math.max(0,t),i=Math.min(e.length,n+1);return e.slice(r,i)}function f(e,t){let n=0,r=e.length-1;for(;n<=r;){let i=n+r>>>1;if(e[i].time<t)n=i+1;else if(e[i].time>t)r=i-1;else return i}return n}function p(e,t,n,r=.05){if(e.length===0)return{min:0,max:1};let i=Math.max(0,t),a=Math.min(e.length-1,n),o=1/0,s=-1/0;for(let t=i;t<=a;t++)e[t].low<o&&(o=e[t].low),e[t].high>s&&(s=e[t].high);if(o===1/0)return{min:0,max:1};let c=s-o||1;return{min:o-c*r,max:s+c*r}}function m(e,t){return{...e,high:Math.max(e.high,t.price),low:Math.min(e.low,t.price),close:t.price,volume:e.volume+(t.volume??0),time:t.time}}function h(e,t=1){return`rgba(${parseInt(e.slice(1,3),16)}, ${parseInt(e.slice(3,5),16)}, ${parseInt(e.slice(5,7),16)}, ${t})`}function g(e,t){if(e.startsWith(`#`))return h(e,t);let n=e.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);return n?`rgba(${n[1]}, ${n[2]}, ${n[3]}, ${t})`:e}function _(e,t,n){let r=e=>(e=e.replace(`#`,``),e.length===3&&(e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]),{r:parseInt(e.slice(0,2),16),g:parseInt(e.slice(2,4),16),b:parseInt(e.slice(4,6),16)}),i=r(e),a=r(t);return`rgb(${Math.round(i.r+(a.r-i.r)*n)},${Math.round(i.g+(a.g-i.g)*n)},${Math.round(i.b+(a.b-i.b)*n)})`}var v={"1s":1e3,"5s":5e3,"15s":15e3,"30s":3e4,"1m":6e4,"3m":18e4,"5m":3e5,"15m":9e5,"30m":18e5,"45m":27e5,"1h":36e5,"2h":72e5,"3h":108e5,"4h":144e5,"6h":216e5,"8h":288e5,"12h":432e5,"1d":864e5,"2d":1728e5,"3d":2592e5,"1w":6048e5,"2w":12096e5,"1M":2592e6,"3M":7776e6,"6M":15552e6,"12M":31536e6};function y(e){return v[e]}function b(e,t){let n=new Date(e),r=v[t];return r>=864e5?n.toLocaleDateString(void 0,{month:`short`,day:`numeric`}):r>=36e5?n.toLocaleTimeString(void 0,{hour:`2-digit`,minute:`2-digit`}):n.toLocaleTimeString(void 0,{hour:`2-digit`,minute:`2-digit`,second:`2-digit`})}function x(e,t){let n=v[t];return Math.floor(e/n)*n}function ee(e,t=2){return e.toFixed(t)}function S(e){return e>=1e9?(e/1e9).toFixed(2)+`B`:e>=1e6?(e/1e6).toFixed(2)+`M`:e>=1e3?(e/1e3).toFixed(2)+`K`:e.toFixed(0)}function C(e){let t=0;for(let n of e){let e=n.toString(),r=e.indexOf(`.`);r>=0&&(t=Math.max(t,e.length-r-1))}return Math.min(t,8)}var w={autoScale:!0,rightMargin:5,minBarSpacing:2,maxBarSpacing:30,grid:{visible:!0,hLineStyle:`solid`,vLineStyle:`solid`},crosshair:{mode:`magnet`}},T=[`1s`,`1m`,`3m`,`5m`,`15m`,`30m`,`1h`,`2h`,`4h`,`6h`,`8h`,`12h`,`1d`,`3d`,`1w`,`1M`],E=[`1m`,`5m`,`15m`,`30m`,`1h`,`2h`,`4h`,`1d`,`1w`,`1M`,`3M`,`6M`,`12M`],D=[`1m`,`5m`,`15m`,`30m`,`1h`,`4h`,`1d`,`1w`,`1M`],O=[`1m`,`5m`,`15m`,`1h`,`4h`,`1d`,`1w`],k=8,A=2,j=70,M=30,N=60,P=120,F={family:`-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`,sizeSmall:10,sizeMedium:12,sizeLarge:14},I={name:`dark`,background:`#131722`,text:`#D1D4DC`,textSecondary:`#787B86`,grid:`#1E222D`,crosshair:`#9598A1`,candleUp:`#26A69A`,candleDown:`#EF5350`,candleUpWick:`#26A69A`,candleDownWick:`#EF5350`,lineColor:`#2196F3`,areaTopColor:`rgba(33, 150, 243, 0.4)`,areaBottomColor:`rgba(33, 150, 243, 0.0)`,volumeUp:`rgba(38, 166, 154, 0.3)`,volumeDown:`rgba(239, 83, 80, 0.3)`,axisLine:`#2A2E39`,axisLabel:`#D1D4DC`,axisLabelBackground:`#2A2E39`,font:F},L={name:`light`,background:`#FFFFFF`,text:`#131722`,textSecondary:`#787B86`,grid:`#F0F3FA`,crosshair:`#9598A1`,candleUp:`#26A69A`,candleDown:`#EF5350`,candleUpWick:`#26A69A`,candleDownWick:`#EF5350`,lineColor:`#2196F3`,areaTopColor:`rgba(33, 150, 243, 0.4)`,areaBottomColor:`rgba(33, 150, 243, 0.0)`,volumeUp:`rgba(38, 166, 154, 0.3)`,volumeDown:`rgba(239, 83, 80, 0.3)`,axisLine:`#E0E3EB`,axisLabel:`#131722`,axisLabelBackground:`#F0F3FA`,font:F},R={candlestick:`Candlestick`,line:`Line`,area:`Area`,bar:`OHLC Bar`,price:`Price`,volume:`Volume`,time:`Time`,open:`Open`,high:`High`,low:`Low`,close:`Close`,sma:`SMA`,ema:`EMA`,bollingerBands:`Bollinger Bands`,vwap:`VWAP`,ichimoku:`Ichimoku Cloud`,parabolicSAR:`Parabolic SAR`,supertrend:`Supertrend`,keltnerChannel:`Keltner Channel`,donchianChannel:`Donchian Channel`,rsi:`RSI`,macd:`MACD`,stochastic:`Stochastic`,atr:`ATR`,adx:`ADX`,obv:`OBV`,williamsR:`Williams %R`,cci:`CCI`,mfi:`MFI`,aroon:`Aroon`,roc:`ROC`,tsi:`TSI`,cmf:`CMF`,stddev:`Std Dev`,volumeProfile:`Volume Profile`,accumulationDistribution:`A/D Line`,vroc:`VROC`,trendLine:`Trend Line`,horizontalLine:`Horizontal Line`,verticalLine:`Vertical Line`,ray:`Ray`,extendedLine:`Extended Line`,parallelChannel:`Parallel Channel`,regressionChannel:`Regression Channel`,fibRetracement:`Fibonacci Retracement`,fibExtension:`Fibonacci Extension`,rectangle:`Rectangle`,ellipse:`Ellipse`,triangle:`Triangle`,pitchfork:`Andrews' Pitchfork`,elliottWave:`Elliott Wave`,priceRange:`Price Range`,dateRange:`Date Range`,measure:`Measure`,textTool:`Text`,arrow:`Arrow`,clearAll:`Clear All`,buy:`Buy`,sell:`Sell`,buyLimit:`Buy Limit`,sellLimit:`Sell Limit`,buyStop:`Buy Stop`,sellStop:`Sell Stop`,stopLoss:`Stop Loss`,takeProfit:`Take Profit`,market:`Market`,limit:`Limit`,stop:`Stop`,cancel:`Cancel`,modify:`Modify`,quantity:`Qty`,pnl:`P&L`,activeOrders:`Active Orders`,positions:`Positions`,noOrders:`No active orders`,noPositions:`No open positions`,placeOrder:`Place Order`,rightClickToTrade:`Right-click chart to place orders`,ceiling:`Ceiling`,floor:`Floor`,reference:`Reference`,session:`Session`,preOpen:`Pre-Open`,continuous:`Continuous`,preClose:`Pre-Close`,closed:`Closed`,settings:`Settings`,theme:`Theme`,darkTheme:`Dark`,lightTheme:`Light`,tools:`Tools`,indicators:`Indicators`,overlays:`Overlays`,panels:`Panels`,orders:`Orders`,autoScale:`Auto Scale`,crosshair:`Crosshair`,grid:`Grid`,loading:`Loading...`,error:`Error`,numberDecimalSeparator:`.`,numberGroupSeparator:`,`},z={candlestick:`Nến`,line:`Đường`,area:`Vùng`,bar:`Thanh OHLC`,price:`Giá`,volume:`Khối lượng`,time:`Thời gian`,open:`Mở`,high:`Cao`,low:`Thấp`,close:`Đóng`,sma:`SMA`,ema:`EMA`,bollingerBands:`Dải Bollinger`,vwap:`VWAP`,ichimoku:`Mây Ichimoku`,parabolicSAR:`Parabolic SAR`,supertrend:`Supertrend`,keltnerChannel:`Kênh Keltner`,donchianChannel:`Kênh Donchian`,rsi:`RSI`,macd:`MACD`,stochastic:`Stochastic`,atr:`ATR`,adx:`ADX`,obv:`OBV`,williamsR:`Williams %R`,cci:`CCI`,mfi:`MFI`,aroon:`Aroon`,roc:`ROC`,tsi:`TSI`,cmf:`CMF`,stddev:`Độ lệch chuẩn`,volumeProfile:`Phân bổ KL`,accumulationDistribution:`Tích lũy/Phân phối`,vroc:`VROC`,trendLine:`Đường xu hướng`,horizontalLine:`Đường ngang`,verticalLine:`Đường dọc`,ray:`Tia`,extendedLine:`Đường kéo dài`,parallelChannel:`Kênh song song`,regressionChannel:`Kênh hồi quy`,fibRetracement:`Fibonacci thoái lui`,fibExtension:`Fibonacci mở rộng`,rectangle:`Hình chữ nhật`,ellipse:`Hình elip`,triangle:`Tam giác`,pitchfork:`Chĩa ba Andrews`,elliottWave:`Sóng Elliott`,priceRange:`Khoảng giá`,dateRange:`Khoảng thời gian`,measure:`Đo lường`,textTool:`Chữ`,arrow:`Mũi tên`,clearAll:`Xóa tất cả`,buy:`Mua`,sell:`Bán`,buyLimit:`Mua giới hạn`,sellLimit:`Bán giới hạn`,buyStop:`Mua chặn`,sellStop:`Bán chặn`,stopLoss:`Cắt lỗ`,takeProfit:`Chốt lời`,market:`Thị trường`,limit:`Giới hạn`,stop:`Dừng`,cancel:`Hủy`,modify:`Sửa`,quantity:`KL`,pnl:`Lãi/Lỗ`,activeOrders:`Lệnh chờ`,positions:`Vị thế`,noOrders:`Không có lệnh chờ`,noPositions:`Không có vị thế mở`,placeOrder:`Đặt lệnh`,rightClickToTrade:`Nhấp chuột phải để đặt lệnh`,ceiling:`Trần`,floor:`Sàn`,reference:`Tham chiếu`,session:`Phiên`,preOpen:`Trước giờ mở`,continuous:`Liên tục`,preClose:`Trước giờ đóng`,closed:`Đóng cửa`,settings:`Cài đặt`,theme:`Giao diện`,darkTheme:`Tối`,lightTheme:`Sáng`,tools:`Công cụ`,indicators:`Chỉ báo`,overlays:`Phủ lên`,panels:`Bảng`,orders:`Lệnh`,autoScale:`Tự co giãn`,crosshair:`Chữ thập`,grid:`Lưới`,loading:`Đang tải...`,error:`Lỗi`,numberDecimalSeparator:`,`,numberGroupSeparator:`.`},B=new Map([[`en`,R],[`vi`,z]]),V=`en`,H=R;function U(e){V=e,H=B.get(e)??R}function W(){return V}function G(e){return H[e]??R[e]??e}function K(e,t){B.set(e,t)}function q(e){return B.get(e??V)??R}function J(e,t=2,n){let r=B.get(n??V)??R,i=r.numberDecimalSeparator,a=r.numberGroupSeparator,[o,s]=e.toFixed(t).split(`.`),c=o.startsWith(`-`),l=c?o.slice(1):o,u=``;for(let e=l.length-1,t=0;e>=0;e--,t++)t>0&&t%3==0&&(u=a+u),u=l[e]+u;return c&&(u=`-`+u),s?u+i+s:u}function Y(e){return J(e,0,`vi`)}function X(e,t){return e>=1e9?J(e/1e9,2,t??V)+`B`:e>=1e6?J(e/1e6,2,t??V)+`M`:e>=1e3?J(e/1e3,2,t??V)+`K`:J(e,0,t??V)}var Z={up:`#FF0000`,down:`#0000FF`,unchanged:`#FFD700`,ceiling:`#FF00FF`,floor:`#00FFFF`,reference:`#FFD700`},Q=[{name:`ATO`,startTime:`09:00`,endTime:`09:15`,type:`preOpen`},{name:`Phiên 1`,startTime:`09:15`,endTime:`11:30`,type:`continuous`},{name:`Nghỉ trưa`,startTime:`11:30`,endTime:`13:00`,type:`closed`},{name:`Phiên 2`,startTime:`13:00`,endTime:`14:30`,type:`continuous`},{name:`ATC`,startTime:`14:30`,endTime:`14:45`,type:`preClose`}],$=[{name:`Phiên 1`,startTime:`09:00`,endTime:`11:30`,type:`continuous`},{name:`Nghỉ trưa`,startTime:`11:30`,endTime:`13:00`,type:`closed`},{name:`Phiên 2`,startTime:`13:00`,endTime:`14:30`,type:`continuous`},{name:`ATC`,startTime:`14:30`,endTime:`14:45`,type:`preClose`}],te={type:`stock`,exchange:`HOSE`,currency:`VND`,pricePrecision:2,volumeUnit:10,priceStep:.05,priceLimits:{enabled:!0,ceilingPercent:7,floorPercent:7},sessions:Q,colorScheme:Z},ne={type:`stock`,exchange:`HNX`,currency:`VND`,pricePrecision:1,volumeUnit:100,priceStep:.1,priceLimits:{enabled:!0,ceilingPercent:10,floorPercent:10},sessions:$,colorScheme:Z},re={type:`stock`,exchange:`UPCOM`,currency:`VND`,pricePrecision:1,volumeUnit:100,priceStep:.1,priceLimits:{enabled:!0,ceilingPercent:15,floorPercent:15},sessions:$,colorScheme:Z},ie={type:`crypto`,currency:`USDT`,pricePrecision:2,priceLimits:{enabled:!1}},ae={type:`stock`,exchange:`NYSE`,currency:`USD`,pricePrecision:2,priceStep:.01,priceLimits:{enabled:!1},sessions:[{name:`Pre-Market`,startTime:`04:00`,endTime:`09:30`,type:`preOpen`},{name:`Regular`,startTime:`09:30`,endTime:`16:00`,type:`continuous`},{name:`After-Hours`,startTime:`16:00`,endTime:`20:00`,type:`preClose`}]};function oe(e){return{...e,candleUp:Z.up,candleDown:Z.down,candleUpWick:Z.up,candleDownWick:Z.down,volumeUp:`rgba(255, 0, 0, 0.3)`,volumeDown:`rgba(0, 0, 255, 0.3)`}}function se(e,t){if(!t.priceLimits?.enabled||!t.priceLimits.ceilingPercent)return null;let n=t.priceLimits.ceilingPercent/100,r=(t.priceLimits.floorPercent??t.priceLimits.ceilingPercent)/100;return{ceiling:e*(1+n),floor:e*(1-r),reference:e}}function ce(e){let t=new Date,n=`${String(t.getHours()).padStart(2,`0`)}:${String(t.getMinutes()).padStart(2,`0`)}`;for(let t of e)if(n>=t.startTime&&n<t.endTime)return t;return null}exports.DARK_THEME=I,exports.DEFAULT_BAR_SPACING=A,exports.DEFAULT_BAR_WIDTH=k,exports.DEFAULT_CHART_OPTIONS=w,exports.DEFAULT_DRAWING_STYLE=t,exports.DEFAULT_PANEL_HEIGHT=P,exports.DEFAULT_RECONNECT=r,exports.DEFAULT_STREAM_CONFIG=i,exports.DEFAULT_TIMEFRAME_FAVORITES=O,exports.DEFAULT_TRADING_CONFIG=n,exports.HNX_SESSIONS=$,exports.HOSE_SESSIONS=Q,exports.LIGHT_THEME=L,exports.LayerType=e,exports.MARKET_CRYPTO=ie,exports.MARKET_HNX=ne,exports.MARKET_HOSE=te,exports.MARKET_NYSE=ae,exports.MARKET_UPCOM=re,exports.MIN_PANEL_HEIGHT=N,exports.PRICE_AXIS_WIDTH=j,exports.TIMEFRAMES_CRYPTO=T,exports.TIMEFRAMES_FOREX=D,exports.TIMEFRAMES_STOCK=E,exports.TIME_AXIS_HEIGHT=M,exports.VN_COLORS=Z,exports.alignToTimeframe=x,exports.clamp=a,exports.computePriceLimits=se,exports.computePriceRange=p,exports.computeTickStep=u,exports.createVNTheme=oe,exports.detectPrecision=C,exports.en=R,exports.findBarIndex=f,exports.formatNumber=J,exports.formatPrice=ee,exports.formatTimestamp=b,exports.formatVND=Y,exports.formatVolume=S,exports.formatVolumeLoc=X,exports.getCurrentSession=ce,exports.getLocale=W,exports.getLocaleStrings=q,exports.hexToRgba=h,exports.inverseLerp=s,exports.lerp=o,exports.lerpColor=_,exports.mergeBar=m,exports.niceNumber=l,exports.registerLocale=K,exports.roundToStep=c,exports.setLocale=U,exports.sliceVisibleData=d,exports.t=G,exports.timeframeToMs=y,exports.vi=z,exports.withAlpha=g;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=function(e){return e[e.Background=0]=`Background`,e[e.Main=1]=`Main`,e[e.Panel=2]=`Panel`,e[e.Overlay=3]=`Overlay`,e[e.UI=4]=`UI`,e}({}),t={color:`#2196F3`,lineWidth:1,lineStyle:`solid`,fillColor:`rgba(33, 150, 243, 0.1)`,fillOpacity:.1,fontSize:12},n={enabled:!0,orderColors:{buy:`#26A69A`,sell:`#EF5350`},positionColors:{profit:`#26A69A`,loss:`#EF5350`,entry:`#2196F3`},depthOverlay:{enabled:!1,bidColor:`rgba(38,166,154,0.15)`,askColor:`rgba(239,83,80,0.15)`,maxWidth:100},contextMenu:{enabled:!0},pricePrecision:2,dragThreshold:3},r={enabled:!0,maxRetries:1/0,baseDelay:1e3,maxDelay:3e4,backoffMultiplier:2},i={historyLimit:500,autoScroll:!0,showCurrentPriceLine:!0,aggregateTicks:!1};function a(e,t,n){return Math.max(t,Math.min(n,e))}function o(e,t,n){return e+(t-e)*n}function s(e,t,n){return e===t?0:(n-e)/(t-e)}function c(e,t){return Math.round(e/t)*t}function l(e,t){let n=Math.floor(Math.log10(e)),r=e/10**n,i;return i=t?r<1.5?1:r<3?2:r<7?5:10:r<=1?1:r<=2?2:r<=5?5:10,i*10**n}function u(e,t,n){return l(l(t-e,!1)/(n-1),!0)}function d(e,t,n){let r=Math.max(0,t),i=Math.min(e.length,n+1);return e.slice(r,i)}function f(e,t){let n=0,r=e.length-1;for(;n<=r;){let i=n+r>>>1;if(e[i].time<t)n=i+1;else if(e[i].time>t)r=i-1;else return i}return n}function p(e,t,n,r=.05){if(e.length===0)return{min:0,max:1};let i=Math.max(0,t),a=Math.min(e.length-1,n),o=1/0,s=-1/0;for(let t=i;t<=a;t++)e[t].low<o&&(o=e[t].low),e[t].high>s&&(s=e[t].high);if(o===1/0)return{min:0,max:1};let c=s-o||1;return{min:o-c*r,max:s+c*r}}function m(e,t){return{...e,high:Math.max(e.high,t.price),low:Math.min(e.low,t.price),close:t.price,volume:e.volume+(t.volume??0),time:t.time}}function h(e,t=1){return`rgba(${parseInt(e.slice(1,3),16)}, ${parseInt(e.slice(3,5),16)}, ${parseInt(e.slice(5,7),16)}, ${t})`}function g(e,t){if(e.startsWith(`#`))return h(e,t);let n=e.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);return n?`rgba(${n[1]}, ${n[2]}, ${n[3]}, ${t})`:e}function _(e,t,n){let r=e=>(e=e.replace(`#`,``),e.length===3&&(e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]),{r:parseInt(e.slice(0,2),16),g:parseInt(e.slice(2,4),16),b:parseInt(e.slice(4,6),16)}),i=r(e),a=r(t);return`rgb(${Math.round(i.r+(a.r-i.r)*n)},${Math.round(i.g+(a.g-i.g)*n)},${Math.round(i.b+(a.b-i.b)*n)})`}var v={"1s":1e3,"5s":5e3,"15s":15e3,"30s":3e4,"1m":6e4,"3m":18e4,"5m":3e5,"15m":9e5,"30m":18e5,"45m":27e5,"1h":36e5,"2h":72e5,"3h":108e5,"4h":144e5,"6h":216e5,"8h":288e5,"12h":432e5,"1d":864e5,"2d":1728e5,"3d":2592e5,"1w":6048e5,"2w":12096e5,"1M":2592e6,"3M":7776e6,"6M":15552e6,"12M":31536e6};function y(e){return v[e]}function b(e,t){let n=new Date(e),r=v[t];return r>=864e5?n.toLocaleDateString(void 0,{month:`short`,day:`numeric`}):r>=36e5?n.toLocaleTimeString(void 0,{hour:`2-digit`,minute:`2-digit`}):n.toLocaleTimeString(void 0,{hour:`2-digit`,minute:`2-digit`,second:`2-digit`})}function x(e,t){let n=v[t];return Math.floor(e/n)*n}function ee(e,t=2,n=`en-US`){return e.toLocaleString(n,{minimumFractionDigits:t,maximumFractionDigits:t})}function S(e){return e>=1e9?(e/1e9).toFixed(2)+`B`:e>=1e6?(e/1e6).toFixed(2)+`M`:e>=1e3?(e/1e3).toFixed(2)+`K`:e.toFixed(0)}function C(e){let t=0;for(let n of e){let e=n.toString(),r=e.indexOf(`.`);r>=0&&(t=Math.max(t,e.length-r-1))}return Math.min(t,8)}var w={autoScale:!0,rightMargin:5,minBarSpacing:2,maxBarSpacing:30,grid:{visible:!0,hLineStyle:`solid`,vLineStyle:`solid`},crosshair:{mode:`magnet`}},T=[`1s`,`1m`,`3m`,`5m`,`15m`,`30m`,`1h`,`2h`,`4h`,`6h`,`8h`,`12h`,`1d`,`3d`,`1w`,`1M`],E=[`1m`,`5m`,`15m`,`30m`,`1h`,`2h`,`4h`,`1d`,`1w`,`1M`,`3M`,`6M`,`12M`],D=[`1m`,`5m`,`15m`,`30m`,`1h`,`4h`,`1d`,`1w`,`1M`],O=[`1m`,`5m`,`15m`,`1h`,`4h`,`1d`,`1w`],k=8,A=2,j=70,M=30,N=60,P=120,F={family:`-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`,sizeSmall:10,sizeMedium:12,sizeLarge:14},I={name:`dark`,background:`#131722`,text:`#D1D4DC`,textSecondary:`#787B86`,grid:`#1E222D`,crosshair:`#9598A1`,candleUp:`#26A69A`,candleDown:`#EF5350`,candleUpWick:`#26A69A`,candleDownWick:`#EF5350`,lineColor:`#2196F3`,areaTopColor:`rgba(33, 150, 243, 0.4)`,areaBottomColor:`rgba(33, 150, 243, 0.0)`,volumeUp:`rgba(38, 166, 154, 0.3)`,volumeDown:`rgba(239, 83, 80, 0.3)`,axisLine:`#2A2E39`,axisLabel:`#D1D4DC`,axisLabelBackground:`#2A2E39`,font:F},L={name:`light`,background:`#FFFFFF`,text:`#131722`,textSecondary:`#787B86`,grid:`#F0F3FA`,crosshair:`#9598A1`,candleUp:`#26A69A`,candleDown:`#EF5350`,candleUpWick:`#26A69A`,candleDownWick:`#EF5350`,lineColor:`#2196F3`,areaTopColor:`rgba(33, 150, 243, 0.4)`,areaBottomColor:`rgba(33, 150, 243, 0.0)`,volumeUp:`rgba(38, 166, 154, 0.3)`,volumeDown:`rgba(239, 83, 80, 0.3)`,axisLine:`#E0E3EB`,axisLabel:`#131722`,axisLabelBackground:`#F0F3FA`,font:F},R={candlestick:`Candlestick`,line:`Line`,area:`Area`,bar:`OHLC Bar`,price:`Price`,volume:`Volume`,time:`Time`,open:`Open`,high:`High`,low:`Low`,close:`Close`,sma:`SMA`,ema:`EMA`,bollingerBands:`Bollinger Bands`,vwap:`VWAP`,ichimoku:`Ichimoku Cloud`,parabolicSAR:`Parabolic SAR`,supertrend:`Supertrend`,keltnerChannel:`Keltner Channel`,donchianChannel:`Donchian Channel`,rsi:`RSI`,macd:`MACD`,stochastic:`Stochastic`,atr:`ATR`,adx:`ADX`,obv:`OBV`,williamsR:`Williams %R`,cci:`CCI`,mfi:`MFI`,aroon:`Aroon`,roc:`ROC`,tsi:`TSI`,cmf:`CMF`,stddev:`Std Dev`,volumeProfile:`Volume Profile`,accumulationDistribution:`A/D Line`,vroc:`VROC`,trendLine:`Trend Line`,horizontalLine:`Horizontal Line`,verticalLine:`Vertical Line`,ray:`Ray`,extendedLine:`Extended Line`,parallelChannel:`Parallel Channel`,regressionChannel:`Regression Channel`,fibRetracement:`Fibonacci Retracement`,fibExtension:`Fibonacci Extension`,rectangle:`Rectangle`,ellipse:`Ellipse`,triangle:`Triangle`,pitchfork:`Andrews' Pitchfork`,elliottWave:`Elliott Wave`,priceRange:`Price Range`,dateRange:`Date Range`,measure:`Measure`,textTool:`Text`,arrow:`Arrow`,clearAll:`Clear All`,buy:`Buy`,sell:`Sell`,buyLimit:`Buy Limit`,sellLimit:`Sell Limit`,buyStop:`Buy Stop`,sellStop:`Sell Stop`,stopLoss:`Stop Loss`,takeProfit:`Take Profit`,market:`Market`,limit:`Limit`,stop:`Stop`,cancel:`Cancel`,modify:`Modify`,quantity:`Qty`,pnl:`P&L`,activeOrders:`Active Orders`,positions:`Positions`,noOrders:`No active orders`,noPositions:`No open positions`,placeOrder:`Place Order`,rightClickToTrade:`Right-click chart to place orders`,ceiling:`Ceiling`,floor:`Floor`,reference:`Reference`,session:`Session`,preOpen:`Pre-Open`,continuous:`Continuous`,preClose:`Pre-Close`,closed:`Closed`,settings:`Settings`,theme:`Theme`,darkTheme:`Dark`,lightTheme:`Light`,tools:`Tools`,indicators:`Indicators`,overlays:`Overlays`,panels:`Panels`,orders:`Orders`,autoScale:`Auto Scale`,crosshair:`Crosshair`,grid:`Grid`,loading:`Loading...`,error:`Error`,numberDecimalSeparator:`.`,numberGroupSeparator:`,`},z={candlestick:`Nến`,line:`Đường`,area:`Vùng`,bar:`Thanh OHLC`,price:`Giá`,volume:`Khối lượng`,time:`Thời gian`,open:`Mở`,high:`Cao`,low:`Thấp`,close:`Đóng`,sma:`SMA`,ema:`EMA`,bollingerBands:`Dải Bollinger`,vwap:`VWAP`,ichimoku:`Mây Ichimoku`,parabolicSAR:`Parabolic SAR`,supertrend:`Supertrend`,keltnerChannel:`Kênh Keltner`,donchianChannel:`Kênh Donchian`,rsi:`RSI`,macd:`MACD`,stochastic:`Stochastic`,atr:`ATR`,adx:`ADX`,obv:`OBV`,williamsR:`Williams %R`,cci:`CCI`,mfi:`MFI`,aroon:`Aroon`,roc:`ROC`,tsi:`TSI`,cmf:`CMF`,stddev:`Độ lệch chuẩn`,volumeProfile:`Phân bổ KL`,accumulationDistribution:`Tích lũy/Phân phối`,vroc:`VROC`,trendLine:`Đường xu hướng`,horizontalLine:`Đường ngang`,verticalLine:`Đường dọc`,ray:`Tia`,extendedLine:`Đường kéo dài`,parallelChannel:`Kênh song song`,regressionChannel:`Kênh hồi quy`,fibRetracement:`Fibonacci thoái lui`,fibExtension:`Fibonacci mở rộng`,rectangle:`Hình chữ nhật`,ellipse:`Hình elip`,triangle:`Tam giác`,pitchfork:`Chĩa ba Andrews`,elliottWave:`Sóng Elliott`,priceRange:`Khoảng giá`,dateRange:`Khoảng thời gian`,measure:`Đo lường`,textTool:`Chữ`,arrow:`Mũi tên`,clearAll:`Xóa tất cả`,buy:`Mua`,sell:`Bán`,buyLimit:`Mua giới hạn`,sellLimit:`Bán giới hạn`,buyStop:`Mua chặn`,sellStop:`Bán chặn`,stopLoss:`Cắt lỗ`,takeProfit:`Chốt lời`,market:`Thị trường`,limit:`Giới hạn`,stop:`Dừng`,cancel:`Hủy`,modify:`Sửa`,quantity:`KL`,pnl:`Lãi/Lỗ`,activeOrders:`Lệnh chờ`,positions:`Vị thế`,noOrders:`Không có lệnh chờ`,noPositions:`Không có vị thế mở`,placeOrder:`Đặt lệnh`,rightClickToTrade:`Nhấp chuột phải để đặt lệnh`,ceiling:`Trần`,floor:`Sàn`,reference:`Tham chiếu`,session:`Phiên`,preOpen:`Trước giờ mở`,continuous:`Liên tục`,preClose:`Trước giờ đóng`,closed:`Đóng cửa`,settings:`Cài đặt`,theme:`Giao diện`,darkTheme:`Tối`,lightTheme:`Sáng`,tools:`Công cụ`,indicators:`Chỉ báo`,overlays:`Phủ lên`,panels:`Bảng`,orders:`Lệnh`,autoScale:`Tự co giãn`,crosshair:`Chữ thập`,grid:`Lưới`,loading:`Đang tải...`,error:`Lỗi`,numberDecimalSeparator:`,`,numberGroupSeparator:`.`},B=new Map([[`en`,R],[`vi`,z]]),V=`en`,H=R;function U(e){V=e,H=B.get(e)??R}function W(){return V}function G(e){return H[e]??R[e]??e}function K(e,t){B.set(e,t)}function q(e){return B.get(e??V)??R}function J(e,t=2,n){let r=B.get(n??V)??R,i=r.numberDecimalSeparator,a=r.numberGroupSeparator,[o,s]=e.toFixed(t).split(`.`),c=o.startsWith(`-`),l=c?o.slice(1):o,u=``;for(let e=l.length-1,t=0;e>=0;e--,t++)t>0&&t%3==0&&(u=a+u),u=l[e]+u;return c&&(u=`-`+u),s?u+i+s:u}function Y(e){return J(e,0,`vi`)}function X(e,t){return e>=1e9?J(e/1e9,2,t??V)+`B`:e>=1e6?J(e/1e6,2,t??V)+`M`:e>=1e3?J(e/1e3,2,t??V)+`K`:J(e,0,t??V)}var Z={up:`#FF0000`,down:`#0000FF`,unchanged:`#FFD700`,ceiling:`#FF00FF`,floor:`#00FFFF`,reference:`#FFD700`},Q=[{name:`ATO`,startTime:`09:00`,endTime:`09:15`,type:`preOpen`},{name:`Phiên 1`,startTime:`09:15`,endTime:`11:30`,type:`continuous`},{name:`Nghỉ trưa`,startTime:`11:30`,endTime:`13:00`,type:`closed`},{name:`Phiên 2`,startTime:`13:00`,endTime:`14:30`,type:`continuous`},{name:`ATC`,startTime:`14:30`,endTime:`14:45`,type:`preClose`}],$=[{name:`Phiên 1`,startTime:`09:00`,endTime:`11:30`,type:`continuous`},{name:`Nghỉ trưa`,startTime:`11:30`,endTime:`13:00`,type:`closed`},{name:`Phiên 2`,startTime:`13:00`,endTime:`14:30`,type:`continuous`},{name:`ATC`,startTime:`14:30`,endTime:`14:45`,type:`preClose`}],te={type:`stock`,exchange:`HOSE`,currency:`VND`,pricePrecision:2,volumeUnit:10,priceStep:.05,priceLimits:{enabled:!0,ceilingPercent:7,floorPercent:7},sessions:Q,colorScheme:Z},ne={type:`stock`,exchange:`HNX`,currency:`VND`,pricePrecision:1,volumeUnit:100,priceStep:.1,priceLimits:{enabled:!0,ceilingPercent:10,floorPercent:10},sessions:$,colorScheme:Z},re={type:`stock`,exchange:`UPCOM`,currency:`VND`,pricePrecision:1,volumeUnit:100,priceStep:.1,priceLimits:{enabled:!0,ceilingPercent:15,floorPercent:15},sessions:$,colorScheme:Z},ie={type:`crypto`,currency:`USDT`,pricePrecision:2,priceLimits:{enabled:!1}},ae={type:`stock`,exchange:`NYSE`,currency:`USD`,pricePrecision:2,priceStep:.01,priceLimits:{enabled:!1},sessions:[{name:`Pre-Market`,startTime:`04:00`,endTime:`09:30`,type:`preOpen`},{name:`Regular`,startTime:`09:30`,endTime:`16:00`,type:`continuous`},{name:`After-Hours`,startTime:`16:00`,endTime:`20:00`,type:`preClose`}]};function oe(e){return{...e,candleUp:Z.up,candleDown:Z.down,candleUpWick:Z.up,candleDownWick:Z.down,volumeUp:`rgba(255, 0, 0, 0.3)`,volumeDown:`rgba(0, 0, 255, 0.3)`}}function se(e,t){if(!t.priceLimits?.enabled||!t.priceLimits.ceilingPercent)return null;let n=t.priceLimits.ceilingPercent/100,r=(t.priceLimits.floorPercent??t.priceLimits.ceilingPercent)/100;return{ceiling:e*(1+n),floor:e*(1-r),reference:e}}function ce(e){let t=new Date,n=`${String(t.getHours()).padStart(2,`0`)}:${String(t.getMinutes()).padStart(2,`0`)}`;for(let t of e)if(n>=t.startTime&&n<t.endTime)return t;return null}exports.DARK_THEME=I,exports.DEFAULT_BAR_SPACING=A,exports.DEFAULT_BAR_WIDTH=k,exports.DEFAULT_CHART_OPTIONS=w,exports.DEFAULT_DRAWING_STYLE=t,exports.DEFAULT_PANEL_HEIGHT=P,exports.DEFAULT_RECONNECT=r,exports.DEFAULT_STREAM_CONFIG=i,exports.DEFAULT_TIMEFRAME_FAVORITES=O,exports.DEFAULT_TRADING_CONFIG=n,exports.HNX_SESSIONS=$,exports.HOSE_SESSIONS=Q,exports.LIGHT_THEME=L,exports.LayerType=e,exports.MARKET_CRYPTO=ie,exports.MARKET_HNX=ne,exports.MARKET_HOSE=te,exports.MARKET_NYSE=ae,exports.MARKET_UPCOM=re,exports.MIN_PANEL_HEIGHT=N,exports.PRICE_AXIS_WIDTH=j,exports.TIMEFRAMES_CRYPTO=T,exports.TIMEFRAMES_FOREX=D,exports.TIMEFRAMES_STOCK=E,exports.TIME_AXIS_HEIGHT=M,exports.VN_COLORS=Z,exports.alignToTimeframe=x,exports.clamp=a,exports.computePriceLimits=se,exports.computePriceRange=p,exports.computeTickStep=u,exports.createVNTheme=oe,exports.detectPrecision=C,exports.en=R,exports.findBarIndex=f,exports.formatNumber=J,exports.formatPrice=ee,exports.formatTimestamp=b,exports.formatVND=Y,exports.formatVolume=S,exports.formatVolumeLoc=X,exports.getCurrentSession=ce,exports.getLocale=W,exports.getLocaleStrings=q,exports.hexToRgba=h,exports.inverseLerp=s,exports.lerp=o,exports.lerpColor=_,exports.mergeBar=m,exports.niceNumber=l,exports.registerLocale=K,exports.roundToStep=c,exports.setLocale=U,exports.sliceVisibleData=d,exports.t=G,exports.timeframeToMs=y,exports.vi=z,exports.withAlpha=g;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/types/rendering.ts","../src/types/drawing.ts","../src/types/trading.ts","../src/types/realtime.ts","../src/utils/math.ts","../src/utils/data.ts","../src/utils/color.ts","../src/utils/time.ts","../src/utils/precision.ts","../src/constants/defaults.ts","../src/constants/themes.ts","../src/i18n/en.ts","../src/i18n/vi.ts","../src/i18n/index.ts","../src/market/presets.ts"],"sourcesContent":["export interface Point {\n x: number;\n y: number;\n}\n\nexport interface Size {\n width: number;\n height: number;\n}\n\nexport interface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface ViewportState {\n visibleRange: { from: number; to: number };\n priceRange: { min: number; max: number };\n barWidth: number;\n barSpacing: number;\n offset: number;\n chartRect: Rect;\n logScale?: boolean;\n}\n\nexport enum LayerType {\n Background = 0,\n Main = 1,\n Panel = 2,\n Overlay = 3,\n UI = 4,\n}\n","import type { Point, ViewportState } from './rendering.js';\n\nexport type DrawingToolType =\n | 'trendLine' | 'horizontalLine' | 'verticalLine' | 'ray' | 'extendedLine'\n | 'parallelChannel' | 'regressionChannel'\n | 'fibRetracement' | 'fibExtension'\n | 'rectangle' | 'ellipse' | 'triangle'\n | 'pitchfork' | 'elliottWave'\n | 'priceRange' | 'dateRange' | 'measure'\n | 'text' | 'arrow'\n | 'gannFan' | 'gannBox'\n | 'anchoredVWAP'\n | 'volumeProfileRange';\n\nexport interface AnchorPoint {\n time: number;\n price: number;\n}\n\nexport interface DrawingStyle {\n color: string;\n lineWidth: number;\n lineStyle: 'solid' | 'dashed' | 'dotted';\n fillColor?: string;\n fillOpacity?: number;\n fontSize?: number;\n text?: string;\n}\n\nexport interface DrawingState {\n id: string;\n type: DrawingToolType;\n anchors: AnchorPoint[];\n style: DrawingStyle;\n visible: boolean;\n locked: boolean;\n meta?: Record<string, unknown>;\n}\n\nexport interface DrawingDescriptor {\n type: DrawingToolType;\n name: string;\n requiredAnchors: number;\n singleClick?: boolean;\n}\n\nexport interface DrawingPlugin {\n descriptor: DrawingDescriptor;\n render(\n ctx: CanvasRenderingContext2D,\n state: DrawingState,\n viewport: ViewportState,\n selected: boolean,\n ): void;\n hitTest(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): boolean;\n hitTestAnchor(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): number;\n}\n\nexport const DEFAULT_DRAWING_STYLE: DrawingStyle = {\n color: '#2196F3',\n lineWidth: 1,\n lineStyle: 'solid',\n fillColor: 'rgba(33, 150, 243, 0.1)',\n fillOpacity: 0.1,\n fontSize: 12,\n};\n","export type OrderSide = 'buy' | 'sell';\nexport type OrderType = 'market' | 'limit' | 'stop' | 'stopLimit';\nexport type OrderStatus = 'pending' | 'filled' | 'cancelled' | 'rejected';\nexport type OrderLabel = 'LIMIT' | 'STOP' | 'SL' | 'TP' | 'STOP LIMIT';\n\nexport interface TradingOrder {\n id: string;\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity: number;\n label?: OrderLabel;\n draggable?: boolean;\n meta?: Record<string, unknown>;\n}\n\nexport interface TradingPosition {\n id: string;\n side: OrderSide;\n entryPrice: number;\n quantity: number;\n stopLoss?: number;\n takeProfit?: number;\n meta?: Record<string, unknown>;\n}\n\nexport interface DepthLevel {\n price: number;\n volume: number;\n}\n\nexport interface DepthData {\n bids: DepthLevel[];\n asks: DepthLevel[];\n}\n\nexport interface TradingConfig {\n enabled: boolean;\n orderColors?: { buy?: string; sell?: string };\n positionColors?: { profit?: string; loss?: string; entry?: string };\n depthOverlay?: {\n enabled?: boolean;\n bidColor?: string;\n askColor?: string;\n maxWidth?: number;\n };\n contextMenu?: { enabled?: boolean };\n pricePrecision?: number;\n dragThreshold?: number;\n}\n\nexport interface OrderPlaceIntent {\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity?: number;\n}\n\nexport interface OrderModifyIntent {\n orderId: string;\n newPrice: number;\n previousPrice: number;\n}\n\nexport interface OrderCancelIntent {\n orderId: string;\n}\n\nexport interface PositionModifyIntent {\n positionId: string;\n stopLoss?: number;\n takeProfit?: number;\n}\n\nexport interface PositionCloseIntent {\n positionId: string;\n}\n\nexport const DEFAULT_TRADING_CONFIG: TradingConfig = {\n enabled: true,\n orderColors: { buy: '#26A69A', sell: '#EF5350' },\n positionColors: { profit: '#26A69A', loss: '#EF5350', entry: '#2196F3' },\n depthOverlay: { enabled: false, bidColor: 'rgba(38,166,154,0.15)', askColor: 'rgba(239,83,80,0.15)', maxWidth: 100 },\n contextMenu: { enabled: true },\n pricePrecision: 2,\n dragThreshold: 3,\n};\n","import type { OHLCBar, TimeFrame } from './ohlc.js';\n\n// --- Connection ---\n\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';\n\nexport interface ConnectionInfo {\n state: ConnectionState;\n latency?: number;\n reconnectAttempt?: number;\n lastMessageTime?: number;\n error?: string;\n}\n\n// --- Ticks & Trades ---\n\nexport interface RawTick {\n time: number;\n price: number;\n volume: number;\n side?: 'buy' | 'sell';\n}\n\nexport interface AggregatedBar extends OHLCBar {\n closed: boolean; // true when bar is finalized\n tickCount: number; // number of ticks in this bar\n}\n\n// --- Data Adapter (Strategy Pattern) ---\n\nexport interface DataAdapterConfig {\n symbol: string;\n timeframe: TimeFrame;\n reconnect?: boolean; // default: true\n reconnectMaxRetries?: number; // default: Infinity\n reconnectBaseDelay?: number; // ms, default: 1000\n reconnectMaxDelay?: number; // ms, default: 30000\n heartbeatInterval?: number; // ms, default: 30000\n bufferSize?: number; // max ticks to buffer, default: 1000\n}\n\nexport type DataAdapterEventType =\n | 'tick'\n | 'bar'\n | 'barClose'\n | 'snapshot' // initial historical data loaded\n | 'connectionChange'\n | 'error';\n\nexport interface DataAdapterEvent<T = unknown> {\n type: DataAdapterEventType;\n data: T;\n timestamp: number;\n}\n\nexport type DataAdapterListener<T = unknown> = (event: DataAdapterEvent<T>) => void;\n\n/**\n * DataAdapter interface — Strategy pattern for pluggable data sources.\n *\n * Implementations handle the specifics of each data source (WebSocket, REST,\n * SSE, etc.) while the StreamManager orchestrates lifecycle and aggregation.\n *\n * Built-in: BinanceAdapter\n * Implement this for: custom exchange APIs, broker feeds, mock data\n */\nexport interface DataAdapter {\n readonly name: string;\n\n connect(config: DataAdapterConfig): void;\n disconnect(): void;\n getConnectionState(): ConnectionState;\n\n /**\n * Load historical bars. Called once on connect, before streaming starts.\n * Returns bars sorted by time ascending.\n */\n fetchHistory(symbol: string, timeframe: TimeFrame, limit?: number): Promise<OHLCBar[]>;\n\n on<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n off<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n\n dispose(): void;\n}\n\n// --- Stream Manager Config ---\n\nexport interface StreamConfig {\n adapter: DataAdapter;\n symbol: string;\n timeframe: TimeFrame;\n historyLimit?: number; // bars to load initially, default: 500\n autoScroll?: boolean; // scroll to end on new bar, default: true\n showCurrentPriceLine?: boolean; // default: true\n aggregateTicks?: boolean; // build bars from ticks, default: false\n reconnect?: ReconnectConfig;\n}\n\nexport interface ReconnectConfig {\n enabled: boolean; // default: true\n maxRetries: number; // default: Infinity\n baseDelay: number; // ms, default: 1000\n maxDelay: number; // ms, default: 30000\n backoffMultiplier: number; // default: 2\n}\n\nexport const DEFAULT_RECONNECT: ReconnectConfig = {\n enabled: true,\n maxRetries: Infinity,\n baseDelay: 1000,\n maxDelay: 30000,\n backoffMultiplier: 2,\n};\n\nexport const DEFAULT_STREAM_CONFIG: Partial<StreamConfig> = {\n historyLimit: 500,\n autoScroll: true,\n showCurrentPriceLine: true,\n aggregateTicks: false,\n};\n","export function clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nexport function inverseLerp(a: number, b: number, value: number): number {\n if (a === b) return 0;\n return (value - a) / (b - a);\n}\n\nexport function roundToStep(value: number, step: number): number {\n return Math.round(value / step) * step;\n}\n\nexport function niceNumber(value: number, round: boolean): number {\n const exp = Math.floor(Math.log10(value));\n const frac = value / Math.pow(10, exp);\n let nice: number;\n if (round) {\n if (frac < 1.5) nice = 1;\n else if (frac < 3) nice = 2;\n else if (frac < 7) nice = 5;\n else nice = 10;\n } else {\n if (frac <= 1) nice = 1;\n else if (frac <= 2) nice = 2;\n else if (frac <= 5) nice = 5;\n else nice = 10;\n }\n return nice * Math.pow(10, exp);\n}\n\nexport function computeTickStep(min: number, max: number, maxTicks: number): number {\n const range = niceNumber(max - min, false);\n return niceNumber(range / (maxTicks - 1), true);\n}\n","import type { OHLCBar, DataSeries } from '../types/ohlc.js';\n\nexport function sliceVisibleData(\n data: DataSeries,\n from: number,\n to: number,\n): DataSeries {\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length, to + 1);\n return data.slice(startIdx, endIdx);\n}\n\nexport function findBarIndex(data: DataSeries, timestamp: number): number {\n let lo = 0;\n let hi = data.length - 1;\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n if (data[mid].time < timestamp) lo = mid + 1;\n else if (data[mid].time > timestamp) hi = mid - 1;\n else return mid;\n }\n return lo;\n}\n\nexport function computePriceRange(\n data: DataSeries,\n from: number,\n to: number,\n padding = 0.05,\n): { min: number; max: number } {\n if (data.length === 0) return { min: 0, max: 1 };\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length - 1, to);\n let min = Infinity;\n let max = -Infinity;\n for (let i = startIdx; i <= endIdx; i++) {\n if (data[i].low < min) min = data[i].low;\n if (data[i].high > max) max = data[i].high;\n }\n if (min === Infinity) return { min: 0, max: 1 };\n const range = max - min || 1;\n return {\n min: min - range * padding,\n max: max + range * padding,\n };\n}\n\nexport function mergeBar(existing: OHLCBar, tick: { price: number; volume?: number; time: number }): OHLCBar {\n return {\n ...existing,\n high: Math.max(existing.high, tick.price),\n low: Math.min(existing.low, tick.price),\n close: tick.price,\n volume: existing.volume + (tick.volume ?? 0),\n time: tick.time,\n };\n}\n","export function hexToRgba(hex: string, alpha = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\nexport function withAlpha(color: string, alpha: number): string {\n if (color.startsWith('#')) {\n return hexToRgba(color, alpha);\n }\n const rgbaMatch = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (rgbaMatch) {\n return `rgba(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]}, ${alpha})`;\n }\n return color;\n}\n\nexport function lerpColor(colorA: string, colorB: string, t: number): string {\n const parseHex = (hex: string) => {\n hex = hex.replace('#', '');\n if (hex.length === 3) hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];\n return {\n r: parseInt(hex.slice(0, 2), 16),\n g: parseInt(hex.slice(2, 4), 16),\n b: parseInt(hex.slice(4, 6), 16),\n };\n };\n const a = parseHex(colorA);\n const b = parseHex(colorB);\n const r = Math.round(a.r + (b.r - a.r) * t);\n const g = Math.round(a.g + (b.g - a.g) * t);\n const bl = Math.round(a.b + (b.b - a.b) * t);\n return `rgb(${r},${g},${bl})`;\n}\n","import type { TimeFrame } from '../types/ohlc.js';\n\nconst TIMEFRAME_MS: Record<TimeFrame, number> = {\n '1s': 1_000,\n '5s': 5_000,\n '15s': 15_000,\n '30s': 30_000,\n '1m': 60_000,\n '3m': 180_000,\n '5m': 300_000,\n '15m': 900_000,\n '30m': 1_800_000,\n '45m': 2_700_000,\n '1h': 3_600_000,\n '2h': 7_200_000,\n '3h': 10_800_000,\n '4h': 14_400_000,\n '6h': 21_600_000,\n '8h': 28_800_000,\n '12h': 43_200_000,\n '1d': 86_400_000,\n '2d': 172_800_000,\n '3d': 259_200_000,\n '1w': 604_800_000,\n '2w': 1_209_600_000,\n '1M': 2_592_000_000,\n '3M': 7_776_000_000,\n '6M': 15_552_000_000,\n '12M': 31_536_000_000,\n};\n\nexport function timeframeToMs(tf: TimeFrame): number {\n return TIMEFRAME_MS[tf];\n}\n\nexport function formatTimestamp(timestamp: number, tf: TimeFrame): string {\n const d = new Date(timestamp);\n const ms = TIMEFRAME_MS[tf];\n if (ms >= 86_400_000) {\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }\n if (ms >= 3_600_000) {\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\n }\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\nexport function alignToTimeframe(timestamp: number, tf: TimeFrame): number {\n const ms = TIMEFRAME_MS[tf];\n return Math.floor(timestamp / ms) * ms;\n}\n","export function formatPrice(value: number, precision = 2): string {\n return value.toFixed(precision);\n}\n\nexport function formatVolume(value: number): string {\n if (value >= 1_000_000_000) return (value / 1_000_000_000).toFixed(2) + 'B';\n if (value >= 1_000_000) return (value / 1_000_000).toFixed(2) + 'M';\n if (value >= 1_000) return (value / 1_000).toFixed(2) + 'K';\n return value.toFixed(0);\n}\n\nexport function detectPrecision(values: number[]): number {\n let maxDecimals = 0;\n for (const v of values) {\n const str = v.toString();\n const dot = str.indexOf('.');\n if (dot >= 0) {\n maxDecimals = Math.max(maxDecimals, str.length - dot - 1);\n }\n }\n return Math.min(maxDecimals, 8);\n}\n","import type { ChartOptions } from '../types/chart.js';\n\nexport const DEFAULT_CHART_OPTIONS: Required<Pick<ChartOptions, 'autoScale' | 'rightMargin' | 'minBarSpacing' | 'maxBarSpacing'>> & Pick<ChartOptions, 'grid' | 'crosshair'> = {\n autoScale: true,\n rightMargin: 5,\n minBarSpacing: 2,\n maxBarSpacing: 30,\n grid: {\n visible: true,\n hLineStyle: 'solid',\n vLineStyle: 'solid',\n },\n crosshair: {\n mode: 'magnet',\n },\n};\n\n// Standard timeframe presets for different market types\nimport type { TimeFrame } from '../types/ohlc.js';\n\n/** Crypto: all timeframes including seconds */\nexport const TIMEFRAMES_CRYPTO: TimeFrame[] = [\n '1s', '1m', '3m', '5m', '15m', '30m',\n '1h', '2h', '4h', '6h', '8h', '12h',\n '1d', '3d', '1w', '1M',\n];\n\n/** Stocks: minute-level and above (no seconds) */\nexport const TIMEFRAMES_STOCK: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '2h', '4h',\n '1d', '1w', '1M', '3M', '6M', '12M',\n];\n\n/** Forex: common forex timeframes */\nexport const TIMEFRAMES_FOREX: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '4h',\n '1d', '1w', '1M',\n];\n\n/** Default favorites shown in quick-access bar */\nexport const DEFAULT_TIMEFRAME_FAVORITES: TimeFrame[] = [\n '1m', '5m', '15m', '1h', '4h', '1d', '1w',\n];\n\nexport const DEFAULT_BAR_WIDTH = 8;\nexport const DEFAULT_BAR_SPACING = 2;\nexport const PRICE_AXIS_WIDTH = 70;\nexport const TIME_AXIS_HEIGHT = 30;\nexport const MIN_PANEL_HEIGHT = 60;\nexport const DEFAULT_PANEL_HEIGHT = 120;\n","import type { Theme } from '../types/theme.js';\n\nconst DEFAULT_FONT = {\n family: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n sizeSmall: 10,\n sizeMedium: 12,\n sizeLarge: 14,\n};\n\nexport const DARK_THEME: Theme = {\n name: 'dark',\n background: '#131722',\n text: '#D1D4DC',\n textSecondary: '#787B86',\n grid: '#1E222D',\n crosshair: '#9598A1',\n candleUp: '#26A69A',\n candleDown: '#EF5350',\n candleUpWick: '#26A69A',\n candleDownWick: '#EF5350',\n lineColor: '#2196F3',\n areaTopColor: 'rgba(33, 150, 243, 0.4)',\n areaBottomColor: 'rgba(33, 150, 243, 0.0)',\n volumeUp: 'rgba(38, 166, 154, 0.3)',\n volumeDown: 'rgba(239, 83, 80, 0.3)',\n axisLine: '#2A2E39',\n axisLabel: '#D1D4DC',\n axisLabelBackground: '#2A2E39',\n font: DEFAULT_FONT,\n};\n\nexport const LIGHT_THEME: Theme = {\n name: 'light',\n background: '#FFFFFF',\n text: '#131722',\n textSecondary: '#787B86',\n grid: '#F0F3FA',\n crosshair: '#9598A1',\n candleUp: '#26A69A',\n candleDown: '#EF5350',\n candleUpWick: '#26A69A',\n candleDownWick: '#EF5350',\n lineColor: '#2196F3',\n areaTopColor: 'rgba(33, 150, 243, 0.4)',\n areaBottomColor: 'rgba(33, 150, 243, 0.0)',\n volumeUp: 'rgba(38, 166, 154, 0.3)',\n volumeDown: 'rgba(239, 83, 80, 0.3)',\n axisLine: '#E0E3EB',\n axisLabel: '#131722',\n axisLabelBackground: '#F0F3FA',\n font: DEFAULT_FONT,\n};\n","import type { LocaleStrings } from './types.js';\n\nexport const en: LocaleStrings = {\n // Chart types\n candlestick: 'Candlestick',\n line: 'Line',\n area: 'Area',\n bar: 'OHLC Bar',\n\n // Axes\n price: 'Price',\n volume: 'Volume',\n time: 'Time',\n open: 'Open',\n high: 'High',\n low: 'Low',\n close: 'Close',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Bollinger Bands',\n vwap: 'VWAP',\n ichimoku: 'Ichimoku Cloud',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Keltner Channel',\n donchianChannel: 'Donchian Channel',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Std Dev',\n volumeProfile: 'Volume Profile',\n accumulationDistribution: 'A/D Line',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Trend Line',\n horizontalLine: 'Horizontal Line',\n verticalLine: 'Vertical Line',\n ray: 'Ray',\n extendedLine: 'Extended Line',\n parallelChannel: 'Parallel Channel',\n regressionChannel: 'Regression Channel',\n fibRetracement: 'Fibonacci Retracement',\n fibExtension: 'Fibonacci Extension',\n rectangle: 'Rectangle',\n ellipse: 'Ellipse',\n triangle: 'Triangle',\n pitchfork: \"Andrews' Pitchfork\",\n elliottWave: 'Elliott Wave',\n priceRange: 'Price Range',\n dateRange: 'Date Range',\n measure: 'Measure',\n textTool: 'Text',\n arrow: 'Arrow',\n clearAll: 'Clear All',\n\n // Trading\n buy: 'Buy',\n sell: 'Sell',\n buyLimit: 'Buy Limit',\n sellLimit: 'Sell Limit',\n buyStop: 'Buy Stop',\n sellStop: 'Sell Stop',\n stopLoss: 'Stop Loss',\n takeProfit: 'Take Profit',\n market: 'Market',\n limit: 'Limit',\n stop: 'Stop',\n cancel: 'Cancel',\n modify: 'Modify',\n quantity: 'Qty',\n pnl: 'P&L',\n activeOrders: 'Active Orders',\n positions: 'Positions',\n noOrders: 'No active orders',\n noPositions: 'No open positions',\n placeOrder: 'Place Order',\n rightClickToTrade: 'Right-click chart to place orders',\n\n // Market\n ceiling: 'Ceiling',\n floor: 'Floor',\n reference: 'Reference',\n session: 'Session',\n preOpen: 'Pre-Open',\n continuous: 'Continuous',\n preClose: 'Pre-Close',\n closed: 'Closed',\n\n // UI\n settings: 'Settings',\n theme: 'Theme',\n darkTheme: 'Dark',\n lightTheme: 'Light',\n tools: 'Tools',\n indicators: 'Indicators',\n overlays: 'Overlays',\n panels: 'Panels',\n orders: 'Orders',\n autoScale: 'Auto Scale',\n crosshair: 'Crosshair',\n grid: 'Grid',\n loading: 'Loading...',\n error: 'Error',\n\n numberDecimalSeparator: '.',\n numberGroupSeparator: ',',\n};\n","import type { LocaleStrings } from './types.js';\n\nexport const vi: LocaleStrings = {\n // Chart types\n candlestick: 'Nến',\n line: 'Đường',\n area: 'Vùng',\n bar: 'Thanh OHLC',\n\n // Axes\n price: 'Giá',\n volume: 'Khối lượng',\n time: 'Thời gian',\n open: 'Mở',\n high: 'Cao',\n low: 'Thấp',\n close: 'Đóng',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Dải Bollinger',\n vwap: 'VWAP',\n ichimoku: 'Mây Ichimoku',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Kênh Keltner',\n donchianChannel: 'Kênh Donchian',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Độ lệch chuẩn',\n volumeProfile: 'Phân bổ KL',\n accumulationDistribution: 'Tích lũy/Phân phối',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Đường xu hướng',\n horizontalLine: 'Đường ngang',\n verticalLine: 'Đường dọc',\n ray: 'Tia',\n extendedLine: 'Đường kéo dài',\n parallelChannel: 'Kênh song song',\n regressionChannel: 'Kênh hồi quy',\n fibRetracement: 'Fibonacci thoái lui',\n fibExtension: 'Fibonacci mở rộng',\n rectangle: 'Hình chữ nhật',\n ellipse: 'Hình elip',\n triangle: 'Tam giác',\n pitchfork: 'Chĩa ba Andrews',\n elliottWave: 'Sóng Elliott',\n priceRange: 'Khoảng giá',\n dateRange: 'Khoảng thời gian',\n measure: 'Đo lường',\n textTool: 'Chữ',\n arrow: 'Mũi tên',\n clearAll: 'Xóa tất cả',\n\n // Trading\n buy: 'Mua',\n sell: 'Bán',\n buyLimit: 'Mua giới hạn',\n sellLimit: 'Bán giới hạn',\n buyStop: 'Mua chặn',\n sellStop: 'Bán chặn',\n stopLoss: 'Cắt lỗ',\n takeProfit: 'Chốt lời',\n market: 'Thị trường',\n limit: 'Giới hạn',\n stop: 'Dừng',\n cancel: 'Hủy',\n modify: 'Sửa',\n quantity: 'KL',\n pnl: 'Lãi/Lỗ',\n activeOrders: 'Lệnh chờ',\n positions: 'Vị thế',\n noOrders: 'Không có lệnh chờ',\n noPositions: 'Không có vị thế mở',\n placeOrder: 'Đặt lệnh',\n rightClickToTrade: 'Nhấp chuột phải để đặt lệnh',\n\n // Market\n ceiling: 'Trần',\n floor: 'Sàn',\n reference: 'Tham chiếu',\n session: 'Phiên',\n preOpen: 'Trước giờ mở',\n continuous: 'Liên tục',\n preClose: 'Trước giờ đóng',\n closed: 'Đóng cửa',\n\n // UI\n settings: 'Cài đặt',\n theme: 'Giao diện',\n darkTheme: 'Tối',\n lightTheme: 'Sáng',\n tools: 'Công cụ',\n indicators: 'Chỉ báo',\n overlays: 'Phủ lên',\n panels: 'Bảng',\n orders: 'Lệnh',\n autoScale: 'Tự co giãn',\n crosshair: 'Chữ thập',\n grid: 'Lưới',\n loading: 'Đang tải...',\n error: 'Lỗi',\n\n numberDecimalSeparator: ',',\n numberGroupSeparator: '.',\n};\n","export type { Locale, LocaleStrings, NumberFormatConfig, DateFormatConfig } from './types.js';\nexport { en } from './en.js';\nexport { vi } from './vi.js';\n\nimport type { Locale, LocaleStrings } from './types.js';\nimport { en } from './en.js';\nimport { vi } from './vi.js';\n\nconst locales = new Map<string, LocaleStrings>([\n ['en', en],\n ['vi', vi],\n]);\n\nlet currentLocale: Locale = 'en';\nlet currentStrings: LocaleStrings = en;\n\nexport function setLocale(locale: Locale): void {\n currentLocale = locale;\n currentStrings = locales.get(locale) ?? en;\n}\n\nexport function getLocale(): Locale {\n return currentLocale;\n}\n\nexport function t(key: keyof LocaleStrings): string {\n return currentStrings[key] ?? (en as any)[key] ?? key;\n}\n\nexport function registerLocale(locale: string, strings: LocaleStrings): void {\n locales.set(locale, strings);\n}\n\nexport function getLocaleStrings(locale?: string): LocaleStrings {\n return locales.get(locale ?? currentLocale) ?? en;\n}\n\n// Number formatting\nexport function formatNumber(value: number, precision = 2, locale?: string): string {\n const strings = locales.get(locale ?? currentLocale) ?? en;\n const dec = strings.numberDecimalSeparator;\n const grp = strings.numberGroupSeparator;\n\n const fixed = value.toFixed(precision);\n const [intPart, decPart] = fixed.split('.');\n\n // Group integer part\n const negative = intPart.startsWith('-');\n const digits = negative ? intPart.slice(1) : intPart;\n let grouped = '';\n for (let i = digits.length - 1, count = 0; i >= 0; i--, count++) {\n if (count > 0 && count % 3 === 0) grouped = grp + grouped;\n grouped = digits[i] + grouped;\n }\n if (negative) grouped = '-' + grouped;\n\n return decPart ? grouped + dec + decPart : grouped;\n}\n\nexport function formatVND(value: number): string {\n return formatNumber(value, 0, 'vi');\n}\n\nexport function formatVolumeLoc(value: number, locale?: string): string {\n if (value >= 1e9) return formatNumber(value / 1e9, 2, locale ?? currentLocale) + 'B';\n if (value >= 1e6) return formatNumber(value / 1e6, 2, locale ?? currentLocale) + 'M';\n if (value >= 1e3) return formatNumber(value / 1e3, 2, locale ?? currentLocale) + 'K';\n return formatNumber(value, 0, locale ?? currentLocale);\n}\n","import type { MarketConfig, MarketColorScheme, TradingSession } from './types.js';\nimport type { Theme } from '../types/theme.js';\n\n// Vietnam stock color convention:\n// Purple/Red = ceiling (trần) - max up\n// Green/Cyan = floor (sàn) - max down\n// Yellow = reference (tham chiếu)\n// Red = up, Blue = down (common VN convention)\nexport const VN_COLORS: MarketColorScheme = {\n up: '#FF0000', // Đỏ - tăng\n down: '#0000FF', // Xanh dương - giảm\n unchanged: '#FFD700', // Vàng - tham chiếu\n ceiling: '#FF00FF', // Tím - trần\n floor: '#00FFFF', // Xanh lam - sàn\n reference: '#FFD700', // Vàng - tham chiếu\n};\n\nexport const HOSE_SESSIONS: TradingSession[] = [\n { name: 'ATO', startTime: '09:00', endTime: '09:15', type: 'preOpen' },\n { name: 'Phiên 1', startTime: '09:15', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\nexport const HNX_SESSIONS: TradingSession[] = [\n { name: 'Phiên 1', startTime: '09:00', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\n// Market presets\nexport const MARKET_HOSE: MarketConfig = {\n type: 'stock',\n exchange: 'HOSE',\n currency: 'VND',\n pricePrecision: 2,\n volumeUnit: 10,\n priceStep: 0.05,\n priceLimits: { enabled: true, ceilingPercent: 7, floorPercent: 7 },\n sessions: HOSE_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_HNX: MarketConfig = {\n type: 'stock',\n exchange: 'HNX',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n priceLimits: { enabled: true, ceilingPercent: 10, floorPercent: 10 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_UPCOM: MarketConfig = {\n type: 'stock',\n exchange: 'UPCOM',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n priceLimits: { enabled: true, ceilingPercent: 15, floorPercent: 15 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_CRYPTO: MarketConfig = {\n type: 'crypto',\n currency: 'USDT',\n pricePrecision: 2,\n priceLimits: { enabled: false },\n};\n\nexport const MARKET_NYSE: MarketConfig = {\n type: 'stock',\n exchange: 'NYSE',\n currency: 'USD',\n pricePrecision: 2,\n priceStep: 0.01,\n priceLimits: { enabled: false },\n sessions: [\n { name: 'Pre-Market', startTime: '04:00', endTime: '09:30', type: 'preOpen' },\n { name: 'Regular', startTime: '09:30', endTime: '16:00', type: 'continuous' },\n { name: 'After-Hours', startTime: '16:00', endTime: '20:00', type: 'preClose' },\n ],\n};\n\n// Build a theme variant for VN stock market\nexport function createVNTheme(base: Theme): Theme {\n return {\n ...base,\n candleUp: VN_COLORS.up,\n candleDown: VN_COLORS.down,\n candleUpWick: VN_COLORS.up,\n candleDownWick: VN_COLORS.down,\n volumeUp: 'rgba(255, 0, 0, 0.3)',\n volumeDown: 'rgba(0, 0, 255, 0.3)',\n };\n}\n\nexport function computePriceLimits(referencePrice: number, config: MarketConfig): { ceiling: number; floor: number; reference: number } | null {\n if (!config.priceLimits?.enabled || !config.priceLimits.ceilingPercent) return null;\n const ceilPct = config.priceLimits.ceilingPercent / 100;\n const floorPct = (config.priceLimits.floorPercent ?? config.priceLimits.ceilingPercent) / 100;\n return {\n ceiling: referencePrice * (1 + ceilPct),\n floor: referencePrice * (1 - floorPct),\n reference: referencePrice,\n };\n}\n\nexport function getCurrentSession(sessions: TradingSession[]): TradingSession | null {\n const now = new Date();\n const hhmm = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;\n for (const session of sessions) {\n if (hhmm >= session.startTime && hhmm < session.endTime) return session;\n }\n return null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/types/rendering.ts","../src/types/drawing.ts","../src/types/trading.ts","../src/types/realtime.ts","../src/utils/math.ts","../src/utils/data.ts","../src/utils/color.ts","../src/utils/time.ts","../src/utils/precision.ts","../src/constants/defaults.ts","../src/constants/themes.ts","../src/i18n/en.ts","../src/i18n/vi.ts","../src/i18n/index.ts","../src/market/presets.ts"],"sourcesContent":["export interface Point {\n x: number;\n y: number;\n}\n\nexport interface Size {\n width: number;\n height: number;\n}\n\nexport interface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface ViewportState {\n visibleRange: { from: number; to: number };\n priceRange: { min: number; max: number };\n barWidth: number;\n barSpacing: number;\n offset: number;\n chartRect: Rect;\n logScale?: boolean;\n}\n\nexport enum LayerType {\n Background = 0,\n Main = 1,\n Panel = 2,\n Overlay = 3,\n UI = 4,\n}\n","import type { Point, ViewportState } from './rendering.js';\n\nexport type DrawingToolType =\n | 'trendLine' | 'horizontalLine' | 'verticalLine' | 'ray' | 'extendedLine'\n | 'parallelChannel' | 'regressionChannel'\n | 'fibRetracement' | 'fibExtension'\n | 'rectangle' | 'ellipse' | 'triangle'\n | 'pitchfork' | 'elliottWave'\n | 'priceRange' | 'dateRange' | 'measure'\n | 'text' | 'arrow'\n | 'gannFan' | 'gannBox'\n | 'anchoredVWAP'\n | 'volumeProfileRange';\n\nexport interface AnchorPoint {\n time: number;\n price: number;\n}\n\nexport interface DrawingStyle {\n color: string;\n lineWidth: number;\n lineStyle: 'solid' | 'dashed' | 'dotted';\n fillColor?: string;\n fillOpacity?: number;\n fontSize?: number;\n text?: string;\n}\n\nexport interface DrawingState {\n id: string;\n type: DrawingToolType;\n anchors: AnchorPoint[];\n style: DrawingStyle;\n visible: boolean;\n locked: boolean;\n meta?: Record<string, unknown>;\n}\n\nexport interface DrawingDescriptor {\n type: DrawingToolType;\n name: string;\n requiredAnchors: number;\n singleClick?: boolean;\n}\n\nexport interface DrawingPlugin {\n descriptor: DrawingDescriptor;\n render(\n ctx: CanvasRenderingContext2D,\n state: DrawingState,\n viewport: ViewportState,\n selected: boolean,\n ): void;\n hitTest(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): boolean;\n hitTestAnchor(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): number;\n}\n\nexport const DEFAULT_DRAWING_STYLE: DrawingStyle = {\n color: '#2196F3',\n lineWidth: 1,\n lineStyle: 'solid',\n fillColor: 'rgba(33, 150, 243, 0.1)',\n fillOpacity: 0.1,\n fontSize: 12,\n};\n","export type OrderSide = 'buy' | 'sell';\nexport type OrderType = 'market' | 'limit' | 'stop' | 'stopLimit';\nexport type OrderStatus = 'pending' | 'filled' | 'cancelled' | 'rejected';\nexport type OrderLabel = 'LIMIT' | 'STOP' | 'SL' | 'TP' | 'STOP LIMIT';\n\nexport interface TradingOrder {\n id: string;\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity: number;\n label?: OrderLabel;\n draggable?: boolean;\n meta?: Record<string, unknown>;\n}\n\nexport interface TradingPosition {\n id: string;\n side: OrderSide;\n entryPrice: number;\n quantity: number;\n stopLoss?: number;\n takeProfit?: number;\n meta?: Record<string, unknown>;\n}\n\nexport interface DepthLevel {\n price: number;\n volume: number;\n}\n\nexport interface DepthData {\n bids: DepthLevel[];\n asks: DepthLevel[];\n}\n\nexport interface TradingConfig {\n enabled: boolean;\n orderColors?: { buy?: string; sell?: string };\n positionColors?: { profit?: string; loss?: string; entry?: string };\n depthOverlay?: {\n enabled?: boolean;\n bidColor?: string;\n askColor?: string;\n maxWidth?: number;\n };\n contextMenu?: { enabled?: boolean };\n pricePrecision?: number;\n dragThreshold?: number;\n}\n\nexport interface OrderPlaceIntent {\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity?: number;\n}\n\nexport interface OrderModifyIntent {\n orderId: string;\n newPrice: number;\n previousPrice: number;\n}\n\nexport interface OrderCancelIntent {\n orderId: string;\n}\n\nexport interface PositionModifyIntent {\n positionId: string;\n stopLoss?: number;\n takeProfit?: number;\n}\n\nexport interface PositionCloseIntent {\n positionId: string;\n}\n\nexport const DEFAULT_TRADING_CONFIG: TradingConfig = {\n enabled: true,\n orderColors: { buy: '#26A69A', sell: '#EF5350' },\n positionColors: { profit: '#26A69A', loss: '#EF5350', entry: '#2196F3' },\n depthOverlay: { enabled: false, bidColor: 'rgba(38,166,154,0.15)', askColor: 'rgba(239,83,80,0.15)', maxWidth: 100 },\n contextMenu: { enabled: true },\n pricePrecision: 2,\n dragThreshold: 3,\n};\n","import type { OHLCBar, TimeFrame } from './ohlc.js';\n\n// --- Connection ---\n\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';\n\nexport interface ConnectionInfo {\n state: ConnectionState;\n latency?: number;\n reconnectAttempt?: number;\n lastMessageTime?: number;\n error?: string;\n}\n\n// --- Ticks & Trades ---\n\nexport interface RawTick {\n time: number;\n price: number;\n volume: number;\n side?: 'buy' | 'sell';\n}\n\nexport interface AggregatedBar extends OHLCBar {\n closed: boolean; // true when bar is finalized\n tickCount: number; // number of ticks in this bar\n}\n\n// --- Data Adapter (Strategy Pattern) ---\n\nexport interface DataAdapterConfig {\n symbol: string;\n timeframe: TimeFrame;\n reconnect?: boolean; // default: true\n reconnectMaxRetries?: number; // default: Infinity\n reconnectBaseDelay?: number; // ms, default: 1000\n reconnectMaxDelay?: number; // ms, default: 30000\n heartbeatInterval?: number; // ms, default: 30000\n bufferSize?: number; // max ticks to buffer, default: 1000\n}\n\nexport type DataAdapterEventType =\n | 'tick'\n | 'bar'\n | 'barClose'\n | 'snapshot' // initial historical data loaded\n | 'connectionChange'\n | 'error';\n\nexport interface DataAdapterEvent<T = unknown> {\n type: DataAdapterEventType;\n data: T;\n timestamp: number;\n}\n\nexport type DataAdapterListener<T = unknown> = (event: DataAdapterEvent<T>) => void;\n\n/**\n * DataAdapter interface — Strategy pattern for pluggable data sources.\n *\n * Implementations handle the specifics of each data source (WebSocket, REST,\n * SSE, etc.) while the StreamManager orchestrates lifecycle and aggregation.\n *\n * Built-in: BinanceAdapter\n * Implement this for: custom exchange APIs, broker feeds, mock data\n */\nexport interface DataAdapter {\n readonly name: string;\n\n connect(config: DataAdapterConfig): void;\n disconnect(): void;\n getConnectionState(): ConnectionState;\n\n /**\n * Load historical bars. Called once on connect, before streaming starts.\n * Returns bars sorted by time ascending.\n */\n fetchHistory(symbol: string, timeframe: TimeFrame, limit?: number): Promise<OHLCBar[]>;\n\n on<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n off<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n\n dispose(): void;\n}\n\n// --- Stream Manager Config ---\n\nexport interface StreamConfig {\n adapter: DataAdapter;\n symbol: string;\n timeframe: TimeFrame;\n historyLimit?: number; // bars to load initially, default: 500\n autoScroll?: boolean; // scroll to end on new bar, default: true\n showCurrentPriceLine?: boolean; // default: true\n aggregateTicks?: boolean; // build bars from ticks, default: false\n reconnect?: ReconnectConfig;\n}\n\nexport interface ReconnectConfig {\n enabled: boolean; // default: true\n maxRetries: number; // default: Infinity\n baseDelay: number; // ms, default: 1000\n maxDelay: number; // ms, default: 30000\n backoffMultiplier: number; // default: 2\n}\n\nexport const DEFAULT_RECONNECT: ReconnectConfig = {\n enabled: true,\n maxRetries: Infinity,\n baseDelay: 1000,\n maxDelay: 30000,\n backoffMultiplier: 2,\n};\n\nexport const DEFAULT_STREAM_CONFIG: Partial<StreamConfig> = {\n historyLimit: 500,\n autoScroll: true,\n showCurrentPriceLine: true,\n aggregateTicks: false,\n};\n","export function clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nexport function inverseLerp(a: number, b: number, value: number): number {\n if (a === b) return 0;\n return (value - a) / (b - a);\n}\n\nexport function roundToStep(value: number, step: number): number {\n return Math.round(value / step) * step;\n}\n\nexport function niceNumber(value: number, round: boolean): number {\n const exp = Math.floor(Math.log10(value));\n const frac = value / Math.pow(10, exp);\n let nice: number;\n if (round) {\n if (frac < 1.5) nice = 1;\n else if (frac < 3) nice = 2;\n else if (frac < 7) nice = 5;\n else nice = 10;\n } else {\n if (frac <= 1) nice = 1;\n else if (frac <= 2) nice = 2;\n else if (frac <= 5) nice = 5;\n else nice = 10;\n }\n return nice * Math.pow(10, exp);\n}\n\nexport function computeTickStep(min: number, max: number, maxTicks: number): number {\n const range = niceNumber(max - min, false);\n return niceNumber(range / (maxTicks - 1), true);\n}\n","import type { OHLCBar, DataSeries } from '../types/ohlc.js';\n\nexport function sliceVisibleData(\n data: DataSeries,\n from: number,\n to: number,\n): DataSeries {\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length, to + 1);\n return data.slice(startIdx, endIdx);\n}\n\nexport function findBarIndex(data: DataSeries, timestamp: number): number {\n let lo = 0;\n let hi = data.length - 1;\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n if (data[mid].time < timestamp) lo = mid + 1;\n else if (data[mid].time > timestamp) hi = mid - 1;\n else return mid;\n }\n return lo;\n}\n\nexport function computePriceRange(\n data: DataSeries,\n from: number,\n to: number,\n padding = 0.05,\n): { min: number; max: number } {\n if (data.length === 0) return { min: 0, max: 1 };\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length - 1, to);\n let min = Infinity;\n let max = -Infinity;\n for (let i = startIdx; i <= endIdx; i++) {\n if (data[i].low < min) min = data[i].low;\n if (data[i].high > max) max = data[i].high;\n }\n if (min === Infinity) return { min: 0, max: 1 };\n const range = max - min || 1;\n return {\n min: min - range * padding,\n max: max + range * padding,\n };\n}\n\nexport function mergeBar(existing: OHLCBar, tick: { price: number; volume?: number; time: number }): OHLCBar {\n return {\n ...existing,\n high: Math.max(existing.high, tick.price),\n low: Math.min(existing.low, tick.price),\n close: tick.price,\n volume: existing.volume + (tick.volume ?? 0),\n time: tick.time,\n };\n}\n","export function hexToRgba(hex: string, alpha = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\nexport function withAlpha(color: string, alpha: number): string {\n if (color.startsWith('#')) {\n return hexToRgba(color, alpha);\n }\n const rgbaMatch = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (rgbaMatch) {\n return `rgba(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]}, ${alpha})`;\n }\n return color;\n}\n\nexport function lerpColor(colorA: string, colorB: string, t: number): string {\n const parseHex = (hex: string) => {\n hex = hex.replace('#', '');\n if (hex.length === 3) hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];\n return {\n r: parseInt(hex.slice(0, 2), 16),\n g: parseInt(hex.slice(2, 4), 16),\n b: parseInt(hex.slice(4, 6), 16),\n };\n };\n const a = parseHex(colorA);\n const b = parseHex(colorB);\n const r = Math.round(a.r + (b.r - a.r) * t);\n const g = Math.round(a.g + (b.g - a.g) * t);\n const bl = Math.round(a.b + (b.b - a.b) * t);\n return `rgb(${r},${g},${bl})`;\n}\n","import type { TimeFrame } from '../types/ohlc.js';\n\nconst TIMEFRAME_MS: Record<TimeFrame, number> = {\n '1s': 1_000,\n '5s': 5_000,\n '15s': 15_000,\n '30s': 30_000,\n '1m': 60_000,\n '3m': 180_000,\n '5m': 300_000,\n '15m': 900_000,\n '30m': 1_800_000,\n '45m': 2_700_000,\n '1h': 3_600_000,\n '2h': 7_200_000,\n '3h': 10_800_000,\n '4h': 14_400_000,\n '6h': 21_600_000,\n '8h': 28_800_000,\n '12h': 43_200_000,\n '1d': 86_400_000,\n '2d': 172_800_000,\n '3d': 259_200_000,\n '1w': 604_800_000,\n '2w': 1_209_600_000,\n '1M': 2_592_000_000,\n '3M': 7_776_000_000,\n '6M': 15_552_000_000,\n '12M': 31_536_000_000,\n};\n\nexport function timeframeToMs(tf: TimeFrame): number {\n return TIMEFRAME_MS[tf];\n}\n\nexport function formatTimestamp(timestamp: number, tf: TimeFrame): string {\n const d = new Date(timestamp);\n const ms = TIMEFRAME_MS[tf];\n if (ms >= 86_400_000) {\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }\n if (ms >= 3_600_000) {\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\n }\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\nexport function alignToTimeframe(timestamp: number, tf: TimeFrame): number {\n const ms = TIMEFRAME_MS[tf];\n return Math.floor(timestamp / ms) * ms;\n}\n","export function formatPrice(value: number, precision = 2, locale = 'en-US'): string {\n return value.toLocaleString(locale, {\n minimumFractionDigits: precision,\n maximumFractionDigits: precision,\n });\n}\n\nexport function formatVolume(value: number): string {\n if (value >= 1_000_000_000) return (value / 1_000_000_000).toFixed(2) + 'B';\n if (value >= 1_000_000) return (value / 1_000_000).toFixed(2) + 'M';\n if (value >= 1_000) return (value / 1_000).toFixed(2) + 'K';\n return value.toFixed(0);\n}\n\nexport function detectPrecision(values: number[]): number {\n let maxDecimals = 0;\n for (const v of values) {\n const str = v.toString();\n const dot = str.indexOf('.');\n if (dot >= 0) {\n maxDecimals = Math.max(maxDecimals, str.length - dot - 1);\n }\n }\n return Math.min(maxDecimals, 8);\n}\n","import type { ChartOptions } from '../types/chart.js';\n\nexport const DEFAULT_CHART_OPTIONS: Required<Pick<ChartOptions, 'autoScale' | 'rightMargin' | 'minBarSpacing' | 'maxBarSpacing'>> & Pick<ChartOptions, 'grid' | 'crosshair'> = {\n autoScale: true,\n rightMargin: 5,\n minBarSpacing: 2,\n maxBarSpacing: 30,\n grid: {\n visible: true,\n hLineStyle: 'solid',\n vLineStyle: 'solid',\n },\n crosshair: {\n mode: 'magnet',\n },\n};\n\n// Standard timeframe presets for different market types\nimport type { TimeFrame } from '../types/ohlc.js';\n\n/** Crypto: all timeframes including seconds */\nexport const TIMEFRAMES_CRYPTO: TimeFrame[] = [\n '1s', '1m', '3m', '5m', '15m', '30m',\n '1h', '2h', '4h', '6h', '8h', '12h',\n '1d', '3d', '1w', '1M',\n];\n\n/** Stocks: minute-level and above (no seconds) */\nexport const TIMEFRAMES_STOCK: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '2h', '4h',\n '1d', '1w', '1M', '3M', '6M', '12M',\n];\n\n/** Forex: common forex timeframes */\nexport const TIMEFRAMES_FOREX: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '4h',\n '1d', '1w', '1M',\n];\n\n/** Default favorites shown in quick-access bar */\nexport const DEFAULT_TIMEFRAME_FAVORITES: TimeFrame[] = [\n '1m', '5m', '15m', '1h', '4h', '1d', '1w',\n];\n\nexport const DEFAULT_BAR_WIDTH = 8;\nexport const DEFAULT_BAR_SPACING = 2;\nexport const PRICE_AXIS_WIDTH = 70;\nexport const TIME_AXIS_HEIGHT = 30;\nexport const MIN_PANEL_HEIGHT = 60;\nexport const DEFAULT_PANEL_HEIGHT = 120;\n","import type { Theme } from '../types/theme.js';\n\nconst DEFAULT_FONT = {\n family: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n sizeSmall: 10,\n sizeMedium: 12,\n sizeLarge: 14,\n};\n\nexport const DARK_THEME: Theme = {\n name: 'dark',\n background: '#131722',\n text: '#D1D4DC',\n textSecondary: '#787B86',\n grid: '#1E222D',\n crosshair: '#9598A1',\n candleUp: '#26A69A',\n candleDown: '#EF5350',\n candleUpWick: '#26A69A',\n candleDownWick: '#EF5350',\n lineColor: '#2196F3',\n areaTopColor: 'rgba(33, 150, 243, 0.4)',\n areaBottomColor: 'rgba(33, 150, 243, 0.0)',\n volumeUp: 'rgba(38, 166, 154, 0.3)',\n volumeDown: 'rgba(239, 83, 80, 0.3)',\n axisLine: '#2A2E39',\n axisLabel: '#D1D4DC',\n axisLabelBackground: '#2A2E39',\n font: DEFAULT_FONT,\n};\n\nexport const LIGHT_THEME: Theme = {\n name: 'light',\n background: '#FFFFFF',\n text: '#131722',\n textSecondary: '#787B86',\n grid: '#F0F3FA',\n crosshair: '#9598A1',\n candleUp: '#26A69A',\n candleDown: '#EF5350',\n candleUpWick: '#26A69A',\n candleDownWick: '#EF5350',\n lineColor: '#2196F3',\n areaTopColor: 'rgba(33, 150, 243, 0.4)',\n areaBottomColor: 'rgba(33, 150, 243, 0.0)',\n volumeUp: 'rgba(38, 166, 154, 0.3)',\n volumeDown: 'rgba(239, 83, 80, 0.3)',\n axisLine: '#E0E3EB',\n axisLabel: '#131722',\n axisLabelBackground: '#F0F3FA',\n font: DEFAULT_FONT,\n};\n","import type { LocaleStrings } from './types.js';\n\nexport const en: LocaleStrings = {\n // Chart types\n candlestick: 'Candlestick',\n line: 'Line',\n area: 'Area',\n bar: 'OHLC Bar',\n\n // Axes\n price: 'Price',\n volume: 'Volume',\n time: 'Time',\n open: 'Open',\n high: 'High',\n low: 'Low',\n close: 'Close',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Bollinger Bands',\n vwap: 'VWAP',\n ichimoku: 'Ichimoku Cloud',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Keltner Channel',\n donchianChannel: 'Donchian Channel',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Std Dev',\n volumeProfile: 'Volume Profile',\n accumulationDistribution: 'A/D Line',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Trend Line',\n horizontalLine: 'Horizontal Line',\n verticalLine: 'Vertical Line',\n ray: 'Ray',\n extendedLine: 'Extended Line',\n parallelChannel: 'Parallel Channel',\n regressionChannel: 'Regression Channel',\n fibRetracement: 'Fibonacci Retracement',\n fibExtension: 'Fibonacci Extension',\n rectangle: 'Rectangle',\n ellipse: 'Ellipse',\n triangle: 'Triangle',\n pitchfork: \"Andrews' Pitchfork\",\n elliottWave: 'Elliott Wave',\n priceRange: 'Price Range',\n dateRange: 'Date Range',\n measure: 'Measure',\n textTool: 'Text',\n arrow: 'Arrow',\n clearAll: 'Clear All',\n\n // Trading\n buy: 'Buy',\n sell: 'Sell',\n buyLimit: 'Buy Limit',\n sellLimit: 'Sell Limit',\n buyStop: 'Buy Stop',\n sellStop: 'Sell Stop',\n stopLoss: 'Stop Loss',\n takeProfit: 'Take Profit',\n market: 'Market',\n limit: 'Limit',\n stop: 'Stop',\n cancel: 'Cancel',\n modify: 'Modify',\n quantity: 'Qty',\n pnl: 'P&L',\n activeOrders: 'Active Orders',\n positions: 'Positions',\n noOrders: 'No active orders',\n noPositions: 'No open positions',\n placeOrder: 'Place Order',\n rightClickToTrade: 'Right-click chart to place orders',\n\n // Market\n ceiling: 'Ceiling',\n floor: 'Floor',\n reference: 'Reference',\n session: 'Session',\n preOpen: 'Pre-Open',\n continuous: 'Continuous',\n preClose: 'Pre-Close',\n closed: 'Closed',\n\n // UI\n settings: 'Settings',\n theme: 'Theme',\n darkTheme: 'Dark',\n lightTheme: 'Light',\n tools: 'Tools',\n indicators: 'Indicators',\n overlays: 'Overlays',\n panels: 'Panels',\n orders: 'Orders',\n autoScale: 'Auto Scale',\n crosshair: 'Crosshair',\n grid: 'Grid',\n loading: 'Loading...',\n error: 'Error',\n\n numberDecimalSeparator: '.',\n numberGroupSeparator: ',',\n};\n","import type { LocaleStrings } from './types.js';\n\nexport const vi: LocaleStrings = {\n // Chart types\n candlestick: 'Nến',\n line: 'Đường',\n area: 'Vùng',\n bar: 'Thanh OHLC',\n\n // Axes\n price: 'Giá',\n volume: 'Khối lượng',\n time: 'Thời gian',\n open: 'Mở',\n high: 'Cao',\n low: 'Thấp',\n close: 'Đóng',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Dải Bollinger',\n vwap: 'VWAP',\n ichimoku: 'Mây Ichimoku',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Kênh Keltner',\n donchianChannel: 'Kênh Donchian',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Độ lệch chuẩn',\n volumeProfile: 'Phân bổ KL',\n accumulationDistribution: 'Tích lũy/Phân phối',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Đường xu hướng',\n horizontalLine: 'Đường ngang',\n verticalLine: 'Đường dọc',\n ray: 'Tia',\n extendedLine: 'Đường kéo dài',\n parallelChannel: 'Kênh song song',\n regressionChannel: 'Kênh hồi quy',\n fibRetracement: 'Fibonacci thoái lui',\n fibExtension: 'Fibonacci mở rộng',\n rectangle: 'Hình chữ nhật',\n ellipse: 'Hình elip',\n triangle: 'Tam giác',\n pitchfork: 'Chĩa ba Andrews',\n elliottWave: 'Sóng Elliott',\n priceRange: 'Khoảng giá',\n dateRange: 'Khoảng thời gian',\n measure: 'Đo lường',\n textTool: 'Chữ',\n arrow: 'Mũi tên',\n clearAll: 'Xóa tất cả',\n\n // Trading\n buy: 'Mua',\n sell: 'Bán',\n buyLimit: 'Mua giới hạn',\n sellLimit: 'Bán giới hạn',\n buyStop: 'Mua chặn',\n sellStop: 'Bán chặn',\n stopLoss: 'Cắt lỗ',\n takeProfit: 'Chốt lời',\n market: 'Thị trường',\n limit: 'Giới hạn',\n stop: 'Dừng',\n cancel: 'Hủy',\n modify: 'Sửa',\n quantity: 'KL',\n pnl: 'Lãi/Lỗ',\n activeOrders: 'Lệnh chờ',\n positions: 'Vị thế',\n noOrders: 'Không có lệnh chờ',\n noPositions: 'Không có vị thế mở',\n placeOrder: 'Đặt lệnh',\n rightClickToTrade: 'Nhấp chuột phải để đặt lệnh',\n\n // Market\n ceiling: 'Trần',\n floor: 'Sàn',\n reference: 'Tham chiếu',\n session: 'Phiên',\n preOpen: 'Trước giờ mở',\n continuous: 'Liên tục',\n preClose: 'Trước giờ đóng',\n closed: 'Đóng cửa',\n\n // UI\n settings: 'Cài đặt',\n theme: 'Giao diện',\n darkTheme: 'Tối',\n lightTheme: 'Sáng',\n tools: 'Công cụ',\n indicators: 'Chỉ báo',\n overlays: 'Phủ lên',\n panels: 'Bảng',\n orders: 'Lệnh',\n autoScale: 'Tự co giãn',\n crosshair: 'Chữ thập',\n grid: 'Lưới',\n loading: 'Đang tải...',\n error: 'Lỗi',\n\n numberDecimalSeparator: ',',\n numberGroupSeparator: '.',\n};\n","export type { Locale, LocaleStrings, NumberFormatConfig, DateFormatConfig } from './types.js';\nexport { en } from './en.js';\nexport { vi } from './vi.js';\n\nimport type { Locale, LocaleStrings } from './types.js';\nimport { en } from './en.js';\nimport { vi } from './vi.js';\n\nconst locales = new Map<string, LocaleStrings>([\n ['en', en],\n ['vi', vi],\n]);\n\nlet currentLocale: Locale = 'en';\nlet currentStrings: LocaleStrings = en;\n\nexport function setLocale(locale: Locale): void {\n currentLocale = locale;\n currentStrings = locales.get(locale) ?? en;\n}\n\nexport function getLocale(): Locale {\n return currentLocale;\n}\n\nexport function t(key: keyof LocaleStrings): string {\n return currentStrings[key] ?? (en as any)[key] ?? key;\n}\n\nexport function registerLocale(locale: string, strings: LocaleStrings): void {\n locales.set(locale, strings);\n}\n\nexport function getLocaleStrings(locale?: string): LocaleStrings {\n return locales.get(locale ?? currentLocale) ?? en;\n}\n\n// Number formatting\nexport function formatNumber(value: number, precision = 2, locale?: string): string {\n const strings = locales.get(locale ?? currentLocale) ?? en;\n const dec = strings.numberDecimalSeparator;\n const grp = strings.numberGroupSeparator;\n\n const fixed = value.toFixed(precision);\n const [intPart, decPart] = fixed.split('.');\n\n // Group integer part\n const negative = intPart.startsWith('-');\n const digits = negative ? intPart.slice(1) : intPart;\n let grouped = '';\n for (let i = digits.length - 1, count = 0; i >= 0; i--, count++) {\n if (count > 0 && count % 3 === 0) grouped = grp + grouped;\n grouped = digits[i] + grouped;\n }\n if (negative) grouped = '-' + grouped;\n\n return decPart ? grouped + dec + decPart : grouped;\n}\n\nexport function formatVND(value: number): string {\n return formatNumber(value, 0, 'vi');\n}\n\nexport function formatVolumeLoc(value: number, locale?: string): string {\n if (value >= 1e9) return formatNumber(value / 1e9, 2, locale ?? currentLocale) + 'B';\n if (value >= 1e6) return formatNumber(value / 1e6, 2, locale ?? currentLocale) + 'M';\n if (value >= 1e3) return formatNumber(value / 1e3, 2, locale ?? currentLocale) + 'K';\n return formatNumber(value, 0, locale ?? currentLocale);\n}\n","import type { MarketConfig, MarketColorScheme, TradingSession } from './types.js';\nimport type { Theme } from '../types/theme.js';\n\n// Vietnam stock color convention:\n// Purple/Red = ceiling (trần) - max up\n// Green/Cyan = floor (sàn) - max down\n// Yellow = reference (tham chiếu)\n// Red = up, Blue = down (common VN convention)\nexport const VN_COLORS: MarketColorScheme = {\n up: '#FF0000', // Đỏ - tăng\n down: '#0000FF', // Xanh dương - giảm\n unchanged: '#FFD700', // Vàng - tham chiếu\n ceiling: '#FF00FF', // Tím - trần\n floor: '#00FFFF', // Xanh lam - sàn\n reference: '#FFD700', // Vàng - tham chiếu\n};\n\nexport const HOSE_SESSIONS: TradingSession[] = [\n { name: 'ATO', startTime: '09:00', endTime: '09:15', type: 'preOpen' },\n { name: 'Phiên 1', startTime: '09:15', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\nexport const HNX_SESSIONS: TradingSession[] = [\n { name: 'Phiên 1', startTime: '09:00', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\n// Market presets\nexport const MARKET_HOSE: MarketConfig = {\n type: 'stock',\n exchange: 'HOSE',\n currency: 'VND',\n pricePrecision: 2,\n volumeUnit: 10,\n priceStep: 0.05,\n priceLimits: { enabled: true, ceilingPercent: 7, floorPercent: 7 },\n sessions: HOSE_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_HNX: MarketConfig = {\n type: 'stock',\n exchange: 'HNX',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n priceLimits: { enabled: true, ceilingPercent: 10, floorPercent: 10 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_UPCOM: MarketConfig = {\n type: 'stock',\n exchange: 'UPCOM',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n priceLimits: { enabled: true, ceilingPercent: 15, floorPercent: 15 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_CRYPTO: MarketConfig = {\n type: 'crypto',\n currency: 'USDT',\n pricePrecision: 2,\n priceLimits: { enabled: false },\n};\n\nexport const MARKET_NYSE: MarketConfig = {\n type: 'stock',\n exchange: 'NYSE',\n currency: 'USD',\n pricePrecision: 2,\n priceStep: 0.01,\n priceLimits: { enabled: false },\n sessions: [\n { name: 'Pre-Market', startTime: '04:00', endTime: '09:30', type: 'preOpen' },\n { name: 'Regular', startTime: '09:30', endTime: '16:00', type: 'continuous' },\n { name: 'After-Hours', startTime: '16:00', endTime: '20:00', type: 'preClose' },\n ],\n};\n\n// Build a theme variant for VN stock market\nexport function createVNTheme(base: Theme): Theme {\n return {\n ...base,\n candleUp: VN_COLORS.up,\n candleDown: VN_COLORS.down,\n candleUpWick: VN_COLORS.up,\n candleDownWick: VN_COLORS.down,\n volumeUp: 'rgba(255, 0, 0, 0.3)',\n volumeDown: 'rgba(0, 0, 255, 0.3)',\n };\n}\n\nexport function computePriceLimits(referencePrice: number, config: MarketConfig): { ceiling: number; floor: number; reference: number } | null {\n if (!config.priceLimits?.enabled || !config.priceLimits.ceilingPercent) return null;\n const ceilPct = config.priceLimits.ceilingPercent / 100;\n const floorPct = (config.priceLimits.floorPercent ?? config.priceLimits.ceilingPercent) / 100;\n return {\n ceiling: referencePrice * (1 + ceilPct),\n floor: referencePrice * (1 - floorPct),\n reference: referencePrice,\n };\n}\n\nexport function getCurrentSession(sessions: TradingSession[]): TradingSession | null {\n const now = new Date();\n const hhmm = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;\n for (const session of sessions) {\n if (hhmm >= session.startTime && hhmm < session.endTime) return session;\n }\n return null;\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -175,8 +175,11 @@ function x(e, t) {
175
175
  }
176
176
  //#endregion
177
177
  //#region src/utils/precision.ts
178
- function ee(e, t = 2) {
179
- return e.toFixed(t);
178
+ function ee(e, t = 2, n = "en-US") {
179
+ return e.toLocaleString(n, {
180
+ minimumFractionDigits: t,
181
+ maximumFractionDigits: t
182
+ });
180
183
  }
181
184
  function S(e) {
182
185
  return e >= 1e9 ? (e / 1e9).toFixed(2) + "B" : e >= 1e6 ? (e / 1e6).toFixed(2) + "M" : e >= 1e3 ? (e / 1e3).toFixed(2) + "K" : e.toFixed(0);
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/realtime.ts","../src/utils/math.ts","../src/utils/data.ts","../src/utils/color.ts","../src/utils/time.ts","../src/utils/precision.ts","../src/constants/defaults.ts","../src/constants/themes.ts","../src/i18n/en.ts","../src/i18n/vi.ts","../src/i18n/index.ts","../src/market/presets.ts"],"sourcesContent":["export interface Point {\n x: number;\n y: number;\n}\n\nexport interface Size {\n width: number;\n height: number;\n}\n\nexport interface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface ViewportState {\n visibleRange: { from: number; to: number };\n priceRange: { min: number; max: number };\n barWidth: number;\n barSpacing: number;\n offset: number;\n chartRect: Rect;\n logScale?: boolean;\n}\n\nexport enum LayerType {\n Background = 0,\n Main = 1,\n Panel = 2,\n Overlay = 3,\n UI = 4,\n}\n","import type { Point, ViewportState } from './rendering.js';\n\nexport type DrawingToolType =\n | 'trendLine' | 'horizontalLine' | 'verticalLine' | 'ray' | 'extendedLine'\n | 'parallelChannel' | 'regressionChannel'\n | 'fibRetracement' | 'fibExtension'\n | 'rectangle' | 'ellipse' | 'triangle'\n | 'pitchfork' | 'elliottWave'\n | 'priceRange' | 'dateRange' | 'measure'\n | 'text' | 'arrow'\n | 'gannFan' | 'gannBox'\n | 'anchoredVWAP'\n | 'volumeProfileRange';\n\nexport interface AnchorPoint {\n time: number;\n price: number;\n}\n\nexport interface DrawingStyle {\n color: string;\n lineWidth: number;\n lineStyle: 'solid' | 'dashed' | 'dotted';\n fillColor?: string;\n fillOpacity?: number;\n fontSize?: number;\n text?: string;\n}\n\nexport interface DrawingState {\n id: string;\n type: DrawingToolType;\n anchors: AnchorPoint[];\n style: DrawingStyle;\n visible: boolean;\n locked: boolean;\n meta?: Record<string, unknown>;\n}\n\nexport interface DrawingDescriptor {\n type: DrawingToolType;\n name: string;\n requiredAnchors: number;\n singleClick?: boolean;\n}\n\nexport interface DrawingPlugin {\n descriptor: DrawingDescriptor;\n render(\n ctx: CanvasRenderingContext2D,\n state: DrawingState,\n viewport: ViewportState,\n selected: boolean,\n ): void;\n hitTest(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): boolean;\n hitTestAnchor(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): number;\n}\n\nexport const DEFAULT_DRAWING_STYLE: DrawingStyle = {\n color: '#2196F3',\n lineWidth: 1,\n lineStyle: 'solid',\n fillColor: 'rgba(33, 150, 243, 0.1)',\n fillOpacity: 0.1,\n fontSize: 12,\n};\n","export type OrderSide = 'buy' | 'sell';\nexport type OrderType = 'market' | 'limit' | 'stop' | 'stopLimit';\nexport type OrderStatus = 'pending' | 'filled' | 'cancelled' | 'rejected';\nexport type OrderLabel = 'LIMIT' | 'STOP' | 'SL' | 'TP' | 'STOP LIMIT';\n\nexport interface TradingOrder {\n id: string;\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity: number;\n label?: OrderLabel;\n draggable?: boolean;\n meta?: Record<string, unknown>;\n}\n\nexport interface TradingPosition {\n id: string;\n side: OrderSide;\n entryPrice: number;\n quantity: number;\n stopLoss?: number;\n takeProfit?: number;\n meta?: Record<string, unknown>;\n}\n\nexport interface DepthLevel {\n price: number;\n volume: number;\n}\n\nexport interface DepthData {\n bids: DepthLevel[];\n asks: DepthLevel[];\n}\n\nexport interface TradingConfig {\n enabled: boolean;\n orderColors?: { buy?: string; sell?: string };\n positionColors?: { profit?: string; loss?: string; entry?: string };\n depthOverlay?: {\n enabled?: boolean;\n bidColor?: string;\n askColor?: string;\n maxWidth?: number;\n };\n contextMenu?: { enabled?: boolean };\n pricePrecision?: number;\n dragThreshold?: number;\n}\n\nexport interface OrderPlaceIntent {\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity?: number;\n}\n\nexport interface OrderModifyIntent {\n orderId: string;\n newPrice: number;\n previousPrice: number;\n}\n\nexport interface OrderCancelIntent {\n orderId: string;\n}\n\nexport interface PositionModifyIntent {\n positionId: string;\n stopLoss?: number;\n takeProfit?: number;\n}\n\nexport interface PositionCloseIntent {\n positionId: string;\n}\n\nexport const DEFAULT_TRADING_CONFIG: TradingConfig = {\n enabled: true,\n orderColors: { buy: '#26A69A', sell: '#EF5350' },\n positionColors: { profit: '#26A69A', loss: '#EF5350', entry: '#2196F3' },\n depthOverlay: { enabled: false, bidColor: 'rgba(38,166,154,0.15)', askColor: 'rgba(239,83,80,0.15)', maxWidth: 100 },\n contextMenu: { enabled: true },\n pricePrecision: 2,\n dragThreshold: 3,\n};\n","import type { OHLCBar, TimeFrame } from './ohlc.js';\n\n// --- Connection ---\n\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';\n\nexport interface ConnectionInfo {\n state: ConnectionState;\n latency?: number;\n reconnectAttempt?: number;\n lastMessageTime?: number;\n error?: string;\n}\n\n// --- Ticks & Trades ---\n\nexport interface RawTick {\n time: number;\n price: number;\n volume: number;\n side?: 'buy' | 'sell';\n}\n\nexport interface AggregatedBar extends OHLCBar {\n closed: boolean; // true when bar is finalized\n tickCount: number; // number of ticks in this bar\n}\n\n// --- Data Adapter (Strategy Pattern) ---\n\nexport interface DataAdapterConfig {\n symbol: string;\n timeframe: TimeFrame;\n reconnect?: boolean; // default: true\n reconnectMaxRetries?: number; // default: Infinity\n reconnectBaseDelay?: number; // ms, default: 1000\n reconnectMaxDelay?: number; // ms, default: 30000\n heartbeatInterval?: number; // ms, default: 30000\n bufferSize?: number; // max ticks to buffer, default: 1000\n}\n\nexport type DataAdapterEventType =\n | 'tick'\n | 'bar'\n | 'barClose'\n | 'snapshot' // initial historical data loaded\n | 'connectionChange'\n | 'error';\n\nexport interface DataAdapterEvent<T = unknown> {\n type: DataAdapterEventType;\n data: T;\n timestamp: number;\n}\n\nexport type DataAdapterListener<T = unknown> = (event: DataAdapterEvent<T>) => void;\n\n/**\n * DataAdapter interface — Strategy pattern for pluggable data sources.\n *\n * Implementations handle the specifics of each data source (WebSocket, REST,\n * SSE, etc.) while the StreamManager orchestrates lifecycle and aggregation.\n *\n * Built-in: BinanceAdapter\n * Implement this for: custom exchange APIs, broker feeds, mock data\n */\nexport interface DataAdapter {\n readonly name: string;\n\n connect(config: DataAdapterConfig): void;\n disconnect(): void;\n getConnectionState(): ConnectionState;\n\n /**\n * Load historical bars. Called once on connect, before streaming starts.\n * Returns bars sorted by time ascending.\n */\n fetchHistory(symbol: string, timeframe: TimeFrame, limit?: number): Promise<OHLCBar[]>;\n\n on<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n off<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n\n dispose(): void;\n}\n\n// --- Stream Manager Config ---\n\nexport interface StreamConfig {\n adapter: DataAdapter;\n symbol: string;\n timeframe: TimeFrame;\n historyLimit?: number; // bars to load initially, default: 500\n autoScroll?: boolean; // scroll to end on new bar, default: true\n showCurrentPriceLine?: boolean; // default: true\n aggregateTicks?: boolean; // build bars from ticks, default: false\n reconnect?: ReconnectConfig;\n}\n\nexport interface ReconnectConfig {\n enabled: boolean; // default: true\n maxRetries: number; // default: Infinity\n baseDelay: number; // ms, default: 1000\n maxDelay: number; // ms, default: 30000\n backoffMultiplier: number; // default: 2\n}\n\nexport const DEFAULT_RECONNECT: ReconnectConfig = {\n enabled: true,\n maxRetries: Infinity,\n baseDelay: 1000,\n maxDelay: 30000,\n backoffMultiplier: 2,\n};\n\nexport const DEFAULT_STREAM_CONFIG: Partial<StreamConfig> = {\n historyLimit: 500,\n autoScroll: true,\n showCurrentPriceLine: true,\n aggregateTicks: false,\n};\n","export function clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nexport function inverseLerp(a: number, b: number, value: number): number {\n if (a === b) return 0;\n return (value - a) / (b - a);\n}\n\nexport function roundToStep(value: number, step: number): number {\n return Math.round(value / step) * step;\n}\n\nexport function niceNumber(value: number, round: boolean): number {\n const exp = Math.floor(Math.log10(value));\n const frac = value / Math.pow(10, exp);\n let nice: number;\n if (round) {\n if (frac < 1.5) nice = 1;\n else if (frac < 3) nice = 2;\n else if (frac < 7) nice = 5;\n else nice = 10;\n } else {\n if (frac <= 1) nice = 1;\n else if (frac <= 2) nice = 2;\n else if (frac <= 5) nice = 5;\n else nice = 10;\n }\n return nice * Math.pow(10, exp);\n}\n\nexport function computeTickStep(min: number, max: number, maxTicks: number): number {\n const range = niceNumber(max - min, false);\n return niceNumber(range / (maxTicks - 1), true);\n}\n","import type { OHLCBar, DataSeries } from '../types/ohlc.js';\n\nexport function sliceVisibleData(\n data: DataSeries,\n from: number,\n to: number,\n): DataSeries {\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length, to + 1);\n return data.slice(startIdx, endIdx);\n}\n\nexport function findBarIndex(data: DataSeries, timestamp: number): number {\n let lo = 0;\n let hi = data.length - 1;\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n if (data[mid].time < timestamp) lo = mid + 1;\n else if (data[mid].time > timestamp) hi = mid - 1;\n else return mid;\n }\n return lo;\n}\n\nexport function computePriceRange(\n data: DataSeries,\n from: number,\n to: number,\n padding = 0.05,\n): { min: number; max: number } {\n if (data.length === 0) return { min: 0, max: 1 };\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length - 1, to);\n let min = Infinity;\n let max = -Infinity;\n for (let i = startIdx; i <= endIdx; i++) {\n if (data[i].low < min) min = data[i].low;\n if (data[i].high > max) max = data[i].high;\n }\n if (min === Infinity) return { min: 0, max: 1 };\n const range = max - min || 1;\n return {\n min: min - range * padding,\n max: max + range * padding,\n };\n}\n\nexport function mergeBar(existing: OHLCBar, tick: { price: number; volume?: number; time: number }): OHLCBar {\n return {\n ...existing,\n high: Math.max(existing.high, tick.price),\n low: Math.min(existing.low, tick.price),\n close: tick.price,\n volume: existing.volume + (tick.volume ?? 0),\n time: tick.time,\n };\n}\n","export function hexToRgba(hex: string, alpha = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\nexport function withAlpha(color: string, alpha: number): string {\n if (color.startsWith('#')) {\n return hexToRgba(color, alpha);\n }\n const rgbaMatch = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (rgbaMatch) {\n return `rgba(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]}, ${alpha})`;\n }\n return color;\n}\n\nexport function lerpColor(colorA: string, colorB: string, t: number): string {\n const parseHex = (hex: string) => {\n hex = hex.replace('#', '');\n if (hex.length === 3) hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];\n return {\n r: parseInt(hex.slice(0, 2), 16),\n g: parseInt(hex.slice(2, 4), 16),\n b: parseInt(hex.slice(4, 6), 16),\n };\n };\n const a = parseHex(colorA);\n const b = parseHex(colorB);\n const r = Math.round(a.r + (b.r - a.r) * t);\n const g = Math.round(a.g + (b.g - a.g) * t);\n const bl = Math.round(a.b + (b.b - a.b) * t);\n return `rgb(${r},${g},${bl})`;\n}\n","import type { TimeFrame } from '../types/ohlc.js';\n\nconst TIMEFRAME_MS: Record<TimeFrame, number> = {\n '1s': 1_000,\n '5s': 5_000,\n '15s': 15_000,\n '30s': 30_000,\n '1m': 60_000,\n '3m': 180_000,\n '5m': 300_000,\n '15m': 900_000,\n '30m': 1_800_000,\n '45m': 2_700_000,\n '1h': 3_600_000,\n '2h': 7_200_000,\n '3h': 10_800_000,\n '4h': 14_400_000,\n '6h': 21_600_000,\n '8h': 28_800_000,\n '12h': 43_200_000,\n '1d': 86_400_000,\n '2d': 172_800_000,\n '3d': 259_200_000,\n '1w': 604_800_000,\n '2w': 1_209_600_000,\n '1M': 2_592_000_000,\n '3M': 7_776_000_000,\n '6M': 15_552_000_000,\n '12M': 31_536_000_000,\n};\n\nexport function timeframeToMs(tf: TimeFrame): number {\n return TIMEFRAME_MS[tf];\n}\n\nexport function formatTimestamp(timestamp: number, tf: TimeFrame): string {\n const d = new Date(timestamp);\n const ms = TIMEFRAME_MS[tf];\n if (ms >= 86_400_000) {\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }\n if (ms >= 3_600_000) {\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\n }\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\nexport function alignToTimeframe(timestamp: number, tf: TimeFrame): number {\n const ms = TIMEFRAME_MS[tf];\n return Math.floor(timestamp / ms) * ms;\n}\n","export function formatPrice(value: number, precision = 2): string {\n return value.toFixed(precision);\n}\n\nexport function formatVolume(value: number): string {\n if (value >= 1_000_000_000) return (value / 1_000_000_000).toFixed(2) + 'B';\n if (value >= 1_000_000) return (value / 1_000_000).toFixed(2) + 'M';\n if (value >= 1_000) return (value / 1_000).toFixed(2) + 'K';\n return value.toFixed(0);\n}\n\nexport function detectPrecision(values: number[]): number {\n let maxDecimals = 0;\n for (const v of values) {\n const str = v.toString();\n const dot = str.indexOf('.');\n if (dot >= 0) {\n maxDecimals = Math.max(maxDecimals, str.length - dot - 1);\n }\n }\n return Math.min(maxDecimals, 8);\n}\n","import type { ChartOptions } from '../types/chart.js';\n\nexport const DEFAULT_CHART_OPTIONS: Required<Pick<ChartOptions, 'autoScale' | 'rightMargin' | 'minBarSpacing' | 'maxBarSpacing'>> & Pick<ChartOptions, 'grid' | 'crosshair'> = {\n autoScale: true,\n rightMargin: 5,\n minBarSpacing: 2,\n maxBarSpacing: 30,\n grid: {\n visible: true,\n hLineStyle: 'solid',\n vLineStyle: 'solid',\n },\n crosshair: {\n mode: 'magnet',\n },\n};\n\n// Standard timeframe presets for different market types\nimport type { TimeFrame } from '../types/ohlc.js';\n\n/** Crypto: all timeframes including seconds */\nexport const TIMEFRAMES_CRYPTO: TimeFrame[] = [\n '1s', '1m', '3m', '5m', '15m', '30m',\n '1h', '2h', '4h', '6h', '8h', '12h',\n '1d', '3d', '1w', '1M',\n];\n\n/** Stocks: minute-level and above (no seconds) */\nexport const TIMEFRAMES_STOCK: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '2h', '4h',\n '1d', '1w', '1M', '3M', '6M', '12M',\n];\n\n/** Forex: common forex timeframes */\nexport const TIMEFRAMES_FOREX: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '4h',\n '1d', '1w', '1M',\n];\n\n/** Default favorites shown in quick-access bar */\nexport const DEFAULT_TIMEFRAME_FAVORITES: TimeFrame[] = [\n '1m', '5m', '15m', '1h', '4h', '1d', '1w',\n];\n\nexport const DEFAULT_BAR_WIDTH = 8;\nexport const DEFAULT_BAR_SPACING = 2;\nexport const PRICE_AXIS_WIDTH = 70;\nexport const TIME_AXIS_HEIGHT = 30;\nexport const MIN_PANEL_HEIGHT = 60;\nexport const DEFAULT_PANEL_HEIGHT = 120;\n","import type { Theme } from '../types/theme.js';\n\nconst DEFAULT_FONT = {\n family: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n sizeSmall: 10,\n sizeMedium: 12,\n sizeLarge: 14,\n};\n\nexport const DARK_THEME: Theme = {\n name: 'dark',\n background: '#131722',\n text: '#D1D4DC',\n textSecondary: '#787B86',\n grid: '#1E222D',\n crosshair: '#9598A1',\n candleUp: '#26A69A',\n candleDown: '#EF5350',\n candleUpWick: '#26A69A',\n candleDownWick: '#EF5350',\n lineColor: '#2196F3',\n areaTopColor: 'rgba(33, 150, 243, 0.4)',\n areaBottomColor: 'rgba(33, 150, 243, 0.0)',\n volumeUp: 'rgba(38, 166, 154, 0.3)',\n volumeDown: 'rgba(239, 83, 80, 0.3)',\n axisLine: '#2A2E39',\n axisLabel: '#D1D4DC',\n axisLabelBackground: '#2A2E39',\n font: DEFAULT_FONT,\n};\n\nexport const LIGHT_THEME: Theme = {\n name: 'light',\n background: '#FFFFFF',\n text: '#131722',\n textSecondary: '#787B86',\n grid: '#F0F3FA',\n crosshair: '#9598A1',\n candleUp: '#26A69A',\n candleDown: '#EF5350',\n candleUpWick: '#26A69A',\n candleDownWick: '#EF5350',\n lineColor: '#2196F3',\n areaTopColor: 'rgba(33, 150, 243, 0.4)',\n areaBottomColor: 'rgba(33, 150, 243, 0.0)',\n volumeUp: 'rgba(38, 166, 154, 0.3)',\n volumeDown: 'rgba(239, 83, 80, 0.3)',\n axisLine: '#E0E3EB',\n axisLabel: '#131722',\n axisLabelBackground: '#F0F3FA',\n font: DEFAULT_FONT,\n};\n","import type { LocaleStrings } from './types.js';\n\nexport const en: LocaleStrings = {\n // Chart types\n candlestick: 'Candlestick',\n line: 'Line',\n area: 'Area',\n bar: 'OHLC Bar',\n\n // Axes\n price: 'Price',\n volume: 'Volume',\n time: 'Time',\n open: 'Open',\n high: 'High',\n low: 'Low',\n close: 'Close',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Bollinger Bands',\n vwap: 'VWAP',\n ichimoku: 'Ichimoku Cloud',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Keltner Channel',\n donchianChannel: 'Donchian Channel',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Std Dev',\n volumeProfile: 'Volume Profile',\n accumulationDistribution: 'A/D Line',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Trend Line',\n horizontalLine: 'Horizontal Line',\n verticalLine: 'Vertical Line',\n ray: 'Ray',\n extendedLine: 'Extended Line',\n parallelChannel: 'Parallel Channel',\n regressionChannel: 'Regression Channel',\n fibRetracement: 'Fibonacci Retracement',\n fibExtension: 'Fibonacci Extension',\n rectangle: 'Rectangle',\n ellipse: 'Ellipse',\n triangle: 'Triangle',\n pitchfork: \"Andrews' Pitchfork\",\n elliottWave: 'Elliott Wave',\n priceRange: 'Price Range',\n dateRange: 'Date Range',\n measure: 'Measure',\n textTool: 'Text',\n arrow: 'Arrow',\n clearAll: 'Clear All',\n\n // Trading\n buy: 'Buy',\n sell: 'Sell',\n buyLimit: 'Buy Limit',\n sellLimit: 'Sell Limit',\n buyStop: 'Buy Stop',\n sellStop: 'Sell Stop',\n stopLoss: 'Stop Loss',\n takeProfit: 'Take Profit',\n market: 'Market',\n limit: 'Limit',\n stop: 'Stop',\n cancel: 'Cancel',\n modify: 'Modify',\n quantity: 'Qty',\n pnl: 'P&L',\n activeOrders: 'Active Orders',\n positions: 'Positions',\n noOrders: 'No active orders',\n noPositions: 'No open positions',\n placeOrder: 'Place Order',\n rightClickToTrade: 'Right-click chart to place orders',\n\n // Market\n ceiling: 'Ceiling',\n floor: 'Floor',\n reference: 'Reference',\n session: 'Session',\n preOpen: 'Pre-Open',\n continuous: 'Continuous',\n preClose: 'Pre-Close',\n closed: 'Closed',\n\n // UI\n settings: 'Settings',\n theme: 'Theme',\n darkTheme: 'Dark',\n lightTheme: 'Light',\n tools: 'Tools',\n indicators: 'Indicators',\n overlays: 'Overlays',\n panels: 'Panels',\n orders: 'Orders',\n autoScale: 'Auto Scale',\n crosshair: 'Crosshair',\n grid: 'Grid',\n loading: 'Loading...',\n error: 'Error',\n\n numberDecimalSeparator: '.',\n numberGroupSeparator: ',',\n};\n","import type { LocaleStrings } from './types.js';\n\nexport const vi: LocaleStrings = {\n // Chart types\n candlestick: 'Nến',\n line: 'Đường',\n area: 'Vùng',\n bar: 'Thanh OHLC',\n\n // Axes\n price: 'Giá',\n volume: 'Khối lượng',\n time: 'Thời gian',\n open: 'Mở',\n high: 'Cao',\n low: 'Thấp',\n close: 'Đóng',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Dải Bollinger',\n vwap: 'VWAP',\n ichimoku: 'Mây Ichimoku',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Kênh Keltner',\n donchianChannel: 'Kênh Donchian',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Độ lệch chuẩn',\n volumeProfile: 'Phân bổ KL',\n accumulationDistribution: 'Tích lũy/Phân phối',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Đường xu hướng',\n horizontalLine: 'Đường ngang',\n verticalLine: 'Đường dọc',\n ray: 'Tia',\n extendedLine: 'Đường kéo dài',\n parallelChannel: 'Kênh song song',\n regressionChannel: 'Kênh hồi quy',\n fibRetracement: 'Fibonacci thoái lui',\n fibExtension: 'Fibonacci mở rộng',\n rectangle: 'Hình chữ nhật',\n ellipse: 'Hình elip',\n triangle: 'Tam giác',\n pitchfork: 'Chĩa ba Andrews',\n elliottWave: 'Sóng Elliott',\n priceRange: 'Khoảng giá',\n dateRange: 'Khoảng thời gian',\n measure: 'Đo lường',\n textTool: 'Chữ',\n arrow: 'Mũi tên',\n clearAll: 'Xóa tất cả',\n\n // Trading\n buy: 'Mua',\n sell: 'Bán',\n buyLimit: 'Mua giới hạn',\n sellLimit: 'Bán giới hạn',\n buyStop: 'Mua chặn',\n sellStop: 'Bán chặn',\n stopLoss: 'Cắt lỗ',\n takeProfit: 'Chốt lời',\n market: 'Thị trường',\n limit: 'Giới hạn',\n stop: 'Dừng',\n cancel: 'Hủy',\n modify: 'Sửa',\n quantity: 'KL',\n pnl: 'Lãi/Lỗ',\n activeOrders: 'Lệnh chờ',\n positions: 'Vị thế',\n noOrders: 'Không có lệnh chờ',\n noPositions: 'Không có vị thế mở',\n placeOrder: 'Đặt lệnh',\n rightClickToTrade: 'Nhấp chuột phải để đặt lệnh',\n\n // Market\n ceiling: 'Trần',\n floor: 'Sàn',\n reference: 'Tham chiếu',\n session: 'Phiên',\n preOpen: 'Trước giờ mở',\n continuous: 'Liên tục',\n preClose: 'Trước giờ đóng',\n closed: 'Đóng cửa',\n\n // UI\n settings: 'Cài đặt',\n theme: 'Giao diện',\n darkTheme: 'Tối',\n lightTheme: 'Sáng',\n tools: 'Công cụ',\n indicators: 'Chỉ báo',\n overlays: 'Phủ lên',\n panels: 'Bảng',\n orders: 'Lệnh',\n autoScale: 'Tự co giãn',\n crosshair: 'Chữ thập',\n grid: 'Lưới',\n loading: 'Đang tải...',\n error: 'Lỗi',\n\n numberDecimalSeparator: ',',\n numberGroupSeparator: '.',\n};\n","export type { Locale, LocaleStrings, NumberFormatConfig, DateFormatConfig } from './types.js';\nexport { en } from './en.js';\nexport { vi } from './vi.js';\n\nimport type { Locale, LocaleStrings } from './types.js';\nimport { en } from './en.js';\nimport { vi } from './vi.js';\n\nconst locales = new Map<string, LocaleStrings>([\n ['en', en],\n ['vi', vi],\n]);\n\nlet currentLocale: Locale = 'en';\nlet currentStrings: LocaleStrings = en;\n\nexport function setLocale(locale: Locale): void {\n currentLocale = locale;\n currentStrings = locales.get(locale) ?? en;\n}\n\nexport function getLocale(): Locale {\n return currentLocale;\n}\n\nexport function t(key: keyof LocaleStrings): string {\n return currentStrings[key] ?? (en as any)[key] ?? key;\n}\n\nexport function registerLocale(locale: string, strings: LocaleStrings): void {\n locales.set(locale, strings);\n}\n\nexport function getLocaleStrings(locale?: string): LocaleStrings {\n return locales.get(locale ?? currentLocale) ?? en;\n}\n\n// Number formatting\nexport function formatNumber(value: number, precision = 2, locale?: string): string {\n const strings = locales.get(locale ?? currentLocale) ?? en;\n const dec = strings.numberDecimalSeparator;\n const grp = strings.numberGroupSeparator;\n\n const fixed = value.toFixed(precision);\n const [intPart, decPart] = fixed.split('.');\n\n // Group integer part\n const negative = intPart.startsWith('-');\n const digits = negative ? intPart.slice(1) : intPart;\n let grouped = '';\n for (let i = digits.length - 1, count = 0; i >= 0; i--, count++) {\n if (count > 0 && count % 3 === 0) grouped = grp + grouped;\n grouped = digits[i] + grouped;\n }\n if (negative) grouped = '-' + grouped;\n\n return decPart ? grouped + dec + decPart : grouped;\n}\n\nexport function formatVND(value: number): string {\n return formatNumber(value, 0, 'vi');\n}\n\nexport function formatVolumeLoc(value: number, locale?: string): string {\n if (value >= 1e9) return formatNumber(value / 1e9, 2, locale ?? currentLocale) + 'B';\n if (value >= 1e6) return formatNumber(value / 1e6, 2, locale ?? currentLocale) + 'M';\n if (value >= 1e3) return formatNumber(value / 1e3, 2, locale ?? currentLocale) + 'K';\n return formatNumber(value, 0, locale ?? currentLocale);\n}\n","import type { MarketConfig, MarketColorScheme, TradingSession } from './types.js';\nimport type { Theme } from '../types/theme.js';\n\n// Vietnam stock color convention:\n// Purple/Red = ceiling (trần) - max up\n// Green/Cyan = floor (sàn) - max down\n// Yellow = reference (tham chiếu)\n// Red = up, Blue = down (common VN convention)\nexport const VN_COLORS: MarketColorScheme = {\n up: '#FF0000', // Đỏ - tăng\n down: '#0000FF', // Xanh dương - giảm\n unchanged: '#FFD700', // Vàng - tham chiếu\n ceiling: '#FF00FF', // Tím - trần\n floor: '#00FFFF', // Xanh lam - sàn\n reference: '#FFD700', // Vàng - tham chiếu\n};\n\nexport const HOSE_SESSIONS: TradingSession[] = [\n { name: 'ATO', startTime: '09:00', endTime: '09:15', type: 'preOpen' },\n { name: 'Phiên 1', startTime: '09:15', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\nexport const HNX_SESSIONS: TradingSession[] = [\n { name: 'Phiên 1', startTime: '09:00', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\n// Market presets\nexport const MARKET_HOSE: MarketConfig = {\n type: 'stock',\n exchange: 'HOSE',\n currency: 'VND',\n pricePrecision: 2,\n volumeUnit: 10,\n priceStep: 0.05,\n priceLimits: { enabled: true, ceilingPercent: 7, floorPercent: 7 },\n sessions: HOSE_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_HNX: MarketConfig = {\n type: 'stock',\n exchange: 'HNX',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n priceLimits: { enabled: true, ceilingPercent: 10, floorPercent: 10 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_UPCOM: MarketConfig = {\n type: 'stock',\n exchange: 'UPCOM',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n priceLimits: { enabled: true, ceilingPercent: 15, floorPercent: 15 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_CRYPTO: MarketConfig = {\n type: 'crypto',\n currency: 'USDT',\n pricePrecision: 2,\n priceLimits: { enabled: false },\n};\n\nexport const MARKET_NYSE: MarketConfig = {\n type: 'stock',\n exchange: 'NYSE',\n currency: 'USD',\n pricePrecision: 2,\n priceStep: 0.01,\n priceLimits: { enabled: false },\n sessions: [\n { name: 'Pre-Market', startTime: '04:00', endTime: '09:30', type: 'preOpen' },\n { name: 'Regular', startTime: '09:30', endTime: '16:00', type: 'continuous' },\n { name: 'After-Hours', startTime: '16:00', endTime: '20:00', type: 'preClose' },\n ],\n};\n\n// Build a theme variant for VN stock market\nexport function createVNTheme(base: Theme): Theme {\n return {\n ...base,\n candleUp: VN_COLORS.up,\n candleDown: VN_COLORS.down,\n candleUpWick: VN_COLORS.up,\n candleDownWick: VN_COLORS.down,\n volumeUp: 'rgba(255, 0, 0, 0.3)',\n volumeDown: 'rgba(0, 0, 255, 0.3)',\n };\n}\n\nexport function computePriceLimits(referencePrice: number, config: MarketConfig): { ceiling: number; floor: number; reference: number } | null {\n if (!config.priceLimits?.enabled || !config.priceLimits.ceilingPercent) return null;\n const ceilPct = config.priceLimits.ceilingPercent / 100;\n const floorPct = (config.priceLimits.floorPercent ?? config.priceLimits.ceilingPercent) / 100;\n return {\n ceiling: referencePrice * (1 + ceilPct),\n floor: referencePrice * (1 - floorPct),\n reference: referencePrice,\n };\n}\n\nexport function getCurrentSession(sessions: TradingSession[]): TradingSession | null {\n const now = new Date();\n const hhmm = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;\n for (const session of sessions) {\n if (hhmm >= session.startTime && hhmm < session.endTime) return session;\n }\n return null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/types/rendering.ts","../src/types/drawing.ts","../src/types/trading.ts","../src/types/realtime.ts","../src/utils/math.ts","../src/utils/data.ts","../src/utils/color.ts","../src/utils/time.ts","../src/utils/precision.ts","../src/constants/defaults.ts","../src/constants/themes.ts","../src/i18n/en.ts","../src/i18n/vi.ts","../src/i18n/index.ts","../src/market/presets.ts"],"sourcesContent":["export interface Point {\n x: number;\n y: number;\n}\n\nexport interface Size {\n width: number;\n height: number;\n}\n\nexport interface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface ViewportState {\n visibleRange: { from: number; to: number };\n priceRange: { min: number; max: number };\n barWidth: number;\n barSpacing: number;\n offset: number;\n chartRect: Rect;\n logScale?: boolean;\n}\n\nexport enum LayerType {\n Background = 0,\n Main = 1,\n Panel = 2,\n Overlay = 3,\n UI = 4,\n}\n","import type { Point, ViewportState } from './rendering.js';\n\nexport type DrawingToolType =\n | 'trendLine' | 'horizontalLine' | 'verticalLine' | 'ray' | 'extendedLine'\n | 'parallelChannel' | 'regressionChannel'\n | 'fibRetracement' | 'fibExtension'\n | 'rectangle' | 'ellipse' | 'triangle'\n | 'pitchfork' | 'elliottWave'\n | 'priceRange' | 'dateRange' | 'measure'\n | 'text' | 'arrow'\n | 'gannFan' | 'gannBox'\n | 'anchoredVWAP'\n | 'volumeProfileRange';\n\nexport interface AnchorPoint {\n time: number;\n price: number;\n}\n\nexport interface DrawingStyle {\n color: string;\n lineWidth: number;\n lineStyle: 'solid' | 'dashed' | 'dotted';\n fillColor?: string;\n fillOpacity?: number;\n fontSize?: number;\n text?: string;\n}\n\nexport interface DrawingState {\n id: string;\n type: DrawingToolType;\n anchors: AnchorPoint[];\n style: DrawingStyle;\n visible: boolean;\n locked: boolean;\n meta?: Record<string, unknown>;\n}\n\nexport interface DrawingDescriptor {\n type: DrawingToolType;\n name: string;\n requiredAnchors: number;\n singleClick?: boolean;\n}\n\nexport interface DrawingPlugin {\n descriptor: DrawingDescriptor;\n render(\n ctx: CanvasRenderingContext2D,\n state: DrawingState,\n viewport: ViewportState,\n selected: boolean,\n ): void;\n hitTest(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): boolean;\n hitTestAnchor(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): number;\n}\n\nexport const DEFAULT_DRAWING_STYLE: DrawingStyle = {\n color: '#2196F3',\n lineWidth: 1,\n lineStyle: 'solid',\n fillColor: 'rgba(33, 150, 243, 0.1)',\n fillOpacity: 0.1,\n fontSize: 12,\n};\n","export type OrderSide = 'buy' | 'sell';\nexport type OrderType = 'market' | 'limit' | 'stop' | 'stopLimit';\nexport type OrderStatus = 'pending' | 'filled' | 'cancelled' | 'rejected';\nexport type OrderLabel = 'LIMIT' | 'STOP' | 'SL' | 'TP' | 'STOP LIMIT';\n\nexport interface TradingOrder {\n id: string;\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity: number;\n label?: OrderLabel;\n draggable?: boolean;\n meta?: Record<string, unknown>;\n}\n\nexport interface TradingPosition {\n id: string;\n side: OrderSide;\n entryPrice: number;\n quantity: number;\n stopLoss?: number;\n takeProfit?: number;\n meta?: Record<string, unknown>;\n}\n\nexport interface DepthLevel {\n price: number;\n volume: number;\n}\n\nexport interface DepthData {\n bids: DepthLevel[];\n asks: DepthLevel[];\n}\n\nexport interface TradingConfig {\n enabled: boolean;\n orderColors?: { buy?: string; sell?: string };\n positionColors?: { profit?: string; loss?: string; entry?: string };\n depthOverlay?: {\n enabled?: boolean;\n bidColor?: string;\n askColor?: string;\n maxWidth?: number;\n };\n contextMenu?: { enabled?: boolean };\n pricePrecision?: number;\n dragThreshold?: number;\n}\n\nexport interface OrderPlaceIntent {\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity?: number;\n}\n\nexport interface OrderModifyIntent {\n orderId: string;\n newPrice: number;\n previousPrice: number;\n}\n\nexport interface OrderCancelIntent {\n orderId: string;\n}\n\nexport interface PositionModifyIntent {\n positionId: string;\n stopLoss?: number;\n takeProfit?: number;\n}\n\nexport interface PositionCloseIntent {\n positionId: string;\n}\n\nexport const DEFAULT_TRADING_CONFIG: TradingConfig = {\n enabled: true,\n orderColors: { buy: '#26A69A', sell: '#EF5350' },\n positionColors: { profit: '#26A69A', loss: '#EF5350', entry: '#2196F3' },\n depthOverlay: { enabled: false, bidColor: 'rgba(38,166,154,0.15)', askColor: 'rgba(239,83,80,0.15)', maxWidth: 100 },\n contextMenu: { enabled: true },\n pricePrecision: 2,\n dragThreshold: 3,\n};\n","import type { OHLCBar, TimeFrame } from './ohlc.js';\n\n// --- Connection ---\n\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';\n\nexport interface ConnectionInfo {\n state: ConnectionState;\n latency?: number;\n reconnectAttempt?: number;\n lastMessageTime?: number;\n error?: string;\n}\n\n// --- Ticks & Trades ---\n\nexport interface RawTick {\n time: number;\n price: number;\n volume: number;\n side?: 'buy' | 'sell';\n}\n\nexport interface AggregatedBar extends OHLCBar {\n closed: boolean; // true when bar is finalized\n tickCount: number; // number of ticks in this bar\n}\n\n// --- Data Adapter (Strategy Pattern) ---\n\nexport interface DataAdapterConfig {\n symbol: string;\n timeframe: TimeFrame;\n reconnect?: boolean; // default: true\n reconnectMaxRetries?: number; // default: Infinity\n reconnectBaseDelay?: number; // ms, default: 1000\n reconnectMaxDelay?: number; // ms, default: 30000\n heartbeatInterval?: number; // ms, default: 30000\n bufferSize?: number; // max ticks to buffer, default: 1000\n}\n\nexport type DataAdapterEventType =\n | 'tick'\n | 'bar'\n | 'barClose'\n | 'snapshot' // initial historical data loaded\n | 'connectionChange'\n | 'error';\n\nexport interface DataAdapterEvent<T = unknown> {\n type: DataAdapterEventType;\n data: T;\n timestamp: number;\n}\n\nexport type DataAdapterListener<T = unknown> = (event: DataAdapterEvent<T>) => void;\n\n/**\n * DataAdapter interface — Strategy pattern for pluggable data sources.\n *\n * Implementations handle the specifics of each data source (WebSocket, REST,\n * SSE, etc.) while the StreamManager orchestrates lifecycle and aggregation.\n *\n * Built-in: BinanceAdapter\n * Implement this for: custom exchange APIs, broker feeds, mock data\n */\nexport interface DataAdapter {\n readonly name: string;\n\n connect(config: DataAdapterConfig): void;\n disconnect(): void;\n getConnectionState(): ConnectionState;\n\n /**\n * Load historical bars. Called once on connect, before streaming starts.\n * Returns bars sorted by time ascending.\n */\n fetchHistory(symbol: string, timeframe: TimeFrame, limit?: number): Promise<OHLCBar[]>;\n\n on<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n off<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n\n dispose(): void;\n}\n\n// --- Stream Manager Config ---\n\nexport interface StreamConfig {\n adapter: DataAdapter;\n symbol: string;\n timeframe: TimeFrame;\n historyLimit?: number; // bars to load initially, default: 500\n autoScroll?: boolean; // scroll to end on new bar, default: true\n showCurrentPriceLine?: boolean; // default: true\n aggregateTicks?: boolean; // build bars from ticks, default: false\n reconnect?: ReconnectConfig;\n}\n\nexport interface ReconnectConfig {\n enabled: boolean; // default: true\n maxRetries: number; // default: Infinity\n baseDelay: number; // ms, default: 1000\n maxDelay: number; // ms, default: 30000\n backoffMultiplier: number; // default: 2\n}\n\nexport const DEFAULT_RECONNECT: ReconnectConfig = {\n enabled: true,\n maxRetries: Infinity,\n baseDelay: 1000,\n maxDelay: 30000,\n backoffMultiplier: 2,\n};\n\nexport const DEFAULT_STREAM_CONFIG: Partial<StreamConfig> = {\n historyLimit: 500,\n autoScroll: true,\n showCurrentPriceLine: true,\n aggregateTicks: false,\n};\n","export function clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nexport function inverseLerp(a: number, b: number, value: number): number {\n if (a === b) return 0;\n return (value - a) / (b - a);\n}\n\nexport function roundToStep(value: number, step: number): number {\n return Math.round(value / step) * step;\n}\n\nexport function niceNumber(value: number, round: boolean): number {\n const exp = Math.floor(Math.log10(value));\n const frac = value / Math.pow(10, exp);\n let nice: number;\n if (round) {\n if (frac < 1.5) nice = 1;\n else if (frac < 3) nice = 2;\n else if (frac < 7) nice = 5;\n else nice = 10;\n } else {\n if (frac <= 1) nice = 1;\n else if (frac <= 2) nice = 2;\n else if (frac <= 5) nice = 5;\n else nice = 10;\n }\n return nice * Math.pow(10, exp);\n}\n\nexport function computeTickStep(min: number, max: number, maxTicks: number): number {\n const range = niceNumber(max - min, false);\n return niceNumber(range / (maxTicks - 1), true);\n}\n","import type { OHLCBar, DataSeries } from '../types/ohlc.js';\n\nexport function sliceVisibleData(\n data: DataSeries,\n from: number,\n to: number,\n): DataSeries {\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length, to + 1);\n return data.slice(startIdx, endIdx);\n}\n\nexport function findBarIndex(data: DataSeries, timestamp: number): number {\n let lo = 0;\n let hi = data.length - 1;\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n if (data[mid].time < timestamp) lo = mid + 1;\n else if (data[mid].time > timestamp) hi = mid - 1;\n else return mid;\n }\n return lo;\n}\n\nexport function computePriceRange(\n data: DataSeries,\n from: number,\n to: number,\n padding = 0.05,\n): { min: number; max: number } {\n if (data.length === 0) return { min: 0, max: 1 };\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length - 1, to);\n let min = Infinity;\n let max = -Infinity;\n for (let i = startIdx; i <= endIdx; i++) {\n if (data[i].low < min) min = data[i].low;\n if (data[i].high > max) max = data[i].high;\n }\n if (min === Infinity) return { min: 0, max: 1 };\n const range = max - min || 1;\n return {\n min: min - range * padding,\n max: max + range * padding,\n };\n}\n\nexport function mergeBar(existing: OHLCBar, tick: { price: number; volume?: number; time: number }): OHLCBar {\n return {\n ...existing,\n high: Math.max(existing.high, tick.price),\n low: Math.min(existing.low, tick.price),\n close: tick.price,\n volume: existing.volume + (tick.volume ?? 0),\n time: tick.time,\n };\n}\n","export function hexToRgba(hex: string, alpha = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\nexport function withAlpha(color: string, alpha: number): string {\n if (color.startsWith('#')) {\n return hexToRgba(color, alpha);\n }\n const rgbaMatch = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (rgbaMatch) {\n return `rgba(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]}, ${alpha})`;\n }\n return color;\n}\n\nexport function lerpColor(colorA: string, colorB: string, t: number): string {\n const parseHex = (hex: string) => {\n hex = hex.replace('#', '');\n if (hex.length === 3) hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];\n return {\n r: parseInt(hex.slice(0, 2), 16),\n g: parseInt(hex.slice(2, 4), 16),\n b: parseInt(hex.slice(4, 6), 16),\n };\n };\n const a = parseHex(colorA);\n const b = parseHex(colorB);\n const r = Math.round(a.r + (b.r - a.r) * t);\n const g = Math.round(a.g + (b.g - a.g) * t);\n const bl = Math.round(a.b + (b.b - a.b) * t);\n return `rgb(${r},${g},${bl})`;\n}\n","import type { TimeFrame } from '../types/ohlc.js';\n\nconst TIMEFRAME_MS: Record<TimeFrame, number> = {\n '1s': 1_000,\n '5s': 5_000,\n '15s': 15_000,\n '30s': 30_000,\n '1m': 60_000,\n '3m': 180_000,\n '5m': 300_000,\n '15m': 900_000,\n '30m': 1_800_000,\n '45m': 2_700_000,\n '1h': 3_600_000,\n '2h': 7_200_000,\n '3h': 10_800_000,\n '4h': 14_400_000,\n '6h': 21_600_000,\n '8h': 28_800_000,\n '12h': 43_200_000,\n '1d': 86_400_000,\n '2d': 172_800_000,\n '3d': 259_200_000,\n '1w': 604_800_000,\n '2w': 1_209_600_000,\n '1M': 2_592_000_000,\n '3M': 7_776_000_000,\n '6M': 15_552_000_000,\n '12M': 31_536_000_000,\n};\n\nexport function timeframeToMs(tf: TimeFrame): number {\n return TIMEFRAME_MS[tf];\n}\n\nexport function formatTimestamp(timestamp: number, tf: TimeFrame): string {\n const d = new Date(timestamp);\n const ms = TIMEFRAME_MS[tf];\n if (ms >= 86_400_000) {\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }\n if (ms >= 3_600_000) {\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\n }\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\nexport function alignToTimeframe(timestamp: number, tf: TimeFrame): number {\n const ms = TIMEFRAME_MS[tf];\n return Math.floor(timestamp / ms) * ms;\n}\n","export function formatPrice(value: number, precision = 2, locale = 'en-US'): string {\n return value.toLocaleString(locale, {\n minimumFractionDigits: precision,\n maximumFractionDigits: precision,\n });\n}\n\nexport function formatVolume(value: number): string {\n if (value >= 1_000_000_000) return (value / 1_000_000_000).toFixed(2) + 'B';\n if (value >= 1_000_000) return (value / 1_000_000).toFixed(2) + 'M';\n if (value >= 1_000) return (value / 1_000).toFixed(2) + 'K';\n return value.toFixed(0);\n}\n\nexport function detectPrecision(values: number[]): number {\n let maxDecimals = 0;\n for (const v of values) {\n const str = v.toString();\n const dot = str.indexOf('.');\n if (dot >= 0) {\n maxDecimals = Math.max(maxDecimals, str.length - dot - 1);\n }\n }\n return Math.min(maxDecimals, 8);\n}\n","import type { ChartOptions } from '../types/chart.js';\n\nexport const DEFAULT_CHART_OPTIONS: Required<Pick<ChartOptions, 'autoScale' | 'rightMargin' | 'minBarSpacing' | 'maxBarSpacing'>> & Pick<ChartOptions, 'grid' | 'crosshair'> = {\n autoScale: true,\n rightMargin: 5,\n minBarSpacing: 2,\n maxBarSpacing: 30,\n grid: {\n visible: true,\n hLineStyle: 'solid',\n vLineStyle: 'solid',\n },\n crosshair: {\n mode: 'magnet',\n },\n};\n\n// Standard timeframe presets for different market types\nimport type { TimeFrame } from '../types/ohlc.js';\n\n/** Crypto: all timeframes including seconds */\nexport const TIMEFRAMES_CRYPTO: TimeFrame[] = [\n '1s', '1m', '3m', '5m', '15m', '30m',\n '1h', '2h', '4h', '6h', '8h', '12h',\n '1d', '3d', '1w', '1M',\n];\n\n/** Stocks: minute-level and above (no seconds) */\nexport const TIMEFRAMES_STOCK: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '2h', '4h',\n '1d', '1w', '1M', '3M', '6M', '12M',\n];\n\n/** Forex: common forex timeframes */\nexport const TIMEFRAMES_FOREX: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '4h',\n '1d', '1w', '1M',\n];\n\n/** Default favorites shown in quick-access bar */\nexport const DEFAULT_TIMEFRAME_FAVORITES: TimeFrame[] = [\n '1m', '5m', '15m', '1h', '4h', '1d', '1w',\n];\n\nexport const DEFAULT_BAR_WIDTH = 8;\nexport const DEFAULT_BAR_SPACING = 2;\nexport const PRICE_AXIS_WIDTH = 70;\nexport const TIME_AXIS_HEIGHT = 30;\nexport const MIN_PANEL_HEIGHT = 60;\nexport const DEFAULT_PANEL_HEIGHT = 120;\n","import type { Theme } from '../types/theme.js';\n\nconst DEFAULT_FONT = {\n family: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n sizeSmall: 10,\n sizeMedium: 12,\n sizeLarge: 14,\n};\n\nexport const DARK_THEME: Theme = {\n name: 'dark',\n background: '#131722',\n text: '#D1D4DC',\n textSecondary: '#787B86',\n grid: '#1E222D',\n crosshair: '#9598A1',\n candleUp: '#26A69A',\n candleDown: '#EF5350',\n candleUpWick: '#26A69A',\n candleDownWick: '#EF5350',\n lineColor: '#2196F3',\n areaTopColor: 'rgba(33, 150, 243, 0.4)',\n areaBottomColor: 'rgba(33, 150, 243, 0.0)',\n volumeUp: 'rgba(38, 166, 154, 0.3)',\n volumeDown: 'rgba(239, 83, 80, 0.3)',\n axisLine: '#2A2E39',\n axisLabel: '#D1D4DC',\n axisLabelBackground: '#2A2E39',\n font: DEFAULT_FONT,\n};\n\nexport const LIGHT_THEME: Theme = {\n name: 'light',\n background: '#FFFFFF',\n text: '#131722',\n textSecondary: '#787B86',\n grid: '#F0F3FA',\n crosshair: '#9598A1',\n candleUp: '#26A69A',\n candleDown: '#EF5350',\n candleUpWick: '#26A69A',\n candleDownWick: '#EF5350',\n lineColor: '#2196F3',\n areaTopColor: 'rgba(33, 150, 243, 0.4)',\n areaBottomColor: 'rgba(33, 150, 243, 0.0)',\n volumeUp: 'rgba(38, 166, 154, 0.3)',\n volumeDown: 'rgba(239, 83, 80, 0.3)',\n axisLine: '#E0E3EB',\n axisLabel: '#131722',\n axisLabelBackground: '#F0F3FA',\n font: DEFAULT_FONT,\n};\n","import type { LocaleStrings } from './types.js';\n\nexport const en: LocaleStrings = {\n // Chart types\n candlestick: 'Candlestick',\n line: 'Line',\n area: 'Area',\n bar: 'OHLC Bar',\n\n // Axes\n price: 'Price',\n volume: 'Volume',\n time: 'Time',\n open: 'Open',\n high: 'High',\n low: 'Low',\n close: 'Close',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Bollinger Bands',\n vwap: 'VWAP',\n ichimoku: 'Ichimoku Cloud',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Keltner Channel',\n donchianChannel: 'Donchian Channel',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Std Dev',\n volumeProfile: 'Volume Profile',\n accumulationDistribution: 'A/D Line',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Trend Line',\n horizontalLine: 'Horizontal Line',\n verticalLine: 'Vertical Line',\n ray: 'Ray',\n extendedLine: 'Extended Line',\n parallelChannel: 'Parallel Channel',\n regressionChannel: 'Regression Channel',\n fibRetracement: 'Fibonacci Retracement',\n fibExtension: 'Fibonacci Extension',\n rectangle: 'Rectangle',\n ellipse: 'Ellipse',\n triangle: 'Triangle',\n pitchfork: \"Andrews' Pitchfork\",\n elliottWave: 'Elliott Wave',\n priceRange: 'Price Range',\n dateRange: 'Date Range',\n measure: 'Measure',\n textTool: 'Text',\n arrow: 'Arrow',\n clearAll: 'Clear All',\n\n // Trading\n buy: 'Buy',\n sell: 'Sell',\n buyLimit: 'Buy Limit',\n sellLimit: 'Sell Limit',\n buyStop: 'Buy Stop',\n sellStop: 'Sell Stop',\n stopLoss: 'Stop Loss',\n takeProfit: 'Take Profit',\n market: 'Market',\n limit: 'Limit',\n stop: 'Stop',\n cancel: 'Cancel',\n modify: 'Modify',\n quantity: 'Qty',\n pnl: 'P&L',\n activeOrders: 'Active Orders',\n positions: 'Positions',\n noOrders: 'No active orders',\n noPositions: 'No open positions',\n placeOrder: 'Place Order',\n rightClickToTrade: 'Right-click chart to place orders',\n\n // Market\n ceiling: 'Ceiling',\n floor: 'Floor',\n reference: 'Reference',\n session: 'Session',\n preOpen: 'Pre-Open',\n continuous: 'Continuous',\n preClose: 'Pre-Close',\n closed: 'Closed',\n\n // UI\n settings: 'Settings',\n theme: 'Theme',\n darkTheme: 'Dark',\n lightTheme: 'Light',\n tools: 'Tools',\n indicators: 'Indicators',\n overlays: 'Overlays',\n panels: 'Panels',\n orders: 'Orders',\n autoScale: 'Auto Scale',\n crosshair: 'Crosshair',\n grid: 'Grid',\n loading: 'Loading...',\n error: 'Error',\n\n numberDecimalSeparator: '.',\n numberGroupSeparator: ',',\n};\n","import type { LocaleStrings } from './types.js';\n\nexport const vi: LocaleStrings = {\n // Chart types\n candlestick: 'Nến',\n line: 'Đường',\n area: 'Vùng',\n bar: 'Thanh OHLC',\n\n // Axes\n price: 'Giá',\n volume: 'Khối lượng',\n time: 'Thời gian',\n open: 'Mở',\n high: 'Cao',\n low: 'Thấp',\n close: 'Đóng',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Dải Bollinger',\n vwap: 'VWAP',\n ichimoku: 'Mây Ichimoku',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Kênh Keltner',\n donchianChannel: 'Kênh Donchian',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Độ lệch chuẩn',\n volumeProfile: 'Phân bổ KL',\n accumulationDistribution: 'Tích lũy/Phân phối',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Đường xu hướng',\n horizontalLine: 'Đường ngang',\n verticalLine: 'Đường dọc',\n ray: 'Tia',\n extendedLine: 'Đường kéo dài',\n parallelChannel: 'Kênh song song',\n regressionChannel: 'Kênh hồi quy',\n fibRetracement: 'Fibonacci thoái lui',\n fibExtension: 'Fibonacci mở rộng',\n rectangle: 'Hình chữ nhật',\n ellipse: 'Hình elip',\n triangle: 'Tam giác',\n pitchfork: 'Chĩa ba Andrews',\n elliottWave: 'Sóng Elliott',\n priceRange: 'Khoảng giá',\n dateRange: 'Khoảng thời gian',\n measure: 'Đo lường',\n textTool: 'Chữ',\n arrow: 'Mũi tên',\n clearAll: 'Xóa tất cả',\n\n // Trading\n buy: 'Mua',\n sell: 'Bán',\n buyLimit: 'Mua giới hạn',\n sellLimit: 'Bán giới hạn',\n buyStop: 'Mua chặn',\n sellStop: 'Bán chặn',\n stopLoss: 'Cắt lỗ',\n takeProfit: 'Chốt lời',\n market: 'Thị trường',\n limit: 'Giới hạn',\n stop: 'Dừng',\n cancel: 'Hủy',\n modify: 'Sửa',\n quantity: 'KL',\n pnl: 'Lãi/Lỗ',\n activeOrders: 'Lệnh chờ',\n positions: 'Vị thế',\n noOrders: 'Không có lệnh chờ',\n noPositions: 'Không có vị thế mở',\n placeOrder: 'Đặt lệnh',\n rightClickToTrade: 'Nhấp chuột phải để đặt lệnh',\n\n // Market\n ceiling: 'Trần',\n floor: 'Sàn',\n reference: 'Tham chiếu',\n session: 'Phiên',\n preOpen: 'Trước giờ mở',\n continuous: 'Liên tục',\n preClose: 'Trước giờ đóng',\n closed: 'Đóng cửa',\n\n // UI\n settings: 'Cài đặt',\n theme: 'Giao diện',\n darkTheme: 'Tối',\n lightTheme: 'Sáng',\n tools: 'Công cụ',\n indicators: 'Chỉ báo',\n overlays: 'Phủ lên',\n panels: 'Bảng',\n orders: 'Lệnh',\n autoScale: 'Tự co giãn',\n crosshair: 'Chữ thập',\n grid: 'Lưới',\n loading: 'Đang tải...',\n error: 'Lỗi',\n\n numberDecimalSeparator: ',',\n numberGroupSeparator: '.',\n};\n","export type { Locale, LocaleStrings, NumberFormatConfig, DateFormatConfig } from './types.js';\nexport { en } from './en.js';\nexport { vi } from './vi.js';\n\nimport type { Locale, LocaleStrings } from './types.js';\nimport { en } from './en.js';\nimport { vi } from './vi.js';\n\nconst locales = new Map<string, LocaleStrings>([\n ['en', en],\n ['vi', vi],\n]);\n\nlet currentLocale: Locale = 'en';\nlet currentStrings: LocaleStrings = en;\n\nexport function setLocale(locale: Locale): void {\n currentLocale = locale;\n currentStrings = locales.get(locale) ?? en;\n}\n\nexport function getLocale(): Locale {\n return currentLocale;\n}\n\nexport function t(key: keyof LocaleStrings): string {\n return currentStrings[key] ?? (en as any)[key] ?? key;\n}\n\nexport function registerLocale(locale: string, strings: LocaleStrings): void {\n locales.set(locale, strings);\n}\n\nexport function getLocaleStrings(locale?: string): LocaleStrings {\n return locales.get(locale ?? currentLocale) ?? en;\n}\n\n// Number formatting\nexport function formatNumber(value: number, precision = 2, locale?: string): string {\n const strings = locales.get(locale ?? currentLocale) ?? en;\n const dec = strings.numberDecimalSeparator;\n const grp = strings.numberGroupSeparator;\n\n const fixed = value.toFixed(precision);\n const [intPart, decPart] = fixed.split('.');\n\n // Group integer part\n const negative = intPart.startsWith('-');\n const digits = negative ? intPart.slice(1) : intPart;\n let grouped = '';\n for (let i = digits.length - 1, count = 0; i >= 0; i--, count++) {\n if (count > 0 && count % 3 === 0) grouped = grp + grouped;\n grouped = digits[i] + grouped;\n }\n if (negative) grouped = '-' + grouped;\n\n return decPart ? grouped + dec + decPart : grouped;\n}\n\nexport function formatVND(value: number): string {\n return formatNumber(value, 0, 'vi');\n}\n\nexport function formatVolumeLoc(value: number, locale?: string): string {\n if (value >= 1e9) return formatNumber(value / 1e9, 2, locale ?? currentLocale) + 'B';\n if (value >= 1e6) return formatNumber(value / 1e6, 2, locale ?? currentLocale) + 'M';\n if (value >= 1e3) return formatNumber(value / 1e3, 2, locale ?? currentLocale) + 'K';\n return formatNumber(value, 0, locale ?? currentLocale);\n}\n","import type { MarketConfig, MarketColorScheme, TradingSession } from './types.js';\nimport type { Theme } from '../types/theme.js';\n\n// Vietnam stock color convention:\n// Purple/Red = ceiling (trần) - max up\n// Green/Cyan = floor (sàn) - max down\n// Yellow = reference (tham chiếu)\n// Red = up, Blue = down (common VN convention)\nexport const VN_COLORS: MarketColorScheme = {\n up: '#FF0000', // Đỏ - tăng\n down: '#0000FF', // Xanh dương - giảm\n unchanged: '#FFD700', // Vàng - tham chiếu\n ceiling: '#FF00FF', // Tím - trần\n floor: '#00FFFF', // Xanh lam - sàn\n reference: '#FFD700', // Vàng - tham chiếu\n};\n\nexport const HOSE_SESSIONS: TradingSession[] = [\n { name: 'ATO', startTime: '09:00', endTime: '09:15', type: 'preOpen' },\n { name: 'Phiên 1', startTime: '09:15', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\nexport const HNX_SESSIONS: TradingSession[] = [\n { name: 'Phiên 1', startTime: '09:00', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\n// Market presets\nexport const MARKET_HOSE: MarketConfig = {\n type: 'stock',\n exchange: 'HOSE',\n currency: 'VND',\n pricePrecision: 2,\n volumeUnit: 10,\n priceStep: 0.05,\n priceLimits: { enabled: true, ceilingPercent: 7, floorPercent: 7 },\n sessions: HOSE_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_HNX: MarketConfig = {\n type: 'stock',\n exchange: 'HNX',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n priceLimits: { enabled: true, ceilingPercent: 10, floorPercent: 10 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_UPCOM: MarketConfig = {\n type: 'stock',\n exchange: 'UPCOM',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n priceLimits: { enabled: true, ceilingPercent: 15, floorPercent: 15 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_CRYPTO: MarketConfig = {\n type: 'crypto',\n currency: 'USDT',\n pricePrecision: 2,\n priceLimits: { enabled: false },\n};\n\nexport const MARKET_NYSE: MarketConfig = {\n type: 'stock',\n exchange: 'NYSE',\n currency: 'USD',\n pricePrecision: 2,\n priceStep: 0.01,\n priceLimits: { enabled: false },\n sessions: [\n { name: 'Pre-Market', startTime: '04:00', endTime: '09:30', type: 'preOpen' },\n { name: 'Regular', startTime: '09:30', endTime: '16:00', type: 'continuous' },\n { name: 'After-Hours', startTime: '16:00', endTime: '20:00', type: 'preClose' },\n ],\n};\n\n// Build a theme variant for VN stock market\nexport function createVNTheme(base: Theme): Theme {\n return {\n ...base,\n candleUp: VN_COLORS.up,\n candleDown: VN_COLORS.down,\n candleUpWick: VN_COLORS.up,\n candleDownWick: VN_COLORS.down,\n volumeUp: 'rgba(255, 0, 0, 0.3)',\n volumeDown: 'rgba(0, 0, 255, 0.3)',\n };\n}\n\nexport function computePriceLimits(referencePrice: number, config: MarketConfig): { ceiling: number; floor: number; reference: number } | null {\n if (!config.priceLimits?.enabled || !config.priceLimits.ceilingPercent) return null;\n const ceilPct = config.priceLimits.ceilingPercent / 100;\n const floorPct = (config.priceLimits.floorPercent ?? config.priceLimits.ceilingPercent) / 100;\n return {\n ceiling: referencePrice * (1 + ceilPct),\n floor: referencePrice * (1 - floorPct),\n reference: referencePrice,\n };\n}\n\nexport function getCurrentSession(sessions: TradingSession[]): TradingSession | null {\n const now = new Date();\n const hhmm = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;\n for (const session of sessions) {\n if (hhmm >= session.startTime && hhmm < session.endTime) return session;\n }\n return null;\n}\n"],"mappings":"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"}
@@ -88,6 +88,8 @@ export interface ChartOptions {
88
88
  sessionBreaks?: SessionBreakOptions;
89
89
  /** Feature toggles — control what users can access */
90
90
  features?: FeaturesConfig;
91
+ /** BCP 47 locale for number formatting (e.g. 'en-US', 'de-DE', 'vi-VN'). Defaults to 'en-US'. */
92
+ numberLocale?: string;
91
93
  }
92
94
  export interface SessionBreakOptions {
93
95
  visible?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"chart.d.ts","sourceRoot":"","sources":["../../src/types/chart.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chart.d.ts","sourceRoot":"","sources":["../../src/types/chart.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- export declare function formatPrice(value: number, precision?: number): string;
1
+ export declare function formatPrice(value: number, precision?: number, locale?: string): string;
2
2
  export declare function formatVolume(value: number): string;
3
3
  export declare function detectPrecision(values: number[]): number;
4
4
  //# sourceMappingURL=precision.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"precision.d.ts","sourceRoot":"","sources":["../../src/utils/precision.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,SAAI,GAAG,MAAM,CAEhE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAUxD"}
1
+ {"version":3,"file":"precision.d.ts","sourceRoot":"","sources":["../../src/utils/precision.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,SAAI,EAAE,MAAM,SAAU,GAAG,MAAM,CAKlF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAUxD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tradecanvas/commons",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "Shared types and utilities for @tradecanvas/chart",
6
6
  "license": "MIT",