@tradecanvas/commons
Advanced tools
| import { Theme } from '../types/theme.js'; | ||
| export declare const DARK_THEME: Theme; | ||
| export declare const LIGHT_THEME: Theme; | ||
| export declare const DARK_TERMINAL: Theme; | ||
| //# sourceMappingURL=themes.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"themes.d.ts","sourceRoot":"","sources":["../../src/constants/themes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAS/C,eAAO,MAAM,UAAU,EAAE,KAoBxB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAoBzB,CAAC"} | ||
| {"version":3,"file":"themes.d.ts","sourceRoot":"","sources":["../../src/constants/themes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAS/C,eAAO,MAAM,UAAU,EAAE,KAoBxB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAoBzB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAyB3B,CAAC"} |
+1
-1
@@ -1,2 +0,2 @@ | ||
| 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; | ||
| 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){return e>0xe8d4a51000?e:e*1e3}function f(e){return{time:d(e.time??e.t??0),open:e.open??e.o??0,high:e.high??e.h??0,low:e.low??e.l??0,close:e.close??e.c??0,volume:e.volume??e.v??0}}function p(e,t,n){let r=Math.max(0,t),i=Math.min(e.length,n+1);return e.slice(r,i)}function m(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 h(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 g(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 _(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 ee(e,t){if(e.startsWith(`#`))return _(e,t);let n=e.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);return n?`rgba(${n[1]}, ${n[2]}, ${n[3]}, ${t})`:e}function v(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 y={"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 te(e){return y[e]}function ne(e,t){let n=new Date(e),r=y[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 re(e,t){let n=y[t];return Math.floor(e/n)*n}function ie(e,t=2,n=`en-US`){return e.toLocaleString(n,{minimumFractionDigits:t,maximumFractionDigits:t})}function b(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 x(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 S={autoScale:!0,rightMargin:5,minBarSpacing:2,maxBarSpacing:30,grid:{visible:!0,hLineStyle:`solid`,vLineStyle:`solid`},crosshair:{mode:`magnet`}},C=[`1s`,`1m`,`3m`,`5m`,`15m`,`30m`,`1h`,`2h`,`4h`,`6h`,`8h`,`12h`,`1d`,`3d`,`1w`,`1M`],w=[`1m`,`5m`,`15m`,`30m`,`1h`,`2h`,`4h`,`1d`,`1w`,`1M`,`3M`,`6M`,`12M`],T=[`1m`,`5m`,`15m`,`30m`,`1h`,`4h`,`1d`,`1w`,`1M`],E=[`1m`,`5m`,`15m`,`1h`,`4h`,`1d`,`1w`],D=8,O=2,k=70,A=30,j=60,M=120,N={family:`-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`,sizeSmall:10,sizeMedium:12,sizeLarge:14},P={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:N},F={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:N},I={name:`terminal`,background:`#0E0E0E`,text:`#C0C0C0`,textSecondary:`#8A8A8A`,grid:`#1A1A1A`,crosshair:`#666666`,candleUp:`#00FF87`,candleDown:`#FF3B4D`,candleUpWick:`#00FF87`,candleDownWick:`#FF3B4D`,lineColor:`#3D8BFD`,areaTopColor:`rgba(61, 139, 253, 0.3)`,areaBottomColor:`rgba(61, 139, 253, 0.0)`,volumeUp:`rgba(0, 255, 135, 0.2)`,volumeDown:`rgba(255, 59, 77, 0.2)`,axisLine:`#1A1A1A`,axisLabel:`#8A8A8A`,axisLabelBackground:`#1A1A1A`,font:{family:`'Roboto Mono', 'JetBrains Mono', 'SF Mono', Consolas, monospace`,sizeSmall:10,sizeMedium:12,sizeLarge:14}},L={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:`,`},R={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:`.`},z=new Map([[`en`,L],[`vi`,R]]),B=`en`,V=L;function H(e){B=e,V=z.get(e)??L}function U(){return B}function W(e){return V[e]??L[e]??e}function G(e,t){z.set(e,t)}function K(e){return z.get(e??B)??L}function q(e,t=2,n){let r=z.get(n??B)??L,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 J(e){return q(e,0,`vi`)}function Y(e,t){return e>=1e9?q(e/1e9,2,t??B)+`B`:e>=1e6?q(e/1e6,2,t??B)+`M`:e>=1e3?q(e/1e3,2,t??B)+`K`:q(e,0,t??B)}var X={up:`#FF0000`,down:`#0000FF`,unchanged:`#FFD700`,ceiling:`#FF00FF`,floor:`#00FFFF`,reference:`#FFD700`},Z=[{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`}],Q=[{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`}],ae={type:`stock`,exchange:`HOSE`,currency:`VND`,pricePrecision:2,volumeUnit:10,priceStep:.05,priceLimits:{enabled:!0,ceilingPercent:7,floorPercent:7},sessions:Z,colorScheme:X},oe={type:`stock`,exchange:`HNX`,currency:`VND`,pricePrecision:1,volumeUnit:100,priceStep:.1,priceLimits:{enabled:!0,ceilingPercent:10,floorPercent:10},sessions:Q,colorScheme:X},se={type:`stock`,exchange:`UPCOM`,currency:`VND`,pricePrecision:1,volumeUnit:100,priceStep:.1,priceLimits:{enabled:!0,ceilingPercent:15,floorPercent:15},sessions:Q,colorScheme:X},ce={type:`crypto`,currency:`USDT`,pricePrecision:2,priceLimits:{enabled:!1}},le={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 $(e){return{...e,candleUp:X.up,candleDown:X.down,candleUpWick:X.up,candleDownWick:X.down,volumeUp:`rgba(255, 0, 0, 0.3)`,volumeDown:`rgba(0, 0, 255, 0.3)`}}function ue(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 de(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_TERMINAL=I,exports.DARK_THEME=P,exports.DEFAULT_BAR_SPACING=O,exports.DEFAULT_BAR_WIDTH=D,exports.DEFAULT_CHART_OPTIONS=S,exports.DEFAULT_DRAWING_STYLE=t,exports.DEFAULT_PANEL_HEIGHT=M,exports.DEFAULT_RECONNECT=r,exports.DEFAULT_STREAM_CONFIG=i,exports.DEFAULT_TIMEFRAME_FAVORITES=E,exports.DEFAULT_TRADING_CONFIG=n,exports.HNX_SESSIONS=Q,exports.HOSE_SESSIONS=Z,exports.LIGHT_THEME=F,exports.LayerType=e,exports.MARKET_CRYPTO=ce,exports.MARKET_HNX=oe,exports.MARKET_HOSE=ae,exports.MARKET_NYSE=le,exports.MARKET_UPCOM=se,exports.MIN_PANEL_HEIGHT=j,exports.PRICE_AXIS_WIDTH=k,exports.TIMEFRAMES_CRYPTO=C,exports.TIMEFRAMES_FOREX=T,exports.TIMEFRAMES_STOCK=w,exports.TIME_AXIS_HEIGHT=A,exports.VN_COLORS=X,exports.alignToTimeframe=re,exports.clamp=a,exports.computePriceLimits=ue,exports.computePriceRange=h,exports.computeTickStep=u,exports.createVNTheme=$,exports.detectPrecision=x,exports.en=L,exports.findBarIndex=m,exports.formatNumber=q,exports.formatPrice=ie,exports.formatTimestamp=ne,exports.formatVND=J,exports.formatVolume=b,exports.formatVolumeLoc=Y,exports.getCurrentSession=de,exports.getLocale=U,exports.getLocaleStrings=K,exports.hexToRgba=_,exports.inverseLerp=s,exports.lerp=o,exports.lerpColor=v,exports.mergeBar=g,exports.niceNumber=l,exports.normalizeBar=f,exports.normalizeBarTime=d,exports.registerLocale=G,exports.roundToStep=c,exports.setLocale=H,exports.sliceVisibleData=p,exports.t=W,exports.timeframeToMs=te,exports.vi=R,exports.withAlpha=ee; | ||
| //# sourceMappingURL=index.cjs.map |
@@ -1,1 +0,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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"} | ||
| {"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 * Data adapter interface. Implements the observer pattern:\n * - connect() to start receiving data\n * - on('bar'|'tick'|'connectionChange', handler) to receive events\n * - disconnect() to stop, then connect() again to switch symbols/timeframes\n * - No separate subscribe/unsubscribe — reconnect is the intended pattern\n *\n * Strategy pattern for pluggable data sources.\n * Implementations handle the specifics of each data source (WebSocket, REST,\n * SSE, etc.) while the StreamManager orchestrates lifecycle and aggregation.\n *\n * Built-in: BinanceAdapter\n * Implement this for: custom exchange APIs, broker feeds, mock data\n */\nexport interface DataAdapter {\n readonly name: string;\n\n connect(config: DataAdapterConfig): void;\n disconnect(): void;\n getConnectionState(): ConnectionState;\n\n /**\n * Load historical bars. Called once on connect, before streaming starts.\n * Returns bars sorted by time ascending.\n */\n fetchHistory(symbol: string, timeframe: TimeFrame, limit?: number): Promise<OHLCBar[]>;\n\n on<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n off<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n\n dispose(): void;\n}\n\n// --- Stream Manager Config ---\n\nexport interface StreamConfig {\n adapter: DataAdapter;\n symbol: string;\n timeframe: TimeFrame;\n historyLimit?: number; // bars to load initially, default: 500\n autoScroll?: boolean; // scroll to end on new bar, default: true\n showCurrentPriceLine?: boolean; // default: true\n aggregateTicks?: boolean; // build bars from ticks, default: false\n reconnect?: ReconnectConfig;\n}\n\nexport interface ReconnectConfig {\n enabled: boolean; // default: true\n maxRetries: number; // default: Infinity\n baseDelay: number; // ms, default: 1000\n maxDelay: number; // ms, default: 30000\n backoffMultiplier: number; // default: 2\n}\n\nexport const DEFAULT_RECONNECT: ReconnectConfig = {\n enabled: true,\n maxRetries: Infinity,\n baseDelay: 1000,\n maxDelay: 30000,\n backoffMultiplier: 2,\n};\n\nexport const DEFAULT_STREAM_CONFIG: Partial<StreamConfig> = {\n historyLimit: 500,\n autoScroll: true,\n showCurrentPriceLine: true,\n aggregateTicks: false,\n};\n","export function clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nexport function inverseLerp(a: number, b: number, value: number): number {\n if (a === b) return 0;\n return (value - a) / (b - a);\n}\n\nexport function roundToStep(value: number, step: number): number {\n return Math.round(value / step) * step;\n}\n\nexport function niceNumber(value: number, round: boolean): number {\n const exp = Math.floor(Math.log10(value));\n const frac = value / Math.pow(10, exp);\n let nice: number;\n if (round) {\n if (frac < 1.5) nice = 1;\n else if (frac < 3) nice = 2;\n else if (frac < 7) nice = 5;\n else nice = 10;\n } else {\n if (frac <= 1) nice = 1;\n else if (frac <= 2) nice = 2;\n else if (frac <= 5) nice = 5;\n else nice = 10;\n }\n return nice * Math.pow(10, exp);\n}\n\nexport function computeTickStep(min: number, max: number, maxTicks: number): number {\n const range = niceNumber(max - min, false);\n return niceNumber(range / (maxTicks - 1), true);\n}\n","import type { OHLCBar, DataSeries } from '../types/ohlc.js';\n\n/**\n * Normalize bar timestamp to milliseconds.\n * Auto-detects: time > 1e12 is already ms, otherwise treats as seconds.\n */\nexport function normalizeBarTime(time: number): number {\n return time > 1e12 ? time : time * 1000;\n}\n\n/**\n * Normalize a bar's timestamp field to milliseconds.\n * Accepts either { time } (ms or s) or { t, o, h, l, c, v } wire format.\n */\nexport function normalizeBar(raw: Record<string, number>): OHLCBar {\n const time = normalizeBarTime(raw.time ?? raw.t ?? 0);\n return {\n time,\n open: raw.open ?? raw.o ?? 0,\n high: raw.high ?? raw.h ?? 0,\n low: raw.low ?? raw.l ?? 0,\n close: raw.close ?? raw.c ?? 0,\n volume: raw.volume ?? raw.v ?? 0,\n };\n}\n\nexport function sliceVisibleData(\n data: DataSeries,\n from: number,\n to: number,\n): DataSeries {\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length, to + 1);\n return data.slice(startIdx, endIdx);\n}\n\nexport function findBarIndex(data: DataSeries, timestamp: number): number {\n let lo = 0;\n let hi = data.length - 1;\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n if (data[mid].time < timestamp) lo = mid + 1;\n else if (data[mid].time > timestamp) hi = mid - 1;\n else return mid;\n }\n return lo;\n}\n\nexport function computePriceRange(\n data: DataSeries,\n from: number,\n to: number,\n padding = 0.05,\n): { min: number; max: number } {\n if (data.length === 0) return { min: 0, max: 1 };\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length - 1, to);\n let min = Infinity;\n let max = -Infinity;\n for (let i = startIdx; i <= endIdx; i++) {\n if (data[i].low < min) min = data[i].low;\n if (data[i].high > max) max = data[i].high;\n }\n if (min === Infinity) return { min: 0, max: 1 };\n const range = max - min || 1;\n return {\n min: min - range * padding,\n max: max + range * padding,\n };\n}\n\nexport function mergeBar(existing: OHLCBar, tick: { price: number; volume?: number; time: number }): OHLCBar {\n return {\n ...existing,\n high: Math.max(existing.high, tick.price),\n low: Math.min(existing.low, tick.price),\n close: tick.price,\n volume: existing.volume + (tick.volume ?? 0),\n time: tick.time,\n };\n}\n","export function hexToRgba(hex: string, alpha = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\nexport function withAlpha(color: string, alpha: number): string {\n if (color.startsWith('#')) {\n return hexToRgba(color, alpha);\n }\n const rgbaMatch = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (rgbaMatch) {\n return `rgba(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]}, ${alpha})`;\n }\n return color;\n}\n\nexport function lerpColor(colorA: string, colorB: string, t: number): string {\n const parseHex = (hex: string) => {\n hex = hex.replace('#', '');\n if (hex.length === 3) hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];\n return {\n r: parseInt(hex.slice(0, 2), 16),\n g: parseInt(hex.slice(2, 4), 16),\n b: parseInt(hex.slice(4, 6), 16),\n };\n };\n const a = parseHex(colorA);\n const b = parseHex(colorB);\n const r = Math.round(a.r + (b.r - a.r) * t);\n const g = Math.round(a.g + (b.g - a.g) * t);\n const bl = Math.round(a.b + (b.b - a.b) * t);\n return `rgb(${r},${g},${bl})`;\n}\n","import type { TimeFrame } from '../types/ohlc.js';\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\nexport const DARK_TERMINAL: Theme = {\n name: 'terminal',\n background: '#0E0E0E',\n text: '#C0C0C0',\n textSecondary: '#8A8A8A',\n grid: '#1A1A1A',\n crosshair: '#666666',\n candleUp: '#00FF87',\n candleDown: '#FF3B4D',\n candleUpWick: '#00FF87',\n candleDownWick: '#FF3B4D',\n lineColor: '#3D8BFD',\n areaTopColor: 'rgba(61, 139, 253, 0.3)',\n areaBottomColor: 'rgba(61, 139, 253, 0.0)',\n volumeUp: 'rgba(0, 255, 135, 0.2)',\n volumeDown: 'rgba(255, 59, 77, 0.2)',\n axisLine: '#1A1A1A',\n axisLabel: '#8A8A8A',\n axisLabelBackground: '#1A1A1A',\n font: {\n family: \"'Roboto Mono', 'JetBrains Mono', 'SF Mono', Consolas, monospace\",\n sizeSmall: 10,\n sizeMedium: 12,\n sizeLarge: 14,\n },\n};\n","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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"} |
+107
-69
@@ -66,7 +66,20 @@ //#region src/types/rendering.ts | ||
| //#region src/utils/data.ts | ||
| function d(e, t, n) { | ||
| function d(e) { | ||
| return e > 0xe8d4a51000 ? e : e * 1e3; | ||
| } | ||
| function f(e) { | ||
| return { | ||
| time: d(e.time ?? e.t ?? 0), | ||
| open: e.open ?? e.o ?? 0, | ||
| high: e.high ?? e.h ?? 0, | ||
| low: e.low ?? e.l ?? 0, | ||
| close: e.close ?? e.c ?? 0, | ||
| volume: e.volume ?? e.v ?? 0 | ||
| }; | ||
| } | ||
| function p(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) { | ||
| function m(e, t) { | ||
| let n = 0, r = e.length - 1; | ||
@@ -81,3 +94,3 @@ for (; n <= r;) { | ||
| } | ||
| function p(e, t, n, r = .05) { | ||
| function h(e, t, n, r = .05) { | ||
| if (e.length === 0) return { | ||
@@ -99,3 +112,3 @@ min: 0, | ||
| } | ||
| function m(e, t) { | ||
| function g(e, t) { | ||
| return { | ||
@@ -112,11 +125,11 @@ ...e, | ||
| //#region src/utils/color.ts | ||
| function h(e, t = 1) { | ||
| function _(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); | ||
| function ee(e, t) { | ||
| if (e.startsWith("#")) return _(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) { | ||
| function v(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]), { | ||
@@ -131,3 +144,3 @@ r: parseInt(e.slice(0, 2), 16), | ||
| //#region src/utils/time.ts | ||
| var v = { | ||
| var y = { | ||
| "1s": 1e3, | ||
@@ -160,7 +173,7 @@ "5s": 5e3, | ||
| }; | ||
| function y(e) { | ||
| return v[e]; | ||
| function te(e) { | ||
| return y[e]; | ||
| } | ||
| function b(e, t) { | ||
| let n = new Date(e), r = v[t]; | ||
| function ne(e, t) { | ||
| let n = new Date(e), r = y[t]; | ||
| return r >= 864e5 ? n.toLocaleDateString(void 0, { | ||
@@ -178,4 +191,4 @@ month: "short", | ||
| } | ||
| function x(e, t) { | ||
| let n = v[t]; | ||
| function re(e, t) { | ||
| let n = y[t]; | ||
| return Math.floor(e / n) * n; | ||
@@ -185,3 +198,3 @@ } | ||
| //#region src/utils/precision.ts | ||
| function ee(e, t = 2, n = "en-US") { | ||
| function ie(e, t = 2, n = "en-US") { | ||
| return e.toLocaleString(n, { | ||
@@ -192,6 +205,6 @@ minimumFractionDigits: t, | ||
| } | ||
| function S(e) { | ||
| function b(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) { | ||
| function x(e) { | ||
| let t = 0; | ||
@@ -206,3 +219,3 @@ for (let n of e) { | ||
| //#region src/constants/defaults.ts | ||
| var w = { | ||
| var S = { | ||
| autoScale: !0, | ||
@@ -218,3 +231,3 @@ rightMargin: 5, | ||
| crosshair: { mode: "magnet" } | ||
| }, T = [ | ||
| }, C = [ | ||
| "1s", | ||
@@ -236,3 +249,3 @@ "1m", | ||
| "1M" | ||
| ], E = [ | ||
| ], w = [ | ||
| "1m", | ||
@@ -251,3 +264,3 @@ "5m", | ||
| "12M" | ||
| ], D = [ | ||
| ], T = [ | ||
| "1m", | ||
@@ -262,3 +275,3 @@ "5m", | ||
| "1M" | ||
| ], O = [ | ||
| ], E = [ | ||
| "1m", | ||
@@ -271,3 +284,3 @@ "5m", | ||
| "1w" | ||
| ], k = 8, A = 2, j = 70, M = 30, N = 60, P = 120, F = { | ||
| ], D = 8, O = 2, k = 70, A = 30, j = 60, M = 120, N = { | ||
| family: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif", | ||
@@ -277,3 +290,3 @@ sizeSmall: 10, | ||
| sizeLarge: 14 | ||
| }, I = { | ||
| }, P = { | ||
| name: "dark", | ||
@@ -297,4 +310,4 @@ background: "#131722", | ||
| axisLabelBackground: "#2A2E39", | ||
| font: F | ||
| }, L = { | ||
| font: N | ||
| }, F = { | ||
| name: "light", | ||
@@ -318,4 +331,29 @@ background: "#FFFFFF", | ||
| axisLabelBackground: "#F0F3FA", | ||
| font: F | ||
| }, R = { | ||
| font: N | ||
| }, I = { | ||
| name: "terminal", | ||
| background: "#0E0E0E", | ||
| text: "#C0C0C0", | ||
| textSecondary: "#8A8A8A", | ||
| grid: "#1A1A1A", | ||
| crosshair: "#666666", | ||
| candleUp: "#00FF87", | ||
| candleDown: "#FF3B4D", | ||
| candleUpWick: "#00FF87", | ||
| candleDownWick: "#FF3B4D", | ||
| lineColor: "#3D8BFD", | ||
| areaTopColor: "rgba(61, 139, 253, 0.3)", | ||
| areaBottomColor: "rgba(61, 139, 253, 0.0)", | ||
| volumeUp: "rgba(0, 255, 135, 0.2)", | ||
| volumeDown: "rgba(255, 59, 77, 0.2)", | ||
| axisLine: "#1A1A1A", | ||
| axisLabel: "#8A8A8A", | ||
| axisLabelBackground: "#1A1A1A", | ||
| font: { | ||
| family: "'Roboto Mono', 'JetBrains Mono', 'SF Mono', Consolas, monospace", | ||
| sizeSmall: 10, | ||
| sizeMedium: 12, | ||
| sizeLarge: 14 | ||
| } | ||
| }, L = { | ||
| candlestick: "Candlestick", | ||
@@ -423,3 +461,3 @@ line: "Line", | ||
| numberGroupSeparator: "," | ||
| }, z = { | ||
| }, R = { | ||
| candlestick: "Nến", | ||
@@ -527,32 +565,32 @@ line: "Đường", | ||
| numberGroupSeparator: "." | ||
| }, B = new Map([["en", R], ["vi", z]]), V = "en", H = R; | ||
| function U(e) { | ||
| V = e, H = B.get(e) ?? R; | ||
| }, z = new Map([["en", L], ["vi", R]]), B = "en", V = L; | ||
| function H(e) { | ||
| B = e, V = z.get(e) ?? L; | ||
| } | ||
| function W() { | ||
| return V; | ||
| function U() { | ||
| return B; | ||
| } | ||
| function G(e) { | ||
| return H[e] ?? R[e] ?? e; | ||
| function W(e) { | ||
| return V[e] ?? L[e] ?? e; | ||
| } | ||
| function K(e, t) { | ||
| B.set(e, t); | ||
| function G(e, t) { | ||
| z.set(e, t); | ||
| } | ||
| function q(e) { | ||
| return B.get(e ?? V) ?? R; | ||
| function K(e) { | ||
| return z.get(e ?? B) ?? L; | ||
| } | ||
| 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 = ""; | ||
| function q(e, t = 2, n) { | ||
| let r = z.get(n ?? B) ?? L, 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 J(e) { | ||
| return q(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); | ||
| function Y(e, t) { | ||
| return e >= 1e9 ? q(e / 1e9, 2, t ?? B) + "B" : e >= 1e6 ? q(e / 1e6, 2, t ?? B) + "M" : e >= 1e3 ? q(e / 1e3, 2, t ?? B) + "K" : q(e, 0, t ?? B); | ||
| } | ||
| //#endregion | ||
| //#region src/market/presets.ts | ||
| var Z = { | ||
| var X = { | ||
| up: "#FF0000", | ||
@@ -564,3 +602,3 @@ down: "#0000FF", | ||
| reference: "#FFD700" | ||
| }, Q = [ | ||
| }, Z = [ | ||
| { | ||
@@ -596,3 +634,3 @@ name: "ATO", | ||
| } | ||
| ], $ = [ | ||
| ], Q = [ | ||
| { | ||
@@ -622,3 +660,3 @@ name: "Phiên 1", | ||
| } | ||
| ], te = { | ||
| ], ae = { | ||
| type: "stock", | ||
@@ -635,5 +673,5 @@ exchange: "HOSE", | ||
| }, | ||
| sessions: Q, | ||
| colorScheme: Z | ||
| }, ne = { | ||
| sessions: Z, | ||
| colorScheme: X | ||
| }, oe = { | ||
| type: "stock", | ||
@@ -650,5 +688,5 @@ exchange: "HNX", | ||
| }, | ||
| sessions: $, | ||
| colorScheme: Z | ||
| }, re = { | ||
| sessions: Q, | ||
| colorScheme: X | ||
| }, se = { | ||
| type: "stock", | ||
@@ -665,5 +703,5 @@ exchange: "UPCOM", | ||
| }, | ||
| sessions: $, | ||
| colorScheme: Z | ||
| }, ie = { | ||
| sessions: Q, | ||
| colorScheme: X | ||
| }, ce = { | ||
| type: "crypto", | ||
@@ -673,3 +711,3 @@ currency: "USDT", | ||
| priceLimits: { enabled: !1 } | ||
| }, ae = { | ||
| }, le = { | ||
| type: "stock", | ||
@@ -702,9 +740,9 @@ exchange: "NYSE", | ||
| }; | ||
| function oe(e) { | ||
| function $(e) { | ||
| return { | ||
| ...e, | ||
| candleUp: Z.up, | ||
| candleDown: Z.down, | ||
| candleUpWick: Z.up, | ||
| candleDownWick: Z.down, | ||
| candleUp: X.up, | ||
| candleDown: X.down, | ||
| candleUpWick: X.up, | ||
| candleDownWick: X.down, | ||
| volumeUp: "rgba(255, 0, 0, 0.3)", | ||
@@ -714,3 +752,3 @@ volumeDown: "rgba(0, 0, 255, 0.3)" | ||
| } | ||
| function se(e, t) { | ||
| function ue(e, t) { | ||
| if (!t.priceLimits?.enabled || !t.priceLimits.ceilingPercent) return null; | ||
@@ -724,3 +762,3 @@ let n = t.priceLimits.ceilingPercent / 100, r = (t.priceLimits.floorPercent ?? t.priceLimits.ceilingPercent) / 100; | ||
| } | ||
| function ce(e) { | ||
| function de(e) { | ||
| let t = /* @__PURE__ */ new Date(), n = `${String(t.getHours()).padStart(2, "0")}:${String(t.getMinutes()).padStart(2, "0")}`; | ||
@@ -731,4 +769,4 @@ for (let t of e) if (n >= t.startTime && n < t.endTime) return t; | ||
| //#endregion | ||
| export { I as DARK_THEME, A as DEFAULT_BAR_SPACING, k as DEFAULT_BAR_WIDTH, w as DEFAULT_CHART_OPTIONS, t as DEFAULT_DRAWING_STYLE, P as DEFAULT_PANEL_HEIGHT, r as DEFAULT_RECONNECT, i as DEFAULT_STREAM_CONFIG, O as DEFAULT_TIMEFRAME_FAVORITES, n as DEFAULT_TRADING_CONFIG, $ as HNX_SESSIONS, Q as HOSE_SESSIONS, L as LIGHT_THEME, e as LayerType, ie as MARKET_CRYPTO, ne as MARKET_HNX, te as MARKET_HOSE, ae as MARKET_NYSE, re as MARKET_UPCOM, N as MIN_PANEL_HEIGHT, j as PRICE_AXIS_WIDTH, T as TIMEFRAMES_CRYPTO, D as TIMEFRAMES_FOREX, E as TIMEFRAMES_STOCK, M as TIME_AXIS_HEIGHT, Z as VN_COLORS, x as alignToTimeframe, a as clamp, se as computePriceLimits, p as computePriceRange, u as computeTickStep, oe as createVNTheme, C as detectPrecision, R as en, f as findBarIndex, J as formatNumber, ee as formatPrice, b as formatTimestamp, Y as formatVND, S as formatVolume, X as formatVolumeLoc, ce as getCurrentSession, W as getLocale, q as getLocaleStrings, h as hexToRgba, s as inverseLerp, o as lerp, _ as lerpColor, m as mergeBar, l as niceNumber, K as registerLocale, c as roundToStep, U as setLocale, d as sliceVisibleData, G as t, y as timeframeToMs, z as vi, g as withAlpha }; | ||
| export { I as DARK_TERMINAL, P as DARK_THEME, O as DEFAULT_BAR_SPACING, D as DEFAULT_BAR_WIDTH, S as DEFAULT_CHART_OPTIONS, t as DEFAULT_DRAWING_STYLE, M as DEFAULT_PANEL_HEIGHT, r as DEFAULT_RECONNECT, i as DEFAULT_STREAM_CONFIG, E as DEFAULT_TIMEFRAME_FAVORITES, n as DEFAULT_TRADING_CONFIG, Q as HNX_SESSIONS, Z as HOSE_SESSIONS, F as LIGHT_THEME, e as LayerType, ce as MARKET_CRYPTO, oe as MARKET_HNX, ae as MARKET_HOSE, le as MARKET_NYSE, se as MARKET_UPCOM, j as MIN_PANEL_HEIGHT, k as PRICE_AXIS_WIDTH, C as TIMEFRAMES_CRYPTO, T as TIMEFRAMES_FOREX, w as TIMEFRAMES_STOCK, A as TIME_AXIS_HEIGHT, X as VN_COLORS, re as alignToTimeframe, a as clamp, ue as computePriceLimits, h as computePriceRange, u as computeTickStep, $ as createVNTheme, x as detectPrecision, L as en, m as findBarIndex, q as formatNumber, ie as formatPrice, ne as formatTimestamp, J as formatVND, b as formatVolume, Y as formatVolumeLoc, de as getCurrentSession, U as getLocale, K as getLocaleStrings, _ as hexToRgba, s as inverseLerp, o as lerp, v as lerpColor, g as mergeBar, l as niceNumber, f as normalizeBar, d as normalizeBarTime, G as registerLocale, c as roundToStep, H as setLocale, p as sliceVisibleData, W as t, te as timeframeToMs, R as vi, ee as withAlpha }; | ||
| //# sourceMappingURL=index.js.map |
@@ -1,1 +0,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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"} | ||
| {"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 * Data adapter interface. Implements the observer pattern:\n * - connect() to start receiving data\n * - on('bar'|'tick'|'connectionChange', handler) to receive events\n * - disconnect() to stop, then connect() again to switch symbols/timeframes\n * - No separate subscribe/unsubscribe — reconnect is the intended pattern\n *\n * Strategy pattern for pluggable data sources.\n * Implementations handle the specifics of each data source (WebSocket, REST,\n * SSE, etc.) while the StreamManager orchestrates lifecycle and aggregation.\n *\n * Built-in: BinanceAdapter\n * Implement this for: custom exchange APIs, broker feeds, mock data\n */\nexport interface DataAdapter {\n readonly name: string;\n\n connect(config: DataAdapterConfig): void;\n disconnect(): void;\n getConnectionState(): ConnectionState;\n\n /**\n * Load historical bars. Called once on connect, before streaming starts.\n * Returns bars sorted by time ascending.\n */\n fetchHistory(symbol: string, timeframe: TimeFrame, limit?: number): Promise<OHLCBar[]>;\n\n on<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n off<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n\n dispose(): void;\n}\n\n// --- Stream Manager Config ---\n\nexport interface StreamConfig {\n adapter: DataAdapter;\n symbol: string;\n timeframe: TimeFrame;\n historyLimit?: number; // bars to load initially, default: 500\n autoScroll?: boolean; // scroll to end on new bar, default: true\n showCurrentPriceLine?: boolean; // default: true\n aggregateTicks?: boolean; // build bars from ticks, default: false\n reconnect?: ReconnectConfig;\n}\n\nexport interface ReconnectConfig {\n enabled: boolean; // default: true\n maxRetries: number; // default: Infinity\n baseDelay: number; // ms, default: 1000\n maxDelay: number; // ms, default: 30000\n backoffMultiplier: number; // default: 2\n}\n\nexport const DEFAULT_RECONNECT: ReconnectConfig = {\n enabled: true,\n maxRetries: Infinity,\n baseDelay: 1000,\n maxDelay: 30000,\n backoffMultiplier: 2,\n};\n\nexport const DEFAULT_STREAM_CONFIG: Partial<StreamConfig> = {\n historyLimit: 500,\n autoScroll: true,\n showCurrentPriceLine: true,\n aggregateTicks: false,\n};\n","export function clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nexport function inverseLerp(a: number, b: number, value: number): number {\n if (a === b) return 0;\n return (value - a) / (b - a);\n}\n\nexport function roundToStep(value: number, step: number): number {\n return Math.round(value / step) * step;\n}\n\nexport function niceNumber(value: number, round: boolean): number {\n const exp = Math.floor(Math.log10(value));\n const frac = value / Math.pow(10, exp);\n let nice: number;\n if (round) {\n if (frac < 1.5) nice = 1;\n else if (frac < 3) nice = 2;\n else if (frac < 7) nice = 5;\n else nice = 10;\n } else {\n if (frac <= 1) nice = 1;\n else if (frac <= 2) nice = 2;\n else if (frac <= 5) nice = 5;\n else nice = 10;\n }\n return nice * Math.pow(10, exp);\n}\n\nexport function computeTickStep(min: number, max: number, maxTicks: number): number {\n const range = niceNumber(max - min, false);\n return niceNumber(range / (maxTicks - 1), true);\n}\n","import type { OHLCBar, DataSeries } from '../types/ohlc.js';\n\n/**\n * Normalize bar timestamp to milliseconds.\n * Auto-detects: time > 1e12 is already ms, otherwise treats as seconds.\n */\nexport function normalizeBarTime(time: number): number {\n return time > 1e12 ? time : time * 1000;\n}\n\n/**\n * Normalize a bar's timestamp field to milliseconds.\n * Accepts either { time } (ms or s) or { t, o, h, l, c, v } wire format.\n */\nexport function normalizeBar(raw: Record<string, number>): OHLCBar {\n const time = normalizeBarTime(raw.time ?? raw.t ?? 0);\n return {\n time,\n open: raw.open ?? raw.o ?? 0,\n high: raw.high ?? raw.h ?? 0,\n low: raw.low ?? raw.l ?? 0,\n close: raw.close ?? raw.c ?? 0,\n volume: raw.volume ?? raw.v ?? 0,\n };\n}\n\nexport function sliceVisibleData(\n data: DataSeries,\n from: number,\n to: number,\n): DataSeries {\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length, to + 1);\n return data.slice(startIdx, endIdx);\n}\n\nexport function findBarIndex(data: DataSeries, timestamp: number): number {\n let lo = 0;\n let hi = data.length - 1;\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n if (data[mid].time < timestamp) lo = mid + 1;\n else if (data[mid].time > timestamp) hi = mid - 1;\n else return mid;\n }\n return lo;\n}\n\nexport function computePriceRange(\n data: DataSeries,\n from: number,\n to: number,\n padding = 0.05,\n): { min: number; max: number } {\n if (data.length === 0) return { min: 0, max: 1 };\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length - 1, to);\n let min = Infinity;\n let max = -Infinity;\n for (let i = startIdx; i <= endIdx; i++) {\n if (data[i].low < min) min = data[i].low;\n if (data[i].high > max) max = data[i].high;\n }\n if (min === Infinity) return { min: 0, max: 1 };\n const range = max - min || 1;\n return {\n min: min - range * padding,\n max: max + range * padding,\n };\n}\n\nexport function mergeBar(existing: OHLCBar, tick: { price: number; volume?: number; time: number }): OHLCBar {\n return {\n ...existing,\n high: Math.max(existing.high, tick.price),\n low: Math.min(existing.low, tick.price),\n close: tick.price,\n volume: existing.volume + (tick.volume ?? 0),\n time: tick.time,\n };\n}\n","export function hexToRgba(hex: string, alpha = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\nexport function withAlpha(color: string, alpha: number): string {\n if (color.startsWith('#')) {\n return hexToRgba(color, alpha);\n }\n const rgbaMatch = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (rgbaMatch) {\n return `rgba(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]}, ${alpha})`;\n }\n return color;\n}\n\nexport function lerpColor(colorA: string, colorB: string, t: number): string {\n const parseHex = (hex: string) => {\n hex = hex.replace('#', '');\n if (hex.length === 3) hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];\n return {\n r: parseInt(hex.slice(0, 2), 16),\n g: parseInt(hex.slice(2, 4), 16),\n b: parseInt(hex.slice(4, 6), 16),\n };\n };\n const a = parseHex(colorA);\n const b = parseHex(colorB);\n const r = Math.round(a.r + (b.r - a.r) * t);\n const g = Math.round(a.g + (b.g - a.g) * t);\n const bl = Math.round(a.b + (b.b - a.b) * t);\n return `rgb(${r},${g},${bl})`;\n}\n","import type { TimeFrame } from '../types/ohlc.js';\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\nexport const DARK_TERMINAL: Theme = {\n name: 'terminal',\n background: '#0E0E0E',\n text: '#C0C0C0',\n textSecondary: '#8A8A8A',\n grid: '#1A1A1A',\n crosshair: '#666666',\n candleUp: '#00FF87',\n candleDown: '#FF3B4D',\n candleUpWick: '#00FF87',\n candleDownWick: '#FF3B4D',\n lineColor: '#3D8BFD',\n areaTopColor: 'rgba(61, 139, 253, 0.3)',\n areaBottomColor: 'rgba(61, 139, 253, 0.0)',\n volumeUp: 'rgba(0, 255, 135, 0.2)',\n volumeDown: 'rgba(255, 59, 77, 0.2)',\n axisLine: '#1A1A1A',\n axisLabel: '#8A8A8A',\n axisLabelBackground: '#1A1A1A',\n font: {\n family: \"'Roboto Mono', 'JetBrains Mono', 'SF Mono', Consolas, monospace\",\n sizeSmall: 10,\n sizeMedium: 12,\n sizeLarge: 14,\n },\n};\n","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,2 +0,2 @@ | ||
| import { OHLCBar } from './ohlc.js'; | ||
| import { OHLCBar, DataSeries } from './ohlc.js'; | ||
| import { Point } from './rendering.js'; | ||
@@ -25,2 +25,72 @@ import { IndicatorValue } from './indicator.js'; | ||
| } | ||
| export interface OrderModifyPayload { | ||
| orderId: string; | ||
| newPrice: number; | ||
| } | ||
| export interface OrderCancelPayload { | ||
| orderId: string; | ||
| } | ||
| export interface PositionModifyPayload { | ||
| positionId: string; | ||
| stopLoss?: number; | ||
| takeProfit?: number; | ||
| } | ||
| export interface PositionClosePayload { | ||
| positionId: string; | ||
| } | ||
| export interface OrderPlacePayload { | ||
| side: 'buy' | 'sell'; | ||
| type: 'market' | 'limit' | 'stop' | 'stopLimit'; | ||
| price: number; | ||
| stopPrice?: number; | ||
| quantity?: number; | ||
| } | ||
| export interface IndicatorChangePayload { | ||
| instanceId: string; | ||
| id: string; | ||
| } | ||
| export interface ThemeChangePayload { | ||
| theme: string; | ||
| } | ||
| export interface ResizePayload { | ||
| width: number; | ||
| height: number; | ||
| } | ||
| export interface ZoomChangePayload { | ||
| barWidth: number; | ||
| } | ||
| export interface PriceRangeChangePayload { | ||
| min: number; | ||
| max: number; | ||
| } | ||
| export interface DrawingCreatePayload { | ||
| id: string; | ||
| type: string; | ||
| } | ||
| export interface DrawingRemovePayload { | ||
| id: string; | ||
| } | ||
| export interface ChartEventMap { | ||
| crosshairMove: CrosshairMovePayload; | ||
| click: { | ||
| x: number; | ||
| y: number; | ||
| }; | ||
| barClick: BarClickPayload; | ||
| visibleRangeChange: VisibleRangeChangePayload; | ||
| priceRangeChange: PriceRangeChangePayload; | ||
| zoomChange: ZoomChangePayload; | ||
| dataUpdate: DataSeries; | ||
| indicatorAdd: IndicatorChangePayload; | ||
| indicatorRemove: IndicatorChangePayload; | ||
| themeChange: ThemeChangePayload; | ||
| resize: ResizePayload; | ||
| orderPlace: OrderPlacePayload; | ||
| orderModify: OrderModifyPayload; | ||
| orderCancel: OrderCancelPayload; | ||
| positionClose: PositionClosePayload; | ||
| positionModify: PositionModifyPayload; | ||
| drawingCreate: DrawingCreatePayload; | ||
| drawingRemove: DrawingRemovePayload; | ||
| } | ||
| export interface TauriBridgeOptions { | ||
@@ -27,0 +97,0 @@ enabled: boolean; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/types/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,MAAM,cAAc,GACtB,eAAe,GACf,OAAO,GACP,UAAU,GACV,oBAAoB,GACpB,kBAAkB,GAClB,YAAY,GACZ,YAAY,GACZ,cAAc,GACd,iBAAiB,GACjB,aAAa,GACb,QAAQ,GACR,YAAY,GACZ,aAAa,GACb,aAAa,GACb,eAAe,GACf,gBAAgB,GAChB,eAAe,GACf,eAAe,CAAC;AAEpB,MAAM,WAAW,UAAU,CAAC,CAAC,GAAG,OAAO;IACrC,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,CAAC,CAAC;CACZ;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CAClD;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,OAAO,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,iBAAiB,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC"} | ||
| {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/types/events.ts"],"names":[],"mappings":"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"} |
| export interface OHLCBar { | ||
| /** Unix timestamp in milliseconds */ | ||
| time: number; | ||
@@ -3,0 +4,0 @@ open: number; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"ohlc.d.ts","sourceRoot":"","sources":["../../src/types/ohlc.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,SAAS,GACjB,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GAC3B,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAC1C,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,GAC/C,IAAI,GAAG,IAAI,GAAG,IAAI,GAClB,IAAI,GAAG,IAAI,GACX,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC;AAE/B,MAAM,MAAM,UAAU,GAAG,OAAO,EAAE,CAAC"} | ||
| {"version":3,"file":"ohlc.d.ts","sourceRoot":"","sources":["../../src/types/ohlc.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,SAAS,GACjB,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GAC3B,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAC1C,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,GAC/C,IAAI,GAAG,IAAI,GAAG,IAAI,GAClB,IAAI,GAAG,IAAI,GACX,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC;AAE/B,MAAM,MAAM,UAAU,GAAG,OAAO,EAAE,CAAC"} |
@@ -38,4 +38,9 @@ import { OHLCBar, TimeFrame } from './ohlc.js'; | ||
| /** | ||
| * DataAdapter interface — Strategy pattern for pluggable data sources. | ||
| * Data adapter interface. Implements the observer pattern: | ||
| * - connect() to start receiving data | ||
| * - on('bar'|'tick'|'connectionChange', handler) to receive events | ||
| * - disconnect() to stop, then connect() again to switch symbols/timeframes | ||
| * - No separate subscribe/unsubscribe — reconnect is the intended pattern | ||
| * | ||
| * Strategy pattern for pluggable data sources. | ||
| * Implementations handle the specifics of each data source (WebSocket, REST, | ||
@@ -42,0 +47,0 @@ * SSE, etc.) while the StreamManager orchestrates lifecycle and aggregation. |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../../src/types/realtime.ts"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../../src/types/realtime.ts"],"names":[],"mappings":"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"} |
+10
-0
| import { OHLCBar, DataSeries } from '../types/ohlc.js'; | ||
| /** | ||
| * Normalize bar timestamp to milliseconds. | ||
| * Auto-detects: time > 1e12 is already ms, otherwise treats as seconds. | ||
| */ | ||
| export declare function normalizeBarTime(time: number): number; | ||
| /** | ||
| * Normalize a bar's timestamp field to milliseconds. | ||
| * Accepts either { time } (ms or s) or { t, o, h, l, c, v } wire format. | ||
| */ | ||
| export declare function normalizeBar(raw: Record<string, number>): OHLCBar; | ||
| export declare function sliceVisibleData(data: DataSeries, from: number, to: number): DataSeries; | ||
@@ -3,0 +13,0 @@ export declare function findBarIndex(data: DataSeries, timestamp: number): number; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../src/utils/data.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE5D,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACT,UAAU,CAIZ;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAUxE;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,OAAO,SAAO,GACb;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAgB9B;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAS3G"} | ||
| {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../src/utils/data.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE5D;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAUjE;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACT,UAAU,CAIZ;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAUxE;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,OAAO,SAAO,GACb;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAgB9B;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAS3G"} |
+1
-1
| { | ||
| "name": "@tradecanvas/commons", | ||
| "version": "0.4.0", | ||
| "version": "0.5.0", | ||
| "type": "module", | ||
@@ -5,0 +5,0 @@ "description": "Shared types and utilities for @tradecanvas/chart", |
184969
6.17%1786
7.85%