@tradecanvas/commons 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +70 -62
- package/dist/index.js.map +1 -1
- package/dist/types/finance.d.ts +77 -0
- package/dist/types/finance.d.ts.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/color.d.ts +1 -0
- package/dist/utils/color.d.ts.map +1 -1
- package/package.json +13 -6
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 TradeCanvas Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=function(e){return e[e.Background=0]=`Background`,e[e.Main=1]=`Main`,e[e.Panel=2]=`Panel`,e[e.Overlay=3]=`Overlay`,e[e.UI=4]=`UI`,e}({}),t={color:`#2196F3`,lineWidth:1,lineStyle:`solid`,fillColor:`rgba(33, 150, 243, 0.1)`,fillOpacity:.1,fontSize:12},n={enabled:!0,orderColors:{buy:`#26A69A`,sell:`#EF5350`},positionColors:{profit:`#26A69A`,loss:`#EF5350`,entry:`#2196F3`},depthOverlay:{enabled:!1,bidColor:`rgba(38,166,154,0.15)`,askColor:`rgba(239,83,80,0.15)`,maxWidth:100},contextMenu:{enabled:!0},pricePrecision:2,dragThreshold:3},r={enabled:!0,maxRetries:1/0,baseDelay:1e3,maxDelay:3e4,backoffMultiplier:2},i={historyLimit:500,autoScroll:!0,showCurrentPriceLine:!0,aggregateTicks:!1};function a(e,t,n){return Math.max(t,Math.min(n,e))}function o(e,t,n){return e+(t-e)*n}function s(e,t,n){return e===t?0:(n-e)/(t-e)}function c(e,t){return Math.round(e/t)*t}function l(e,t){let n=Math.floor(Math.log10(e)),r=e/10**n,i;return i=t?r<1.5?1:r<3?2:r<7?5:10:r<=1?1:r<=2?2:r<=5?5:10,i*10**n}function u(e,t,n){return l(l(t-e,!1)/(n-1),!0)}function d(e,t,n){let r=Math.max(0,t),i=Math.min(e.length,n+1);return e.slice(r,i)}function f(e,t){let n=0,r=e.length-1;for(;n<=r;){let i=n+r>>>1;if(e[i].time<t)n=i+1;else if(e[i].time>t)r=i-1;else return i}return n}function p(e,t,n,r=.05){if(e.length===0)return{min:0,max:1};let i=Math.max(0,t),a=Math.min(e.length-1,n),o=1/0,s=-1/0;for(let t=i;t<=a;t++)e[t].low<o&&(o=e[t].low),e[t].high>s&&(s=e[t].high);if(o===1/0)return{min:0,max:1};let c=s-o||1;return{min:o-c*r,max:s+c*r}}function m(e,t){return{...e,high:Math.max(e.high,t.price),low:Math.min(e.low,t.price),close:t.price,volume:e.volume+(t.volume??0),time:t.time}}function h(e,t=1){return`rgba(${parseInt(e.slice(1,3),16)}, ${parseInt(e.slice(3,5),16)}, ${parseInt(e.slice(5,7),16)}, ${t})`}function ee(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}var g={"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 _(e){return g[e]}function v(e,t){let n=new Date(e),r=g[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 y(e,t){let n=g[t];return Math.floor(e/n)*n}function b(e,t=2){return e.toFixed(t)}function x(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 S(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 C={autoScale:!0,rightMargin:5,minBarSpacing:2,maxBarSpacing:30,grid:{visible:!0,hLineStyle:`solid`,vLineStyle:`solid`},crosshair:{mode:`magnet`}},w=[`1s`,`1m`,`3m`,`5m`,`15m`,`30m`,`1h`,`2h`,`4h`,`6h`,`8h`,`12h`,`1d`,`3d`,`1w`,`1M`],T=[`1m`,`5m`,`15m`,`30m`,`1h`,`2h`,`4h`,`1d`,`1w`,`1M`,`3M`,`6M`,`12M`],E=[`1m`,`5m`,`15m`,`30m`,`1h`,`4h`,`1d`,`1w`,`1M`],D=[`1m`,`5m`,`15m`,`1h`,`4h`,`1d`,`1w`],O=8,k=2,A=70,j=30,M=60,N=120,P={family:`-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`,sizeSmall:10,sizeMedium:12,sizeLarge:14},F={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:P},I={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:P},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`}],$={type:`stock`,exchange:`HOSE`,currency:`VND`,pricePrecision:2,volumeUnit:10,priceStep:.05,priceLimits:{enabled:!0,ceilingPercent:7,floorPercent:7},sessions:Z,colorScheme:X},te={type:`stock`,exchange:`HNX`,currency:`VND`,pricePrecision:1,volumeUnit:100,priceStep:.1,priceLimits:{enabled:!0,ceilingPercent:10,floorPercent:10},sessions:Q,colorScheme:X},ne={type:`stock`,exchange:`UPCOM`,currency:`VND`,pricePrecision:1,volumeUnit:100,priceStep:.1,priceLimits:{enabled:!0,ceilingPercent:15,floorPercent:15},sessions:Q,colorScheme:X},re={type:`crypto`,currency:`USDT`,pricePrecision:2,priceLimits:{enabled:!1}},ie={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 ae(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 oe(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 se(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=F,exports.DEFAULT_BAR_SPACING=k,exports.DEFAULT_BAR_WIDTH=O,exports.DEFAULT_CHART_OPTIONS=C,exports.DEFAULT_DRAWING_STYLE=t,exports.DEFAULT_PANEL_HEIGHT=N,exports.DEFAULT_RECONNECT=r,exports.DEFAULT_STREAM_CONFIG=i,exports.DEFAULT_TIMEFRAME_FAVORITES=D,exports.DEFAULT_TRADING_CONFIG=n,exports.HNX_SESSIONS=Q,exports.HOSE_SESSIONS=Z,exports.LIGHT_THEME=I,exports.LayerType=e,exports.MARKET_CRYPTO=re,exports.MARKET_HNX=te,exports.MARKET_HOSE=$,exports.MARKET_NYSE=ie,exports.MARKET_UPCOM=ne,exports.MIN_PANEL_HEIGHT=M,exports.PRICE_AXIS_WIDTH=A,exports.TIMEFRAMES_CRYPTO=w,exports.TIMEFRAMES_FOREX=E,exports.TIMEFRAMES_STOCK=T,exports.TIME_AXIS_HEIGHT=j,exports.VN_COLORS=X,exports.alignToTimeframe=y,exports.clamp=a,exports.computePriceLimits=oe,exports.computePriceRange=p,exports.computeTickStep=u,exports.createVNTheme=ae,exports.detectPrecision=S,exports.en=L,exports.findBarIndex=f,exports.formatNumber=q,exports.formatPrice=b,exports.formatTimestamp=v,exports.formatVND=J,exports.formatVolume=x,exports.formatVolumeLoc=Y,exports.getCurrentSession=se,exports.getLocale=U,exports.getLocaleStrings=K,exports.hexToRgba=h,exports.inverseLerp=s,exports.lerp=o,exports.mergeBar=m,exports.niceNumber=l,exports.registerLocale=G,exports.roundToStep=c,exports.setLocale=H,exports.sliceVisibleData=d,exports.t=W,exports.timeframeToMs=_,exports.vi=R,exports.withAlpha=ee;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=function(e){return e[e.Background=0]=`Background`,e[e.Main=1]=`Main`,e[e.Panel=2]=`Panel`,e[e.Overlay=3]=`Overlay`,e[e.UI=4]=`UI`,e}({}),t={color:`#2196F3`,lineWidth:1,lineStyle:`solid`,fillColor:`rgba(33, 150, 243, 0.1)`,fillOpacity:.1,fontSize:12},n={enabled:!0,orderColors:{buy:`#26A69A`,sell:`#EF5350`},positionColors:{profit:`#26A69A`,loss:`#EF5350`,entry:`#2196F3`},depthOverlay:{enabled:!1,bidColor:`rgba(38,166,154,0.15)`,askColor:`rgba(239,83,80,0.15)`,maxWidth:100},contextMenu:{enabled:!0},pricePrecision:2,dragThreshold:3},r={enabled:!0,maxRetries:1/0,baseDelay:1e3,maxDelay:3e4,backoffMultiplier:2},i={historyLimit:500,autoScroll:!0,showCurrentPriceLine:!0,aggregateTicks:!1};function a(e,t,n){return Math.max(t,Math.min(n,e))}function o(e,t,n){return e+(t-e)*n}function s(e,t,n){return e===t?0:(n-e)/(t-e)}function c(e,t){return Math.round(e/t)*t}function l(e,t){let n=Math.floor(Math.log10(e)),r=e/10**n,i;return i=t?r<1.5?1:r<3?2:r<7?5:10:r<=1?1:r<=2?2:r<=5?5:10,i*10**n}function u(e,t,n){return l(l(t-e,!1)/(n-1),!0)}function d(e,t,n){let r=Math.max(0,t),i=Math.min(e.length,n+1);return e.slice(r,i)}function f(e,t){let n=0,r=e.length-1;for(;n<=r;){let i=n+r>>>1;if(e[i].time<t)n=i+1;else if(e[i].time>t)r=i-1;else return i}return n}function p(e,t,n,r=.05){if(e.length===0)return{min:0,max:1};let i=Math.max(0,t),a=Math.min(e.length-1,n),o=1/0,s=-1/0;for(let t=i;t<=a;t++)e[t].low<o&&(o=e[t].low),e[t].high>s&&(s=e[t].high);if(o===1/0)return{min:0,max:1};let c=s-o||1;return{min:o-c*r,max:s+c*r}}function m(e,t){return{...e,high:Math.max(e.high,t.price),low:Math.min(e.low,t.price),close:t.price,volume:e.volume+(t.volume??0),time:t.time}}function h(e,t=1){return`rgba(${parseInt(e.slice(1,3),16)}, ${parseInt(e.slice(3,5),16)}, ${parseInt(e.slice(5,7),16)}, ${t})`}function g(e,t){if(e.startsWith(`#`))return h(e,t);let n=e.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);return n?`rgba(${n[1]}, ${n[2]}, ${n[3]}, ${t})`:e}function _(e,t,n){let r=e=>(e=e.replace(`#`,``),e.length===3&&(e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]),{r:parseInt(e.slice(0,2),16),g:parseInt(e.slice(2,4),16),b:parseInt(e.slice(4,6),16)}),i=r(e),a=r(t);return`rgb(${Math.round(i.r+(a.r-i.r)*n)},${Math.round(i.g+(a.g-i.g)*n)},${Math.round(i.b+(a.b-i.b)*n)})`}var v={"1s":1e3,"5s":5e3,"15s":15e3,"30s":3e4,"1m":6e4,"3m":18e4,"5m":3e5,"15m":9e5,"30m":18e5,"45m":27e5,"1h":36e5,"2h":72e5,"3h":108e5,"4h":144e5,"6h":216e5,"8h":288e5,"12h":432e5,"1d":864e5,"2d":1728e5,"3d":2592e5,"1w":6048e5,"2w":12096e5,"1M":2592e6,"3M":7776e6,"6M":15552e6,"12M":31536e6};function y(e){return v[e]}function b(e,t){let n=new Date(e),r=v[t];return r>=864e5?n.toLocaleDateString(void 0,{month:`short`,day:`numeric`}):r>=36e5?n.toLocaleTimeString(void 0,{hour:`2-digit`,minute:`2-digit`}):n.toLocaleTimeString(void 0,{hour:`2-digit`,minute:`2-digit`,second:`2-digit`})}function x(e,t){let n=v[t];return Math.floor(e/n)*n}function ee(e,t=2){return e.toFixed(t)}function S(e){return e>=1e9?(e/1e9).toFixed(2)+`B`:e>=1e6?(e/1e6).toFixed(2)+`M`:e>=1e3?(e/1e3).toFixed(2)+`K`:e.toFixed(0)}function C(e){let t=0;for(let n of e){let e=n.toString(),r=e.indexOf(`.`);r>=0&&(t=Math.max(t,e.length-r-1))}return Math.min(t,8)}var w={autoScale:!0,rightMargin:5,minBarSpacing:2,maxBarSpacing:30,grid:{visible:!0,hLineStyle:`solid`,vLineStyle:`solid`},crosshair:{mode:`magnet`}},T=[`1s`,`1m`,`3m`,`5m`,`15m`,`30m`,`1h`,`2h`,`4h`,`6h`,`8h`,`12h`,`1d`,`3d`,`1w`,`1M`],E=[`1m`,`5m`,`15m`,`30m`,`1h`,`2h`,`4h`,`1d`,`1w`,`1M`,`3M`,`6M`,`12M`],D=[`1m`,`5m`,`15m`,`30m`,`1h`,`4h`,`1d`,`1w`,`1M`],O=[`1m`,`5m`,`15m`,`1h`,`4h`,`1d`,`1w`],k=8,A=2,j=70,M=30,N=60,P=120,F={family:`-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`,sizeSmall:10,sizeMedium:12,sizeLarge:14},I={name:`dark`,background:`#131722`,text:`#D1D4DC`,textSecondary:`#787B86`,grid:`#1E222D`,crosshair:`#9598A1`,candleUp:`#26A69A`,candleDown:`#EF5350`,candleUpWick:`#26A69A`,candleDownWick:`#EF5350`,lineColor:`#2196F3`,areaTopColor:`rgba(33, 150, 243, 0.4)`,areaBottomColor:`rgba(33, 150, 243, 0.0)`,volumeUp:`rgba(38, 166, 154, 0.3)`,volumeDown:`rgba(239, 83, 80, 0.3)`,axisLine:`#2A2E39`,axisLabel:`#D1D4DC`,axisLabelBackground:`#2A2E39`,font:F},L={name:`light`,background:`#FFFFFF`,text:`#131722`,textSecondary:`#787B86`,grid:`#F0F3FA`,crosshair:`#9598A1`,candleUp:`#26A69A`,candleDown:`#EF5350`,candleUpWick:`#26A69A`,candleDownWick:`#EF5350`,lineColor:`#2196F3`,areaTopColor:`rgba(33, 150, 243, 0.4)`,areaBottomColor:`rgba(33, 150, 243, 0.0)`,volumeUp:`rgba(38, 166, 154, 0.3)`,volumeDown:`rgba(239, 83, 80, 0.3)`,axisLine:`#E0E3EB`,axisLabel:`#131722`,axisLabelBackground:`#F0F3FA`,font:F},R={candlestick:`Candlestick`,line:`Line`,area:`Area`,bar:`OHLC Bar`,price:`Price`,volume:`Volume`,time:`Time`,open:`Open`,high:`High`,low:`Low`,close:`Close`,sma:`SMA`,ema:`EMA`,bollingerBands:`Bollinger Bands`,vwap:`VWAP`,ichimoku:`Ichimoku Cloud`,parabolicSAR:`Parabolic SAR`,supertrend:`Supertrend`,keltnerChannel:`Keltner Channel`,donchianChannel:`Donchian Channel`,rsi:`RSI`,macd:`MACD`,stochastic:`Stochastic`,atr:`ATR`,adx:`ADX`,obv:`OBV`,williamsR:`Williams %R`,cci:`CCI`,mfi:`MFI`,aroon:`Aroon`,roc:`ROC`,tsi:`TSI`,cmf:`CMF`,stddev:`Std Dev`,volumeProfile:`Volume Profile`,accumulationDistribution:`A/D Line`,vroc:`VROC`,trendLine:`Trend Line`,horizontalLine:`Horizontal Line`,verticalLine:`Vertical Line`,ray:`Ray`,extendedLine:`Extended Line`,parallelChannel:`Parallel Channel`,regressionChannel:`Regression Channel`,fibRetracement:`Fibonacci Retracement`,fibExtension:`Fibonacci Extension`,rectangle:`Rectangle`,ellipse:`Ellipse`,triangle:`Triangle`,pitchfork:`Andrews' Pitchfork`,elliottWave:`Elliott Wave`,priceRange:`Price Range`,dateRange:`Date Range`,measure:`Measure`,textTool:`Text`,arrow:`Arrow`,clearAll:`Clear All`,buy:`Buy`,sell:`Sell`,buyLimit:`Buy Limit`,sellLimit:`Sell Limit`,buyStop:`Buy Stop`,sellStop:`Sell Stop`,stopLoss:`Stop Loss`,takeProfit:`Take Profit`,market:`Market`,limit:`Limit`,stop:`Stop`,cancel:`Cancel`,modify:`Modify`,quantity:`Qty`,pnl:`P&L`,activeOrders:`Active Orders`,positions:`Positions`,noOrders:`No active orders`,noPositions:`No open positions`,placeOrder:`Place Order`,rightClickToTrade:`Right-click chart to place orders`,ceiling:`Ceiling`,floor:`Floor`,reference:`Reference`,session:`Session`,preOpen:`Pre-Open`,continuous:`Continuous`,preClose:`Pre-Close`,closed:`Closed`,settings:`Settings`,theme:`Theme`,darkTheme:`Dark`,lightTheme:`Light`,tools:`Tools`,indicators:`Indicators`,overlays:`Overlays`,panels:`Panels`,orders:`Orders`,autoScale:`Auto Scale`,crosshair:`Crosshair`,grid:`Grid`,loading:`Loading...`,error:`Error`,numberDecimalSeparator:`.`,numberGroupSeparator:`,`},z={candlestick:`Nến`,line:`Đường`,area:`Vùng`,bar:`Thanh OHLC`,price:`Giá`,volume:`Khối lượng`,time:`Thời gian`,open:`Mở`,high:`Cao`,low:`Thấp`,close:`Đóng`,sma:`SMA`,ema:`EMA`,bollingerBands:`Dải Bollinger`,vwap:`VWAP`,ichimoku:`Mây Ichimoku`,parabolicSAR:`Parabolic SAR`,supertrend:`Supertrend`,keltnerChannel:`Kênh Keltner`,donchianChannel:`Kênh Donchian`,rsi:`RSI`,macd:`MACD`,stochastic:`Stochastic`,atr:`ATR`,adx:`ADX`,obv:`OBV`,williamsR:`Williams %R`,cci:`CCI`,mfi:`MFI`,aroon:`Aroon`,roc:`ROC`,tsi:`TSI`,cmf:`CMF`,stddev:`Độ lệch chuẩn`,volumeProfile:`Phân bổ KL`,accumulationDistribution:`Tích lũy/Phân phối`,vroc:`VROC`,trendLine:`Đường xu hướng`,horizontalLine:`Đường ngang`,verticalLine:`Đường dọc`,ray:`Tia`,extendedLine:`Đường kéo dài`,parallelChannel:`Kênh song song`,regressionChannel:`Kênh hồi quy`,fibRetracement:`Fibonacci thoái lui`,fibExtension:`Fibonacci mở rộng`,rectangle:`Hình chữ nhật`,ellipse:`Hình elip`,triangle:`Tam giác`,pitchfork:`Chĩa ba Andrews`,elliottWave:`Sóng Elliott`,priceRange:`Khoảng giá`,dateRange:`Khoảng thời gian`,measure:`Đo lường`,textTool:`Chữ`,arrow:`Mũi tên`,clearAll:`Xóa tất cả`,buy:`Mua`,sell:`Bán`,buyLimit:`Mua giới hạn`,sellLimit:`Bán giới hạn`,buyStop:`Mua chặn`,sellStop:`Bán chặn`,stopLoss:`Cắt lỗ`,takeProfit:`Chốt lời`,market:`Thị trường`,limit:`Giới hạn`,stop:`Dừng`,cancel:`Hủy`,modify:`Sửa`,quantity:`KL`,pnl:`Lãi/Lỗ`,activeOrders:`Lệnh chờ`,positions:`Vị thế`,noOrders:`Không có lệnh chờ`,noPositions:`Không có vị thế mở`,placeOrder:`Đặt lệnh`,rightClickToTrade:`Nhấp chuột phải để đặt lệnh`,ceiling:`Trần`,floor:`Sàn`,reference:`Tham chiếu`,session:`Phiên`,preOpen:`Trước giờ mở`,continuous:`Liên tục`,preClose:`Trước giờ đóng`,closed:`Đóng cửa`,settings:`Cài đặt`,theme:`Giao diện`,darkTheme:`Tối`,lightTheme:`Sáng`,tools:`Công cụ`,indicators:`Chỉ báo`,overlays:`Phủ lên`,panels:`Bảng`,orders:`Lệnh`,autoScale:`Tự co giãn`,crosshair:`Chữ thập`,grid:`Lưới`,loading:`Đang tải...`,error:`Lỗi`,numberDecimalSeparator:`,`,numberGroupSeparator:`.`},B=new Map([[`en`,R],[`vi`,z]]),V=`en`,H=R;function U(e){V=e,H=B.get(e)??R}function W(){return V}function G(e){return H[e]??R[e]??e}function K(e,t){B.set(e,t)}function q(e){return B.get(e??V)??R}function J(e,t=2,n){let r=B.get(n??V)??R,i=r.numberDecimalSeparator,a=r.numberGroupSeparator,[o,s]=e.toFixed(t).split(`.`),c=o.startsWith(`-`),l=c?o.slice(1):o,u=``;for(let e=l.length-1,t=0;e>=0;e--,t++)t>0&&t%3==0&&(u=a+u),u=l[e]+u;return c&&(u=`-`+u),s?u+i+s:u}function Y(e){return J(e,0,`vi`)}function X(e,t){return e>=1e9?J(e/1e9,2,t??V)+`B`:e>=1e6?J(e/1e6,2,t??V)+`M`:e>=1e3?J(e/1e3,2,t??V)+`K`:J(e,0,t??V)}var Z={up:`#FF0000`,down:`#0000FF`,unchanged:`#FFD700`,ceiling:`#FF00FF`,floor:`#00FFFF`,reference:`#FFD700`},Q=[{name:`ATO`,startTime:`09:00`,endTime:`09:15`,type:`preOpen`},{name:`Phiên 1`,startTime:`09:15`,endTime:`11:30`,type:`continuous`},{name:`Nghỉ trưa`,startTime:`11:30`,endTime:`13:00`,type:`closed`},{name:`Phiên 2`,startTime:`13:00`,endTime:`14:30`,type:`continuous`},{name:`ATC`,startTime:`14:30`,endTime:`14:45`,type:`preClose`}],$=[{name:`Phiên 1`,startTime:`09:00`,endTime:`11:30`,type:`continuous`},{name:`Nghỉ trưa`,startTime:`11:30`,endTime:`13:00`,type:`closed`},{name:`Phiên 2`,startTime:`13:00`,endTime:`14:30`,type:`continuous`},{name:`ATC`,startTime:`14:30`,endTime:`14:45`,type:`preClose`}],te={type:`stock`,exchange:`HOSE`,currency:`VND`,pricePrecision:2,volumeUnit:10,priceStep:.05,priceLimits:{enabled:!0,ceilingPercent:7,floorPercent:7},sessions:Q,colorScheme:Z},ne={type:`stock`,exchange:`HNX`,currency:`VND`,pricePrecision:1,volumeUnit:100,priceStep:.1,priceLimits:{enabled:!0,ceilingPercent:10,floorPercent:10},sessions:$,colorScheme:Z},re={type:`stock`,exchange:`UPCOM`,currency:`VND`,pricePrecision:1,volumeUnit:100,priceStep:.1,priceLimits:{enabled:!0,ceilingPercent:15,floorPercent:15},sessions:$,colorScheme:Z},ie={type:`crypto`,currency:`USDT`,pricePrecision:2,priceLimits:{enabled:!1}},ae={type:`stock`,exchange:`NYSE`,currency:`USD`,pricePrecision:2,priceStep:.01,priceLimits:{enabled:!1},sessions:[{name:`Pre-Market`,startTime:`04:00`,endTime:`09:30`,type:`preOpen`},{name:`Regular`,startTime:`09:30`,endTime:`16:00`,type:`continuous`},{name:`After-Hours`,startTime:`16:00`,endTime:`20:00`,type:`preClose`}]};function oe(e){return{...e,candleUp:Z.up,candleDown:Z.down,candleUpWick:Z.up,candleDownWick:Z.down,volumeUp:`rgba(255, 0, 0, 0.3)`,volumeDown:`rgba(0, 0, 255, 0.3)`}}function se(e,t){if(!t.priceLimits?.enabled||!t.priceLimits.ceilingPercent)return null;let n=t.priceLimits.ceilingPercent/100,r=(t.priceLimits.floorPercent??t.priceLimits.ceilingPercent)/100;return{ceiling:e*(1+n),floor:e*(1-r),reference:e}}function ce(e){let t=new Date,n=`${String(t.getHours()).padStart(2,`0`)}:${String(t.getMinutes()).padStart(2,`0`)}`;for(let t of e)if(n>=t.startTime&&n<t.endTime)return t;return null}exports.DARK_THEME=I,exports.DEFAULT_BAR_SPACING=A,exports.DEFAULT_BAR_WIDTH=k,exports.DEFAULT_CHART_OPTIONS=w,exports.DEFAULT_DRAWING_STYLE=t,exports.DEFAULT_PANEL_HEIGHT=P,exports.DEFAULT_RECONNECT=r,exports.DEFAULT_STREAM_CONFIG=i,exports.DEFAULT_TIMEFRAME_FAVORITES=O,exports.DEFAULT_TRADING_CONFIG=n,exports.HNX_SESSIONS=$,exports.HOSE_SESSIONS=Q,exports.LIGHT_THEME=L,exports.LayerType=e,exports.MARKET_CRYPTO=ie,exports.MARKET_HNX=ne,exports.MARKET_HOSE=te,exports.MARKET_NYSE=ae,exports.MARKET_UPCOM=re,exports.MIN_PANEL_HEIGHT=N,exports.PRICE_AXIS_WIDTH=j,exports.TIMEFRAMES_CRYPTO=T,exports.TIMEFRAMES_FOREX=D,exports.TIMEFRAMES_STOCK=E,exports.TIME_AXIS_HEIGHT=M,exports.VN_COLORS=Z,exports.alignToTimeframe=x,exports.clamp=a,exports.computePriceLimits=se,exports.computePriceRange=p,exports.computeTickStep=u,exports.createVNTheme=oe,exports.detectPrecision=C,exports.en=R,exports.findBarIndex=f,exports.formatNumber=J,exports.formatPrice=ee,exports.formatTimestamp=b,exports.formatVND=Y,exports.formatVolume=S,exports.formatVolumeLoc=X,exports.getCurrentSession=ce,exports.getLocale=W,exports.getLocaleStrings=q,exports.hexToRgba=h,exports.inverseLerp=s,exports.lerp=o,exports.lerpColor=_,exports.mergeBar=m,exports.niceNumber=l,exports.registerLocale=K,exports.roundToStep=c,exports.setLocale=U,exports.sliceVisibleData=d,exports.t=G,exports.timeframeToMs=y,exports.vi=z,exports.withAlpha=g;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/types/rendering.ts","../src/types/drawing.ts","../src/types/trading.ts","../src/types/realtime.ts","../src/utils/math.ts","../src/utils/data.ts","../src/utils/color.ts","../src/utils/time.ts","../src/utils/precision.ts","../src/constants/defaults.ts","../src/constants/themes.ts","../src/i18n/en.ts","../src/i18n/vi.ts","../src/i18n/index.ts","../src/market/presets.ts"],"sourcesContent":["export interface Point {\n x: number;\n y: number;\n}\n\nexport interface Size {\n width: number;\n height: number;\n}\n\nexport interface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface ViewportState {\n visibleRange: { from: number; to: number };\n priceRange: { min: number; max: number };\n barWidth: number;\n barSpacing: number;\n offset: number;\n chartRect: Rect;\n logScale?: boolean;\n}\n\nexport enum LayerType {\n Background = 0,\n Main = 1,\n Panel = 2,\n Overlay = 3,\n UI = 4,\n}\n","import type { Point, ViewportState } from './rendering.js';\n\nexport type DrawingToolType =\n | 'trendLine' | 'horizontalLine' | 'verticalLine' | 'ray' | 'extendedLine'\n | 'parallelChannel' | 'regressionChannel'\n | 'fibRetracement' | 'fibExtension'\n | 'rectangle' | 'ellipse' | 'triangle'\n | 'pitchfork' | 'elliottWave'\n | 'priceRange' | 'dateRange' | 'measure'\n | 'text' | 'arrow'\n | 'gannFan' | 'gannBox'\n | 'anchoredVWAP'\n | 'volumeProfileRange';\n\nexport interface AnchorPoint {\n time: number;\n price: number;\n}\n\nexport interface DrawingStyle {\n color: string;\n lineWidth: number;\n lineStyle: 'solid' | 'dashed' | 'dotted';\n fillColor?: string;\n fillOpacity?: number;\n fontSize?: number;\n text?: string;\n}\n\nexport interface DrawingState {\n id: string;\n type: DrawingToolType;\n anchors: AnchorPoint[];\n style: DrawingStyle;\n visible: boolean;\n locked: boolean;\n meta?: Record<string, unknown>;\n}\n\nexport interface DrawingDescriptor {\n type: DrawingToolType;\n name: string;\n requiredAnchors: number;\n singleClick?: boolean;\n}\n\nexport interface DrawingPlugin {\n descriptor: DrawingDescriptor;\n render(\n ctx: CanvasRenderingContext2D,\n state: DrawingState,\n viewport: ViewportState,\n selected: boolean,\n ): void;\n hitTest(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): boolean;\n hitTestAnchor(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): number;\n}\n\nexport const DEFAULT_DRAWING_STYLE: DrawingStyle = {\n color: '#2196F3',\n lineWidth: 1,\n lineStyle: 'solid',\n fillColor: 'rgba(33, 150, 243, 0.1)',\n fillOpacity: 0.1,\n fontSize: 12,\n};\n","export type OrderSide = 'buy' | 'sell';\nexport type OrderType = 'market' | 'limit' | 'stop' | 'stopLimit';\nexport type OrderStatus = 'pending' | 'filled' | 'cancelled' | 'rejected';\nexport type OrderLabel = 'LIMIT' | 'STOP' | 'SL' | 'TP' | 'STOP LIMIT';\n\nexport interface TradingOrder {\n id: string;\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity: number;\n label?: OrderLabel;\n draggable?: boolean;\n meta?: Record<string, unknown>;\n}\n\nexport interface TradingPosition {\n id: string;\n side: OrderSide;\n entryPrice: number;\n quantity: number;\n stopLoss?: number;\n takeProfit?: number;\n meta?: Record<string, unknown>;\n}\n\nexport interface DepthLevel {\n price: number;\n volume: number;\n}\n\nexport interface DepthData {\n bids: DepthLevel[];\n asks: DepthLevel[];\n}\n\nexport interface TradingConfig {\n enabled: boolean;\n orderColors?: { buy?: string; sell?: string };\n positionColors?: { profit?: string; loss?: string; entry?: string };\n depthOverlay?: {\n enabled?: boolean;\n bidColor?: string;\n askColor?: string;\n maxWidth?: number;\n };\n contextMenu?: { enabled?: boolean };\n pricePrecision?: number;\n dragThreshold?: number;\n}\n\nexport interface OrderPlaceIntent {\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity?: number;\n}\n\nexport interface OrderModifyIntent {\n orderId: string;\n newPrice: number;\n previousPrice: number;\n}\n\nexport interface OrderCancelIntent {\n orderId: string;\n}\n\nexport interface PositionModifyIntent {\n positionId: string;\n stopLoss?: number;\n takeProfit?: number;\n}\n\nexport interface PositionCloseIntent {\n positionId: string;\n}\n\nexport const DEFAULT_TRADING_CONFIG: TradingConfig = {\n enabled: true,\n orderColors: { buy: '#26A69A', sell: '#EF5350' },\n positionColors: { profit: '#26A69A', loss: '#EF5350', entry: '#2196F3' },\n depthOverlay: { enabled: false, bidColor: 'rgba(38,166,154,0.15)', askColor: 'rgba(239,83,80,0.15)', maxWidth: 100 },\n contextMenu: { enabled: true },\n pricePrecision: 2,\n dragThreshold: 3,\n};\n","import type { OHLCBar, TimeFrame } from './ohlc.js';\n\n// --- Connection ---\n\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';\n\nexport interface ConnectionInfo {\n state: ConnectionState;\n latency?: number;\n reconnectAttempt?: number;\n lastMessageTime?: number;\n error?: string;\n}\n\n// --- Ticks & Trades ---\n\nexport interface RawTick {\n time: number;\n price: number;\n volume: number;\n side?: 'buy' | 'sell';\n}\n\nexport interface AggregatedBar extends OHLCBar {\n closed: boolean; // true when bar is finalized\n tickCount: number; // number of ticks in this bar\n}\n\n// --- Data Adapter (Strategy Pattern) ---\n\nexport interface DataAdapterConfig {\n symbol: string;\n timeframe: TimeFrame;\n reconnect?: boolean; // default: true\n reconnectMaxRetries?: number; // default: Infinity\n reconnectBaseDelay?: number; // ms, default: 1000\n reconnectMaxDelay?: number; // ms, default: 30000\n heartbeatInterval?: number; // ms, default: 30000\n bufferSize?: number; // max ticks to buffer, default: 1000\n}\n\nexport type DataAdapterEventType =\n | 'tick'\n | 'bar'\n | 'barClose'\n | 'snapshot' // initial historical data loaded\n | 'connectionChange'\n | 'error';\n\nexport interface DataAdapterEvent<T = unknown> {\n type: DataAdapterEventType;\n data: T;\n timestamp: number;\n}\n\nexport type DataAdapterListener<T = unknown> = (event: DataAdapterEvent<T>) => void;\n\n/**\n * DataAdapter interface — Strategy pattern for pluggable data sources.\n *\n * Implementations handle the specifics of each data source (WebSocket, REST,\n * SSE, etc.) while the StreamManager orchestrates lifecycle and aggregation.\n *\n * Built-in: BinanceAdapter\n * Implement this for: custom exchange APIs, broker feeds, mock data\n */\nexport interface DataAdapter {\n readonly name: string;\n\n connect(config: DataAdapterConfig): void;\n disconnect(): void;\n getConnectionState(): ConnectionState;\n\n /**\n * Load historical bars. Called once on connect, before streaming starts.\n * Returns bars sorted by time ascending.\n */\n fetchHistory(symbol: string, timeframe: TimeFrame, limit?: number): Promise<OHLCBar[]>;\n\n on<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n off<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n\n dispose(): void;\n}\n\n// --- Stream Manager Config ---\n\nexport interface StreamConfig {\n adapter: DataAdapter;\n symbol: string;\n timeframe: TimeFrame;\n historyLimit?: number; // bars to load initially, default: 500\n autoScroll?: boolean; // scroll to end on new bar, default: true\n showCurrentPriceLine?: boolean; // default: true\n aggregateTicks?: boolean; // build bars from ticks, default: false\n reconnect?: ReconnectConfig;\n}\n\nexport interface ReconnectConfig {\n enabled: boolean; // default: true\n maxRetries: number; // default: Infinity\n baseDelay: number; // ms, default: 1000\n maxDelay: number; // ms, default: 30000\n backoffMultiplier: number; // default: 2\n}\n\nexport const DEFAULT_RECONNECT: ReconnectConfig = {\n enabled: true,\n maxRetries: Infinity,\n baseDelay: 1000,\n maxDelay: 30000,\n backoffMultiplier: 2,\n};\n\nexport const DEFAULT_STREAM_CONFIG: Partial<StreamConfig> = {\n historyLimit: 500,\n autoScroll: true,\n showCurrentPriceLine: true,\n aggregateTicks: false,\n};\n","export function clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nexport function inverseLerp(a: number, b: number, value: number): number {\n if (a === b) return 0;\n return (value - a) / (b - a);\n}\n\nexport function roundToStep(value: number, step: number): number {\n return Math.round(value / step) * step;\n}\n\nexport function niceNumber(value: number, round: boolean): number {\n const exp = Math.floor(Math.log10(value));\n const frac = value / Math.pow(10, exp);\n let nice: number;\n if (round) {\n if (frac < 1.5) nice = 1;\n else if (frac < 3) nice = 2;\n else if (frac < 7) nice = 5;\n else nice = 10;\n } else {\n if (frac <= 1) nice = 1;\n else if (frac <= 2) nice = 2;\n else if (frac <= 5) nice = 5;\n else nice = 10;\n }\n return nice * Math.pow(10, exp);\n}\n\nexport function computeTickStep(min: number, max: number, maxTicks: number): number {\n const range = niceNumber(max - min, false);\n return niceNumber(range / (maxTicks - 1), true);\n}\n","import type { OHLCBar, DataSeries } from '../types/ohlc.js';\n\nexport function sliceVisibleData(\n data: DataSeries,\n from: number,\n to: number,\n): DataSeries {\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length, to + 1);\n return data.slice(startIdx, endIdx);\n}\n\nexport function findBarIndex(data: DataSeries, timestamp: number): number {\n let lo = 0;\n let hi = data.length - 1;\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n if (data[mid].time < timestamp) lo = mid + 1;\n else if (data[mid].time > timestamp) hi = mid - 1;\n else return mid;\n }\n return lo;\n}\n\nexport function computePriceRange(\n data: DataSeries,\n from: number,\n to: number,\n padding = 0.05,\n): { min: number; max: number } {\n if (data.length === 0) return { min: 0, max: 1 };\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length - 1, to);\n let min = Infinity;\n let max = -Infinity;\n for (let i = startIdx; i <= endIdx; i++) {\n if (data[i].low < min) min = data[i].low;\n if (data[i].high > max) max = data[i].high;\n }\n if (min === Infinity) return { min: 0, max: 1 };\n const range = max - min || 1;\n return {\n min: min - range * padding,\n max: max + range * padding,\n };\n}\n\nexport function mergeBar(existing: OHLCBar, tick: { price: number; volume?: number; time: number }): OHLCBar {\n return {\n ...existing,\n high: Math.max(existing.high, tick.price),\n low: Math.min(existing.low, tick.price),\n close: tick.price,\n volume: existing.volume + (tick.volume ?? 0),\n time: tick.time,\n };\n}\n","export function hexToRgba(hex: string, alpha = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\nexport function withAlpha(color: string, alpha: number): string {\n if (color.startsWith('#')) {\n return hexToRgba(color, alpha);\n }\n const rgbaMatch = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (rgbaMatch) {\n return `rgba(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]}, ${alpha})`;\n }\n return color;\n}\n","import type { TimeFrame } from '../types/ohlc.js';\n\nconst TIMEFRAME_MS: Record<TimeFrame, number> = {\n '1s': 1_000,\n '5s': 5_000,\n '15s': 15_000,\n '30s': 30_000,\n '1m': 60_000,\n '3m': 180_000,\n '5m': 300_000,\n '15m': 900_000,\n '30m': 1_800_000,\n '45m': 2_700_000,\n '1h': 3_600_000,\n '2h': 7_200_000,\n '3h': 10_800_000,\n '4h': 14_400_000,\n '6h': 21_600_000,\n '8h': 28_800_000,\n '12h': 43_200_000,\n '1d': 86_400_000,\n '2d': 172_800_000,\n '3d': 259_200_000,\n '1w': 604_800_000,\n '2w': 1_209_600_000,\n '1M': 2_592_000_000,\n '3M': 7_776_000_000,\n '6M': 15_552_000_000,\n '12M': 31_536_000_000,\n};\n\nexport function timeframeToMs(tf: TimeFrame): number {\n return TIMEFRAME_MS[tf];\n}\n\nexport function formatTimestamp(timestamp: number, tf: TimeFrame): string {\n const d = new Date(timestamp);\n const ms = TIMEFRAME_MS[tf];\n if (ms >= 86_400_000) {\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }\n if (ms >= 3_600_000) {\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\n }\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\nexport function alignToTimeframe(timestamp: number, tf: TimeFrame): number {\n const ms = TIMEFRAME_MS[tf];\n return Math.floor(timestamp / ms) * ms;\n}\n","export function formatPrice(value: number, precision = 2): string {\n return value.toFixed(precision);\n}\n\nexport function formatVolume(value: number): string {\n if (value >= 1_000_000_000) return (value / 1_000_000_000).toFixed(2) + 'B';\n if (value >= 1_000_000) return (value / 1_000_000).toFixed(2) + 'M';\n if (value >= 1_000) return (value / 1_000).toFixed(2) + 'K';\n return value.toFixed(0);\n}\n\nexport function detectPrecision(values: number[]): number {\n let maxDecimals = 0;\n for (const v of values) {\n const str = v.toString();\n const dot = str.indexOf('.');\n if (dot >= 0) {\n maxDecimals = Math.max(maxDecimals, str.length - dot - 1);\n }\n }\n return Math.min(maxDecimals, 8);\n}\n","import type { ChartOptions } from '../types/chart.js';\n\nexport const DEFAULT_CHART_OPTIONS: Required<Pick<ChartOptions, 'autoScale' | 'rightMargin' | 'minBarSpacing' | 'maxBarSpacing'>> & Pick<ChartOptions, 'grid' | 'crosshair'> = {\n autoScale: true,\n rightMargin: 5,\n minBarSpacing: 2,\n maxBarSpacing: 30,\n grid: {\n visible: true,\n hLineStyle: 'solid',\n vLineStyle: 'solid',\n },\n crosshair: {\n mode: 'magnet',\n },\n};\n\n// Standard timeframe presets for different market types\nimport type { TimeFrame } from '../types/ohlc.js';\n\n/** Crypto: all timeframes including seconds */\nexport const TIMEFRAMES_CRYPTO: TimeFrame[] = [\n '1s', '1m', '3m', '5m', '15m', '30m',\n '1h', '2h', '4h', '6h', '8h', '12h',\n '1d', '3d', '1w', '1M',\n];\n\n/** Stocks: minute-level and above (no seconds) */\nexport const TIMEFRAMES_STOCK: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '2h', '4h',\n '1d', '1w', '1M', '3M', '6M', '12M',\n];\n\n/** Forex: common forex timeframes */\nexport const TIMEFRAMES_FOREX: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '4h',\n '1d', '1w', '1M',\n];\n\n/** Default favorites shown in quick-access bar */\nexport const DEFAULT_TIMEFRAME_FAVORITES: TimeFrame[] = [\n '1m', '5m', '15m', '1h', '4h', '1d', '1w',\n];\n\nexport const DEFAULT_BAR_WIDTH = 8;\nexport const DEFAULT_BAR_SPACING = 2;\nexport const PRICE_AXIS_WIDTH = 70;\nexport const TIME_AXIS_HEIGHT = 30;\nexport const MIN_PANEL_HEIGHT = 60;\nexport const DEFAULT_PANEL_HEIGHT = 120;\n","import type { Theme } from '../types/theme.js';\n\nconst DEFAULT_FONT = {\n family: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n sizeSmall: 10,\n sizeMedium: 12,\n sizeLarge: 14,\n};\n\nexport const DARK_THEME: Theme = {\n name: 'dark',\n background: '#131722',\n text: '#D1D4DC',\n textSecondary: '#787B86',\n grid: '#1E222D',\n crosshair: '#9598A1',\n candleUp: '#26A69A',\n candleDown: '#EF5350',\n candleUpWick: '#26A69A',\n candleDownWick: '#EF5350',\n lineColor: '#2196F3',\n areaTopColor: 'rgba(33, 150, 243, 0.4)',\n areaBottomColor: 'rgba(33, 150, 243, 0.0)',\n volumeUp: 'rgba(38, 166, 154, 0.3)',\n volumeDown: 'rgba(239, 83, 80, 0.3)',\n axisLine: '#2A2E39',\n axisLabel: '#D1D4DC',\n axisLabelBackground: '#2A2E39',\n font: DEFAULT_FONT,\n};\n\nexport const LIGHT_THEME: Theme = {\n name: 'light',\n background: '#FFFFFF',\n text: '#131722',\n textSecondary: '#787B86',\n grid: '#F0F3FA',\n crosshair: '#9598A1',\n candleUp: '#26A69A',\n candleDown: '#EF5350',\n candleUpWick: '#26A69A',\n candleDownWick: '#EF5350',\n lineColor: '#2196F3',\n areaTopColor: 'rgba(33, 150, 243, 0.4)',\n areaBottomColor: 'rgba(33, 150, 243, 0.0)',\n volumeUp: 'rgba(38, 166, 154, 0.3)',\n volumeDown: 'rgba(239, 83, 80, 0.3)',\n axisLine: '#E0E3EB',\n axisLabel: '#131722',\n axisLabelBackground: '#F0F3FA',\n font: DEFAULT_FONT,\n};\n","import type { LocaleStrings } from './types.js';\n\nexport const en: LocaleStrings = {\n // Chart types\n candlestick: 'Candlestick',\n line: 'Line',\n area: 'Area',\n bar: 'OHLC Bar',\n\n // Axes\n price: 'Price',\n volume: 'Volume',\n time: 'Time',\n open: 'Open',\n high: 'High',\n low: 'Low',\n close: 'Close',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Bollinger Bands',\n vwap: 'VWAP',\n ichimoku: 'Ichimoku Cloud',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Keltner Channel',\n donchianChannel: 'Donchian Channel',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Std Dev',\n volumeProfile: 'Volume Profile',\n accumulationDistribution: 'A/D Line',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Trend Line',\n horizontalLine: 'Horizontal Line',\n verticalLine: 'Vertical Line',\n ray: 'Ray',\n extendedLine: 'Extended Line',\n parallelChannel: 'Parallel Channel',\n regressionChannel: 'Regression Channel',\n fibRetracement: 'Fibonacci Retracement',\n fibExtension: 'Fibonacci Extension',\n rectangle: 'Rectangle',\n ellipse: 'Ellipse',\n triangle: 'Triangle',\n pitchfork: \"Andrews' Pitchfork\",\n elliottWave: 'Elliott Wave',\n priceRange: 'Price Range',\n dateRange: 'Date Range',\n measure: 'Measure',\n textTool: 'Text',\n arrow: 'Arrow',\n clearAll: 'Clear All',\n\n // Trading\n buy: 'Buy',\n sell: 'Sell',\n buyLimit: 'Buy Limit',\n sellLimit: 'Sell Limit',\n buyStop: 'Buy Stop',\n sellStop: 'Sell Stop',\n stopLoss: 'Stop Loss',\n takeProfit: 'Take Profit',\n market: 'Market',\n limit: 'Limit',\n stop: 'Stop',\n cancel: 'Cancel',\n modify: 'Modify',\n quantity: 'Qty',\n pnl: 'P&L',\n activeOrders: 'Active Orders',\n positions: 'Positions',\n noOrders: 'No active orders',\n noPositions: 'No open positions',\n placeOrder: 'Place Order',\n rightClickToTrade: 'Right-click chart to place orders',\n\n // Market\n ceiling: 'Ceiling',\n floor: 'Floor',\n reference: 'Reference',\n session: 'Session',\n preOpen: 'Pre-Open',\n continuous: 'Continuous',\n preClose: 'Pre-Close',\n closed: 'Closed',\n\n // UI\n settings: 'Settings',\n theme: 'Theme',\n darkTheme: 'Dark',\n lightTheme: 'Light',\n tools: 'Tools',\n indicators: 'Indicators',\n overlays: 'Overlays',\n panels: 'Panels',\n orders: 'Orders',\n autoScale: 'Auto Scale',\n crosshair: 'Crosshair',\n grid: 'Grid',\n loading: 'Loading...',\n error: 'Error',\n\n numberDecimalSeparator: '.',\n numberGroupSeparator: ',',\n};\n","import type { LocaleStrings } from './types.js';\n\nexport const vi: LocaleStrings = {\n // Chart types\n candlestick: 'Nến',\n line: 'Đường',\n area: 'Vùng',\n bar: 'Thanh OHLC',\n\n // Axes\n price: 'Giá',\n volume: 'Khối lượng',\n time: 'Thời gian',\n open: 'Mở',\n high: 'Cao',\n low: 'Thấp',\n close: 'Đóng',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Dải Bollinger',\n vwap: 'VWAP',\n ichimoku: 'Mây Ichimoku',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Kênh Keltner',\n donchianChannel: 'Kênh Donchian',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Độ lệch chuẩn',\n volumeProfile: 'Phân bổ KL',\n accumulationDistribution: 'Tích lũy/Phân phối',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Đường xu hướng',\n horizontalLine: 'Đường ngang',\n verticalLine: 'Đường dọc',\n ray: 'Tia',\n extendedLine: 'Đường kéo dài',\n parallelChannel: 'Kênh song song',\n regressionChannel: 'Kênh hồi quy',\n fibRetracement: 'Fibonacci thoái lui',\n fibExtension: 'Fibonacci mở rộng',\n rectangle: 'Hình chữ nhật',\n ellipse: 'Hình elip',\n triangle: 'Tam giác',\n pitchfork: 'Chĩa ba Andrews',\n elliottWave: 'Sóng Elliott',\n priceRange: 'Khoảng giá',\n dateRange: 'Khoảng thời gian',\n measure: 'Đo lường',\n textTool: 'Chữ',\n arrow: 'Mũi tên',\n clearAll: 'Xóa tất cả',\n\n // Trading\n buy: 'Mua',\n sell: 'Bán',\n buyLimit: 'Mua giới hạn',\n sellLimit: 'Bán giới hạn',\n buyStop: 'Mua chặn',\n sellStop: 'Bán chặn',\n stopLoss: 'Cắt lỗ',\n takeProfit: 'Chốt lời',\n market: 'Thị trường',\n limit: 'Giới hạn',\n stop: 'Dừng',\n cancel: 'Hủy',\n modify: 'Sửa',\n quantity: 'KL',\n pnl: 'Lãi/Lỗ',\n activeOrders: 'Lệnh chờ',\n positions: 'Vị thế',\n noOrders: 'Không có lệnh chờ',\n noPositions: 'Không có vị thế mở',\n placeOrder: 'Đặt lệnh',\n rightClickToTrade: 'Nhấp chuột phải để đặt lệnh',\n\n // Market\n ceiling: 'Trần',\n floor: 'Sàn',\n reference: 'Tham chiếu',\n session: 'Phiên',\n preOpen: 'Trước giờ mở',\n continuous: 'Liên tục',\n preClose: 'Trước giờ đóng',\n closed: 'Đóng cửa',\n\n // UI\n settings: 'Cài đặt',\n theme: 'Giao diện',\n darkTheme: 'Tối',\n lightTheme: 'Sáng',\n tools: 'Công cụ',\n indicators: 'Chỉ báo',\n overlays: 'Phủ lên',\n panels: 'Bảng',\n orders: 'Lệnh',\n autoScale: 'Tự co giãn',\n crosshair: 'Chữ thập',\n grid: 'Lưới',\n loading: 'Đang tải...',\n error: 'Lỗi',\n\n numberDecimalSeparator: ',',\n numberGroupSeparator: '.',\n};\n","export type { Locale, LocaleStrings, NumberFormatConfig, DateFormatConfig } from './types.js';\nexport { en } from './en.js';\nexport { vi } from './vi.js';\n\nimport type { Locale, LocaleStrings } from './types.js';\nimport { en } from './en.js';\nimport { vi } from './vi.js';\n\nconst locales = new Map<string, LocaleStrings>([\n ['en', en],\n ['vi', vi],\n]);\n\nlet currentLocale: Locale = 'en';\nlet currentStrings: LocaleStrings = en;\n\nexport function setLocale(locale: Locale): void {\n currentLocale = locale;\n currentStrings = locales.get(locale) ?? en;\n}\n\nexport function getLocale(): Locale {\n return currentLocale;\n}\n\nexport function t(key: keyof LocaleStrings): string {\n return currentStrings[key] ?? (en as any)[key] ?? key;\n}\n\nexport function registerLocale(locale: string, strings: LocaleStrings): void {\n locales.set(locale, strings);\n}\n\nexport function getLocaleStrings(locale?: string): LocaleStrings {\n return locales.get(locale ?? currentLocale) ?? en;\n}\n\n// Number formatting\nexport function formatNumber(value: number, precision = 2, locale?: string): string {\n const strings = locales.get(locale ?? currentLocale) ?? en;\n const dec = strings.numberDecimalSeparator;\n const grp = strings.numberGroupSeparator;\n\n const fixed = value.toFixed(precision);\n const [intPart, decPart] = fixed.split('.');\n\n // Group integer part\n const negative = intPart.startsWith('-');\n const digits = negative ? intPart.slice(1) : intPart;\n let grouped = '';\n for (let i = digits.length - 1, count = 0; i >= 0; i--, count++) {\n if (count > 0 && count % 3 === 0) grouped = grp + grouped;\n grouped = digits[i] + grouped;\n }\n if (negative) grouped = '-' + grouped;\n\n return decPart ? grouped + dec + decPart : grouped;\n}\n\nexport function formatVND(value: number): string {\n return formatNumber(value, 0, 'vi');\n}\n\nexport function formatVolumeLoc(value: number, locale?: string): string {\n if (value >= 1e9) return formatNumber(value / 1e9, 2, locale ?? currentLocale) + 'B';\n if (value >= 1e6) return formatNumber(value / 1e6, 2, locale ?? currentLocale) + 'M';\n if (value >= 1e3) return formatNumber(value / 1e3, 2, locale ?? currentLocale) + 'K';\n return formatNumber(value, 0, locale ?? currentLocale);\n}\n","import type { MarketConfig, MarketColorScheme, TradingSession } from './types.js';\nimport type { Theme } from '../types/theme.js';\n\n// Vietnam stock color convention:\n// Purple/Red = ceiling (trần) - max up\n// Green/Cyan = floor (sàn) - max down\n// Yellow = reference (tham chiếu)\n// Red = up, Blue = down (common VN convention)\nexport const VN_COLORS: MarketColorScheme = {\n up: '#FF0000', // Đỏ - tăng\n down: '#0000FF', // Xanh dương - giảm\n unchanged: '#FFD700', // Vàng - tham chiếu\n ceiling: '#FF00FF', // Tím - trần\n floor: '#00FFFF', // Xanh lam - sàn\n reference: '#FFD700', // Vàng - tham chiếu\n};\n\nexport const HOSE_SESSIONS: TradingSession[] = [\n { name: 'ATO', startTime: '09:00', endTime: '09:15', type: 'preOpen' },\n { name: 'Phiên 1', startTime: '09:15', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\nexport const HNX_SESSIONS: TradingSession[] = [\n { name: 'Phiên 1', startTime: '09:00', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\n// Market presets\nexport const MARKET_HOSE: MarketConfig = {\n type: 'stock',\n exchange: 'HOSE',\n currency: 'VND',\n pricePrecision: 2,\n volumeUnit: 10,\n priceStep: 0.05,\n priceLimits: { enabled: true, ceilingPercent: 7, floorPercent: 7 },\n sessions: HOSE_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_HNX: MarketConfig = {\n type: 'stock',\n exchange: 'HNX',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n priceLimits: { enabled: true, ceilingPercent: 10, floorPercent: 10 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_UPCOM: MarketConfig = {\n type: 'stock',\n exchange: 'UPCOM',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n priceLimits: { enabled: true, ceilingPercent: 15, floorPercent: 15 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_CRYPTO: MarketConfig = {\n type: 'crypto',\n currency: 'USDT',\n pricePrecision: 2,\n priceLimits: { enabled: false },\n};\n\nexport const MARKET_NYSE: MarketConfig = {\n type: 'stock',\n exchange: 'NYSE',\n currency: 'USD',\n pricePrecision: 2,\n priceStep: 0.01,\n priceLimits: { enabled: false },\n sessions: [\n { name: 'Pre-Market', startTime: '04:00', endTime: '09:30', type: 'preOpen' },\n { name: 'Regular', startTime: '09:30', endTime: '16:00', type: 'continuous' },\n { name: 'After-Hours', startTime: '16:00', endTime: '20:00', type: 'preClose' },\n ],\n};\n\n// Build a theme variant for VN stock market\nexport function createVNTheme(base: Theme): Theme {\n return {\n ...base,\n candleUp: VN_COLORS.up,\n candleDown: VN_COLORS.down,\n candleUpWick: VN_COLORS.up,\n candleDownWick: VN_COLORS.down,\n volumeUp: 'rgba(255, 0, 0, 0.3)',\n volumeDown: 'rgba(0, 0, 255, 0.3)',\n };\n}\n\nexport function computePriceLimits(referencePrice: number, config: MarketConfig): { ceiling: number; floor: number; reference: number } | null {\n if (!config.priceLimits?.enabled || !config.priceLimits.ceilingPercent) return null;\n const ceilPct = config.priceLimits.ceilingPercent / 100;\n const floorPct = (config.priceLimits.floorPercent ?? config.priceLimits.ceilingPercent) / 100;\n return {\n ceiling: referencePrice * (1 + ceilPct),\n floor: referencePrice * (1 - floorPct),\n reference: referencePrice,\n };\n}\n\nexport function getCurrentSession(sessions: TradingSession[]): TradingSession | null {\n const now = new Date();\n const hhmm = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;\n for (const session of sessions) {\n if (hhmm >= session.startTime && hhmm < session.endTime) return session;\n }\n return null;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../src/types/rendering.ts","../src/types/drawing.ts","../src/types/trading.ts","../src/types/realtime.ts","../src/utils/math.ts","../src/utils/data.ts","../src/utils/color.ts","../src/utils/time.ts","../src/utils/precision.ts","../src/constants/defaults.ts","../src/constants/themes.ts","../src/i18n/en.ts","../src/i18n/vi.ts","../src/i18n/index.ts","../src/market/presets.ts"],"sourcesContent":["export interface Point {\n x: number;\n y: number;\n}\n\nexport interface Size {\n width: number;\n height: number;\n}\n\nexport interface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface ViewportState {\n visibleRange: { from: number; to: number };\n priceRange: { min: number; max: number };\n barWidth: number;\n barSpacing: number;\n offset: number;\n chartRect: Rect;\n logScale?: boolean;\n}\n\nexport enum LayerType {\n Background = 0,\n Main = 1,\n Panel = 2,\n Overlay = 3,\n UI = 4,\n}\n","import type { Point, ViewportState } from './rendering.js';\n\nexport type DrawingToolType =\n | 'trendLine' | 'horizontalLine' | 'verticalLine' | 'ray' | 'extendedLine'\n | 'parallelChannel' | 'regressionChannel'\n | 'fibRetracement' | 'fibExtension'\n | 'rectangle' | 'ellipse' | 'triangle'\n | 'pitchfork' | 'elliottWave'\n | 'priceRange' | 'dateRange' | 'measure'\n | 'text' | 'arrow'\n | 'gannFan' | 'gannBox'\n | 'anchoredVWAP'\n | 'volumeProfileRange';\n\nexport interface AnchorPoint {\n time: number;\n price: number;\n}\n\nexport interface DrawingStyle {\n color: string;\n lineWidth: number;\n lineStyle: 'solid' | 'dashed' | 'dotted';\n fillColor?: string;\n fillOpacity?: number;\n fontSize?: number;\n text?: string;\n}\n\nexport interface DrawingState {\n id: string;\n type: DrawingToolType;\n anchors: AnchorPoint[];\n style: DrawingStyle;\n visible: boolean;\n locked: boolean;\n meta?: Record<string, unknown>;\n}\n\nexport interface DrawingDescriptor {\n type: DrawingToolType;\n name: string;\n requiredAnchors: number;\n singleClick?: boolean;\n}\n\nexport interface DrawingPlugin {\n descriptor: DrawingDescriptor;\n render(\n ctx: CanvasRenderingContext2D,\n state: DrawingState,\n viewport: ViewportState,\n selected: boolean,\n ): void;\n hitTest(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): boolean;\n hitTestAnchor(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): number;\n}\n\nexport const DEFAULT_DRAWING_STYLE: DrawingStyle = {\n color: '#2196F3',\n lineWidth: 1,\n lineStyle: 'solid',\n fillColor: 'rgba(33, 150, 243, 0.1)',\n fillOpacity: 0.1,\n fontSize: 12,\n};\n","export type OrderSide = 'buy' | 'sell';\nexport type OrderType = 'market' | 'limit' | 'stop' | 'stopLimit';\nexport type OrderStatus = 'pending' | 'filled' | 'cancelled' | 'rejected';\nexport type OrderLabel = 'LIMIT' | 'STOP' | 'SL' | 'TP' | 'STOP LIMIT';\n\nexport interface TradingOrder {\n id: string;\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity: number;\n label?: OrderLabel;\n draggable?: boolean;\n meta?: Record<string, unknown>;\n}\n\nexport interface TradingPosition {\n id: string;\n side: OrderSide;\n entryPrice: number;\n quantity: number;\n stopLoss?: number;\n takeProfit?: number;\n meta?: Record<string, unknown>;\n}\n\nexport interface DepthLevel {\n price: number;\n volume: number;\n}\n\nexport interface DepthData {\n bids: DepthLevel[];\n asks: DepthLevel[];\n}\n\nexport interface TradingConfig {\n enabled: boolean;\n orderColors?: { buy?: string; sell?: string };\n positionColors?: { profit?: string; loss?: string; entry?: string };\n depthOverlay?: {\n enabled?: boolean;\n bidColor?: string;\n askColor?: string;\n maxWidth?: number;\n };\n contextMenu?: { enabled?: boolean };\n pricePrecision?: number;\n dragThreshold?: number;\n}\n\nexport interface OrderPlaceIntent {\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity?: number;\n}\n\nexport interface OrderModifyIntent {\n orderId: string;\n newPrice: number;\n previousPrice: number;\n}\n\nexport interface OrderCancelIntent {\n orderId: string;\n}\n\nexport interface PositionModifyIntent {\n positionId: string;\n stopLoss?: number;\n takeProfit?: number;\n}\n\nexport interface PositionCloseIntent {\n positionId: string;\n}\n\nexport const DEFAULT_TRADING_CONFIG: TradingConfig = {\n enabled: true,\n orderColors: { buy: '#26A69A', sell: '#EF5350' },\n positionColors: { profit: '#26A69A', loss: '#EF5350', entry: '#2196F3' },\n depthOverlay: { enabled: false, bidColor: 'rgba(38,166,154,0.15)', askColor: 'rgba(239,83,80,0.15)', maxWidth: 100 },\n contextMenu: { enabled: true },\n pricePrecision: 2,\n dragThreshold: 3,\n};\n","import type { OHLCBar, TimeFrame } from './ohlc.js';\n\n// --- Connection ---\n\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';\n\nexport interface ConnectionInfo {\n state: ConnectionState;\n latency?: number;\n reconnectAttempt?: number;\n lastMessageTime?: number;\n error?: string;\n}\n\n// --- Ticks & Trades ---\n\nexport interface RawTick {\n time: number;\n price: number;\n volume: number;\n side?: 'buy' | 'sell';\n}\n\nexport interface AggregatedBar extends OHLCBar {\n closed: boolean; // true when bar is finalized\n tickCount: number; // number of ticks in this bar\n}\n\n// --- Data Adapter (Strategy Pattern) ---\n\nexport interface DataAdapterConfig {\n symbol: string;\n timeframe: TimeFrame;\n reconnect?: boolean; // default: true\n reconnectMaxRetries?: number; // default: Infinity\n reconnectBaseDelay?: number; // ms, default: 1000\n reconnectMaxDelay?: number; // ms, default: 30000\n heartbeatInterval?: number; // ms, default: 30000\n bufferSize?: number; // max ticks to buffer, default: 1000\n}\n\nexport type DataAdapterEventType =\n | 'tick'\n | 'bar'\n | 'barClose'\n | 'snapshot' // initial historical data loaded\n | 'connectionChange'\n | 'error';\n\nexport interface DataAdapterEvent<T = unknown> {\n type: DataAdapterEventType;\n data: T;\n timestamp: number;\n}\n\nexport type DataAdapterListener<T = unknown> = (event: DataAdapterEvent<T>) => void;\n\n/**\n * DataAdapter interface — Strategy pattern for pluggable data sources.\n *\n * Implementations handle the specifics of each data source (WebSocket, REST,\n * SSE, etc.) while the StreamManager orchestrates lifecycle and aggregation.\n *\n * Built-in: BinanceAdapter\n * Implement this for: custom exchange APIs, broker feeds, mock data\n */\nexport interface DataAdapter {\n readonly name: string;\n\n connect(config: DataAdapterConfig): void;\n disconnect(): void;\n getConnectionState(): ConnectionState;\n\n /**\n * Load historical bars. Called once on connect, before streaming starts.\n * Returns bars sorted by time ascending.\n */\n fetchHistory(symbol: string, timeframe: TimeFrame, limit?: number): Promise<OHLCBar[]>;\n\n on<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n off<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n\n dispose(): void;\n}\n\n// --- Stream Manager Config ---\n\nexport interface StreamConfig {\n adapter: DataAdapter;\n symbol: string;\n timeframe: TimeFrame;\n historyLimit?: number; // bars to load initially, default: 500\n autoScroll?: boolean; // scroll to end on new bar, default: true\n showCurrentPriceLine?: boolean; // default: true\n aggregateTicks?: boolean; // build bars from ticks, default: false\n reconnect?: ReconnectConfig;\n}\n\nexport interface ReconnectConfig {\n enabled: boolean; // default: true\n maxRetries: number; // default: Infinity\n baseDelay: number; // ms, default: 1000\n maxDelay: number; // ms, default: 30000\n backoffMultiplier: number; // default: 2\n}\n\nexport const DEFAULT_RECONNECT: ReconnectConfig = {\n enabled: true,\n maxRetries: Infinity,\n baseDelay: 1000,\n maxDelay: 30000,\n backoffMultiplier: 2,\n};\n\nexport const DEFAULT_STREAM_CONFIG: Partial<StreamConfig> = {\n historyLimit: 500,\n autoScroll: true,\n showCurrentPriceLine: true,\n aggregateTicks: false,\n};\n","export function clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nexport function inverseLerp(a: number, b: number, value: number): number {\n if (a === b) return 0;\n return (value - a) / (b - a);\n}\n\nexport function roundToStep(value: number, step: number): number {\n return Math.round(value / step) * step;\n}\n\nexport function niceNumber(value: number, round: boolean): number {\n const exp = Math.floor(Math.log10(value));\n const frac = value / Math.pow(10, exp);\n let nice: number;\n if (round) {\n if (frac < 1.5) nice = 1;\n else if (frac < 3) nice = 2;\n else if (frac < 7) nice = 5;\n else nice = 10;\n } else {\n if (frac <= 1) nice = 1;\n else if (frac <= 2) nice = 2;\n else if (frac <= 5) nice = 5;\n else nice = 10;\n }\n return nice * Math.pow(10, exp);\n}\n\nexport function computeTickStep(min: number, max: number, maxTicks: number): number {\n const range = niceNumber(max - min, false);\n return niceNumber(range / (maxTicks - 1), true);\n}\n","import type { OHLCBar, DataSeries } from '../types/ohlc.js';\n\nexport function sliceVisibleData(\n data: DataSeries,\n from: number,\n to: number,\n): DataSeries {\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length, to + 1);\n return data.slice(startIdx, endIdx);\n}\n\nexport function findBarIndex(data: DataSeries, timestamp: number): number {\n let lo = 0;\n let hi = data.length - 1;\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n if (data[mid].time < timestamp) lo = mid + 1;\n else if (data[mid].time > timestamp) hi = mid - 1;\n else return mid;\n }\n return lo;\n}\n\nexport function computePriceRange(\n data: DataSeries,\n from: number,\n to: number,\n padding = 0.05,\n): { min: number; max: number } {\n if (data.length === 0) return { min: 0, max: 1 };\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length - 1, to);\n let min = Infinity;\n let max = -Infinity;\n for (let i = startIdx; i <= endIdx; i++) {\n if (data[i].low < min) min = data[i].low;\n if (data[i].high > max) max = data[i].high;\n }\n if (min === Infinity) return { min: 0, max: 1 };\n const range = max - min || 1;\n return {\n min: min - range * padding,\n max: max + range * padding,\n };\n}\n\nexport function mergeBar(existing: OHLCBar, tick: { price: number; volume?: number; time: number }): OHLCBar {\n return {\n ...existing,\n high: Math.max(existing.high, tick.price),\n low: Math.min(existing.low, tick.price),\n close: tick.price,\n volume: existing.volume + (tick.volume ?? 0),\n time: tick.time,\n };\n}\n","export function hexToRgba(hex: string, alpha = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\nexport function withAlpha(color: string, alpha: number): string {\n if (color.startsWith('#')) {\n return hexToRgba(color, alpha);\n }\n const rgbaMatch = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (rgbaMatch) {\n return `rgba(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]}, ${alpha})`;\n }\n return color;\n}\n\nexport function lerpColor(colorA: string, colorB: string, t: number): string {\n const parseHex = (hex: string) => {\n hex = hex.replace('#', '');\n if (hex.length === 3) hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];\n return {\n r: parseInt(hex.slice(0, 2), 16),\n g: parseInt(hex.slice(2, 4), 16),\n b: parseInt(hex.slice(4, 6), 16),\n };\n };\n const a = parseHex(colorA);\n const b = parseHex(colorB);\n const r = Math.round(a.r + (b.r - a.r) * t);\n const g = Math.round(a.g + (b.g - a.g) * t);\n const bl = Math.round(a.b + (b.b - a.b) * t);\n return `rgb(${r},${g},${bl})`;\n}\n","import type { TimeFrame } from '../types/ohlc.js';\n\nconst TIMEFRAME_MS: Record<TimeFrame, number> = {\n '1s': 1_000,\n '5s': 5_000,\n '15s': 15_000,\n '30s': 30_000,\n '1m': 60_000,\n '3m': 180_000,\n '5m': 300_000,\n '15m': 900_000,\n '30m': 1_800_000,\n '45m': 2_700_000,\n '1h': 3_600_000,\n '2h': 7_200_000,\n '3h': 10_800_000,\n '4h': 14_400_000,\n '6h': 21_600_000,\n '8h': 28_800_000,\n '12h': 43_200_000,\n '1d': 86_400_000,\n '2d': 172_800_000,\n '3d': 259_200_000,\n '1w': 604_800_000,\n '2w': 1_209_600_000,\n '1M': 2_592_000_000,\n '3M': 7_776_000_000,\n '6M': 15_552_000_000,\n '12M': 31_536_000_000,\n};\n\nexport function timeframeToMs(tf: TimeFrame): number {\n return TIMEFRAME_MS[tf];\n}\n\nexport function formatTimestamp(timestamp: number, tf: TimeFrame): string {\n const d = new Date(timestamp);\n const ms = TIMEFRAME_MS[tf];\n if (ms >= 86_400_000) {\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }\n if (ms >= 3_600_000) {\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\n }\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\nexport function alignToTimeframe(timestamp: number, tf: TimeFrame): number {\n const ms = TIMEFRAME_MS[tf];\n return Math.floor(timestamp / ms) * ms;\n}\n","export function formatPrice(value: number, precision = 2): string {\n return value.toFixed(precision);\n}\n\nexport function formatVolume(value: number): string {\n if (value >= 1_000_000_000) return (value / 1_000_000_000).toFixed(2) + 'B';\n if (value >= 1_000_000) return (value / 1_000_000).toFixed(2) + 'M';\n if (value >= 1_000) return (value / 1_000).toFixed(2) + 'K';\n return value.toFixed(0);\n}\n\nexport function detectPrecision(values: number[]): number {\n let maxDecimals = 0;\n for (const v of values) {\n const str = v.toString();\n const dot = str.indexOf('.');\n if (dot >= 0) {\n maxDecimals = Math.max(maxDecimals, str.length - dot - 1);\n }\n }\n return Math.min(maxDecimals, 8);\n}\n","import type { ChartOptions } from '../types/chart.js';\n\nexport const DEFAULT_CHART_OPTIONS: Required<Pick<ChartOptions, 'autoScale' | 'rightMargin' | 'minBarSpacing' | 'maxBarSpacing'>> & Pick<ChartOptions, 'grid' | 'crosshair'> = {\n autoScale: true,\n rightMargin: 5,\n minBarSpacing: 2,\n maxBarSpacing: 30,\n grid: {\n visible: true,\n hLineStyle: 'solid',\n vLineStyle: 'solid',\n },\n crosshair: {\n mode: 'magnet',\n },\n};\n\n// Standard timeframe presets for different market types\nimport type { TimeFrame } from '../types/ohlc.js';\n\n/** Crypto: all timeframes including seconds */\nexport const TIMEFRAMES_CRYPTO: TimeFrame[] = [\n '1s', '1m', '3m', '5m', '15m', '30m',\n '1h', '2h', '4h', '6h', '8h', '12h',\n '1d', '3d', '1w', '1M',\n];\n\n/** Stocks: minute-level and above (no seconds) */\nexport const TIMEFRAMES_STOCK: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '2h', '4h',\n '1d', '1w', '1M', '3M', '6M', '12M',\n];\n\n/** Forex: common forex timeframes */\nexport const TIMEFRAMES_FOREX: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '4h',\n '1d', '1w', '1M',\n];\n\n/** Default favorites shown in quick-access bar */\nexport const DEFAULT_TIMEFRAME_FAVORITES: TimeFrame[] = [\n '1m', '5m', '15m', '1h', '4h', '1d', '1w',\n];\n\nexport const DEFAULT_BAR_WIDTH = 8;\nexport const DEFAULT_BAR_SPACING = 2;\nexport const PRICE_AXIS_WIDTH = 70;\nexport const TIME_AXIS_HEIGHT = 30;\nexport const MIN_PANEL_HEIGHT = 60;\nexport const DEFAULT_PANEL_HEIGHT = 120;\n","import type { Theme } from '../types/theme.js';\n\nconst DEFAULT_FONT = {\n family: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n sizeSmall: 10,\n sizeMedium: 12,\n sizeLarge: 14,\n};\n\nexport const DARK_THEME: Theme = {\n name: 'dark',\n background: '#131722',\n text: '#D1D4DC',\n textSecondary: '#787B86',\n grid: '#1E222D',\n crosshair: '#9598A1',\n candleUp: '#26A69A',\n candleDown: '#EF5350',\n candleUpWick: '#26A69A',\n candleDownWick: '#EF5350',\n lineColor: '#2196F3',\n areaTopColor: 'rgba(33, 150, 243, 0.4)',\n areaBottomColor: 'rgba(33, 150, 243, 0.0)',\n volumeUp: 'rgba(38, 166, 154, 0.3)',\n volumeDown: 'rgba(239, 83, 80, 0.3)',\n axisLine: '#2A2E39',\n axisLabel: '#D1D4DC',\n axisLabelBackground: '#2A2E39',\n font: DEFAULT_FONT,\n};\n\nexport const LIGHT_THEME: Theme = {\n name: 'light',\n background: '#FFFFFF',\n text: '#131722',\n textSecondary: '#787B86',\n grid: '#F0F3FA',\n crosshair: '#9598A1',\n candleUp: '#26A69A',\n candleDown: '#EF5350',\n candleUpWick: '#26A69A',\n candleDownWick: '#EF5350',\n lineColor: '#2196F3',\n areaTopColor: 'rgba(33, 150, 243, 0.4)',\n areaBottomColor: 'rgba(33, 150, 243, 0.0)',\n volumeUp: 'rgba(38, 166, 154, 0.3)',\n volumeDown: 'rgba(239, 83, 80, 0.3)',\n axisLine: '#E0E3EB',\n axisLabel: '#131722',\n axisLabelBackground: '#F0F3FA',\n font: DEFAULT_FONT,\n};\n","import type { LocaleStrings } from './types.js';\n\nexport const en: LocaleStrings = {\n // Chart types\n candlestick: 'Candlestick',\n line: 'Line',\n area: 'Area',\n bar: 'OHLC Bar',\n\n // Axes\n price: 'Price',\n volume: 'Volume',\n time: 'Time',\n open: 'Open',\n high: 'High',\n low: 'Low',\n close: 'Close',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Bollinger Bands',\n vwap: 'VWAP',\n ichimoku: 'Ichimoku Cloud',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Keltner Channel',\n donchianChannel: 'Donchian Channel',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Std Dev',\n volumeProfile: 'Volume Profile',\n accumulationDistribution: 'A/D Line',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Trend Line',\n horizontalLine: 'Horizontal Line',\n verticalLine: 'Vertical Line',\n ray: 'Ray',\n extendedLine: 'Extended Line',\n parallelChannel: 'Parallel Channel',\n regressionChannel: 'Regression Channel',\n fibRetracement: 'Fibonacci Retracement',\n fibExtension: 'Fibonacci Extension',\n rectangle: 'Rectangle',\n ellipse: 'Ellipse',\n triangle: 'Triangle',\n pitchfork: \"Andrews' Pitchfork\",\n elliottWave: 'Elliott Wave',\n priceRange: 'Price Range',\n dateRange: 'Date Range',\n measure: 'Measure',\n textTool: 'Text',\n arrow: 'Arrow',\n clearAll: 'Clear All',\n\n // Trading\n buy: 'Buy',\n sell: 'Sell',\n buyLimit: 'Buy Limit',\n sellLimit: 'Sell Limit',\n buyStop: 'Buy Stop',\n sellStop: 'Sell Stop',\n stopLoss: 'Stop Loss',\n takeProfit: 'Take Profit',\n market: 'Market',\n limit: 'Limit',\n stop: 'Stop',\n cancel: 'Cancel',\n modify: 'Modify',\n quantity: 'Qty',\n pnl: 'P&L',\n activeOrders: 'Active Orders',\n positions: 'Positions',\n noOrders: 'No active orders',\n noPositions: 'No open positions',\n placeOrder: 'Place Order',\n rightClickToTrade: 'Right-click chart to place orders',\n\n // Market\n ceiling: 'Ceiling',\n floor: 'Floor',\n reference: 'Reference',\n session: 'Session',\n preOpen: 'Pre-Open',\n continuous: 'Continuous',\n preClose: 'Pre-Close',\n closed: 'Closed',\n\n // UI\n settings: 'Settings',\n theme: 'Theme',\n darkTheme: 'Dark',\n lightTheme: 'Light',\n tools: 'Tools',\n indicators: 'Indicators',\n overlays: 'Overlays',\n panels: 'Panels',\n orders: 'Orders',\n autoScale: 'Auto Scale',\n crosshair: 'Crosshair',\n grid: 'Grid',\n loading: 'Loading...',\n error: 'Error',\n\n numberDecimalSeparator: '.',\n numberGroupSeparator: ',',\n};\n","import type { LocaleStrings } from './types.js';\n\nexport const vi: LocaleStrings = {\n // Chart types\n candlestick: 'Nến',\n line: 'Đường',\n area: 'Vùng',\n bar: 'Thanh OHLC',\n\n // Axes\n price: 'Giá',\n volume: 'Khối lượng',\n time: 'Thời gian',\n open: 'Mở',\n high: 'Cao',\n low: 'Thấp',\n close: 'Đóng',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Dải Bollinger',\n vwap: 'VWAP',\n ichimoku: 'Mây Ichimoku',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Kênh Keltner',\n donchianChannel: 'Kênh Donchian',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Độ lệch chuẩn',\n volumeProfile: 'Phân bổ KL',\n accumulationDistribution: 'Tích lũy/Phân phối',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Đường xu hướng',\n horizontalLine: 'Đường ngang',\n verticalLine: 'Đường dọc',\n ray: 'Tia',\n extendedLine: 'Đường kéo dài',\n parallelChannel: 'Kênh song song',\n regressionChannel: 'Kênh hồi quy',\n fibRetracement: 'Fibonacci thoái lui',\n fibExtension: 'Fibonacci mở rộng',\n rectangle: 'Hình chữ nhật',\n ellipse: 'Hình elip',\n triangle: 'Tam giác',\n pitchfork: 'Chĩa ba Andrews',\n elliottWave: 'Sóng Elliott',\n priceRange: 'Khoảng giá',\n dateRange: 'Khoảng thời gian',\n measure: 'Đo lường',\n textTool: 'Chữ',\n arrow: 'Mũi tên',\n clearAll: 'Xóa tất cả',\n\n // Trading\n buy: 'Mua',\n sell: 'Bán',\n buyLimit: 'Mua giới hạn',\n sellLimit: 'Bán giới hạn',\n buyStop: 'Mua chặn',\n sellStop: 'Bán chặn',\n stopLoss: 'Cắt lỗ',\n takeProfit: 'Chốt lời',\n market: 'Thị trường',\n limit: 'Giới hạn',\n stop: 'Dừng',\n cancel: 'Hủy',\n modify: 'Sửa',\n quantity: 'KL',\n pnl: 'Lãi/Lỗ',\n activeOrders: 'Lệnh chờ',\n positions: 'Vị thế',\n noOrders: 'Không có lệnh chờ',\n noPositions: 'Không có vị thế mở',\n placeOrder: 'Đặt lệnh',\n rightClickToTrade: 'Nhấp chuột phải để đặt lệnh',\n\n // Market\n ceiling: 'Trần',\n floor: 'Sàn',\n reference: 'Tham chiếu',\n session: 'Phiên',\n preOpen: 'Trước giờ mở',\n continuous: 'Liên tục',\n preClose: 'Trước giờ đóng',\n closed: 'Đóng cửa',\n\n // UI\n settings: 'Cài đặt',\n theme: 'Giao diện',\n darkTheme: 'Tối',\n lightTheme: 'Sáng',\n tools: 'Công cụ',\n indicators: 'Chỉ báo',\n overlays: 'Phủ lên',\n panels: 'Bảng',\n orders: 'Lệnh',\n autoScale: 'Tự co giãn',\n crosshair: 'Chữ thập',\n grid: 'Lưới',\n loading: 'Đang tải...',\n error: 'Lỗi',\n\n numberDecimalSeparator: ',',\n numberGroupSeparator: '.',\n};\n","export type { Locale, LocaleStrings, NumberFormatConfig, DateFormatConfig } from './types.js';\nexport { en } from './en.js';\nexport { vi } from './vi.js';\n\nimport type { Locale, LocaleStrings } from './types.js';\nimport { en } from './en.js';\nimport { vi } from './vi.js';\n\nconst locales = new Map<string, LocaleStrings>([\n ['en', en],\n ['vi', vi],\n]);\n\nlet currentLocale: Locale = 'en';\nlet currentStrings: LocaleStrings = en;\n\nexport function setLocale(locale: Locale): void {\n currentLocale = locale;\n currentStrings = locales.get(locale) ?? en;\n}\n\nexport function getLocale(): Locale {\n return currentLocale;\n}\n\nexport function t(key: keyof LocaleStrings): string {\n return currentStrings[key] ?? (en as any)[key] ?? key;\n}\n\nexport function registerLocale(locale: string, strings: LocaleStrings): void {\n locales.set(locale, strings);\n}\n\nexport function getLocaleStrings(locale?: string): LocaleStrings {\n return locales.get(locale ?? currentLocale) ?? en;\n}\n\n// Number formatting\nexport function formatNumber(value: number, precision = 2, locale?: string): string {\n const strings = locales.get(locale ?? currentLocale) ?? en;\n const dec = strings.numberDecimalSeparator;\n const grp = strings.numberGroupSeparator;\n\n const fixed = value.toFixed(precision);\n const [intPart, decPart] = fixed.split('.');\n\n // Group integer part\n const negative = intPart.startsWith('-');\n const digits = negative ? intPart.slice(1) : intPart;\n let grouped = '';\n for (let i = digits.length - 1, count = 0; i >= 0; i--, count++) {\n if (count > 0 && count % 3 === 0) grouped = grp + grouped;\n grouped = digits[i] + grouped;\n }\n if (negative) grouped = '-' + grouped;\n\n return decPart ? grouped + dec + decPart : grouped;\n}\n\nexport function formatVND(value: number): string {\n return formatNumber(value, 0, 'vi');\n}\n\nexport function formatVolumeLoc(value: number, locale?: string): string {\n if (value >= 1e9) return formatNumber(value / 1e9, 2, locale ?? currentLocale) + 'B';\n if (value >= 1e6) return formatNumber(value / 1e6, 2, locale ?? currentLocale) + 'M';\n if (value >= 1e3) return formatNumber(value / 1e3, 2, locale ?? currentLocale) + 'K';\n return formatNumber(value, 0, locale ?? currentLocale);\n}\n","import type { MarketConfig, MarketColorScheme, TradingSession } from './types.js';\nimport type { Theme } from '../types/theme.js';\n\n// Vietnam stock color convention:\n// Purple/Red = ceiling (trần) - max up\n// Green/Cyan = floor (sàn) - max down\n// Yellow = reference (tham chiếu)\n// Red = up, Blue = down (common VN convention)\nexport const VN_COLORS: MarketColorScheme = {\n up: '#FF0000', // Đỏ - tăng\n down: '#0000FF', // Xanh dương - giảm\n unchanged: '#FFD700', // Vàng - tham chiếu\n ceiling: '#FF00FF', // Tím - trần\n floor: '#00FFFF', // Xanh lam - sàn\n reference: '#FFD700', // Vàng - tham chiếu\n};\n\nexport const HOSE_SESSIONS: TradingSession[] = [\n { name: 'ATO', startTime: '09:00', endTime: '09:15', type: 'preOpen' },\n { name: 'Phiên 1', startTime: '09:15', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\nexport const HNX_SESSIONS: TradingSession[] = [\n { name: 'Phiên 1', startTime: '09:00', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\n// Market presets\nexport const MARKET_HOSE: MarketConfig = {\n type: 'stock',\n exchange: 'HOSE',\n currency: 'VND',\n pricePrecision: 2,\n volumeUnit: 10,\n priceStep: 0.05,\n priceLimits: { enabled: true, ceilingPercent: 7, floorPercent: 7 },\n sessions: HOSE_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_HNX: MarketConfig = {\n type: 'stock',\n exchange: 'HNX',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n priceLimits: { enabled: true, ceilingPercent: 10, floorPercent: 10 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_UPCOM: MarketConfig = {\n type: 'stock',\n exchange: 'UPCOM',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n priceLimits: { enabled: true, ceilingPercent: 15, floorPercent: 15 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_CRYPTO: MarketConfig = {\n type: 'crypto',\n currency: 'USDT',\n pricePrecision: 2,\n priceLimits: { enabled: false },\n};\n\nexport const MARKET_NYSE: MarketConfig = {\n type: 'stock',\n exchange: 'NYSE',\n currency: 'USD',\n pricePrecision: 2,\n priceStep: 0.01,\n priceLimits: { enabled: false },\n sessions: [\n { name: 'Pre-Market', startTime: '04:00', endTime: '09:30', type: 'preOpen' },\n { name: 'Regular', startTime: '09:30', endTime: '16:00', type: 'continuous' },\n { name: 'After-Hours', startTime: '16:00', endTime: '20:00', type: 'preClose' },\n ],\n};\n\n// Build a theme variant for VN stock market\nexport function createVNTheme(base: Theme): Theme {\n return {\n ...base,\n candleUp: VN_COLORS.up,\n candleDown: VN_COLORS.down,\n candleUpWick: VN_COLORS.up,\n candleDownWick: VN_COLORS.down,\n volumeUp: 'rgba(255, 0, 0, 0.3)',\n volumeDown: 'rgba(0, 0, 255, 0.3)',\n };\n}\n\nexport function computePriceLimits(referencePrice: number, config: MarketConfig): { ceiling: number; floor: number; reference: number } | null {\n if (!config.priceLimits?.enabled || !config.priceLimits.ceilingPercent) return null;\n const ceilPct = config.priceLimits.ceilingPercent / 100;\n const floorPct = (config.priceLimits.floorPercent ?? config.priceLimits.ceilingPercent) / 100;\n return {\n ceiling: referencePrice * (1 + ceilPct),\n floor: referencePrice * (1 - floorPct),\n reference: referencePrice,\n };\n}\n\nexport function getCurrentSession(sessions: TradingSession[]): TradingSession | null {\n const now = new Date();\n const hhmm = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;\n for (const session of sessions) {\n if (hhmm >= session.startTime && hhmm < session.endTime) return session;\n }\n return null;\n}\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -109,14 +109,22 @@ function m(e, t) {
|
|
|
109
109
|
function h(e, t = 1) {
|
|
110
110
|
return `rgba(${parseInt(e.slice(1, 3), 16)}, ${parseInt(e.slice(3, 5), 16)}, ${parseInt(e.slice(5, 7), 16)}, ${t})`;
|
|
111
111
|
}
|
|
112
|
-
function
|
|
112
|
+
function g(e, t) {
|
|
113
113
|
if (e.startsWith("#")) return h(e, t);
|
|
114
114
|
let n = e.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
|
|
115
115
|
return n ? `rgba(${n[1]}, ${n[2]}, ${n[3]}, ${t})` : e;
|
|
116
116
|
}
|
|
117
|
+
function _(e, t, n) {
|
|
118
|
+
let r = (e) => (e = e.replace("#", ""), e.length === 3 && (e = e[0] + e[0] + e[1] + e[1] + e[2] + e[2]), {
|
|
119
|
+
r: parseInt(e.slice(0, 2), 16),
|
|
120
|
+
g: parseInt(e.slice(2, 4), 16),
|
|
121
|
+
b: parseInt(e.slice(4, 6), 16)
|
|
122
|
+
}), i = r(e), a = r(t);
|
|
123
|
+
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)})`;
|
|
124
|
+
}
|
|
117
125
|
//#endregion
|
|
118
126
|
//#region src/utils/time.ts
|
|
119
|
-
var
|
|
127
|
+
var v = {
|
|
120
128
|
"1s": 1e3,
|
|
121
129
|
"5s": 5e3,
|
|
122
130
|
"15s": 15e3,
|
|
@@ -144,11 +152,11 @@ var g = {
|
|
|
144
152
|
"6M": 15552e6,
|
|
145
153
|
"12M": 31536e6
|
|
146
154
|
};
|
|
147
|
-
function
|
|
148
|
-
return
|
|
155
|
+
function y(e) {
|
|
156
|
+
return v[e];
|
|
149
157
|
}
|
|
150
|
-
function
|
|
151
|
-
let n = new Date(e), r =
|
|
158
|
+
function b(e, t) {
|
|
159
|
+
let n = new Date(e), r = v[t];
|
|
152
160
|
return r >= 864e5 ? n.toLocaleDateString(void 0, {
|
|
153
161
|
month: "short",
|
|
154
162
|
day: "numeric"
|
|
@@ -161,19 +169,19 @@ function v(e, t) {
|
|
|
161
169
|
second: "2-digit"
|
|
162
170
|
});
|
|
163
171
|
}
|
|
164
|
-
function
|
|
165
|
-
let n =
|
|
172
|
+
function x(e, t) {
|
|
173
|
+
let n = v[t];
|
|
166
174
|
return Math.floor(e / n) * n;
|
|
167
175
|
}
|
|
168
176
|
//#endregion
|
|
169
177
|
//#region src/utils/precision.ts
|
|
170
|
-
function
|
|
178
|
+
function ee(e, t = 2) {
|
|
171
179
|
return e.toFixed(t);
|
|
172
180
|
}
|
|
173
|
-
function
|
|
181
|
+
function S(e) {
|
|
174
182
|
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);
|
|
175
183
|
}
|
|
176
|
-
function
|
|
184
|
+
function C(e) {
|
|
177
185
|
let t = 0;
|
|
178
186
|
for (let n of e) {
|
|
179
187
|
let e = n.toString(), r = e.indexOf(".");
|
|
@@ -183,7 +191,7 @@ function S(e) {
|
|
|
183
191
|
}
|
|
184
192
|
//#endregion
|
|
185
193
|
//#region src/constants/defaults.ts
|
|
186
|
-
var
|
|
194
|
+
var w = {
|
|
187
195
|
autoScale: !0,
|
|
188
196
|
rightMargin: 5,
|
|
189
197
|
minBarSpacing: 2,
|
|
@@ -194,7 +202,7 @@ var C = {
|
|
|
194
202
|
vLineStyle: "solid"
|
|
195
203
|
},
|
|
196
204
|
crosshair: { mode: "magnet" }
|
|
197
|
-
},
|
|
205
|
+
}, T = [
|
|
198
206
|
"1s",
|
|
199
207
|
"1m",
|
|
200
208
|
"3m",
|
|
@@ -211,7 +219,7 @@ var C = {
|
|
|
211
219
|
"3d",
|
|
212
220
|
"1w",
|
|
213
221
|
"1M"
|
|
214
|
-
],
|
|
222
|
+
], E = [
|
|
215
223
|
"1m",
|
|
216
224
|
"5m",
|
|
217
225
|
"15m",
|
|
@@ -225,7 +233,7 @@ var C = {
|
|
|
225
233
|
"3M",
|
|
226
234
|
"6M",
|
|
227
235
|
"12M"
|
|
228
|
-
],
|
|
236
|
+
], D = [
|
|
229
237
|
"1m",
|
|
230
238
|
"5m",
|
|
231
239
|
"15m",
|
|
@@ -235,7 +243,7 @@ var C = {
|
|
|
235
243
|
"1d",
|
|
236
244
|
"1w",
|
|
237
245
|
"1M"
|
|
238
|
-
],
|
|
246
|
+
], O = [
|
|
239
247
|
"1m",
|
|
240
248
|
"5m",
|
|
241
249
|
"15m",
|
|
@@ -243,12 +251,12 @@ var C = {
|
|
|
243
251
|
"4h",
|
|
244
252
|
"1d",
|
|
245
253
|
"1w"
|
|
246
|
-
],
|
|
254
|
+
], k = 8, A = 2, j = 70, M = 30, N = 60, P = 120, F = {
|
|
247
255
|
family: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif",
|
|
248
256
|
sizeSmall: 10,
|
|
249
257
|
sizeMedium: 12,
|
|
250
258
|
sizeLarge: 14
|
|
251
|
-
},
|
|
259
|
+
}, I = {
|
|
252
260
|
name: "dark",
|
|
253
261
|
background: "#131722",
|
|
254
262
|
text: "#D1D4DC",
|
|
@@ -267,8 +275,8 @@ var C = {
|
|
|
267
275
|
axisLine: "#2A2E39",
|
|
268
276
|
axisLabel: "#D1D4DC",
|
|
269
277
|
axisLabelBackground: "#2A2E39",
|
|
270
|
-
font:
|
|
271
|
-
},
|
|
278
|
+
font: F
|
|
279
|
+
}, L = {
|
|
272
280
|
name: "light",
|
|
273
281
|
background: "#FFFFFF",
|
|
274
282
|
text: "#131722",
|
|
@@ -287,8 +295,8 @@ var C = {
|
|
|
287
295
|
axisLine: "#E0E3EB",
|
|
288
296
|
axisLabel: "#131722",
|
|
289
297
|
axisLabelBackground: "#F0F3FA",
|
|
290
|
-
font:
|
|
291
|
-
},
|
|
298
|
+
font: F
|
|
299
|
+
}, R = {
|
|
292
300
|
candlestick: "Candlestick",
|
|
293
301
|
line: "Line",
|
|
294
302
|
area: "Area",
|
|
@@ -391,7 +399,7 @@ var C = {
|
|
|
391
399
|
error: "Error",
|
|
392
400
|
numberDecimalSeparator: ".",
|
|
393
401
|
numberGroupSeparator: ","
|
|
394
|
-
},
|
|
402
|
+
}, z = {
|
|
395
403
|
candlestick: "Nến",
|
|
396
404
|
line: "Đường",
|
|
397
405
|
area: "Vùng",
|
|
@@ -494,43 +502,43 @@ var C = {
|
|
|
494
502
|
error: "Lỗi",
|
|
495
503
|
numberDecimalSeparator: ",",
|
|
496
504
|
numberGroupSeparator: "."
|
|
497
|
-
},
|
|
498
|
-
function
|
|
499
|
-
|
|
505
|
+
}, B = new Map([["en", R], ["vi", z]]), V = "en", H = R;
|
|
506
|
+
function U(e) {
|
|
507
|
+
V = e, H = B.get(e) ?? R;
|
|
500
508
|
}
|
|
501
|
-
function
|
|
502
|
-
return
|
|
509
|
+
function W() {
|
|
510
|
+
return V;
|
|
503
511
|
}
|
|
504
|
-
function
|
|
505
|
-
return
|
|
512
|
+
function G(e) {
|
|
513
|
+
return H[e] ?? R[e] ?? e;
|
|
506
514
|
}
|
|
507
|
-
function
|
|
508
|
-
|
|
515
|
+
function K(e, t) {
|
|
516
|
+
B.set(e, t);
|
|
509
517
|
}
|
|
510
|
-
function
|
|
511
|
-
return
|
|
518
|
+
function q(e) {
|
|
519
|
+
return B.get(e ?? V) ?? R;
|
|
512
520
|
}
|
|
513
|
-
function
|
|
514
|
-
let r =
|
|
521
|
+
function J(e, t = 2, n) {
|
|
522
|
+
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 = "";
|
|
515
523
|
for (let e = l.length - 1, t = 0; e >= 0; e--, t++) t > 0 && t % 3 == 0 && (u = a + u), u = l[e] + u;
|
|
516
524
|
return c && (u = "-" + u), s ? u + i + s : u;
|
|
517
525
|
}
|
|
518
|
-
function
|
|
519
|
-
return
|
|
526
|
+
function Y(e) {
|
|
527
|
+
return J(e, 0, "vi");
|
|
520
528
|
}
|
|
521
|
-
function
|
|
522
|
-
return e >= 1e9 ?
|
|
529
|
+
function X(e, t) {
|
|
530
|
+
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);
|
|
523
531
|
}
|
|
524
532
|
//#endregion
|
|
525
533
|
//#region src/market/presets.ts
|
|
526
|
-
var
|
|
534
|
+
var Z = {
|
|
527
535
|
up: "#FF0000",
|
|
528
536
|
down: "#0000FF",
|
|
529
537
|
unchanged: "#FFD700",
|
|
530
538
|
ceiling: "#FF00FF",
|
|
531
539
|
floor: "#00FFFF",
|
|
532
540
|
reference: "#FFD700"
|
|
533
|
-
},
|
|
541
|
+
}, Q = [
|
|
534
542
|
{
|
|
535
543
|
name: "ATO",
|
|
536
544
|
startTime: "09:00",
|
|
@@ -561,7 +569,7 @@ var X = {
|
|
|
561
569
|
endTime: "14:45",
|
|
562
570
|
type: "preClose"
|
|
563
571
|
}
|
|
564
|
-
],
|
|
572
|
+
], $ = [
|
|
565
573
|
{
|
|
566
574
|
name: "Phiên 1",
|
|
567
575
|
startTime: "09:00",
|
|
@@ -586,7 +594,7 @@ var X = {
|
|
|
586
594
|
endTime: "14:45",
|
|
587
595
|
type: "preClose"
|
|
588
596
|
}
|
|
589
|
-
],
|
|
597
|
+
], te = {
|
|
590
598
|
type: "stock",
|
|
591
599
|
exchange: "HOSE",
|
|
592
600
|
currency: "VND",
|
|
@@ -598,9 +606,9 @@ var X = {
|
|
|
598
606
|
ceilingPercent: 7,
|
|
599
607
|
floorPercent: 7
|
|
600
608
|
},
|
|
601
|
-
sessions:
|
|
602
|
-
colorScheme:
|
|
603
|
-
},
|
|
609
|
+
sessions: Q,
|
|
610
|
+
colorScheme: Z
|
|
611
|
+
}, ne = {
|
|
604
612
|
type: "stock",
|
|
605
613
|
exchange: "HNX",
|
|
606
614
|
currency: "VND",
|
|
@@ -612,9 +620,9 @@ var X = {
|
|
|
612
620
|
ceilingPercent: 10,
|
|
613
621
|
floorPercent: 10
|
|
614
622
|
},
|
|
615
|
-
sessions:
|
|
616
|
-
colorScheme:
|
|
617
|
-
},
|
|
623
|
+
sessions: $,
|
|
624
|
+
colorScheme: Z
|
|
625
|
+
}, re = {
|
|
618
626
|
type: "stock",
|
|
619
627
|
exchange: "UPCOM",
|
|
620
628
|
currency: "VND",
|
|
@@ -626,14 +634,14 @@ var X = {
|
|
|
626
634
|
ceilingPercent: 15,
|
|
627
635
|
floorPercent: 15
|
|
628
636
|
},
|
|
629
|
-
sessions:
|
|
630
|
-
colorScheme:
|
|
631
|
-
},
|
|
637
|
+
sessions: $,
|
|
638
|
+
colorScheme: Z
|
|
639
|
+
}, ie = {
|
|
632
640
|
type: "crypto",
|
|
633
641
|
currency: "USDT",
|
|
634
642
|
pricePrecision: 2,
|
|
635
643
|
priceLimits: { enabled: !1 }
|
|
636
|
-
},
|
|
644
|
+
}, ae = {
|
|
637
645
|
type: "stock",
|
|
638
646
|
exchange: "NYSE",
|
|
639
647
|
currency: "USD",
|
|
@@ -661,18 +669,18 @@ var X = {
|
|
|
661
669
|
}
|
|
662
670
|
]
|
|
663
671
|
};
|
|
664
|
-
function
|
|
672
|
+
function oe(e) {
|
|
665
673
|
return {
|
|
666
674
|
...e,
|
|
667
|
-
candleUp:
|
|
668
|
-
candleDown:
|
|
669
|
-
candleUpWick:
|
|
670
|
-
candleDownWick:
|
|
675
|
+
candleUp: Z.up,
|
|
676
|
+
candleDown: Z.down,
|
|
677
|
+
candleUpWick: Z.up,
|
|
678
|
+
candleDownWick: Z.down,
|
|
671
679
|
volumeUp: "rgba(255, 0, 0, 0.3)",
|
|
672
680
|
volumeDown: "rgba(0, 0, 255, 0.3)"
|
|
673
681
|
};
|
|
674
682
|
}
|
|
675
|
-
function
|
|
683
|
+
function se(e, t) {
|
|
676
684
|
if (!t.priceLimits?.enabled || !t.priceLimits.ceilingPercent) return null;
|
|
677
685
|
let n = t.priceLimits.ceilingPercent / 100, r = (t.priceLimits.floorPercent ?? t.priceLimits.ceilingPercent) / 100;
|
|
678
686
|
return {
|
|
@@ -681,12 +689,12 @@ function oe(e, t) {
|
|
|
681
689
|
reference: e
|
|
682
690
|
};
|
|
683
691
|
}
|
|
684
|
-
function
|
|
692
|
+
function ce(e) {
|
|
685
693
|
let t = /* @__PURE__ */ new Date(), n = `${String(t.getHours()).padStart(2, "0")}:${String(t.getMinutes()).padStart(2, "0")}`;
|
|
686
694
|
for (let t of e) if (n >= t.startTime && n < t.endTime) return t;
|
|
687
695
|
return null;
|
|
688
696
|
}
|
|
689
697
|
//#endregion
|
|
690
|
-
export {
|
|
698
|
+
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 };
|
|
691
699
|
|
|
692
700
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/types/rendering.ts","../src/types/drawing.ts","../src/types/trading.ts","../src/types/realtime.ts","../src/utils/math.ts","../src/utils/data.ts","../src/utils/color.ts","../src/utils/time.ts","../src/utils/precision.ts","../src/constants/defaults.ts","../src/constants/themes.ts","../src/i18n/en.ts","../src/i18n/vi.ts","../src/i18n/index.ts","../src/market/presets.ts"],"sourcesContent":["export interface Point {\n x: number;\n y: number;\n}\n\nexport interface Size {\n width: number;\n height: number;\n}\n\nexport interface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface ViewportState {\n visibleRange: { from: number; to: number };\n priceRange: { min: number; max: number };\n barWidth: number;\n barSpacing: number;\n offset: number;\n chartRect: Rect;\n logScale?: boolean;\n}\n\nexport enum LayerType {\n Background = 0,\n Main = 1,\n Panel = 2,\n Overlay = 3,\n UI = 4,\n}\n","import type { Point, ViewportState } from './rendering.js';\n\nexport type DrawingToolType =\n | 'trendLine' | 'horizontalLine' | 'verticalLine' | 'ray' | 'extendedLine'\n | 'parallelChannel' | 'regressionChannel'\n | 'fibRetracement' | 'fibExtension'\n | 'rectangle' | 'ellipse' | 'triangle'\n | 'pitchfork' | 'elliottWave'\n | 'priceRange' | 'dateRange' | 'measure'\n | 'text' | 'arrow'\n | 'gannFan' | 'gannBox'\n | 'anchoredVWAP'\n | 'volumeProfileRange';\n\nexport interface AnchorPoint {\n time: number;\n price: number;\n}\n\nexport interface DrawingStyle {\n color: string;\n lineWidth: number;\n lineStyle: 'solid' | 'dashed' | 'dotted';\n fillColor?: string;\n fillOpacity?: number;\n fontSize?: number;\n text?: string;\n}\n\nexport interface DrawingState {\n id: string;\n type: DrawingToolType;\n anchors: AnchorPoint[];\n style: DrawingStyle;\n visible: boolean;\n locked: boolean;\n meta?: Record<string, unknown>;\n}\n\nexport interface DrawingDescriptor {\n type: DrawingToolType;\n name: string;\n requiredAnchors: number;\n singleClick?: boolean;\n}\n\nexport interface DrawingPlugin {\n descriptor: DrawingDescriptor;\n render(\n ctx: CanvasRenderingContext2D,\n state: DrawingState,\n viewport: ViewportState,\n selected: boolean,\n ): void;\n hitTest(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): boolean;\n hitTestAnchor(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): number;\n}\n\nexport const DEFAULT_DRAWING_STYLE: DrawingStyle = {\n color: '#2196F3',\n lineWidth: 1,\n lineStyle: 'solid',\n fillColor: 'rgba(33, 150, 243, 0.1)',\n fillOpacity: 0.1,\n fontSize: 12,\n};\n","export type OrderSide = 'buy' | 'sell';\nexport type OrderType = 'market' | 'limit' | 'stop' | 'stopLimit';\nexport type OrderStatus = 'pending' | 'filled' | 'cancelled' | 'rejected';\nexport type OrderLabel = 'LIMIT' | 'STOP' | 'SL' | 'TP' | 'STOP LIMIT';\n\nexport interface TradingOrder {\n id: string;\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity: number;\n label?: OrderLabel;\n draggable?: boolean;\n meta?: Record<string, unknown>;\n}\n\nexport interface TradingPosition {\n id: string;\n side: OrderSide;\n entryPrice: number;\n quantity: number;\n stopLoss?: number;\n takeProfit?: number;\n meta?: Record<string, unknown>;\n}\n\nexport interface DepthLevel {\n price: number;\n volume: number;\n}\n\nexport interface DepthData {\n bids: DepthLevel[];\n asks: DepthLevel[];\n}\n\nexport interface TradingConfig {\n enabled: boolean;\n orderColors?: { buy?: string; sell?: string };\n positionColors?: { profit?: string; loss?: string; entry?: string };\n depthOverlay?: {\n enabled?: boolean;\n bidColor?: string;\n askColor?: string;\n maxWidth?: number;\n };\n contextMenu?: { enabled?: boolean };\n pricePrecision?: number;\n dragThreshold?: number;\n}\n\nexport interface OrderPlaceIntent {\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity?: number;\n}\n\nexport interface OrderModifyIntent {\n orderId: string;\n newPrice: number;\n previousPrice: number;\n}\n\nexport interface OrderCancelIntent {\n orderId: string;\n}\n\nexport interface PositionModifyIntent {\n positionId: string;\n stopLoss?: number;\n takeProfit?: number;\n}\n\nexport interface PositionCloseIntent {\n positionId: string;\n}\n\nexport const DEFAULT_TRADING_CONFIG: TradingConfig = {\n enabled: true,\n orderColors: { buy: '#26A69A', sell: '#EF5350' },\n positionColors: { profit: '#26A69A', loss: '#EF5350', entry: '#2196F3' },\n depthOverlay: { enabled: false, bidColor: 'rgba(38,166,154,0.15)', askColor: 'rgba(239,83,80,0.15)', maxWidth: 100 },\n contextMenu: { enabled: true },\n pricePrecision: 2,\n dragThreshold: 3,\n};\n","import type { OHLCBar, TimeFrame } from './ohlc.js';\n\n// --- Connection ---\n\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';\n\nexport interface ConnectionInfo {\n state: ConnectionState;\n latency?: number;\n reconnectAttempt?: number;\n lastMessageTime?: number;\n error?: string;\n}\n\n// --- Ticks & Trades ---\n\nexport interface RawTick {\n time: number;\n price: number;\n volume: number;\n side?: 'buy' | 'sell';\n}\n\nexport interface AggregatedBar extends OHLCBar {\n closed: boolean; // true when bar is finalized\n tickCount: number; // number of ticks in this bar\n}\n\n// --- Data Adapter (Strategy Pattern) ---\n\nexport interface DataAdapterConfig {\n symbol: string;\n timeframe: TimeFrame;\n reconnect?: boolean; // default: true\n reconnectMaxRetries?: number; // default: Infinity\n reconnectBaseDelay?: number; // ms, default: 1000\n reconnectMaxDelay?: number; // ms, default: 30000\n heartbeatInterval?: number; // ms, default: 30000\n bufferSize?: number; // max ticks to buffer, default: 1000\n}\n\nexport type DataAdapterEventType =\n | 'tick'\n | 'bar'\n | 'barClose'\n | 'snapshot' // initial historical data loaded\n | 'connectionChange'\n | 'error';\n\nexport interface DataAdapterEvent<T = unknown> {\n type: DataAdapterEventType;\n data: T;\n timestamp: number;\n}\n\nexport type DataAdapterListener<T = unknown> = (event: DataAdapterEvent<T>) => void;\n\n/**\n * DataAdapter interface — Strategy pattern for pluggable data sources.\n *\n * Implementations handle the specifics of each data source (WebSocket, REST,\n * SSE, etc.) while the StreamManager orchestrates lifecycle and aggregation.\n *\n * Built-in: BinanceAdapter\n * Implement this for: custom exchange APIs, broker feeds, mock data\n */\nexport interface DataAdapter {\n readonly name: string;\n\n connect(config: DataAdapterConfig): void;\n disconnect(): void;\n getConnectionState(): ConnectionState;\n\n /**\n * Load historical bars. Called once on connect, before streaming starts.\n * Returns bars sorted by time ascending.\n */\n fetchHistory(symbol: string, timeframe: TimeFrame, limit?: number): Promise<OHLCBar[]>;\n\n on<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n off<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n\n dispose(): void;\n}\n\n// --- Stream Manager Config ---\n\nexport interface StreamConfig {\n adapter: DataAdapter;\n symbol: string;\n timeframe: TimeFrame;\n historyLimit?: number; // bars to load initially, default: 500\n autoScroll?: boolean; // scroll to end on new bar, default: true\n showCurrentPriceLine?: boolean; // default: true\n aggregateTicks?: boolean; // build bars from ticks, default: false\n reconnect?: ReconnectConfig;\n}\n\nexport interface ReconnectConfig {\n enabled: boolean; // default: true\n maxRetries: number; // default: Infinity\n baseDelay: number; // ms, default: 1000\n maxDelay: number; // ms, default: 30000\n backoffMultiplier: number; // default: 2\n}\n\nexport const DEFAULT_RECONNECT: ReconnectConfig = {\n enabled: true,\n maxRetries: Infinity,\n baseDelay: 1000,\n maxDelay: 30000,\n backoffMultiplier: 2,\n};\n\nexport const DEFAULT_STREAM_CONFIG: Partial<StreamConfig> = {\n historyLimit: 500,\n autoScroll: true,\n showCurrentPriceLine: true,\n aggregateTicks: false,\n};\n","export function clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nexport function inverseLerp(a: number, b: number, value: number): number {\n if (a === b) return 0;\n return (value - a) / (b - a);\n}\n\nexport function roundToStep(value: number, step: number): number {\n return Math.round(value / step) * step;\n}\n\nexport function niceNumber(value: number, round: boolean): number {\n const exp = Math.floor(Math.log10(value));\n const frac = value / Math.pow(10, exp);\n let nice: number;\n if (round) {\n if (frac < 1.5) nice = 1;\n else if (frac < 3) nice = 2;\n else if (frac < 7) nice = 5;\n else nice = 10;\n } else {\n if (frac <= 1) nice = 1;\n else if (frac <= 2) nice = 2;\n else if (frac <= 5) nice = 5;\n else nice = 10;\n }\n return nice * Math.pow(10, exp);\n}\n\nexport function computeTickStep(min: number, max: number, maxTicks: number): number {\n const range = niceNumber(max - min, false);\n return niceNumber(range / (maxTicks - 1), true);\n}\n","import type { OHLCBar, DataSeries } from '../types/ohlc.js';\n\nexport function sliceVisibleData(\n data: DataSeries,\n from: number,\n to: number,\n): DataSeries {\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length, to + 1);\n return data.slice(startIdx, endIdx);\n}\n\nexport function findBarIndex(data: DataSeries, timestamp: number): number {\n let lo = 0;\n let hi = data.length - 1;\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n if (data[mid].time < timestamp) lo = mid + 1;\n else if (data[mid].time > timestamp) hi = mid - 1;\n else return mid;\n }\n return lo;\n}\n\nexport function computePriceRange(\n data: DataSeries,\n from: number,\n to: number,\n padding = 0.05,\n): { min: number; max: number } {\n if (data.length === 0) return { min: 0, max: 1 };\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length - 1, to);\n let min = Infinity;\n let max = -Infinity;\n for (let i = startIdx; i <= endIdx; i++) {\n if (data[i].low < min) min = data[i].low;\n if (data[i].high > max) max = data[i].high;\n }\n if (min === Infinity) return { min: 0, max: 1 };\n const range = max - min || 1;\n return {\n min: min - range * padding,\n max: max + range * padding,\n };\n}\n\nexport function mergeBar(existing: OHLCBar, tick: { price: number; volume?: number; time: number }): OHLCBar {\n return {\n ...existing,\n high: Math.max(existing.high, tick.price),\n low: Math.min(existing.low, tick.price),\n close: tick.price,\n volume: existing.volume + (tick.volume ?? 0),\n time: tick.time,\n };\n}\n","export function hexToRgba(hex: string, alpha = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\nexport function withAlpha(color: string, alpha: number): string {\n if (color.startsWith('#')) {\n return hexToRgba(color, alpha);\n }\n const rgbaMatch = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (rgbaMatch) {\n return `rgba(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]}, ${alpha})`;\n }\n return color;\n}\n","import type { TimeFrame } from '../types/ohlc.js';\n\nconst TIMEFRAME_MS: Record<TimeFrame, number> = {\n '1s': 1_000,\n '5s': 5_000,\n '15s': 15_000,\n '30s': 30_000,\n '1m': 60_000,\n '3m': 180_000,\n '5m': 300_000,\n '15m': 900_000,\n '30m': 1_800_000,\n '45m': 2_700_000,\n '1h': 3_600_000,\n '2h': 7_200_000,\n '3h': 10_800_000,\n '4h': 14_400_000,\n '6h': 21_600_000,\n '8h': 28_800_000,\n '12h': 43_200_000,\n '1d': 86_400_000,\n '2d': 172_800_000,\n '3d': 259_200_000,\n '1w': 604_800_000,\n '2w': 1_209_600_000,\n '1M': 2_592_000_000,\n '3M': 7_776_000_000,\n '6M': 15_552_000_000,\n '12M': 31_536_000_000,\n};\n\nexport function timeframeToMs(tf: TimeFrame): number {\n return TIMEFRAME_MS[tf];\n}\n\nexport function formatTimestamp(timestamp: number, tf: TimeFrame): string {\n const d = new Date(timestamp);\n const ms = TIMEFRAME_MS[tf];\n if (ms >= 86_400_000) {\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }\n if (ms >= 3_600_000) {\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\n }\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\nexport function alignToTimeframe(timestamp: number, tf: TimeFrame): number {\n const ms = TIMEFRAME_MS[tf];\n return Math.floor(timestamp / ms) * ms;\n}\n","export function formatPrice(value: number, precision = 2): string {\n return value.toFixed(precision);\n}\n\nexport function formatVolume(value: number): string {\n if (value >= 1_000_000_000) return (value / 1_000_000_000).toFixed(2) + 'B';\n if (value >= 1_000_000) return (value / 1_000_000).toFixed(2) + 'M';\n if (value >= 1_000) return (value / 1_000).toFixed(2) + 'K';\n return value.toFixed(0);\n}\n\nexport function detectPrecision(values: number[]): number {\n let maxDecimals = 0;\n for (const v of values) {\n const str = v.toString();\n const dot = str.indexOf('.');\n if (dot >= 0) {\n maxDecimals = Math.max(maxDecimals, str.length - dot - 1);\n }\n }\n return Math.min(maxDecimals, 8);\n}\n","import type { ChartOptions } from '../types/chart.js';\n\nexport const DEFAULT_CHART_OPTIONS: Required<Pick<ChartOptions, 'autoScale' | 'rightMargin' | 'minBarSpacing' | 'maxBarSpacing'>> & Pick<ChartOptions, 'grid' | 'crosshair'> = {\n autoScale: true,\n rightMargin: 5,\n minBarSpacing: 2,\n maxBarSpacing: 30,\n grid: {\n visible: true,\n hLineStyle: 'solid',\n vLineStyle: 'solid',\n },\n crosshair: {\n mode: 'magnet',\n },\n};\n\n// Standard timeframe presets for different market types\nimport type { TimeFrame } from '../types/ohlc.js';\n\n/** Crypto: all timeframes including seconds */\nexport const TIMEFRAMES_CRYPTO: TimeFrame[] = [\n '1s', '1m', '3m', '5m', '15m', '30m',\n '1h', '2h', '4h', '6h', '8h', '12h',\n '1d', '3d', '1w', '1M',\n];\n\n/** Stocks: minute-level and above (no seconds) */\nexport const TIMEFRAMES_STOCK: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '2h', '4h',\n '1d', '1w', '1M', '3M', '6M', '12M',\n];\n\n/** Forex: common forex timeframes */\nexport const TIMEFRAMES_FOREX: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '4h',\n '1d', '1w', '1M',\n];\n\n/** Default favorites shown in quick-access bar */\nexport const DEFAULT_TIMEFRAME_FAVORITES: TimeFrame[] = [\n '1m', '5m', '15m', '1h', '4h', '1d', '1w',\n];\n\nexport const DEFAULT_BAR_WIDTH = 8;\nexport const DEFAULT_BAR_SPACING = 2;\nexport const PRICE_AXIS_WIDTH = 70;\nexport const TIME_AXIS_HEIGHT = 30;\nexport const MIN_PANEL_HEIGHT = 60;\nexport const DEFAULT_PANEL_HEIGHT = 120;\n","import type { Theme } from '../types/theme.js';\n\nconst DEFAULT_FONT = {\n family: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n sizeSmall: 10,\n sizeMedium: 12,\n sizeLarge: 14,\n};\n\nexport const DARK_THEME: Theme = {\n name: 'dark',\n background: '#131722',\n text: '#D1D4DC',\n textSecondary: '#787B86',\n grid: '#1E222D',\n crosshair: '#9598A1',\n candleUp: '#26A69A',\n candleDown: '#EF5350',\n candleUpWick: '#26A69A',\n candleDownWick: '#EF5350',\n lineColor: '#2196F3',\n areaTopColor: 'rgba(33, 150, 243, 0.4)',\n areaBottomColor: 'rgba(33, 150, 243, 0.0)',\n volumeUp: 'rgba(38, 166, 154, 0.3)',\n volumeDown: 'rgba(239, 83, 80, 0.3)',\n axisLine: '#2A2E39',\n axisLabel: '#D1D4DC',\n axisLabelBackground: '#2A2E39',\n font: DEFAULT_FONT,\n};\n\nexport const LIGHT_THEME: Theme = {\n name: 'light',\n background: '#FFFFFF',\n text: '#131722',\n textSecondary: '#787B86',\n grid: '#F0F3FA',\n crosshair: '#9598A1',\n candleUp: '#26A69A',\n candleDown: '#EF5350',\n candleUpWick: '#26A69A',\n candleDownWick: '#EF5350',\n lineColor: '#2196F3',\n areaTopColor: 'rgba(33, 150, 243, 0.4)',\n areaBottomColor: 'rgba(33, 150, 243, 0.0)',\n volumeUp: 'rgba(38, 166, 154, 0.3)',\n volumeDown: 'rgba(239, 83, 80, 0.3)',\n axisLine: '#E0E3EB',\n axisLabel: '#131722',\n axisLabelBackground: '#F0F3FA',\n font: DEFAULT_FONT,\n};\n","import type { LocaleStrings } from './types.js';\n\nexport const en: LocaleStrings = {\n // Chart types\n candlestick: 'Candlestick',\n line: 'Line',\n area: 'Area',\n bar: 'OHLC Bar',\n\n // Axes\n price: 'Price',\n volume: 'Volume',\n time: 'Time',\n open: 'Open',\n high: 'High',\n low: 'Low',\n close: 'Close',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Bollinger Bands',\n vwap: 'VWAP',\n ichimoku: 'Ichimoku Cloud',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Keltner Channel',\n donchianChannel: 'Donchian Channel',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Std Dev',\n volumeProfile: 'Volume Profile',\n accumulationDistribution: 'A/D Line',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Trend Line',\n horizontalLine: 'Horizontal Line',\n verticalLine: 'Vertical Line',\n ray: 'Ray',\n extendedLine: 'Extended Line',\n parallelChannel: 'Parallel Channel',\n regressionChannel: 'Regression Channel',\n fibRetracement: 'Fibonacci Retracement',\n fibExtension: 'Fibonacci Extension',\n rectangle: 'Rectangle',\n ellipse: 'Ellipse',\n triangle: 'Triangle',\n pitchfork: \"Andrews' Pitchfork\",\n elliottWave: 'Elliott Wave',\n priceRange: 'Price Range',\n dateRange: 'Date Range',\n measure: 'Measure',\n textTool: 'Text',\n arrow: 'Arrow',\n clearAll: 'Clear All',\n\n // Trading\n buy: 'Buy',\n sell: 'Sell',\n buyLimit: 'Buy Limit',\n sellLimit: 'Sell Limit',\n buyStop: 'Buy Stop',\n sellStop: 'Sell Stop',\n stopLoss: 'Stop Loss',\n takeProfit: 'Take Profit',\n market: 'Market',\n limit: 'Limit',\n stop: 'Stop',\n cancel: 'Cancel',\n modify: 'Modify',\n quantity: 'Qty',\n pnl: 'P&L',\n activeOrders: 'Active Orders',\n positions: 'Positions',\n noOrders: 'No active orders',\n noPositions: 'No open positions',\n placeOrder: 'Place Order',\n rightClickToTrade: 'Right-click chart to place orders',\n\n // Market\n ceiling: 'Ceiling',\n floor: 'Floor',\n reference: 'Reference',\n session: 'Session',\n preOpen: 'Pre-Open',\n continuous: 'Continuous',\n preClose: 'Pre-Close',\n closed: 'Closed',\n\n // UI\n settings: 'Settings',\n theme: 'Theme',\n darkTheme: 'Dark',\n lightTheme: 'Light',\n tools: 'Tools',\n indicators: 'Indicators',\n overlays: 'Overlays',\n panels: 'Panels',\n orders: 'Orders',\n autoScale: 'Auto Scale',\n crosshair: 'Crosshair',\n grid: 'Grid',\n loading: 'Loading...',\n error: 'Error',\n\n numberDecimalSeparator: '.',\n numberGroupSeparator: ',',\n};\n","import type { LocaleStrings } from './types.js';\n\nexport const vi: LocaleStrings = {\n // Chart types\n candlestick: 'Nến',\n line: 'Đường',\n area: 'Vùng',\n bar: 'Thanh OHLC',\n\n // Axes\n price: 'Giá',\n volume: 'Khối lượng',\n time: 'Thời gian',\n open: 'Mở',\n high: 'Cao',\n low: 'Thấp',\n close: 'Đóng',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Dải Bollinger',\n vwap: 'VWAP',\n ichimoku: 'Mây Ichimoku',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Kênh Keltner',\n donchianChannel: 'Kênh Donchian',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Độ lệch chuẩn',\n volumeProfile: 'Phân bổ KL',\n accumulationDistribution: 'Tích lũy/Phân phối',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Đường xu hướng',\n horizontalLine: 'Đường ngang',\n verticalLine: 'Đường dọc',\n ray: 'Tia',\n extendedLine: 'Đường kéo dài',\n parallelChannel: 'Kênh song song',\n regressionChannel: 'Kênh hồi quy',\n fibRetracement: 'Fibonacci thoái lui',\n fibExtension: 'Fibonacci mở rộng',\n rectangle: 'Hình chữ nhật',\n ellipse: 'Hình elip',\n triangle: 'Tam giác',\n pitchfork: 'Chĩa ba Andrews',\n elliottWave: 'Sóng Elliott',\n priceRange: 'Khoảng giá',\n dateRange: 'Khoảng thời gian',\n measure: 'Đo lường',\n textTool: 'Chữ',\n arrow: 'Mũi tên',\n clearAll: 'Xóa tất cả',\n\n // Trading\n buy: 'Mua',\n sell: 'Bán',\n buyLimit: 'Mua giới hạn',\n sellLimit: 'Bán giới hạn',\n buyStop: 'Mua chặn',\n sellStop: 'Bán chặn',\n stopLoss: 'Cắt lỗ',\n takeProfit: 'Chốt lời',\n market: 'Thị trường',\n limit: 'Giới hạn',\n stop: 'Dừng',\n cancel: 'Hủy',\n modify: 'Sửa',\n quantity: 'KL',\n pnl: 'Lãi/Lỗ',\n activeOrders: 'Lệnh chờ',\n positions: 'Vị thế',\n noOrders: 'Không có lệnh chờ',\n noPositions: 'Không có vị thế mở',\n placeOrder: 'Đặt lệnh',\n rightClickToTrade: 'Nhấp chuột phải để đặt lệnh',\n\n // Market\n ceiling: 'Trần',\n floor: 'Sàn',\n reference: 'Tham chiếu',\n session: 'Phiên',\n preOpen: 'Trước giờ mở',\n continuous: 'Liên tục',\n preClose: 'Trước giờ đóng',\n closed: 'Đóng cửa',\n\n // UI\n settings: 'Cài đặt',\n theme: 'Giao diện',\n darkTheme: 'Tối',\n lightTheme: 'Sáng',\n tools: 'Công cụ',\n indicators: 'Chỉ báo',\n overlays: 'Phủ lên',\n panels: 'Bảng',\n orders: 'Lệnh',\n autoScale: 'Tự co giãn',\n crosshair: 'Chữ thập',\n grid: 'Lưới',\n loading: 'Đang tải...',\n error: 'Lỗi',\n\n numberDecimalSeparator: ',',\n numberGroupSeparator: '.',\n};\n","export type { Locale, LocaleStrings, NumberFormatConfig, DateFormatConfig } from './types.js';\nexport { en } from './en.js';\nexport { vi } from './vi.js';\n\nimport type { Locale, LocaleStrings } from './types.js';\nimport { en } from './en.js';\nimport { vi } from './vi.js';\n\nconst locales = new Map<string, LocaleStrings>([\n ['en', en],\n ['vi', vi],\n]);\n\nlet currentLocale: Locale = 'en';\nlet currentStrings: LocaleStrings = en;\n\nexport function setLocale(locale: Locale): void {\n currentLocale = locale;\n currentStrings = locales.get(locale) ?? en;\n}\n\nexport function getLocale(): Locale {\n return currentLocale;\n}\n\nexport function t(key: keyof LocaleStrings): string {\n return currentStrings[key] ?? (en as any)[key] ?? key;\n}\n\nexport function registerLocale(locale: string, strings: LocaleStrings): void {\n locales.set(locale, strings);\n}\n\nexport function getLocaleStrings(locale?: string): LocaleStrings {\n return locales.get(locale ?? currentLocale) ?? en;\n}\n\n// Number formatting\nexport function formatNumber(value: number, precision = 2, locale?: string): string {\n const strings = locales.get(locale ?? currentLocale) ?? en;\n const dec = strings.numberDecimalSeparator;\n const grp = strings.numberGroupSeparator;\n\n const fixed = value.toFixed(precision);\n const [intPart, decPart] = fixed.split('.');\n\n // Group integer part\n const negative = intPart.startsWith('-');\n const digits = negative ? intPart.slice(1) : intPart;\n let grouped = '';\n for (let i = digits.length - 1, count = 0; i >= 0; i--, count++) {\n if (count > 0 && count % 3 === 0) grouped = grp + grouped;\n grouped = digits[i] + grouped;\n }\n if (negative) grouped = '-' + grouped;\n\n return decPart ? grouped + dec + decPart : grouped;\n}\n\nexport function formatVND(value: number): string {\n return formatNumber(value, 0, 'vi');\n}\n\nexport function formatVolumeLoc(value: number, locale?: string): string {\n if (value >= 1e9) return formatNumber(value / 1e9, 2, locale ?? currentLocale) + 'B';\n if (value >= 1e6) return formatNumber(value / 1e6, 2, locale ?? currentLocale) + 'M';\n if (value >= 1e3) return formatNumber(value / 1e3, 2, locale ?? currentLocale) + 'K';\n return formatNumber(value, 0, locale ?? currentLocale);\n}\n","import type { MarketConfig, MarketColorScheme, TradingSession } from './types.js';\nimport type { Theme } from '../types/theme.js';\n\n// Vietnam stock color convention:\n// Purple/Red = ceiling (trần) - max up\n// Green/Cyan = floor (sàn) - max down\n// Yellow = reference (tham chiếu)\n// Red = up, Blue = down (common VN convention)\nexport const VN_COLORS: MarketColorScheme = {\n up: '#FF0000', // Đỏ - tăng\n down: '#0000FF', // Xanh dương - giảm\n unchanged: '#FFD700', // Vàng - tham chiếu\n ceiling: '#FF00FF', // Tím - trần\n floor: '#00FFFF', // Xanh lam - sàn\n reference: '#FFD700', // Vàng - tham chiếu\n};\n\nexport const HOSE_SESSIONS: TradingSession[] = [\n { name: 'ATO', startTime: '09:00', endTime: '09:15', type: 'preOpen' },\n { name: 'Phiên 1', startTime: '09:15', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\nexport const HNX_SESSIONS: TradingSession[] = [\n { name: 'Phiên 1', startTime: '09:00', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\n// Market presets\nexport const MARKET_HOSE: MarketConfig = {\n type: 'stock',\n exchange: 'HOSE',\n currency: 'VND',\n pricePrecision: 2,\n volumeUnit: 10,\n priceStep: 0.05,\n priceLimits: { enabled: true, ceilingPercent: 7, floorPercent: 7 },\n sessions: HOSE_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_HNX: MarketConfig = {\n type: 'stock',\n exchange: 'HNX',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n priceLimits: { enabled: true, ceilingPercent: 10, floorPercent: 10 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_UPCOM: MarketConfig = {\n type: 'stock',\n exchange: 'UPCOM',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n priceLimits: { enabled: true, ceilingPercent: 15, floorPercent: 15 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_CRYPTO: MarketConfig = {\n type: 'crypto',\n currency: 'USDT',\n pricePrecision: 2,\n priceLimits: { enabled: false },\n};\n\nexport const MARKET_NYSE: MarketConfig = {\n type: 'stock',\n exchange: 'NYSE',\n currency: 'USD',\n pricePrecision: 2,\n priceStep: 0.01,\n priceLimits: { enabled: false },\n sessions: [\n { name: 'Pre-Market', startTime: '04:00', endTime: '09:30', type: 'preOpen' },\n { name: 'Regular', startTime: '09:30', endTime: '16:00', type: 'continuous' },\n { name: 'After-Hours', startTime: '16:00', endTime: '20:00', type: 'preClose' },\n ],\n};\n\n// Build a theme variant for VN stock market\nexport function createVNTheme(base: Theme): Theme {\n return {\n ...base,\n candleUp: VN_COLORS.up,\n candleDown: VN_COLORS.down,\n candleUpWick: VN_COLORS.up,\n candleDownWick: VN_COLORS.down,\n volumeUp: 'rgba(255, 0, 0, 0.3)',\n volumeDown: 'rgba(0, 0, 255, 0.3)',\n };\n}\n\nexport function computePriceLimits(referencePrice: number, config: MarketConfig): { ceiling: number; floor: number; reference: number } | null {\n if (!config.priceLimits?.enabled || !config.priceLimits.ceilingPercent) return null;\n const ceilPct = config.priceLimits.ceilingPercent / 100;\n const floorPct = (config.priceLimits.floorPercent ?? config.priceLimits.ceilingPercent) / 100;\n return {\n ceiling: referencePrice * (1 + ceilPct),\n floor: referencePrice * (1 - floorPct),\n reference: referencePrice,\n };\n}\n\nexport function getCurrentSession(sessions: TradingSession[]): TradingSession | null {\n const now = new Date();\n const hhmm = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;\n for (const session of sessions) {\n if (hhmm >= session.startTime && hhmm < session.endTime) return session;\n }\n return null;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/types/rendering.ts","../src/types/drawing.ts","../src/types/trading.ts","../src/types/realtime.ts","../src/utils/math.ts","../src/utils/data.ts","../src/utils/color.ts","../src/utils/time.ts","../src/utils/precision.ts","../src/constants/defaults.ts","../src/constants/themes.ts","../src/i18n/en.ts","../src/i18n/vi.ts","../src/i18n/index.ts","../src/market/presets.ts"],"sourcesContent":["export interface Point {\n x: number;\n y: number;\n}\n\nexport interface Size {\n width: number;\n height: number;\n}\n\nexport interface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface ViewportState {\n visibleRange: { from: number; to: number };\n priceRange: { min: number; max: number };\n barWidth: number;\n barSpacing: number;\n offset: number;\n chartRect: Rect;\n logScale?: boolean;\n}\n\nexport enum LayerType {\n Background = 0,\n Main = 1,\n Panel = 2,\n Overlay = 3,\n UI = 4,\n}\n","import type { Point, ViewportState } from './rendering.js';\n\nexport type DrawingToolType =\n | 'trendLine' | 'horizontalLine' | 'verticalLine' | 'ray' | 'extendedLine'\n | 'parallelChannel' | 'regressionChannel'\n | 'fibRetracement' | 'fibExtension'\n | 'rectangle' | 'ellipse' | 'triangle'\n | 'pitchfork' | 'elliottWave'\n | 'priceRange' | 'dateRange' | 'measure'\n | 'text' | 'arrow'\n | 'gannFan' | 'gannBox'\n | 'anchoredVWAP'\n | 'volumeProfileRange';\n\nexport interface AnchorPoint {\n time: number;\n price: number;\n}\n\nexport interface DrawingStyle {\n color: string;\n lineWidth: number;\n lineStyle: 'solid' | 'dashed' | 'dotted';\n fillColor?: string;\n fillOpacity?: number;\n fontSize?: number;\n text?: string;\n}\n\nexport interface DrawingState {\n id: string;\n type: DrawingToolType;\n anchors: AnchorPoint[];\n style: DrawingStyle;\n visible: boolean;\n locked: boolean;\n meta?: Record<string, unknown>;\n}\n\nexport interface DrawingDescriptor {\n type: DrawingToolType;\n name: string;\n requiredAnchors: number;\n singleClick?: boolean;\n}\n\nexport interface DrawingPlugin {\n descriptor: DrawingDescriptor;\n render(\n ctx: CanvasRenderingContext2D,\n state: DrawingState,\n viewport: ViewportState,\n selected: boolean,\n ): void;\n hitTest(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): boolean;\n hitTestAnchor(\n point: Point,\n state: DrawingState,\n viewport: ViewportState,\n tolerance: number,\n ): number;\n}\n\nexport const DEFAULT_DRAWING_STYLE: DrawingStyle = {\n color: '#2196F3',\n lineWidth: 1,\n lineStyle: 'solid',\n fillColor: 'rgba(33, 150, 243, 0.1)',\n fillOpacity: 0.1,\n fontSize: 12,\n};\n","export type OrderSide = 'buy' | 'sell';\nexport type OrderType = 'market' | 'limit' | 'stop' | 'stopLimit';\nexport type OrderStatus = 'pending' | 'filled' | 'cancelled' | 'rejected';\nexport type OrderLabel = 'LIMIT' | 'STOP' | 'SL' | 'TP' | 'STOP LIMIT';\n\nexport interface TradingOrder {\n id: string;\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity: number;\n label?: OrderLabel;\n draggable?: boolean;\n meta?: Record<string, unknown>;\n}\n\nexport interface TradingPosition {\n id: string;\n side: OrderSide;\n entryPrice: number;\n quantity: number;\n stopLoss?: number;\n takeProfit?: number;\n meta?: Record<string, unknown>;\n}\n\nexport interface DepthLevel {\n price: number;\n volume: number;\n}\n\nexport interface DepthData {\n bids: DepthLevel[];\n asks: DepthLevel[];\n}\n\nexport interface TradingConfig {\n enabled: boolean;\n orderColors?: { buy?: string; sell?: string };\n positionColors?: { profit?: string; loss?: string; entry?: string };\n depthOverlay?: {\n enabled?: boolean;\n bidColor?: string;\n askColor?: string;\n maxWidth?: number;\n };\n contextMenu?: { enabled?: boolean };\n pricePrecision?: number;\n dragThreshold?: number;\n}\n\nexport interface OrderPlaceIntent {\n side: OrderSide;\n type: OrderType;\n price: number;\n stopPrice?: number;\n quantity?: number;\n}\n\nexport interface OrderModifyIntent {\n orderId: string;\n newPrice: number;\n previousPrice: number;\n}\n\nexport interface OrderCancelIntent {\n orderId: string;\n}\n\nexport interface PositionModifyIntent {\n positionId: string;\n stopLoss?: number;\n takeProfit?: number;\n}\n\nexport interface PositionCloseIntent {\n positionId: string;\n}\n\nexport const DEFAULT_TRADING_CONFIG: TradingConfig = {\n enabled: true,\n orderColors: { buy: '#26A69A', sell: '#EF5350' },\n positionColors: { profit: '#26A69A', loss: '#EF5350', entry: '#2196F3' },\n depthOverlay: { enabled: false, bidColor: 'rgba(38,166,154,0.15)', askColor: 'rgba(239,83,80,0.15)', maxWidth: 100 },\n contextMenu: { enabled: true },\n pricePrecision: 2,\n dragThreshold: 3,\n};\n","import type { OHLCBar, TimeFrame } from './ohlc.js';\n\n// --- Connection ---\n\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';\n\nexport interface ConnectionInfo {\n state: ConnectionState;\n latency?: number;\n reconnectAttempt?: number;\n lastMessageTime?: number;\n error?: string;\n}\n\n// --- Ticks & Trades ---\n\nexport interface RawTick {\n time: number;\n price: number;\n volume: number;\n side?: 'buy' | 'sell';\n}\n\nexport interface AggregatedBar extends OHLCBar {\n closed: boolean; // true when bar is finalized\n tickCount: number; // number of ticks in this bar\n}\n\n// --- Data Adapter (Strategy Pattern) ---\n\nexport interface DataAdapterConfig {\n symbol: string;\n timeframe: TimeFrame;\n reconnect?: boolean; // default: true\n reconnectMaxRetries?: number; // default: Infinity\n reconnectBaseDelay?: number; // ms, default: 1000\n reconnectMaxDelay?: number; // ms, default: 30000\n heartbeatInterval?: number; // ms, default: 30000\n bufferSize?: number; // max ticks to buffer, default: 1000\n}\n\nexport type DataAdapterEventType =\n | 'tick'\n | 'bar'\n | 'barClose'\n | 'snapshot' // initial historical data loaded\n | 'connectionChange'\n | 'error';\n\nexport interface DataAdapterEvent<T = unknown> {\n type: DataAdapterEventType;\n data: T;\n timestamp: number;\n}\n\nexport type DataAdapterListener<T = unknown> = (event: DataAdapterEvent<T>) => void;\n\n/**\n * DataAdapter interface — Strategy pattern for pluggable data sources.\n *\n * Implementations handle the specifics of each data source (WebSocket, REST,\n * SSE, etc.) while the StreamManager orchestrates lifecycle and aggregation.\n *\n * Built-in: BinanceAdapter\n * Implement this for: custom exchange APIs, broker feeds, mock data\n */\nexport interface DataAdapter {\n readonly name: string;\n\n connect(config: DataAdapterConfig): void;\n disconnect(): void;\n getConnectionState(): ConnectionState;\n\n /**\n * Load historical bars. Called once on connect, before streaming starts.\n * Returns bars sorted by time ascending.\n */\n fetchHistory(symbol: string, timeframe: TimeFrame, limit?: number): Promise<OHLCBar[]>;\n\n on<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n off<T = unknown>(event: DataAdapterEventType, listener: DataAdapterListener<T>): void;\n\n dispose(): void;\n}\n\n// --- Stream Manager Config ---\n\nexport interface StreamConfig {\n adapter: DataAdapter;\n symbol: string;\n timeframe: TimeFrame;\n historyLimit?: number; // bars to load initially, default: 500\n autoScroll?: boolean; // scroll to end on new bar, default: true\n showCurrentPriceLine?: boolean; // default: true\n aggregateTicks?: boolean; // build bars from ticks, default: false\n reconnect?: ReconnectConfig;\n}\n\nexport interface ReconnectConfig {\n enabled: boolean; // default: true\n maxRetries: number; // default: Infinity\n baseDelay: number; // ms, default: 1000\n maxDelay: number; // ms, default: 30000\n backoffMultiplier: number; // default: 2\n}\n\nexport const DEFAULT_RECONNECT: ReconnectConfig = {\n enabled: true,\n maxRetries: Infinity,\n baseDelay: 1000,\n maxDelay: 30000,\n backoffMultiplier: 2,\n};\n\nexport const DEFAULT_STREAM_CONFIG: Partial<StreamConfig> = {\n historyLimit: 500,\n autoScroll: true,\n showCurrentPriceLine: true,\n aggregateTicks: false,\n};\n","export function clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nexport function inverseLerp(a: number, b: number, value: number): number {\n if (a === b) return 0;\n return (value - a) / (b - a);\n}\n\nexport function roundToStep(value: number, step: number): number {\n return Math.round(value / step) * step;\n}\n\nexport function niceNumber(value: number, round: boolean): number {\n const exp = Math.floor(Math.log10(value));\n const frac = value / Math.pow(10, exp);\n let nice: number;\n if (round) {\n if (frac < 1.5) nice = 1;\n else if (frac < 3) nice = 2;\n else if (frac < 7) nice = 5;\n else nice = 10;\n } else {\n if (frac <= 1) nice = 1;\n else if (frac <= 2) nice = 2;\n else if (frac <= 5) nice = 5;\n else nice = 10;\n }\n return nice * Math.pow(10, exp);\n}\n\nexport function computeTickStep(min: number, max: number, maxTicks: number): number {\n const range = niceNumber(max - min, false);\n return niceNumber(range / (maxTicks - 1), true);\n}\n","import type { OHLCBar, DataSeries } from '../types/ohlc.js';\n\nexport function sliceVisibleData(\n data: DataSeries,\n from: number,\n to: number,\n): DataSeries {\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length, to + 1);\n return data.slice(startIdx, endIdx);\n}\n\nexport function findBarIndex(data: DataSeries, timestamp: number): number {\n let lo = 0;\n let hi = data.length - 1;\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n if (data[mid].time < timestamp) lo = mid + 1;\n else if (data[mid].time > timestamp) hi = mid - 1;\n else return mid;\n }\n return lo;\n}\n\nexport function computePriceRange(\n data: DataSeries,\n from: number,\n to: number,\n padding = 0.05,\n): { min: number; max: number } {\n if (data.length === 0) return { min: 0, max: 1 };\n const startIdx = Math.max(0, from);\n const endIdx = Math.min(data.length - 1, to);\n let min = Infinity;\n let max = -Infinity;\n for (let i = startIdx; i <= endIdx; i++) {\n if (data[i].low < min) min = data[i].low;\n if (data[i].high > max) max = data[i].high;\n }\n if (min === Infinity) return { min: 0, max: 1 };\n const range = max - min || 1;\n return {\n min: min - range * padding,\n max: max + range * padding,\n };\n}\n\nexport function mergeBar(existing: OHLCBar, tick: { price: number; volume?: number; time: number }): OHLCBar {\n return {\n ...existing,\n high: Math.max(existing.high, tick.price),\n low: Math.min(existing.low, tick.price),\n close: tick.price,\n volume: existing.volume + (tick.volume ?? 0),\n time: tick.time,\n };\n}\n","export function hexToRgba(hex: string, alpha = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\nexport function withAlpha(color: string, alpha: number): string {\n if (color.startsWith('#')) {\n return hexToRgba(color, alpha);\n }\n const rgbaMatch = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (rgbaMatch) {\n return `rgba(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]}, ${alpha})`;\n }\n return color;\n}\n\nexport function lerpColor(colorA: string, colorB: string, t: number): string {\n const parseHex = (hex: string) => {\n hex = hex.replace('#', '');\n if (hex.length === 3) hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];\n return {\n r: parseInt(hex.slice(0, 2), 16),\n g: parseInt(hex.slice(2, 4), 16),\n b: parseInt(hex.slice(4, 6), 16),\n };\n };\n const a = parseHex(colorA);\n const b = parseHex(colorB);\n const r = Math.round(a.r + (b.r - a.r) * t);\n const g = Math.round(a.g + (b.g - a.g) * t);\n const bl = Math.round(a.b + (b.b - a.b) * t);\n return `rgb(${r},${g},${bl})`;\n}\n","import type { TimeFrame } from '../types/ohlc.js';\n\nconst TIMEFRAME_MS: Record<TimeFrame, number> = {\n '1s': 1_000,\n '5s': 5_000,\n '15s': 15_000,\n '30s': 30_000,\n '1m': 60_000,\n '3m': 180_000,\n '5m': 300_000,\n '15m': 900_000,\n '30m': 1_800_000,\n '45m': 2_700_000,\n '1h': 3_600_000,\n '2h': 7_200_000,\n '3h': 10_800_000,\n '4h': 14_400_000,\n '6h': 21_600_000,\n '8h': 28_800_000,\n '12h': 43_200_000,\n '1d': 86_400_000,\n '2d': 172_800_000,\n '3d': 259_200_000,\n '1w': 604_800_000,\n '2w': 1_209_600_000,\n '1M': 2_592_000_000,\n '3M': 7_776_000_000,\n '6M': 15_552_000_000,\n '12M': 31_536_000_000,\n};\n\nexport function timeframeToMs(tf: TimeFrame): number {\n return TIMEFRAME_MS[tf];\n}\n\nexport function formatTimestamp(timestamp: number, tf: TimeFrame): string {\n const d = new Date(timestamp);\n const ms = TIMEFRAME_MS[tf];\n if (ms >= 86_400_000) {\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }\n if (ms >= 3_600_000) {\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\n }\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\nexport function alignToTimeframe(timestamp: number, tf: TimeFrame): number {\n const ms = TIMEFRAME_MS[tf];\n return Math.floor(timestamp / ms) * ms;\n}\n","export function formatPrice(value: number, precision = 2): string {\n return value.toFixed(precision);\n}\n\nexport function formatVolume(value: number): string {\n if (value >= 1_000_000_000) return (value / 1_000_000_000).toFixed(2) + 'B';\n if (value >= 1_000_000) return (value / 1_000_000).toFixed(2) + 'M';\n if (value >= 1_000) return (value / 1_000).toFixed(2) + 'K';\n return value.toFixed(0);\n}\n\nexport function detectPrecision(values: number[]): number {\n let maxDecimals = 0;\n for (const v of values) {\n const str = v.toString();\n const dot = str.indexOf('.');\n if (dot >= 0) {\n maxDecimals = Math.max(maxDecimals, str.length - dot - 1);\n }\n }\n return Math.min(maxDecimals, 8);\n}\n","import type { ChartOptions } from '../types/chart.js';\n\nexport const DEFAULT_CHART_OPTIONS: Required<Pick<ChartOptions, 'autoScale' | 'rightMargin' | 'minBarSpacing' | 'maxBarSpacing'>> & Pick<ChartOptions, 'grid' | 'crosshair'> = {\n autoScale: true,\n rightMargin: 5,\n minBarSpacing: 2,\n maxBarSpacing: 30,\n grid: {\n visible: true,\n hLineStyle: 'solid',\n vLineStyle: 'solid',\n },\n crosshair: {\n mode: 'magnet',\n },\n};\n\n// Standard timeframe presets for different market types\nimport type { TimeFrame } from '../types/ohlc.js';\n\n/** Crypto: all timeframes including seconds */\nexport const TIMEFRAMES_CRYPTO: TimeFrame[] = [\n '1s', '1m', '3m', '5m', '15m', '30m',\n '1h', '2h', '4h', '6h', '8h', '12h',\n '1d', '3d', '1w', '1M',\n];\n\n/** Stocks: minute-level and above (no seconds) */\nexport const TIMEFRAMES_STOCK: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '2h', '4h',\n '1d', '1w', '1M', '3M', '6M', '12M',\n];\n\n/** Forex: common forex timeframes */\nexport const TIMEFRAMES_FOREX: TimeFrame[] = [\n '1m', '5m', '15m', '30m',\n '1h', '4h',\n '1d', '1w', '1M',\n];\n\n/** Default favorites shown in quick-access bar */\nexport const DEFAULT_TIMEFRAME_FAVORITES: TimeFrame[] = [\n '1m', '5m', '15m', '1h', '4h', '1d', '1w',\n];\n\nexport const DEFAULT_BAR_WIDTH = 8;\nexport const DEFAULT_BAR_SPACING = 2;\nexport const PRICE_AXIS_WIDTH = 70;\nexport const TIME_AXIS_HEIGHT = 30;\nexport const MIN_PANEL_HEIGHT = 60;\nexport const DEFAULT_PANEL_HEIGHT = 120;\n","import type { Theme } from '../types/theme.js';\n\nconst DEFAULT_FONT = {\n family: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n sizeSmall: 10,\n sizeMedium: 12,\n sizeLarge: 14,\n};\n\nexport const DARK_THEME: Theme = {\n name: 'dark',\n background: '#131722',\n text: '#D1D4DC',\n textSecondary: '#787B86',\n grid: '#1E222D',\n crosshair: '#9598A1',\n candleUp: '#26A69A',\n candleDown: '#EF5350',\n candleUpWick: '#26A69A',\n candleDownWick: '#EF5350',\n lineColor: '#2196F3',\n areaTopColor: 'rgba(33, 150, 243, 0.4)',\n areaBottomColor: 'rgba(33, 150, 243, 0.0)',\n volumeUp: 'rgba(38, 166, 154, 0.3)',\n volumeDown: 'rgba(239, 83, 80, 0.3)',\n axisLine: '#2A2E39',\n axisLabel: '#D1D4DC',\n axisLabelBackground: '#2A2E39',\n font: DEFAULT_FONT,\n};\n\nexport const LIGHT_THEME: Theme = {\n name: 'light',\n background: '#FFFFFF',\n text: '#131722',\n textSecondary: '#787B86',\n grid: '#F0F3FA',\n crosshair: '#9598A1',\n candleUp: '#26A69A',\n candleDown: '#EF5350',\n candleUpWick: '#26A69A',\n candleDownWick: '#EF5350',\n lineColor: '#2196F3',\n areaTopColor: 'rgba(33, 150, 243, 0.4)',\n areaBottomColor: 'rgba(33, 150, 243, 0.0)',\n volumeUp: 'rgba(38, 166, 154, 0.3)',\n volumeDown: 'rgba(239, 83, 80, 0.3)',\n axisLine: '#E0E3EB',\n axisLabel: '#131722',\n axisLabelBackground: '#F0F3FA',\n font: DEFAULT_FONT,\n};\n","import type { LocaleStrings } from './types.js';\n\nexport const en: LocaleStrings = {\n // Chart types\n candlestick: 'Candlestick',\n line: 'Line',\n area: 'Area',\n bar: 'OHLC Bar',\n\n // Axes\n price: 'Price',\n volume: 'Volume',\n time: 'Time',\n open: 'Open',\n high: 'High',\n low: 'Low',\n close: 'Close',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Bollinger Bands',\n vwap: 'VWAP',\n ichimoku: 'Ichimoku Cloud',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Keltner Channel',\n donchianChannel: 'Donchian Channel',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Std Dev',\n volumeProfile: 'Volume Profile',\n accumulationDistribution: 'A/D Line',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Trend Line',\n horizontalLine: 'Horizontal Line',\n verticalLine: 'Vertical Line',\n ray: 'Ray',\n extendedLine: 'Extended Line',\n parallelChannel: 'Parallel Channel',\n regressionChannel: 'Regression Channel',\n fibRetracement: 'Fibonacci Retracement',\n fibExtension: 'Fibonacci Extension',\n rectangle: 'Rectangle',\n ellipse: 'Ellipse',\n triangle: 'Triangle',\n pitchfork: \"Andrews' Pitchfork\",\n elliottWave: 'Elliott Wave',\n priceRange: 'Price Range',\n dateRange: 'Date Range',\n measure: 'Measure',\n textTool: 'Text',\n arrow: 'Arrow',\n clearAll: 'Clear All',\n\n // Trading\n buy: 'Buy',\n sell: 'Sell',\n buyLimit: 'Buy Limit',\n sellLimit: 'Sell Limit',\n buyStop: 'Buy Stop',\n sellStop: 'Sell Stop',\n stopLoss: 'Stop Loss',\n takeProfit: 'Take Profit',\n market: 'Market',\n limit: 'Limit',\n stop: 'Stop',\n cancel: 'Cancel',\n modify: 'Modify',\n quantity: 'Qty',\n pnl: 'P&L',\n activeOrders: 'Active Orders',\n positions: 'Positions',\n noOrders: 'No active orders',\n noPositions: 'No open positions',\n placeOrder: 'Place Order',\n rightClickToTrade: 'Right-click chart to place orders',\n\n // Market\n ceiling: 'Ceiling',\n floor: 'Floor',\n reference: 'Reference',\n session: 'Session',\n preOpen: 'Pre-Open',\n continuous: 'Continuous',\n preClose: 'Pre-Close',\n closed: 'Closed',\n\n // UI\n settings: 'Settings',\n theme: 'Theme',\n darkTheme: 'Dark',\n lightTheme: 'Light',\n tools: 'Tools',\n indicators: 'Indicators',\n overlays: 'Overlays',\n panels: 'Panels',\n orders: 'Orders',\n autoScale: 'Auto Scale',\n crosshair: 'Crosshair',\n grid: 'Grid',\n loading: 'Loading...',\n error: 'Error',\n\n numberDecimalSeparator: '.',\n numberGroupSeparator: ',',\n};\n","import type { LocaleStrings } from './types.js';\n\nexport const vi: LocaleStrings = {\n // Chart types\n candlestick: 'Nến',\n line: 'Đường',\n area: 'Vùng',\n bar: 'Thanh OHLC',\n\n // Axes\n price: 'Giá',\n volume: 'Khối lượng',\n time: 'Thời gian',\n open: 'Mở',\n high: 'Cao',\n low: 'Thấp',\n close: 'Đóng',\n\n // Indicators - overlays\n sma: 'SMA',\n ema: 'EMA',\n bollingerBands: 'Dải Bollinger',\n vwap: 'VWAP',\n ichimoku: 'Mây Ichimoku',\n parabolicSAR: 'Parabolic SAR',\n supertrend: 'Supertrend',\n keltnerChannel: 'Kênh Keltner',\n donchianChannel: 'Kênh Donchian',\n\n // Indicators - panels\n rsi: 'RSI',\n macd: 'MACD',\n stochastic: 'Stochastic',\n atr: 'ATR',\n adx: 'ADX',\n obv: 'OBV',\n williamsR: 'Williams %R',\n cci: 'CCI',\n mfi: 'MFI',\n aroon: 'Aroon',\n roc: 'ROC',\n tsi: 'TSI',\n cmf: 'CMF',\n stddev: 'Độ lệch chuẩn',\n volumeProfile: 'Phân bổ KL',\n accumulationDistribution: 'Tích lũy/Phân phối',\n vroc: 'VROC',\n\n // Drawing tools\n trendLine: 'Đường xu hướng',\n horizontalLine: 'Đường ngang',\n verticalLine: 'Đường dọc',\n ray: 'Tia',\n extendedLine: 'Đường kéo dài',\n parallelChannel: 'Kênh song song',\n regressionChannel: 'Kênh hồi quy',\n fibRetracement: 'Fibonacci thoái lui',\n fibExtension: 'Fibonacci mở rộng',\n rectangle: 'Hình chữ nhật',\n ellipse: 'Hình elip',\n triangle: 'Tam giác',\n pitchfork: 'Chĩa ba Andrews',\n elliottWave: 'Sóng Elliott',\n priceRange: 'Khoảng giá',\n dateRange: 'Khoảng thời gian',\n measure: 'Đo lường',\n textTool: 'Chữ',\n arrow: 'Mũi tên',\n clearAll: 'Xóa tất cả',\n\n // Trading\n buy: 'Mua',\n sell: 'Bán',\n buyLimit: 'Mua giới hạn',\n sellLimit: 'Bán giới hạn',\n buyStop: 'Mua chặn',\n sellStop: 'Bán chặn',\n stopLoss: 'Cắt lỗ',\n takeProfit: 'Chốt lời',\n market: 'Thị trường',\n limit: 'Giới hạn',\n stop: 'Dừng',\n cancel: 'Hủy',\n modify: 'Sửa',\n quantity: 'KL',\n pnl: 'Lãi/Lỗ',\n activeOrders: 'Lệnh chờ',\n positions: 'Vị thế',\n noOrders: 'Không có lệnh chờ',\n noPositions: 'Không có vị thế mở',\n placeOrder: 'Đặt lệnh',\n rightClickToTrade: 'Nhấp chuột phải để đặt lệnh',\n\n // Market\n ceiling: 'Trần',\n floor: 'Sàn',\n reference: 'Tham chiếu',\n session: 'Phiên',\n preOpen: 'Trước giờ mở',\n continuous: 'Liên tục',\n preClose: 'Trước giờ đóng',\n closed: 'Đóng cửa',\n\n // UI\n settings: 'Cài đặt',\n theme: 'Giao diện',\n darkTheme: 'Tối',\n lightTheme: 'Sáng',\n tools: 'Công cụ',\n indicators: 'Chỉ báo',\n overlays: 'Phủ lên',\n panels: 'Bảng',\n orders: 'Lệnh',\n autoScale: 'Tự co giãn',\n crosshair: 'Chữ thập',\n grid: 'Lưới',\n loading: 'Đang tải...',\n error: 'Lỗi',\n\n numberDecimalSeparator: ',',\n numberGroupSeparator: '.',\n};\n","export type { Locale, LocaleStrings, NumberFormatConfig, DateFormatConfig } from './types.js';\nexport { en } from './en.js';\nexport { vi } from './vi.js';\n\nimport type { Locale, LocaleStrings } from './types.js';\nimport { en } from './en.js';\nimport { vi } from './vi.js';\n\nconst locales = new Map<string, LocaleStrings>([\n ['en', en],\n ['vi', vi],\n]);\n\nlet currentLocale: Locale = 'en';\nlet currentStrings: LocaleStrings = en;\n\nexport function setLocale(locale: Locale): void {\n currentLocale = locale;\n currentStrings = locales.get(locale) ?? en;\n}\n\nexport function getLocale(): Locale {\n return currentLocale;\n}\n\nexport function t(key: keyof LocaleStrings): string {\n return currentStrings[key] ?? (en as any)[key] ?? key;\n}\n\nexport function registerLocale(locale: string, strings: LocaleStrings): void {\n locales.set(locale, strings);\n}\n\nexport function getLocaleStrings(locale?: string): LocaleStrings {\n return locales.get(locale ?? currentLocale) ?? en;\n}\n\n// Number formatting\nexport function formatNumber(value: number, precision = 2, locale?: string): string {\n const strings = locales.get(locale ?? currentLocale) ?? en;\n const dec = strings.numberDecimalSeparator;\n const grp = strings.numberGroupSeparator;\n\n const fixed = value.toFixed(precision);\n const [intPart, decPart] = fixed.split('.');\n\n // Group integer part\n const negative = intPart.startsWith('-');\n const digits = negative ? intPart.slice(1) : intPart;\n let grouped = '';\n for (let i = digits.length - 1, count = 0; i >= 0; i--, count++) {\n if (count > 0 && count % 3 === 0) grouped = grp + grouped;\n grouped = digits[i] + grouped;\n }\n if (negative) grouped = '-' + grouped;\n\n return decPart ? grouped + dec + decPart : grouped;\n}\n\nexport function formatVND(value: number): string {\n return formatNumber(value, 0, 'vi');\n}\n\nexport function formatVolumeLoc(value: number, locale?: string): string {\n if (value >= 1e9) return formatNumber(value / 1e9, 2, locale ?? currentLocale) + 'B';\n if (value >= 1e6) return formatNumber(value / 1e6, 2, locale ?? currentLocale) + 'M';\n if (value >= 1e3) return formatNumber(value / 1e3, 2, locale ?? currentLocale) + 'K';\n return formatNumber(value, 0, locale ?? currentLocale);\n}\n","import type { MarketConfig, MarketColorScheme, TradingSession } from './types.js';\nimport type { Theme } from '../types/theme.js';\n\n// Vietnam stock color convention:\n// Purple/Red = ceiling (trần) - max up\n// Green/Cyan = floor (sàn) - max down\n// Yellow = reference (tham chiếu)\n// Red = up, Blue = down (common VN convention)\nexport const VN_COLORS: MarketColorScheme = {\n up: '#FF0000', // Đỏ - tăng\n down: '#0000FF', // Xanh dương - giảm\n unchanged: '#FFD700', // Vàng - tham chiếu\n ceiling: '#FF00FF', // Tím - trần\n floor: '#00FFFF', // Xanh lam - sàn\n reference: '#FFD700', // Vàng - tham chiếu\n};\n\nexport const HOSE_SESSIONS: TradingSession[] = [\n { name: 'ATO', startTime: '09:00', endTime: '09:15', type: 'preOpen' },\n { name: 'Phiên 1', startTime: '09:15', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\nexport const HNX_SESSIONS: TradingSession[] = [\n { name: 'Phiên 1', startTime: '09:00', endTime: '11:30', type: 'continuous' },\n { name: 'Nghỉ trưa', startTime: '11:30', endTime: '13:00', type: 'closed' },\n { name: 'Phiên 2', startTime: '13:00', endTime: '14:30', type: 'continuous' },\n { name: 'ATC', startTime: '14:30', endTime: '14:45', type: 'preClose' },\n];\n\n// Market presets\nexport const MARKET_HOSE: MarketConfig = {\n type: 'stock',\n exchange: 'HOSE',\n currency: 'VND',\n pricePrecision: 2,\n volumeUnit: 10,\n priceStep: 0.05,\n priceLimits: { enabled: true, ceilingPercent: 7, floorPercent: 7 },\n sessions: HOSE_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_HNX: MarketConfig = {\n type: 'stock',\n exchange: 'HNX',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n priceLimits: { enabled: true, ceilingPercent: 10, floorPercent: 10 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_UPCOM: MarketConfig = {\n type: 'stock',\n exchange: 'UPCOM',\n currency: 'VND',\n pricePrecision: 1,\n volumeUnit: 100,\n priceStep: 0.1,\n priceLimits: { enabled: true, ceilingPercent: 15, floorPercent: 15 },\n sessions: HNX_SESSIONS,\n colorScheme: VN_COLORS,\n};\n\nexport const MARKET_CRYPTO: MarketConfig = {\n type: 'crypto',\n currency: 'USDT',\n pricePrecision: 2,\n priceLimits: { enabled: false },\n};\n\nexport const MARKET_NYSE: MarketConfig = {\n type: 'stock',\n exchange: 'NYSE',\n currency: 'USD',\n pricePrecision: 2,\n priceStep: 0.01,\n priceLimits: { enabled: false },\n sessions: [\n { name: 'Pre-Market', startTime: '04:00', endTime: '09:30', type: 'preOpen' },\n { name: 'Regular', startTime: '09:30', endTime: '16:00', type: 'continuous' },\n { name: 'After-Hours', startTime: '16:00', endTime: '20:00', type: 'preClose' },\n ],\n};\n\n// Build a theme variant for VN stock market\nexport function createVNTheme(base: Theme): Theme {\n return {\n ...base,\n candleUp: VN_COLORS.up,\n candleDown: VN_COLORS.down,\n candleUpWick: VN_COLORS.up,\n candleDownWick: VN_COLORS.down,\n volumeUp: 'rgba(255, 0, 0, 0.3)',\n volumeDown: 'rgba(0, 0, 255, 0.3)',\n };\n}\n\nexport function computePriceLimits(referencePrice: number, config: MarketConfig): { ceiling: number; floor: number; reference: number } | null {\n if (!config.priceLimits?.enabled || !config.priceLimits.ceilingPercent) return null;\n const ceilPct = config.priceLimits.ceilingPercent / 100;\n const floorPct = (config.priceLimits.floorPercent ?? config.priceLimits.ceilingPercent) / 100;\n return {\n ceiling: referencePrice * (1 + ceilPct),\n floor: referencePrice * (1 - floorPct),\n reference: referencePrice,\n };\n}\n\nexport function getCurrentSession(sessions: TradingSession[]): TradingSession | null {\n const now = new Date();\n const hhmm = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;\n for (const session of sessions) {\n if (hhmm >= session.startTime && hhmm < session.endTime) return session;\n }\n return null;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Theme, ThemeName } from './theme.js';
|
|
2
|
+
import { DepthData } from './trading.js';
|
|
3
|
+
export interface BaseFinanceChartOptions {
|
|
4
|
+
width?: number;
|
|
5
|
+
height?: number;
|
|
6
|
+
theme?: ThemeName | Theme;
|
|
7
|
+
}
|
|
8
|
+
export interface SparklineOptions extends BaseFinanceChartOptions {
|
|
9
|
+
data: number[];
|
|
10
|
+
mode?: 'line' | 'area';
|
|
11
|
+
color?: string;
|
|
12
|
+
fillColor?: string;
|
|
13
|
+
lineWidth?: number;
|
|
14
|
+
showLastPoint?: boolean;
|
|
15
|
+
showMinMax?: boolean;
|
|
16
|
+
lastPointColor?: string;
|
|
17
|
+
minPointColor?: string;
|
|
18
|
+
maxPointColor?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface DepthChartOptions extends BaseFinanceChartOptions {
|
|
21
|
+
data: DepthData;
|
|
22
|
+
bidColor?: string;
|
|
23
|
+
askColor?: string;
|
|
24
|
+
bidFillColor?: string;
|
|
25
|
+
askFillColor?: string;
|
|
26
|
+
midPriceLine?: boolean;
|
|
27
|
+
spreadLabel?: boolean;
|
|
28
|
+
crosshair?: boolean;
|
|
29
|
+
priceFormat?: (price: number) => string;
|
|
30
|
+
volumeFormat?: (vol: number) => string;
|
|
31
|
+
}
|
|
32
|
+
export interface EquityPoint {
|
|
33
|
+
time: number;
|
|
34
|
+
value: number;
|
|
35
|
+
}
|
|
36
|
+
export interface EquityCurveOptions extends BaseFinanceChartOptions {
|
|
37
|
+
data: EquityPoint[];
|
|
38
|
+
drawdown?: boolean;
|
|
39
|
+
drawdownColor?: string;
|
|
40
|
+
lineColor?: string;
|
|
41
|
+
lineWidth?: number;
|
|
42
|
+
benchmark?: EquityPoint[];
|
|
43
|
+
benchmarkColor?: string;
|
|
44
|
+
benchmarkLabel?: string;
|
|
45
|
+
crosshair?: boolean;
|
|
46
|
+
timeFormat?: (ts: number) => string;
|
|
47
|
+
valueFormat?: (val: number) => string;
|
|
48
|
+
fillArea?: boolean;
|
|
49
|
+
}
|
|
50
|
+
export interface HeatmapCell {
|
|
51
|
+
id: string;
|
|
52
|
+
label: string;
|
|
53
|
+
value: number;
|
|
54
|
+
weight?: number;
|
|
55
|
+
group?: string;
|
|
56
|
+
meta?: Record<string, unknown>;
|
|
57
|
+
}
|
|
58
|
+
export interface HeatmapOptions extends BaseFinanceChartOptions {
|
|
59
|
+
data: HeatmapCell[];
|
|
60
|
+
colorScale?: {
|
|
61
|
+
negative: string;
|
|
62
|
+
zero: string;
|
|
63
|
+
positive: string;
|
|
64
|
+
min?: number;
|
|
65
|
+
max?: number;
|
|
66
|
+
};
|
|
67
|
+
weighted?: boolean;
|
|
68
|
+
cellPadding?: number;
|
|
69
|
+
cellRadius?: number;
|
|
70
|
+
labelFormat?: (cell: HeatmapCell) => string;
|
|
71
|
+
valueFormat?: (value: number) => string;
|
|
72
|
+
showLabels?: boolean;
|
|
73
|
+
showValues?: boolean;
|
|
74
|
+
onCellClick?: (cell: HeatmapCell) => void;
|
|
75
|
+
crosshair?: boolean;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=finance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finance.d.ts","sourceRoot":"","sources":["../../src/types/finance.ts"],"names":[],"mappings":"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"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC"}
|
package/dist/utils/color.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../../src/utils/color.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,MAAM,CAKxD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAS9D"}
|
|
1
|
+
{"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../../src/utils/color.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,MAAM,CAKxD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAS9D;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAgB3E"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradecanvas/commons",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Shared types and utilities for @tradecanvas/chart",
|
|
6
6
|
"license": "MIT",
|
|
@@ -13,7 +13,12 @@
|
|
|
13
13
|
"access": "public"
|
|
14
14
|
},
|
|
15
15
|
"sideEffects": false,
|
|
16
|
-
"keywords": [
|
|
16
|
+
"keywords": [
|
|
17
|
+
"trading",
|
|
18
|
+
"chart",
|
|
19
|
+
"canvas",
|
|
20
|
+
"types"
|
|
21
|
+
],
|
|
17
22
|
"main": "./dist/index.cjs",
|
|
18
23
|
"module": "./dist/index.js",
|
|
19
24
|
"types": "./dist/index.d.ts",
|
|
@@ -24,11 +29,13 @@
|
|
|
24
29
|
"require": "./dist/index.cjs"
|
|
25
30
|
}
|
|
26
31
|
},
|
|
27
|
-
"files": [
|
|
32
|
+
"files": [
|
|
33
|
+
"dist",
|
|
34
|
+
"README.md"
|
|
35
|
+
],
|
|
28
36
|
"scripts": {
|
|
29
37
|
"build": "vite build",
|
|
30
38
|
"dev": "vite build --watch",
|
|
31
|
-
"clean": "rm -rf dist"
|
|
32
|
-
"prepublishOnly": "pnpm build"
|
|
39
|
+
"clean": "rm -rf dist"
|
|
33
40
|
}
|
|
34
|
-
}
|
|
41
|
+
}
|