@itssumitrai/fin-charter 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/README.md +96 -0
- package/dist/api/chart-api.d.ts +173 -0
- package/dist/api/export.d.ts +46 -0
- package/dist/api/indicator-api.d.ts +38 -0
- package/dist/api/options.d.ts +226 -0
- package/dist/api/pane-api.d.ts +28 -0
- package/dist/api/series-api.d.ts +115 -0
- package/dist/core/accessibility.d.ts +90 -0
- package/dist/core/alert-line.d.ts +49 -0
- package/dist/core/chart-state.d.ts +39 -0
- package/dist/core/chart-sync.d.ts +83 -0
- package/dist/core/crosshair.d.ts +28 -0
- package/dist/core/css-theme.d.ts +41 -0
- package/dist/core/custom-indicator.d.ts +70 -0
- package/dist/core/data-feed.d.ts +59 -0
- package/dist/core/data-layer.d.ts +38 -0
- package/dist/core/invalidation.d.ts +24 -0
- package/dist/core/market-session.d.ts +11 -0
- package/dist/core/order-line.d.ts +134 -0
- package/dist/core/pane-divider.d.ts +22 -0
- package/dist/core/pane.d.ts +32 -0
- package/dist/core/periodicity.d.ts +6 -0
- package/dist/core/plugin.d.ts +90 -0
- package/dist/core/price-line.d.ts +17 -0
- package/dist/core/price-scale.d.ts +74 -0
- package/dist/core/replay.d.ts +73 -0
- package/dist/core/rtl.d.ts +22 -0
- package/dist/core/segment-tree.d.ts +38 -0
- package/dist/core/series-markers.d.ts +18 -0
- package/dist/core/storage-adapter.d.ts +50 -0
- package/dist/core/streaming-adapter.d.ts +102 -0
- package/dist/core/symbol-resolver.d.ts +32 -0
- package/dist/core/text-label.d.ts +72 -0
- package/dist/core/time-scale.d.ts +109 -0
- package/dist/core/types.d.ts +144 -0
- package/dist/core/undo-redo.d.ts +46 -0
- package/dist/currency/currency.d.ts +8 -0
- package/dist/currency/index.d.ts +2 -0
- package/dist/drawings/arrow.d.ts +10 -0
- package/dist/drawings/base.d.ts +79 -0
- package/dist/drawings/channel.d.ts +10 -0
- package/dist/drawings/crossline.d.ts +10 -0
- package/dist/drawings/ellipse.d.ts +10 -0
- package/dist/drawings/fib-arc.d.ts +10 -0
- package/dist/drawings/fib-fan.d.ts +12 -0
- package/dist/drawings/fib-projection.d.ts +11 -0
- package/dist/drawings/fibonacci.d.ts +11 -0
- package/dist/drawings/horizontal-line.d.ts +10 -0
- package/dist/drawings/index.d.ts +7 -0
- package/dist/drawings/measurement.d.ts +11 -0
- package/dist/drawings/pitchfork.d.ts +12 -0
- package/dist/drawings/ray.d.ts +12 -0
- package/dist/drawings/rectangle.d.ts +10 -0
- package/dist/drawings/text-annotation.d.ts +11 -0
- package/dist/drawings/trendline.d.ts +10 -0
- package/dist/drawings/vertical-line.d.ts +10 -0
- package/dist/formatting/index.d.ts +5 -0
- package/dist/formatting/price-formatter.d.ts +6 -0
- package/dist/formatting/time-formatter.d.ts +7 -0
- package/dist/formatting/volume-formatter.d.ts +1 -0
- package/dist/i18n/i18n.d.ts +6 -0
- package/dist/i18n/index.d.ts +3 -0
- package/dist/i18n/locales/en.d.ts +3 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index10.js +2 -0
- package/dist/index10.js.map +1 -0
- package/dist/index100.js +2 -0
- package/dist/index100.js.map +1 -0
- package/dist/index101.js +2 -0
- package/dist/index101.js.map +1 -0
- package/dist/index102.js +2 -0
- package/dist/index102.js.map +1 -0
- package/dist/index103.js +2 -0
- package/dist/index103.js.map +1 -0
- package/dist/index104.js +2 -0
- package/dist/index104.js.map +1 -0
- package/dist/index105.js +2 -0
- package/dist/index105.js.map +1 -0
- package/dist/index106.js +2 -0
- package/dist/index106.js.map +1 -0
- package/dist/index107.js +2 -0
- package/dist/index107.js.map +1 -0
- package/dist/index108.js +2 -0
- package/dist/index108.js.map +1 -0
- package/dist/index109.js +2 -0
- package/dist/index109.js.map +1 -0
- package/dist/index11.js +2 -0
- package/dist/index11.js.map +1 -0
- package/dist/index110.js +2 -0
- package/dist/index110.js.map +1 -0
- package/dist/index111.js +2 -0
- package/dist/index111.js.map +1 -0
- package/dist/index112.js +2 -0
- package/dist/index112.js.map +1 -0
- package/dist/index113.js +2 -0
- package/dist/index113.js.map +1 -0
- package/dist/index114.js +2 -0
- package/dist/index114.js.map +1 -0
- package/dist/index115.js +2 -0
- package/dist/index115.js.map +1 -0
- package/dist/index116.js +2 -0
- package/dist/index116.js.map +1 -0
- package/dist/index117.js +2 -0
- package/dist/index117.js.map +1 -0
- package/dist/index118.js +2 -0
- package/dist/index118.js.map +1 -0
- package/dist/index119.js +2 -0
- package/dist/index119.js.map +1 -0
- package/dist/index12.js +2 -0
- package/dist/index12.js.map +1 -0
- package/dist/index120.js +2 -0
- package/dist/index120.js.map +1 -0
- package/dist/index121.js +2 -0
- package/dist/index121.js.map +1 -0
- package/dist/index122.js +2 -0
- package/dist/index122.js.map +1 -0
- package/dist/index123.js +2 -0
- package/dist/index123.js.map +1 -0
- package/dist/index124.js +2 -0
- package/dist/index124.js.map +1 -0
- package/dist/index13.js +2 -0
- package/dist/index13.js.map +1 -0
- package/dist/index14.js +2 -0
- package/dist/index14.js.map +1 -0
- package/dist/index15.js +2 -0
- package/dist/index15.js.map +1 -0
- package/dist/index16.js +2 -0
- package/dist/index16.js.map +1 -0
- package/dist/index17.js +2 -0
- package/dist/index17.js.map +1 -0
- package/dist/index18.js +2 -0
- package/dist/index18.js.map +1 -0
- package/dist/index19.js +2 -0
- package/dist/index19.js.map +1 -0
- package/dist/index2.js +2 -0
- package/dist/index2.js.map +1 -0
- package/dist/index20.js +2 -0
- package/dist/index20.js.map +1 -0
- package/dist/index21.js +2 -0
- package/dist/index21.js.map +1 -0
- package/dist/index22.js +2 -0
- package/dist/index22.js.map +1 -0
- package/dist/index23.js +2 -0
- package/dist/index23.js.map +1 -0
- package/dist/index24.js +2 -0
- package/dist/index24.js.map +1 -0
- package/dist/index25.js +2 -0
- package/dist/index25.js.map +1 -0
- package/dist/index26.js +2 -0
- package/dist/index26.js.map +1 -0
- package/dist/index27.js +2 -0
- package/dist/index27.js.map +1 -0
- package/dist/index28.js +2 -0
- package/dist/index28.js.map +1 -0
- package/dist/index29.js +2 -0
- package/dist/index29.js.map +1 -0
- package/dist/index3.js +2 -0
- package/dist/index3.js.map +1 -0
- package/dist/index30.js +2 -0
- package/dist/index30.js.map +1 -0
- package/dist/index31.js +2 -0
- package/dist/index31.js.map +1 -0
- package/dist/index32.js +2 -0
- package/dist/index32.js.map +1 -0
- package/dist/index33.js +2 -0
- package/dist/index33.js.map +1 -0
- package/dist/index34.js +2 -0
- package/dist/index34.js.map +1 -0
- package/dist/index35.js +2 -0
- package/dist/index35.js.map +1 -0
- package/dist/index36.js +2 -0
- package/dist/index36.js.map +1 -0
- package/dist/index37.js +2 -0
- package/dist/index37.js.map +1 -0
- package/dist/index38.js +2 -0
- package/dist/index38.js.map +1 -0
- package/dist/index39.js +2 -0
- package/dist/index39.js.map +1 -0
- package/dist/index4.js +2 -0
- package/dist/index4.js.map +1 -0
- package/dist/index40.js +2 -0
- package/dist/index40.js.map +1 -0
- package/dist/index41.js +2 -0
- package/dist/index41.js.map +1 -0
- package/dist/index42.js +2 -0
- package/dist/index42.js.map +1 -0
- package/dist/index43.js +2 -0
- package/dist/index43.js.map +1 -0
- package/dist/index44.js +2 -0
- package/dist/index44.js.map +1 -0
- package/dist/index45.js +2 -0
- package/dist/index45.js.map +1 -0
- package/dist/index46.js +2 -0
- package/dist/index46.js.map +1 -0
- package/dist/index47.js +2 -0
- package/dist/index47.js.map +1 -0
- package/dist/index48.js +2 -0
- package/dist/index48.js.map +1 -0
- package/dist/index49.js +2 -0
- package/dist/index49.js.map +1 -0
- package/dist/index5.js +2 -0
- package/dist/index5.js.map +1 -0
- package/dist/index50.js +2 -0
- package/dist/index50.js.map +1 -0
- package/dist/index51.js +2 -0
- package/dist/index51.js.map +1 -0
- package/dist/index52.js +2 -0
- package/dist/index52.js.map +1 -0
- package/dist/index53.js +2 -0
- package/dist/index53.js.map +1 -0
- package/dist/index54.js +2 -0
- package/dist/index54.js.map +1 -0
- package/dist/index55.js +2 -0
- package/dist/index55.js.map +1 -0
- package/dist/index56.js +2 -0
- package/dist/index56.js.map +1 -0
- package/dist/index57.js +2 -0
- package/dist/index57.js.map +1 -0
- package/dist/index58.js +2 -0
- package/dist/index58.js.map +1 -0
- package/dist/index59.js +2 -0
- package/dist/index59.js.map +1 -0
- package/dist/index6.js +2 -0
- package/dist/index6.js.map +1 -0
- package/dist/index60.js +2 -0
- package/dist/index60.js.map +1 -0
- package/dist/index61.js +2 -0
- package/dist/index61.js.map +1 -0
- package/dist/index62.js +2 -0
- package/dist/index62.js.map +1 -0
- package/dist/index63.js +2 -0
- package/dist/index63.js.map +1 -0
- package/dist/index64.js +2 -0
- package/dist/index64.js.map +1 -0
- package/dist/index65.js +3 -0
- package/dist/index65.js.map +1 -0
- package/dist/index66.js +2 -0
- package/dist/index66.js.map +1 -0
- package/dist/index67.js +2 -0
- package/dist/index67.js.map +1 -0
- package/dist/index68.js +2 -0
- package/dist/index68.js.map +1 -0
- package/dist/index69.js +2 -0
- package/dist/index69.js.map +1 -0
- package/dist/index7.js +2 -0
- package/dist/index7.js.map +1 -0
- package/dist/index70.js +2 -0
- package/dist/index70.js.map +1 -0
- package/dist/index71.js +2 -0
- package/dist/index71.js.map +1 -0
- package/dist/index72.js +2 -0
- package/dist/index72.js.map +1 -0
- package/dist/index73.js +2 -0
- package/dist/index73.js.map +1 -0
- package/dist/index74.js +2 -0
- package/dist/index74.js.map +1 -0
- package/dist/index75.js +2 -0
- package/dist/index75.js.map +1 -0
- package/dist/index76.js +2 -0
- package/dist/index76.js.map +1 -0
- package/dist/index77.js +2 -0
- package/dist/index77.js.map +1 -0
- package/dist/index78.js +2 -0
- package/dist/index78.js.map +1 -0
- package/dist/index79.js +2 -0
- package/dist/index79.js.map +1 -0
- package/dist/index8.js +2 -0
- package/dist/index8.js.map +1 -0
- package/dist/index80.js +2 -0
- package/dist/index80.js.map +1 -0
- package/dist/index81.js +2 -0
- package/dist/index81.js.map +1 -0
- package/dist/index82.js +2 -0
- package/dist/index82.js.map +1 -0
- package/dist/index83.js +2 -0
- package/dist/index83.js.map +1 -0
- package/dist/index84.js +2 -0
- package/dist/index84.js.map +1 -0
- package/dist/index85.js +2 -0
- package/dist/index85.js.map +1 -0
- package/dist/index86.js +2 -0
- package/dist/index86.js.map +1 -0
- package/dist/index87.js +2 -0
- package/dist/index87.js.map +1 -0
- package/dist/index88.js +2 -0
- package/dist/index88.js.map +1 -0
- package/dist/index89.js +2 -0
- package/dist/index89.js.map +1 -0
- package/dist/index9.js +2 -0
- package/dist/index9.js.map +1 -0
- package/dist/index90.js +2 -0
- package/dist/index90.js.map +1 -0
- package/dist/index91.js +2 -0
- package/dist/index91.js.map +1 -0
- package/dist/index92.js +2 -0
- package/dist/index92.js.map +1 -0
- package/dist/index93.js +2 -0
- package/dist/index93.js.map +1 -0
- package/dist/index94.js +2 -0
- package/dist/index94.js.map +1 -0
- package/dist/index95.js +2 -0
- package/dist/index95.js.map +1 -0
- package/dist/index96.js +2 -0
- package/dist/index96.js.map +1 -0
- package/dist/index97.js +2 -0
- package/dist/index97.js.map +1 -0
- package/dist/index98.js +2 -0
- package/dist/index98.js.map +1 -0
- package/dist/index99.js +2 -0
- package/dist/index99.js.map +1 -0
- package/dist/indicators/adx.d.ts +6 -0
- package/dist/indicators/aroon.d.ts +5 -0
- package/dist/indicators/atr.d.ts +1 -0
- package/dist/indicators/awesome-oscillator.d.ts +1 -0
- package/dist/indicators/bollinger.d.ts +6 -0
- package/dist/indicators/cci.d.ts +1 -0
- package/dist/indicators/chaikin-mf.d.ts +1 -0
- package/dist/indicators/choppiness.d.ts +1 -0
- package/dist/indicators/coppock.d.ts +1 -0
- package/dist/indicators/donchian.d.ts +6 -0
- package/dist/indicators/elder-force.d.ts +1 -0
- package/dist/indicators/ema.d.ts +1 -0
- package/dist/indicators/ichimoku.d.ts +8 -0
- package/dist/indicators/index.d.ts +31 -0
- package/dist/indicators/keltner.d.ts +6 -0
- package/dist/indicators/linear-regression.d.ts +1 -0
- package/dist/indicators/macd.d.ts +6 -0
- package/dist/indicators/mfi.d.ts +1 -0
- package/dist/indicators/obv.d.ts +1 -0
- package/dist/indicators/parabolic-sar.d.ts +1 -0
- package/dist/indicators/pivot-points.d.ts +10 -0
- package/dist/indicators/roc.d.ts +1 -0
- package/dist/indicators/rsi.d.ts +1 -0
- package/dist/indicators/sma.d.ts +1 -0
- package/dist/indicators/stochastic.d.ts +5 -0
- package/dist/indicators/supertrend.d.ts +5 -0
- package/dist/indicators/trix.d.ts +5 -0
- package/dist/indicators/utils.d.ts +20 -0
- package/dist/indicators/volume-profile.d.ts +37 -0
- package/dist/indicators/volume.d.ts +1 -0
- package/dist/indicators/vwap.d.ts +1 -0
- package/dist/indicators/vwma.d.ts +1 -0
- package/dist/indicators/williams-r.d.ts +1 -0
- package/dist/interactions/axis-drag.d.ts +24 -0
- package/dist/interactions/context-menu-handler.d.ts +42 -0
- package/dist/interactions/crosshair.d.ts +20 -0
- package/dist/interactions/drawing-handler.d.ts +39 -0
- package/dist/interactions/event-router.d.ts +37 -0
- package/dist/interactions/keyboard-nav.d.ts +11 -0
- package/dist/interactions/pan-zoom.d.ts +39 -0
- package/dist/interactions/range-selection.d.ts +103 -0
- package/dist/interactions/touch-gestures.d.ts +36 -0
- package/dist/logo.svg +40 -0
- package/dist/market/exchange-map.d.ts +3 -0
- package/dist/market/index.d.ts +4 -0
- package/dist/market/market-calendar.d.ts +4 -0
- package/dist/market/market-definition.d.ts +22 -0
- package/dist/mockServiceWorker.js +349 -0
- package/dist/renderers/area.d.ts +17 -0
- package/dist/renderers/bar-ohlc.d.ts +17 -0
- package/dist/renderers/baseline-delta-mountain.d.ts +22 -0
- package/dist/renderers/baseline.d.ts +19 -0
- package/dist/renderers/candlestick.d.ts +21 -0
- package/dist/renderers/canvas-renderer.d.ts +28 -0
- package/dist/renderers/colored-line.d.ts +15 -0
- package/dist/renderers/colored-mountain.d.ts +18 -0
- package/dist/renderers/column.d.ts +14 -0
- package/dist/renderers/high-low.d.ts +14 -0
- package/dist/renderers/histogram.d.ts +16 -0
- package/dist/renderers/hlc-area.d.ts +16 -0
- package/dist/renderers/hollow-candle.d.ts +18 -0
- package/dist/renderers/kagi.d.ts +22 -0
- package/dist/renderers/line-break.d.ts +20 -0
- package/dist/renderers/line.d.ts +17 -0
- package/dist/renderers/point-figure.d.ts +20 -0
- package/dist/renderers/renderer.d.ts +59 -0
- package/dist/renderers/renko.d.ts +24 -0
- package/dist/renderers/step-line.d.ts +14 -0
- package/dist/renderers/text-cache.d.ts +23 -0
- package/dist/renderers/volume-candle.d.ts +20 -0
- package/dist/renderers/webgl/area-webgl.d.ts +28 -0
- package/dist/renderers/webgl/candlestick-webgl.d.ts +30 -0
- package/dist/renderers/webgl/index.d.ts +7 -0
- package/dist/renderers/webgl/line-webgl.d.ts +23 -0
- package/dist/renderers/webgl/webgl-utils.d.ts +23 -0
- package/dist/timezone/index.d.ts +2 -0
- package/dist/timezone/timezone.d.ts +12 -0
- package/dist/transforms/aggregate.d.ts +2 -0
- package/dist/transforms/heikin-ashi.d.ts +2 -0
- package/dist/transforms/index.d.ts +2 -0
- package/dist/ui/context-menu.d.ts +14 -0
- package/dist/ui/hud.d.ts +43 -0
- package/dist/ui/settings-popup.d.ts +15 -0
- package/package.json +129 -0
package/dist/index60.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var o={boxSize:1,reversalBoxes:3,upColor:"#22AB94",downColor:"#F7525F"},t=class{constructor(){this._options={...o}}applyOptions(o){this._options={...this._options,...o}}_buildColumns(o,t,e){const{boxSize:n,reversalBoxes:s}=this._options;if(n<=0||s<=0)return[];const h=Math.min(e,o.length-1);if(t>h)return[];const i=[],x=Math.floor(o.close[t]/n);let r={startIndex:t,endIndex:t,isX:!0,lowBox:x,highBox:x},l=!1;for(let a=t+1;a<=h;a++){const t=o.close[a],e=Math.floor(t/n);l?r.isX?e>r.highBox?(r.highBox=e,r.endIndex=a):r.highBox-e>=s&&(i.push({...r}),r={startIndex:a,endIndex:a,isX:!1,lowBox:e,highBox:r.highBox-1}):e<r.lowBox?(r.lowBox=e,r.endIndex=a):e-r.lowBox>=s&&(i.push({...r}),r={startIndex:a,endIndex:a,isX:!0,lowBox:r.lowBox+1,highBox:e}):e>r.highBox?(r.isX=!0,r.highBox=e,r.endIndex=a,l=!0):e<r.lowBox&&(r.isX=!1,r.lowBox=e,r.endIndex=a,l=!0)}return l&&i.push(r),i}draw(o,t,e,n,s,h){const{context:i,pixelRatio:x}=o,{fromIdx:r,toIdx:l}=e;if(r>=l||0===t.length)return;const a=this._options,d=this._buildColumns(t,r,l);if(0===d.length)return;const u=Math.max(1,Math.round(h*x/2)),B=Math.max(1,Math.round(1.5*x)),p=Math.max(1,Math.round(2*x));i.save(),i.lineWidth=B,i.lineCap="round";for(let c=0;c<d.length;c++){const o=d[c],t=Math.round((o.startIndex+o.endIndex)/2),e=Math.round(n(t)*x);i.strokeStyle=o.isX?a.upColor:a.downColor;for(let n=o.lowBox;n<=o.highBox;n++){const t=(n+1)*a.boxSize,h=n*a.boxSize,r=e-u+p,l=e+u-p,d=Math.round(s(t)*x)+p,B=Math.round(s(h)*x)-p;if(o.isX)i.beginPath(),i.moveTo(r,d),i.lineTo(l,B),i.moveTo(l,d),i.lineTo(r,B),i.stroke();else{const o=e,t=(d+B)/2,n=Math.max(1,(l-r)/2),s=Math.max(1,(B-d)/2);i.beginPath(),i.ellipse(o,t,n,s,0,0,2*Math.PI),i.stroke()}}}i.restore()}};export{t as PointFigureRenderer};
|
|
2
|
+
//# sourceMappingURL=index60.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index60.js","names":[],"sources":["../src/renderers/point-figure.ts"],"sourcesContent":["import type { ColumnStore, IRenderTarget, VisibleRange } from '../core/types';\n\nexport interface PointFigureRendererOptions {\n boxSize: number;\n reversalBoxes: number;\n upColor: string;\n downColor: string;\n}\n\nconst DEFAULT_OPTIONS: PointFigureRendererOptions = {\n boxSize: 1,\n reversalBoxes: 3,\n upColor: '#22AB94',\n downColor: '#F7525F',\n};\n\n/** A column of Xs (rising) or Os (falling). */\ninterface PFColumn {\n /** Source bar index where this column starts. */\n startIndex: number;\n /** Source bar index where this column ends. */\n endIndex: number;\n /** True = X column (rising), false = O column (falling). */\n isX: boolean;\n /** Lowest box level in this column (in box units = price / boxSize). */\n lowBox: number;\n /** Highest box level in this column (in box units). */\n highBox: number;\n}\n\n/**\n * PointFigureRenderer — draws Point & Figure chart with X and O columns.\n *\n * X columns represent rising prices, O columns represent falling prices.\n * A new column starts when price reverses by `reversalBoxes * boxSize`.\n * Each box is drawn as an X (two crossing diagonals) or O (ellipse).\n */\nexport class PointFigureRenderer {\n private _options: PointFigureRendererOptions = { ...DEFAULT_OPTIONS };\n\n applyOptions(options: Partial<PointFigureRendererOptions>): void {\n this._options = { ...this._options, ...options };\n }\n\n private _buildColumns(store: ColumnStore, fromIdx: number, toIdx: number): PFColumn[] {\n const { boxSize, reversalBoxes } = this._options;\n if (boxSize <= 0 || reversalBoxes <= 0) return [];\n\n const end = Math.min(toIdx, store.length - 1);\n if (fromIdx > end) return [];\n\n const columns: PFColumn[] = [];\n\n // Initialize from the first close.\n const firstBox = Math.floor(store.close[fromIdx] / boxSize);\n let currentColumn: PFColumn = {\n startIndex: fromIdx,\n endIndex: fromIdx,\n isX: true, // Will be determined by first movement.\n lowBox: firstBox,\n highBox: firstBox,\n };\n let directionEstablished = false;\n\n for (let i = fromIdx + 1; i <= end; i++) {\n const close = store.close[i];\n const box = Math.floor(close / boxSize);\n\n if (!directionEstablished) {\n // Determine initial direction from first significant movement.\n if (box > currentColumn.highBox) {\n currentColumn.isX = true;\n currentColumn.highBox = box;\n currentColumn.endIndex = i;\n directionEstablished = true;\n } else if (box < currentColumn.lowBox) {\n currentColumn.isX = false;\n currentColumn.lowBox = box;\n currentColumn.endIndex = i;\n directionEstablished = true;\n }\n continue;\n }\n\n if (currentColumn.isX) {\n // Currently in an X (rising) column.\n if (box > currentColumn.highBox) {\n // Extend upward.\n currentColumn.highBox = box;\n currentColumn.endIndex = i;\n } else if (currentColumn.highBox - box >= reversalBoxes) {\n // Reversal down — save current column and start O column.\n columns.push({ ...currentColumn });\n currentColumn = {\n startIndex: i,\n endIndex: i,\n isX: false,\n // New O column starts one box below the previous high.\n lowBox: box,\n highBox: currentColumn.highBox - 1,\n };\n }\n } else {\n // Currently in an O (falling) column.\n if (box < currentColumn.lowBox) {\n // Extend downward.\n currentColumn.lowBox = box;\n currentColumn.endIndex = i;\n } else if (box - currentColumn.lowBox >= reversalBoxes) {\n // Reversal up — save current column and start X column.\n columns.push({ ...currentColumn });\n currentColumn = {\n startIndex: i,\n endIndex: i,\n isX: true,\n // New X column starts one box above the previous low.\n lowBox: currentColumn.lowBox + 1,\n highBox: box,\n };\n }\n }\n }\n\n // Push the last column.\n if (directionEstablished) {\n columns.push(currentColumn);\n }\n\n return columns;\n }\n\n draw(\n target: IRenderTarget,\n store: ColumnStore,\n range: VisibleRange,\n indexToX: (i: number) => number,\n priceToY: (price: number) => number,\n barWidth: number,\n ): void {\n const { context: ctx, pixelRatio: pr } = target;\n const { fromIdx, toIdx } = range;\n\n if (fromIdx >= toIdx || store.length === 0) return;\n\n const opts = this._options;\n const columns = this._buildColumns(store, fromIdx, toIdx);\n if (columns.length === 0) return;\n\n const halfBody = Math.max(1, Math.round((barWidth * pr) / 2));\n const markLineWidth = Math.max(1, Math.round(1.5 * pr));\n // Padding inside each box so marks don't touch edges.\n const pad = Math.max(1, Math.round(2 * pr));\n\n ctx.save();\n ctx.lineWidth = markLineWidth;\n ctx.lineCap = 'round';\n\n for (let c = 0; c < columns.length; c++) {\n const col = columns[c];\n // Use the midpoint index for the column x-position.\n const midIndex = Math.round((col.startIndex + col.endIndex) / 2);\n const cx = Math.round(indexToX(midIndex) * pr);\n\n ctx.strokeStyle = col.isX ? opts.upColor : opts.downColor;\n\n for (let box = col.lowBox; box <= col.highBox; box++) {\n const boxTopPrice = (box + 1) * opts.boxSize;\n const boxBottomPrice = box * opts.boxSize;\n const topY = Math.round(priceToY(boxTopPrice) * pr);\n const bottomY = Math.round(priceToY(boxBottomPrice) * pr);\n\n // Box boundaries with padding.\n const left = cx - halfBody + pad;\n const right = cx + halfBody - pad;\n const top = topY + pad;\n const bottom = bottomY - pad;\n\n if (col.isX) {\n // Draw X: two crossing diagonal lines.\n ctx.beginPath();\n ctx.moveTo(left, top);\n ctx.lineTo(right, bottom);\n ctx.moveTo(right, top);\n ctx.lineTo(left, bottom);\n ctx.stroke();\n } else {\n // Draw O: ellipse.\n const centerX = cx;\n const centerY = (top + bottom) / 2;\n const radiusX = Math.max(1, (right - left) / 2);\n const radiusY = Math.max(1, (bottom - top) / 2);\n\n ctx.beginPath();\n ctx.ellipse(centerX, centerY, radiusX, radiusY, 0, 0, Math.PI * 2);\n ctx.stroke();\n }\n }\n }\n\n ctx.restore();\n }\n}\n"],"mappings":"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"}
|
package/dist/index61.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function e(){if("undefined"==typeof document)return!1;try{return null!==document.createElement("canvas").getContext("webgl2")}catch{return!1}}function r(e,r,t){const a=e.createShader(r);if(!a)throw new Error("Failed to create shader");if(e.shaderSource(a,t),e.compileShader(a),!e.getShaderParameter(a,e.COMPILE_STATUS)){const r=e.getShaderInfoLog(a);throw e.deleteShader(a),new Error(`Shader compilation failed: ${r}`)}return a}function t(e,t,a){const n=r(e,e.VERTEX_SHADER,t),o=r(e,e.FRAGMENT_SHADER,a),d=e.createProgram();if(!d)throw e.deleteShader(n),e.deleteShader(o),new Error("Failed to create program");try{if(e.attachShader(d,n),e.attachShader(d,o),e.linkProgram(d),!e.getProgramParameter(d,e.LINK_STATUS)){const r=e.getProgramInfoLog(d);throw e.deleteProgram(d),new Error(`Program linking failed: ${r}`)}return d}finally{e.detachShader(d,n),e.detachShader(d,o),e.deleteShader(n),e.deleteShader(o)}}function a(e){const r=e.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([\d.]+))?\s*\)/);if(r)return[parseInt(r[1])/255,parseInt(r[2])/255,parseInt(r[3])/255,void 0!==r[4]?parseFloat(r[4]):1];if(e.startsWith("#")){let r=e.slice(1);if(3===r.length&&(r=r[0]+r[0]+r[1]+r[1]+r[2]+r[2]),6!==r.length&&8!==r.length)return[1,1,1,1];const t=parseInt(r.slice(0,2),16),a=parseInt(r.slice(2,4),16),n=parseInt(r.slice(4,6),16),o=8===r.length?parseInt(r.slice(6,8),16)/255:1;return isNaN(t)||isNaN(a)||isNaN(n)||isNaN(o)?[1,1,1,1]:[t/255,a/255,n/255,o]}return[1,1,1,1]}function n(e,r,t){e.bindBuffer(e.ARRAY_BUFFER,r),e.bufferData(e.ARRAY_BUFFER,t,e.DYNAMIC_DRAW)}export{t as createProgram,e as isWebGLAvailable,a as parseColor,n as uploadBuffer};
|
|
2
|
+
//# sourceMappingURL=index61.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index61.js","names":[],"sources":["../src/renderers/webgl/webgl-utils.ts"],"sourcesContent":["/**\n * WebGL utility functions: shader compilation, program linking, buffer helpers.\n */\n\n/**\n * Check whether WebGL2 is available in the current environment.\n */\nexport function isWebGLAvailable(): boolean {\n if (typeof document === 'undefined') return false;\n try {\n const canvas = document.createElement('canvas');\n const gl = canvas.getContext('webgl2');\n return gl !== null;\n } catch {\n return false;\n }\n}\n\n/**\n * Compile a shader from source. Throws on compilation failure.\n */\nexport function compileShader(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader {\n const shader = gl.createShader(type);\n if (!shader) throw new Error('Failed to create shader');\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n const info = gl.getShaderInfoLog(shader);\n gl.deleteShader(shader);\n throw new Error(`Shader compilation failed: ${info}`);\n }\n return shader;\n}\n\n/**\n * Link vertex + fragment shaders into a program. Throws on failure.\n */\nexport function createProgram(\n gl: WebGL2RenderingContext,\n vertexSource: string,\n fragmentSource: string,\n): WebGLProgram {\n const vs = compileShader(gl, gl.VERTEX_SHADER, vertexSource);\n const fs = compileShader(gl, gl.FRAGMENT_SHADER, fragmentSource);\n const program = gl.createProgram();\n if (!program) {\n gl.deleteShader(vs);\n gl.deleteShader(fs);\n throw new Error('Failed to create program');\n }\n\n try {\n gl.attachShader(program, vs);\n gl.attachShader(program, fs);\n gl.linkProgram(program);\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n const info = gl.getProgramInfoLog(program);\n gl.deleteProgram(program);\n throw new Error(`Program linking failed: ${info}`);\n }\n return program;\n } finally {\n gl.detachShader(program, vs);\n gl.detachShader(program, fs);\n gl.deleteShader(vs);\n gl.deleteShader(fs);\n }\n}\n\n/**\n * Parse a CSS color string into normalized [r, g, b, a] values (0–1).\n */\nexport function parseColor(color: string): [number, number, number, number] {\n // Handle rgba(r, g, b, a)\n const rgbaMatch = color.match(\n /rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)(?:\\s*,\\s*([\\d.]+))?\\s*\\)/,\n );\n if (rgbaMatch) {\n return [\n parseInt(rgbaMatch[1]) / 255,\n parseInt(rgbaMatch[2]) / 255,\n parseInt(rgbaMatch[3]) / 255,\n rgbaMatch[4] !== undefined ? parseFloat(rgbaMatch[4]) : 1,\n ];\n }\n // Handle #RGB, #RRGGBB, or #RRGGBBAA\n if (color.startsWith('#')) {\n let hex = color.slice(1);\n if (hex.length === 3) hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];\n if (hex.length !== 6 && hex.length !== 8) return [1, 1, 1, 1]; // unsupported format\n const r = parseInt(hex.slice(0, 2), 16);\n const g = parseInt(hex.slice(2, 4), 16);\n const b = parseInt(hex.slice(4, 6), 16);\n const a = hex.length === 8 ? parseInt(hex.slice(6, 8), 16) / 255 : 1;\n if (isNaN(r) || isNaN(g) || isNaN(b) || isNaN(a)) return [1, 1, 1, 1];\n return [r / 255, g / 255, b / 255, a];\n }\n // Fallback\n return [1, 1, 1, 1];\n}\n\n/**\n * Upload Float32Array data to a buffer object.\n */\nexport function uploadBuffer(\n gl: WebGL2RenderingContext,\n buffer: WebGLBuffer,\n data: Float32Array,\n): void {\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n gl.bufferData(gl.ARRAY_BUFFER, data, gl.DYNAMIC_DRAW);\n}\n"],"mappings":"AAOA,SAAgB,IACd,GAAwB,oBAAb,SAA0B,OAAO,EAC5C,IAGE,OAAc,OAFC,SAAS,cAAc,UACpB,WAAW,gBAG7B,OAAO,GAOX,SAAgB,EAAc,EAA4B,EAAc,GACtE,MAAM,EAAS,EAAG,aAAa,GAC/B,IAAK,EAAQ,MAAM,IAAI,MAAM,2BAG7B,GAFA,EAAG,aAAa,EAAQ,GACxB,EAAG,cAAc,IACZ,EAAG,mBAAmB,EAAQ,EAAG,gBAAiB,CACrD,MAAM,EAAO,EAAG,iBAAiB,GAEjC,MADA,EAAG,aAAa,GACV,IAAI,MAAM,8BAA8B,KAEhD,OAAO,EAMT,SAAgB,EACd,EACA,EACA,GAEA,MAAM,EAAK,EAAc,EAAI,EAAG,cAAe,GACzC,EAAK,EAAc,EAAI,EAAG,gBAAiB,GAC3C,EAAU,EAAG,gBACnB,IAAK,EAGH,MAFA,EAAG,aAAa,GAChB,EAAG,aAAa,GACV,IAAI,MAAM,4BAGlB,IAIE,GAHA,EAAG,aAAa,EAAS,GACzB,EAAG,aAAa,EAAS,GACzB,EAAG,YAAY,IACV,EAAG,oBAAoB,EAAS,EAAG,aAAc,CACpD,MAAM,EAAO,EAAG,kBAAkB,GAElC,MADA,EAAG,cAAc,GACX,IAAI,MAAM,2BAA2B,KAE7C,OAAO,UAEP,EAAG,aAAa,EAAS,GACzB,EAAG,aAAa,EAAS,GACzB,EAAG,aAAa,GAChB,EAAG,aAAa,IAOpB,SAAgB,EAAW,GAEzB,MAAM,EAAY,EAAM,MACtB,oEAEF,GAAI,EACF,MAAO,CACL,SAAS,EAAU,IAAM,IACzB,SAAS,EAAU,IAAM,IACzB,SAAS,EAAU,IAAM,SACR,IAAjB,EAAU,GAAmB,WAAW,EAAU,IAAM,GAI5D,GAAI,EAAM,WAAW,KAAM,CACzB,IAAI,EAAM,EAAM,MAAM,GAEtB,GADmB,IAAf,EAAI,SAAc,EAAM,EAAI,GAAK,EAAI,GAAK,EAAI,GAAK,EAAI,GAAK,EAAI,GAAK,EAAI,IAC1D,IAAf,EAAI,QAA+B,IAAf,EAAI,OAAc,MAAO,CAAC,EAAG,EAAG,EAAG,GAC3D,MAAM,EAAI,SAAS,EAAI,MAAM,EAAG,GAAI,IAC9B,EAAI,SAAS,EAAI,MAAM,EAAG,GAAI,IAC9B,EAAI,SAAS,EAAI,MAAM,EAAG,GAAI,IAC9B,EAAmB,IAAf,EAAI,OAAe,SAAS,EAAI,MAAM,EAAG,GAAI,IAAM,IAAM,EACnE,OAAI,MAAM,IAAM,MAAM,IAAM,MAAM,IAAM,MAAM,GAAW,CAAC,EAAG,EAAG,EAAG,GAC5D,CAAC,EAAI,IAAK,EAAI,IAAK,EAAI,IAAK,GAGrC,MAAO,CAAC,EAAG,EAAG,EAAG,GAMnB,SAAgB,EACd,EACA,EACA,GAEA,EAAG,WAAW,EAAG,aAAc,GAC/B,EAAG,WAAW,EAAG,aAAc,EAAM,EAAG"}
|
package/dist/index62.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{createProgram as o,parseColor as r,uploadBuffer as t}from"./index61.js";var i={upColor:"#22AB94",downColor:"#F7525F",wickUpColor:"#22AB94",wickDownColor:"#F7525F"},e=class{constructor(){this._options={...i},this._resources=/* @__PURE__ */new Map,this._posData=new Float32Array(0),this._colorData=new Float32Array(0),this._upColor=r(i.upColor),this._downColor=r(i.downColor),this._wickUpColor=r(i.wickUpColor),this._wickDownColor=r(i.wickDownColor)}applyOptions(o){void 0!==o.upColor&&o.upColor!==this._options.upColor&&(this._upColor=r(o.upColor)),void 0!==o.downColor&&o.downColor!==this._options.downColor&&(this._downColor=r(o.downColor)),void 0!==o.wickUpColor&&o.wickUpColor!==this._options.wickUpColor&&(this._wickUpColor=r(o.wickUpColor)),void 0!==o.wickDownColor&&o.wickDownColor!==this._options.wickDownColor&&(this._wickDownColor=r(o.wickDownColor)),this._options={...this._options,...o}}_getResources(r){let t=this._resources.get(r);if(t)return t;const i=o(r,"#version 300 es\nprecision highp float;\n\n// Per-vertex: xy position in pixels\nlayout(location = 0) in vec2 a_position;\n// Per-vertex: rgba color\nlayout(location = 1) in vec4 a_color;\n\nuniform vec2 u_resolution;\n\nout vec4 v_color;\n\nvoid main() {\n // Convert pixel coords to clip space (-1..+1)\n vec2 clipPos = (a_position / u_resolution) * 2.0 - 1.0;\n // Flip Y (canvas Y=0 is top)\n clipPos.y = -clipPos.y;\n gl_Position = vec4(clipPos, 0.0, 1.0);\n v_color = a_color;\n}\n","#version 300 es\nprecision highp float;\n\nin vec4 v_color;\nout vec4 fragColor;\n\nvoid main() {\n fragColor = v_color;\n}\n"),e=r.getUniformLocation(i,"u_resolution"),n=r.createVertexArray();r.bindVertexArray(n);const s=r.createBuffer();r.bindBuffer(r.ARRAY_BUFFER,s),r.enableVertexAttribArray(0),r.vertexAttribPointer(0,2,r.FLOAT,!1,0,0);const l=r.createBuffer();return r.bindBuffer(r.ARRAY_BUFFER,l),r.enableVertexAttribArray(1),r.vertexAttribPointer(1,4,r.FLOAT,!1,0,0),r.bindVertexArray(null),t={program:i,vao:n,posBuf:s,colorBuf:l,resolutionLoc:e},this._resources.set(r,t),t}draw(o,r,i,e,n,s,l,a,c){const{fromIdx:p,toIdx:u}=s;if(p>=u||0===n.length)return;const h=this._getResources(o),_=e,w=this._upColor,C=this._downColor,f=this._wickUpColor,d=this._wickDownColor,v=Math.min(u,n.length-1)-p+1,A=12*v*2,x=12*v*4;this._posData.length<A&&(this._posData=new Float32Array(A)),this._colorData.length<x&&(this._colorData=new Float32Array(x));const g=this._posData,y=this._colorData;let m=0,k=0;const D=Math.max(1,c*_/2),B=Math.max(.5,_/2);for(let t=p;t<=u&&t<n.length;t++){const o=n.open[t],r=n.close[t],i=n.high[t],e=n.low[t],s=r>=o,c=l(t)*_,p=a(o)*_,u=a(r)*_,h=a(i)*_,v=a(e)*_,A=Math.min(p,u),x=Math.max(1,Math.max(p,u)-A),b=s?f:d,F=s?w:C,U=c-B,P=c+B,R=h,V=v;g[m++]=U,g[m++]=R,g[m++]=P,g[m++]=R,g[m++]=U,g[m++]=V,g[m++]=P,g[m++]=R,g[m++]=P,g[m++]=V,g[m++]=U,g[m++]=V;for(let t=0;t<6;t++)y[k++]=b[0],y[k++]=b[1],y[k++]=b[2],y[k++]=b[3];const M=c-D,L=c+D,Y=A,E=A+x;g[m++]=M,g[m++]=Y,g[m++]=L,g[m++]=Y,g[m++]=M,g[m++]=E,g[m++]=L,g[m++]=Y,g[m++]=L,g[m++]=E,g[m++]=M,g[m++]=E;for(let t=0;t<6;t++)y[k++]=F[0],y[k++]=F[1],y[k++]=F[2],y[k++]=F[3]}o.useProgram(h.program),o.uniform2f(h.resolutionLoc,r*_,i*_),o.bindVertexArray(h.vao),t(o,h.posBuf,g.subarray(0,m)),t(o,h.colorBuf,y.subarray(0,k)),o.drawArrays(o.TRIANGLES,0,m/2),o.bindVertexArray(null)}dispose(){for(const[o,r]of this._resources)o.deleteProgram(r.program),o.deleteVertexArray(r.vao),o.deleteBuffer(r.posBuf),o.deleteBuffer(r.colorBuf);this._resources.clear()}};export{e as CandlestickWebGLRenderer};
|
|
2
|
+
//# sourceMappingURL=index62.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index62.js","names":[],"sources":["../src/renderers/webgl/candlestick-webgl.ts"],"sourcesContent":["import type { ColumnStore, VisibleRange } from '../../core/types';\nimport { createProgram, parseColor, uploadBuffer } from './webgl-utils';\n\nexport interface CandlestickWebGLOptions {\n upColor: string;\n downColor: string;\n wickUpColor: string;\n wickDownColor: string;\n}\n\nconst DEFAULT_OPTIONS: CandlestickWebGLOptions = {\n upColor: '#22AB94',\n downColor: '#F7525F',\n wickUpColor: '#22AB94',\n wickDownColor: '#F7525F',\n};\n\n// ── Shaders ─────────────────────────────────────────────────────────────────\n\nconst VERT_SOURCE = `#version 300 es\nprecision highp float;\n\n// Per-vertex: xy position in pixels\nlayout(location = 0) in vec2 a_position;\n// Per-vertex: rgba color\nlayout(location = 1) in vec4 a_color;\n\nuniform vec2 u_resolution;\n\nout vec4 v_color;\n\nvoid main() {\n // Convert pixel coords to clip space (-1..+1)\n vec2 clipPos = (a_position / u_resolution) * 2.0 - 1.0;\n // Flip Y (canvas Y=0 is top)\n clipPos.y = -clipPos.y;\n gl_Position = vec4(clipPos, 0.0, 1.0);\n v_color = a_color;\n}\n`;\n\nconst FRAG_SOURCE = `#version 300 es\nprecision highp float;\n\nin vec4 v_color;\nout vec4 fragColor;\n\nvoid main() {\n fragColor = v_color;\n}\n`;\n\n/** Cached GL resources for a single WebGL2 context. */\ninterface GLResources {\n program: WebGLProgram;\n vao: WebGLVertexArrayObject;\n posBuf: WebGLBuffer;\n colorBuf: WebGLBuffer;\n resolutionLoc: WebGLUniformLocation | null;\n}\n\n/**\n * GPU-accelerated candlestick renderer using per-vertex rectangle geometry.\n *\n * Each candle is composed of two rectangles (wick + body), with each\n * rectangle emitted as two triangles (6 vertices) into typed arrays.\n * The vertex buffer is rebuilt each frame from the visible range — fast\n * enough for 500k+ bars because only the visible subset is generated and\n * uploaded.\n */\nexport class CandlestickWebGLRenderer {\n private _options: CandlestickWebGLOptions = { ...DEFAULT_OPTIONS };\n private _resources: Map<WebGL2RenderingContext, GLResources> = new Map();\n\n // Pre-allocated typed arrays, grown as needed\n private _posData: Float32Array = new Float32Array(0);\n private _colorData: Float32Array = new Float32Array(0);\n\n // Cached parsed colors — only reparsed when values actually change\n private _upColor: [number, number, number, number] = parseColor(DEFAULT_OPTIONS.upColor);\n private _downColor: [number, number, number, number] = parseColor(DEFAULT_OPTIONS.downColor);\n private _wickUpColor: [number, number, number, number] = parseColor(DEFAULT_OPTIONS.wickUpColor);\n private _wickDownColor: [number, number, number, number] = parseColor(DEFAULT_OPTIONS.wickDownColor);\n\n applyOptions(options: Partial<CandlestickWebGLOptions>): void {\n if (options.upColor !== undefined && options.upColor !== this._options.upColor) {\n this._upColor = parseColor(options.upColor);\n }\n if (options.downColor !== undefined && options.downColor !== this._options.downColor) {\n this._downColor = parseColor(options.downColor);\n }\n if (options.wickUpColor !== undefined && options.wickUpColor !== this._options.wickUpColor) {\n this._wickUpColor = parseColor(options.wickUpColor);\n }\n if (options.wickDownColor !== undefined && options.wickDownColor !== this._options.wickDownColor) {\n this._wickDownColor = parseColor(options.wickDownColor);\n }\n this._options = { ...this._options, ...options };\n }\n\n private _getResources(gl: WebGL2RenderingContext): GLResources {\n let res = this._resources.get(gl);\n if (res) return res;\n\n const program = createProgram(gl, VERT_SOURCE, FRAG_SOURCE);\n const resolutionLoc = gl.getUniformLocation(program, 'u_resolution');\n\n const vao = gl.createVertexArray()!;\n gl.bindVertexArray(vao);\n\n const posBuf = gl.createBuffer()!;\n gl.bindBuffer(gl.ARRAY_BUFFER, posBuf);\n gl.enableVertexAttribArray(0);\n gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);\n\n const colorBuf = gl.createBuffer()!;\n gl.bindBuffer(gl.ARRAY_BUFFER, colorBuf);\n gl.enableVertexAttribArray(1);\n gl.vertexAttribPointer(1, 4, gl.FLOAT, false, 0, 0);\n\n gl.bindVertexArray(null);\n\n res = { program, vao, posBuf, colorBuf, resolutionLoc };\n this._resources.set(gl, res);\n return res;\n }\n\n draw(\n gl: WebGL2RenderingContext,\n width: number,\n height: number,\n pixelRatio: number,\n store: ColumnStore,\n range: VisibleRange,\n indexToX: (i: number) => number,\n priceToY: (price: number) => number,\n barWidth: number,\n ): void {\n const { fromIdx, toIdx } = range;\n if (fromIdx >= toIdx || store.length === 0) return;\n\n const res = this._getResources(gl);\n const pr = pixelRatio;\n\n const upColor = this._upColor;\n const downColor = this._downColor;\n const wickUpColor = this._wickUpColor;\n const wickDownColor = this._wickDownColor;\n\n const count = Math.min(toIdx, store.length - 1) - fromIdx + 1;\n // 2 rects per candle × 6 vertices per rect = 12 vertices per candle\n const posNeeded = count * 12 * 2;\n const colorNeeded = count * 12 * 4;\n if (this._posData.length < posNeeded) this._posData = new Float32Array(posNeeded);\n if (this._colorData.length < colorNeeded) this._colorData = new Float32Array(colorNeeded);\n\n const posData = this._posData;\n const colorData = this._colorData;\n\n let vi = 0; // vertex index into posData (stride 2)\n let ci = 0; // vertex index into colorData (stride 4)\n\n const halfBody = Math.max(1, (barWidth * pr) / 2);\n const wickHalf = Math.max(0.5, pr / 2);\n\n for (let i = fromIdx; i <= toIdx && i < store.length; i++) {\n const open = store.open[i];\n const close = store.close[i];\n const high = store.high[i];\n const low = store.low[i];\n const isUp = close >= open;\n\n const cx = indexToX(i) * pr;\n const openY = priceToY(open) * pr;\n const closeY = priceToY(close) * pr;\n const highY = priceToY(high) * pr;\n const lowY = priceToY(low) * pr;\n\n const bodyTop = Math.min(openY, closeY);\n const bodyBottom = Math.max(openY, closeY);\n const bodyH = Math.max(1, bodyBottom - bodyTop);\n\n const wColor = isUp ? wickUpColor : wickDownColor;\n const bColor = isUp ? upColor : downColor;\n\n // ── Wick rect ──\n const wx0 = cx - wickHalf;\n const wx1 = cx + wickHalf;\n const wy0 = highY;\n const wy1 = lowY;\n // Triangle 1\n posData[vi++] = wx0; posData[vi++] = wy0;\n posData[vi++] = wx1; posData[vi++] = wy0;\n posData[vi++] = wx0; posData[vi++] = wy1;\n // Triangle 2\n posData[vi++] = wx1; posData[vi++] = wy0;\n posData[vi++] = wx1; posData[vi++] = wy1;\n posData[vi++] = wx0; posData[vi++] = wy1;\n for (let v = 0; v < 6; v++) {\n colorData[ci++] = wColor[0];\n colorData[ci++] = wColor[1];\n colorData[ci++] = wColor[2];\n colorData[ci++] = wColor[3];\n }\n\n // ── Body rect ──\n const bx0 = cx - halfBody;\n const bx1 = cx + halfBody;\n const by0 = bodyTop;\n const by1 = bodyTop + bodyH;\n // Triangle 1\n posData[vi++] = bx0; posData[vi++] = by0;\n posData[vi++] = bx1; posData[vi++] = by0;\n posData[vi++] = bx0; posData[vi++] = by1;\n // Triangle 2\n posData[vi++] = bx1; posData[vi++] = by0;\n posData[vi++] = bx1; posData[vi++] = by1;\n posData[vi++] = bx0; posData[vi++] = by1;\n for (let v = 0; v < 6; v++) {\n colorData[ci++] = bColor[0];\n colorData[ci++] = bColor[1];\n colorData[ci++] = bColor[2];\n colorData[ci++] = bColor[3];\n }\n }\n\n // Upload & draw\n gl.useProgram(res.program);\n gl.uniform2f(res.resolutionLoc, width * pr, height * pr);\n gl.bindVertexArray(res.vao);\n\n uploadBuffer(gl, res.posBuf, posData.subarray(0, vi));\n uploadBuffer(gl, res.colorBuf, colorData.subarray(0, ci));\n\n gl.drawArrays(gl.TRIANGLES, 0, vi / 2);\n gl.bindVertexArray(null);\n }\n\n dispose(): void {\n for (const [gl, res] of this._resources) {\n gl.deleteProgram(res.program);\n gl.deleteVertexArray(res.vao);\n gl.deleteBuffer(res.posBuf);\n gl.deleteBuffer(res.colorBuf);\n }\n this._resources.clear();\n }\n}\n"],"mappings":"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"}
|
package/dist/index63.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{createProgram as o,parseColor as r,uploadBuffer as t}from"./index61.js";var e={color:"#2196F3",lineWidth:2},s=class{constructor(){this._options={...e},this._resources=/* @__PURE__ */new Map,this._posData=new Float32Array(0),this._parsedColor=r(e.color)}applyOptions(o){const t=this._options.color;this._options={...this._options,...o},void 0!==o.color&&o.color!==t&&(this._parsedColor=r(o.color))}_getResources(r){let t=this._resources.get(r);if(t)return t;const e=o(r,"#version 300 es\nprecision highp float;\n\nlayout(location = 0) in vec2 a_position;\n\nuniform vec2 u_resolution;\n\nvoid main() {\n vec2 clipPos = (a_position / u_resolution) * 2.0 - 1.0;\n clipPos.y = -clipPos.y;\n gl_Position = vec4(clipPos, 0.0, 1.0);\n}\n","#version 300 es\nprecision highp float;\n\nuniform vec4 u_color;\nout vec4 fragColor;\n\nvoid main() {\n fragColor = u_color;\n}\n"),s=r.getUniformLocation(e,"u_resolution"),n=r.getUniformLocation(e,"u_color"),i=r.createVertexArray();r.bindVertexArray(i);const a=r.createBuffer();return r.bindBuffer(r.ARRAY_BUFFER,a),r.enableVertexAttribArray(0),r.vertexAttribPointer(0,2,r.FLOAT,!1,0,0),r.bindVertexArray(null),t={program:e,vao:i,posBuf:a,resolutionLoc:s,colorLoc:n},this._resources.set(r,t),t}draw(o,r,e,s,n,i,a,c){const{fromIdx:l,toIdx:u}=i;if(l>=u||0===n.length)return;const p=Math.min(u,n.length-1)-l+1;if(p<2)return;const f=this._getResources(o),h=s,_=this._options.lineWidth*h/2,d=6*(p-1)*2;this._posData.length<d&&(this._posData=new Float32Array(d));const g=this._posData;let m=0,v=a(l)*h,A=c(n.close[l])*h;for(let t=l+1;t<=u&&t<n.length;t++){const o=a(t)*h,r=c(n.close[t])*h,e=o-v,s=r-A,i=Math.sqrt(e*e+s*s);if(i>0){const t=-s/i*_,n=e/i*_,a=v+t,c=A+n,l=v-t,u=A-n,p=o+t,f=r+n,h=o-t,d=r-n;g[m++]=a,g[m++]=c,g[m++]=l,g[m++]=u,g[m++]=p,g[m++]=f,g[m++]=l,g[m++]=u,g[m++]=h,g[m++]=d,g[m++]=p,g[m++]=f}v=o,A=r}const y=this._parsedColor;o.useProgram(f.program),o.uniform2f(f.resolutionLoc,r*h,e*h),o.uniform4f(f.colorLoc,y[0],y[1],y[2],y[3]),o.bindVertexArray(f.vao),t(o,f.posBuf,g.subarray(0,m)),o.drawArrays(o.TRIANGLES,0,m/2),o.bindVertexArray(null)}dispose(){for(const[o,r]of this._resources)o.deleteProgram(r.program),o.deleteVertexArray(r.vao),o.deleteBuffer(r.posBuf);this._resources.clear()}};export{s as LineWebGLRenderer};
|
|
2
|
+
//# sourceMappingURL=index63.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index63.js","names":[],"sources":["../src/renderers/webgl/line-webgl.ts"],"sourcesContent":["import type { ColumnStore, VisibleRange } from '../../core/types';\nimport { createProgram, parseColor, uploadBuffer } from './webgl-utils';\n\nexport interface LineWebGLOptions {\n color: string;\n lineWidth: number;\n}\n\nconst DEFAULT_OPTIONS: LineWebGLOptions = {\n color: '#2196F3',\n lineWidth: 2,\n};\n\n// ── Shaders ─────────────────────────────────────────────────────────────────\n\nconst VERT_SOURCE = `#version 300 es\nprecision highp float;\n\nlayout(location = 0) in vec2 a_position;\n\nuniform vec2 u_resolution;\n\nvoid main() {\n vec2 clipPos = (a_position / u_resolution) * 2.0 - 1.0;\n clipPos.y = -clipPos.y;\n gl_Position = vec4(clipPos, 0.0, 1.0);\n}\n`;\n\nconst FRAG_SOURCE = `#version 300 es\nprecision highp float;\n\nuniform vec4 u_color;\nout vec4 fragColor;\n\nvoid main() {\n fragColor = u_color;\n}\n`;\n\n/** Cached GL resources for a single WebGL2 context. */\ninterface GLResources {\n program: WebGLProgram;\n vao: WebGLVertexArrayObject;\n posBuf: WebGLBuffer;\n resolutionLoc: WebGLUniformLocation | null;\n colorLoc: WebGLUniformLocation | null;\n}\n\n/**\n * GPU-accelerated line renderer.\n *\n * Draws the close-price polyline as a screen-space ribbon: each line segment\n * is expanded into a quad (2 triangles) on the CPU when building the vertex\n * buffer, and the vertex shader transforms those positions to clip space,\n * giving a consistent pixel-width line regardless of zoom level.\n */\nexport class LineWebGLRenderer {\n private _options: LineWebGLOptions = { ...DEFAULT_OPTIONS };\n private _resources: Map<WebGL2RenderingContext, GLResources> = new Map();\n\n // Pre-allocated typed array, grown as needed\n private _posData: Float32Array = new Float32Array(0);\n\n // Cached parsed color — only reparsed when value actually changes\n private _parsedColor: [number, number, number, number] = parseColor(DEFAULT_OPTIONS.color);\n\n applyOptions(options: Partial<LineWebGLOptions>): void {\n const previousColor = this._options.color;\n this._options = { ...this._options, ...options };\n if (options.color !== undefined && options.color !== previousColor) {\n this._parsedColor = parseColor(options.color);\n }\n }\n\n private _getResources(gl: WebGL2RenderingContext): GLResources {\n let res = this._resources.get(gl);\n if (res) return res;\n\n const program = createProgram(gl, VERT_SOURCE, FRAG_SOURCE);\n const resolutionLoc = gl.getUniformLocation(program, 'u_resolution');\n const colorLoc = gl.getUniformLocation(program, 'u_color');\n\n const vao = gl.createVertexArray()!;\n gl.bindVertexArray(vao);\n\n const posBuf = gl.createBuffer()!;\n gl.bindBuffer(gl.ARRAY_BUFFER, posBuf);\n gl.enableVertexAttribArray(0);\n gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);\n\n gl.bindVertexArray(null);\n\n res = { program, vao, posBuf, resolutionLoc, colorLoc };\n this._resources.set(gl, res);\n return res;\n }\n\n draw(\n gl: WebGL2RenderingContext,\n width: number,\n height: number,\n pixelRatio: number,\n store: ColumnStore,\n range: VisibleRange,\n indexToX: (i: number) => number,\n priceToY: (price: number) => number,\n ): void {\n const { fromIdx, toIdx } = range;\n if (fromIdx >= toIdx || store.length === 0) return;\n\n const count = Math.min(toIdx, store.length - 1) - fromIdx + 1;\n if (count < 2) return;\n\n const res = this._getResources(gl);\n const pr = pixelRatio;\n const lw = this._options.lineWidth * pr;\n const halfW = lw / 2;\n\n // Build ribbon quads directly — no intermediate points array\n const numSegments = count - 1;\n const posNeeded = numSegments * 6 * 2;\n if (this._posData.length < posNeeded) this._posData = new Float32Array(posNeeded);\n const posData = this._posData;\n let vi = 0;\n\n let prevX = indexToX(fromIdx) * pr;\n let prevY = priceToY(store.close[fromIdx]) * pr;\n\n for (let i = fromIdx + 1; i <= toIdx && i < store.length; i++) {\n const curX = indexToX(i) * pr;\n const curY = priceToY(store.close[i]) * pr;\n const dx = curX - prevX;\n const dy = curY - prevY;\n const len = Math.sqrt(dx * dx + dy * dy);\n if (len > 0) {\n // Perpendicular normal\n const nx = (-dy / len) * halfW;\n const ny = (dx / len) * halfW;\n\n // Quad corners\n const ax = prevX + nx, ay = prevY + ny;\n const bx = prevX - nx, by = prevY - ny;\n const cx = curX + nx, cy = curY + ny;\n const ddx = curX - nx, ddy = curY - ny;\n\n // Triangle 1\n posData[vi++] = ax; posData[vi++] = ay;\n posData[vi++] = bx; posData[vi++] = by;\n posData[vi++] = cx; posData[vi++] = cy;\n // Triangle 2\n posData[vi++] = bx; posData[vi++] = by;\n posData[vi++] = ddx; posData[vi++] = ddy;\n posData[vi++] = cx; posData[vi++] = cy;\n }\n prevX = curX;\n prevY = curY;\n }\n\n const color = this._parsedColor;\n\n gl.useProgram(res.program);\n gl.uniform2f(res.resolutionLoc, width * pr, height * pr);\n gl.uniform4f(res.colorLoc, color[0], color[1], color[2], color[3]);\n\n gl.bindVertexArray(res.vao);\n uploadBuffer(gl, res.posBuf, posData.subarray(0, vi));\n\n gl.drawArrays(gl.TRIANGLES, 0, vi / 2);\n gl.bindVertexArray(null);\n }\n\n dispose(): void {\n for (const [gl, res] of this._resources) {\n gl.deleteProgram(res.program);\n gl.deleteVertexArray(res.vao);\n gl.deleteBuffer(res.posBuf);\n }\n this._resources.clear();\n }\n}\n"],"mappings":"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"}
|
package/dist/index64.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{createProgram as o,parseColor as t,uploadBuffer as r}from"./index61.js";var e={lineColor:"#2196F3",lineWidth:2,topColor:"rgba(33, 150, 243, 0.4)",bottomColor:"rgba(33, 150, 243, 0)"},i=class{constructor(){this._options={...e},this._resources=/* @__PURE__ */new Map,this._fillPos=new Float32Array(0),this._fillT=new Float32Array(0),this._linePos=new Float32Array(0),this._topColor=t(e.topColor),this._bottomColor=t(e.bottomColor),this._lineColor=t(e.lineColor)}applyOptions(o){void 0!==o.topColor&&o.topColor!==this._options.topColor&&(this._topColor=t(o.topColor)),void 0!==o.bottomColor&&o.bottomColor!==this._options.bottomColor&&(this._bottomColor=t(o.bottomColor)),void 0!==o.lineColor&&o.lineColor!==this._options.lineColor&&(this._lineColor=t(o.lineColor)),this._options={...this._options,...o}}_getResources(t){let r=this._resources.get(t);if(r)return r;const e=o(t,"#version 300 es\nprecision highp float;\n\nlayout(location = 0) in vec2 a_position;\nlayout(location = 1) in float a_t; // 0 = top of fill, 1 = bottom\n\nuniform vec2 u_resolution;\n\nout float v_t;\n\nvoid main() {\n vec2 clipPos = (a_position / u_resolution) * 2.0 - 1.0;\n clipPos.y = -clipPos.y;\n gl_Position = vec4(clipPos, 0.0, 1.0);\n v_t = a_t;\n}\n","#version 300 es\nprecision highp float;\n\nin float v_t;\nuniform vec4 u_topColor;\nuniform vec4 u_bottomColor;\n\nout vec4 fragColor;\n\nvoid main() {\n fragColor = mix(u_topColor, u_bottomColor, v_t);\n}\n"),i=t.createVertexArray();t.bindVertexArray(i);const n=t.createBuffer();t.bindBuffer(t.ARRAY_BUFFER,n),t.enableVertexAttribArray(0),t.vertexAttribPointer(0,2,t.FLOAT,!1,0,0);const l=t.createBuffer();t.bindBuffer(t.ARRAY_BUFFER,l),t.enableVertexAttribArray(1),t.vertexAttribPointer(1,1,t.FLOAT,!1,0,0),t.bindVertexArray(null);const s=o(t,"#version 300 es\nprecision highp float;\n\nlayout(location = 0) in vec2 a_position;\nuniform vec2 u_resolution;\n\nvoid main() {\n vec2 clipPos = (a_position / u_resolution) * 2.0 - 1.0;\n clipPos.y = -clipPos.y;\n gl_Position = vec4(clipPos, 0.0, 1.0);\n}\n","#version 300 es\nprecision highp float;\n\nuniform vec4 u_color;\nout vec4 fragColor;\n\nvoid main() {\n fragColor = u_color;\n}\n"),a=t.createVertexArray();t.bindVertexArray(a);const f=t.createBuffer();return t.bindBuffer(t.ARRAY_BUFFER,f),t.enableVertexAttribArray(0),t.vertexAttribPointer(0,2,t.FLOAT,!1,0,0),t.bindVertexArray(null),r={fill:{program:e,vao:i,posBuf:n,tBuf:l,resolutionLoc:t.getUniformLocation(e,"u_resolution"),topColorLoc:t.getUniformLocation(e,"u_topColor"),botColorLoc:t.getUniformLocation(e,"u_bottomColor")},line:{program:s,vao:a,posBuf:f,resolutionLoc:t.getUniformLocation(s,"u_resolution"),colorLoc:t.getUniformLocation(s,"u_color")}},this._resources.set(t,r),r}draw(o,t,e,i,n,l,s,a){const{fromIdx:f,toIdx:c}=l;if(f>=c||0===n.length)return;const u=Math.min(c,n.length-1)-f+1;if(u<2)return;const _=this._getResources(o),p=i,h=e*p,m=u-1,C=6*m*2,b=6*m;this._fillPos.length<C&&(this._fillPos=new Float32Array(C)),this._fillT.length<b&&(this._fillT=new Float32Array(b));const A=this._fillPos,g=this._fillT;let v=0,d=0,y=1/0,P=s(f)*p,x=a(n.close[f])*p;x<y&&(y=x);for(let r=f+1;r<=c&&r<n.length;r++){const o=a(n.close[r])*p;o<y&&(y=o)}const B=h-y;for(let r=f+1;r<=c&&r<n.length;r++){const o=s(r)*p,t=a(n.close[r])*p,e=B>0?(x-y)/B:0,i=B>0?(t-y)/B:0;A[v++]=P,A[v++]=x,A[v++]=P,A[v++]=h,A[v++]=o,A[v++]=t,g[d++]=e,g[d++]=1,g[d++]=i,A[v++]=o,A[v++]=t,A[v++]=P,A[v++]=h,A[v++]=o,A[v++]=h,g[d++]=i,g[d++]=1,g[d++]=1,P=o,x=t}const L=this._topColor,F=this._bottomColor;o.useProgram(_.fill.program),o.uniform2f(_.fill.resolutionLoc,t*p,e*p),o.uniform4f(_.fill.topColorLoc,L[0],L[1],L[2],L[3]),o.uniform4f(_.fill.botColorLoc,F[0],F[1],F[2],F[3]),o.bindVertexArray(_.fill.vao),r(o,_.fill.posBuf,A.subarray(0,v)),r(o,_.fill.tBuf,g.subarray(0,d)),o.drawArrays(o.TRIANGLES,0,v/2),o.bindVertexArray(null);const V=this._options.lineWidth*p/2,R=6*m*2;this._linePos.length<R&&(this._linePos=new Float32Array(R));const w=this._linePos;let T=0;P=s(f)*p,x=a(n.close[f])*p;for(let r=f+1;r<=c&&r<n.length;r++){const o=s(r)*p,t=a(n.close[r])*p,e=o-P,i=t-x,l=Math.sqrt(e*e+i*i);if(l>0){const r=-i/l*V,n=e/l*V;w[T++]=P+r,w[T++]=x+n,w[T++]=P-r,w[T++]=x-n,w[T++]=o+r,w[T++]=t+n,w[T++]=P-r,w[T++]=x-n,w[T++]=o-r,w[T++]=t-n,w[T++]=o+r,w[T++]=t+n}P=o,x=t}const U=this._lineColor;o.useProgram(_.line.program),o.uniform2f(_.line.resolutionLoc,t*p,e*p),o.uniform4f(_.line.colorLoc,U[0],U[1],U[2],U[3]),o.bindVertexArray(_.line.vao),r(o,_.line.posBuf,w.subarray(0,T)),o.drawArrays(o.TRIANGLES,0,T/2),o.bindVertexArray(null)}dispose(){for(const[o,t]of this._resources)o.deleteProgram(t.fill.program),o.deleteVertexArray(t.fill.vao),o.deleteBuffer(t.fill.posBuf),o.deleteBuffer(t.fill.tBuf),o.deleteProgram(t.line.program),o.deleteVertexArray(t.line.vao),o.deleteBuffer(t.line.posBuf);this._resources.clear()}};export{i as AreaWebGLRenderer};
|
|
2
|
+
//# sourceMappingURL=index64.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index64.js","names":[],"sources":["../src/renderers/webgl/area-webgl.ts"],"sourcesContent":["import type { ColumnStore, VisibleRange } from '../../core/types';\nimport { createProgram, parseColor, uploadBuffer } from './webgl-utils';\n\nexport interface AreaWebGLOptions {\n lineColor: string;\n lineWidth: number;\n topColor: string;\n bottomColor: string;\n}\n\nconst DEFAULT_OPTIONS: AreaWebGLOptions = {\n lineColor: '#2196F3',\n lineWidth: 2,\n topColor: 'rgba(33, 150, 243, 0.4)',\n bottomColor: 'rgba(33, 150, 243, 0)',\n};\n\n// ── Shaders for gradient fill ───────────────────────────────────────────────\n\nconst FILL_VERT_SOURCE = `#version 300 es\nprecision highp float;\n\nlayout(location = 0) in vec2 a_position;\nlayout(location = 1) in float a_t; // 0 = top of fill, 1 = bottom\n\nuniform vec2 u_resolution;\n\nout float v_t;\n\nvoid main() {\n vec2 clipPos = (a_position / u_resolution) * 2.0 - 1.0;\n clipPos.y = -clipPos.y;\n gl_Position = vec4(clipPos, 0.0, 1.0);\n v_t = a_t;\n}\n`;\n\nconst FILL_FRAG_SOURCE = `#version 300 es\nprecision highp float;\n\nin float v_t;\nuniform vec4 u_topColor;\nuniform vec4 u_bottomColor;\n\nout vec4 fragColor;\n\nvoid main() {\n fragColor = mix(u_topColor, u_bottomColor, v_t);\n}\n`;\n\n// ── Shaders for the line on top ─────────────────────────────────────────────\n\nconst LINE_VERT_SOURCE = `#version 300 es\nprecision highp float;\n\nlayout(location = 0) in vec2 a_position;\nuniform vec2 u_resolution;\n\nvoid main() {\n vec2 clipPos = (a_position / u_resolution) * 2.0 - 1.0;\n clipPos.y = -clipPos.y;\n gl_Position = vec4(clipPos, 0.0, 1.0);\n}\n`;\n\nconst LINE_FRAG_SOURCE = `#version 300 es\nprecision highp float;\n\nuniform vec4 u_color;\nout vec4 fragColor;\n\nvoid main() {\n fragColor = u_color;\n}\n`;\n\n/** Cached GL resources for fill pass. */\ninterface FillResources {\n program: WebGLProgram;\n vao: WebGLVertexArrayObject;\n posBuf: WebGLBuffer;\n tBuf: WebGLBuffer;\n resolutionLoc: WebGLUniformLocation | null;\n topColorLoc: WebGLUniformLocation | null;\n botColorLoc: WebGLUniformLocation | null;\n}\n\n/** Cached GL resources for line pass. */\ninterface LineResources {\n program: WebGLProgram;\n vao: WebGLVertexArrayObject;\n posBuf: WebGLBuffer;\n resolutionLoc: WebGLUniformLocation | null;\n colorLoc: WebGLUniformLocation | null;\n}\n\ninterface GLResources {\n fill: FillResources;\n line: LineResources;\n}\n\n/**\n * GPU-accelerated area (mountain) chart renderer.\n *\n * Renders two passes:\n * 1. Gradient-filled polygon from the price line down to the pane bottom.\n * 2. Thick line along the close prices (same ribbon approach as LineWebGLRenderer).\n */\nexport class AreaWebGLRenderer {\n private _options: AreaWebGLOptions = { ...DEFAULT_OPTIONS };\n private _resources: Map<WebGL2RenderingContext, GLResources> = new Map();\n\n // Pre-allocated typed arrays, grown as needed\n private _fillPos: Float32Array = new Float32Array(0);\n private _fillT: Float32Array = new Float32Array(0);\n private _linePos: Float32Array = new Float32Array(0);\n\n // Cached parsed colors\n private _topColor: [number, number, number, number] = parseColor(DEFAULT_OPTIONS.topColor);\n private _bottomColor: [number, number, number, number] = parseColor(DEFAULT_OPTIONS.bottomColor);\n private _lineColor: [number, number, number, number] = parseColor(DEFAULT_OPTIONS.lineColor);\n\n applyOptions(options: Partial<AreaWebGLOptions>): void {\n if (options.topColor !== undefined && options.topColor !== this._options.topColor) {\n this._topColor = parseColor(options.topColor);\n }\n if (options.bottomColor !== undefined && options.bottomColor !== this._options.bottomColor) {\n this._bottomColor = parseColor(options.bottomColor);\n }\n if (options.lineColor !== undefined && options.lineColor !== this._options.lineColor) {\n this._lineColor = parseColor(options.lineColor);\n }\n this._options = { ...this._options, ...options };\n }\n\n private _getResources(gl: WebGL2RenderingContext): GLResources {\n let res = this._resources.get(gl);\n if (res) return res;\n\n // ── Fill pass setup ──\n const fillProgram = createProgram(gl, FILL_VERT_SOURCE, FILL_FRAG_SOURCE);\n const fillVao = gl.createVertexArray()!;\n gl.bindVertexArray(fillVao);\n\n const fillPosBuf = gl.createBuffer()!;\n gl.bindBuffer(gl.ARRAY_BUFFER, fillPosBuf);\n gl.enableVertexAttribArray(0);\n gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);\n\n const fillTBuf = gl.createBuffer()!;\n gl.bindBuffer(gl.ARRAY_BUFFER, fillTBuf);\n gl.enableVertexAttribArray(1);\n gl.vertexAttribPointer(1, 1, gl.FLOAT, false, 0, 0);\n\n gl.bindVertexArray(null);\n\n // ── Line pass setup ──\n const lineProgram = createProgram(gl, LINE_VERT_SOURCE, LINE_FRAG_SOURCE);\n const lineVao = gl.createVertexArray()!;\n gl.bindVertexArray(lineVao);\n\n const linePosBuf = gl.createBuffer()!;\n gl.bindBuffer(gl.ARRAY_BUFFER, linePosBuf);\n gl.enableVertexAttribArray(0);\n gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);\n\n gl.bindVertexArray(null);\n\n res = {\n fill: {\n program: fillProgram,\n vao: fillVao,\n posBuf: fillPosBuf,\n tBuf: fillTBuf,\n resolutionLoc: gl.getUniformLocation(fillProgram, 'u_resolution'),\n topColorLoc: gl.getUniformLocation(fillProgram, 'u_topColor'),\n botColorLoc: gl.getUniformLocation(fillProgram, 'u_bottomColor'),\n },\n line: {\n program: lineProgram,\n vao: lineVao,\n posBuf: linePosBuf,\n resolutionLoc: gl.getUniformLocation(lineProgram, 'u_resolution'),\n colorLoc: gl.getUniformLocation(lineProgram, 'u_color'),\n },\n };\n this._resources.set(gl, res);\n return res;\n }\n\n draw(\n gl: WebGL2RenderingContext,\n width: number,\n height: number,\n pixelRatio: number,\n store: ColumnStore,\n range: VisibleRange,\n indexToX: (i: number) => number,\n priceToY: (price: number) => number,\n ): void {\n const { fromIdx, toIdx } = range;\n if (fromIdx >= toIdx || store.length === 0) return;\n\n const count = Math.min(toIdx, store.length - 1) - fromIdx + 1;\n if (count < 2) return;\n\n const res = this._getResources(gl);\n const pr = pixelRatio;\n const bottomY = height * pr;\n const numSeg = count - 1;\n\n // ── Pass 1: gradient fill ──\n // Build fill triangles directly — no intermediate points array\n const fillPosNeeded = numSeg * 6 * 2;\n const fillTNeeded = numSeg * 6;\n if (this._fillPos.length < fillPosNeeded) this._fillPos = new Float32Array(fillPosNeeded);\n if (this._fillT.length < fillTNeeded) this._fillT = new Float32Array(fillTNeeded);\n\n const fillPos = this._fillPos;\n const fillT = this._fillT;\n let fi = 0;\n let ti = 0;\n\n // First pass: find minY for gradient interpolation\n let minY = Infinity;\n let prevX = indexToX(fromIdx) * pr;\n let prevY = priceToY(store.close[fromIdx]) * pr;\n if (prevY < minY) minY = prevY;\n for (let i = fromIdx + 1; i <= toIdx && i < store.length; i++) {\n const y = priceToY(store.close[i]) * pr;\n if (y < minY) minY = y;\n }\n const rangeY = bottomY - minY;\n\n // Build fill geometry\n for (let i = fromIdx + 1; i <= toIdx && i < store.length; i++) {\n const curX = indexToX(i) * pr;\n const curY = priceToY(store.close[i]) * pr;\n const t0 = rangeY > 0 ? (prevY - minY) / rangeY : 0;\n const t1 = rangeY > 0 ? (curY - minY) / rangeY : 0;\n\n // Triangle 1: prev, prevBottom, cur\n fillPos[fi++] = prevX; fillPos[fi++] = prevY;\n fillPos[fi++] = prevX; fillPos[fi++] = bottomY;\n fillPos[fi++] = curX; fillPos[fi++] = curY;\n fillT[ti++] = t0; fillT[ti++] = 1; fillT[ti++] = t1;\n\n // Triangle 2: cur, prevBottom, curBottom\n fillPos[fi++] = curX; fillPos[fi++] = curY;\n fillPos[fi++] = prevX; fillPos[fi++] = bottomY;\n fillPos[fi++] = curX; fillPos[fi++] = bottomY;\n fillT[ti++] = t1; fillT[ti++] = 1; fillT[ti++] = 1;\n\n prevX = curX;\n prevY = curY;\n }\n\n const topColor = this._topColor;\n const botColor = this._bottomColor;\n\n gl.useProgram(res.fill.program);\n gl.uniform2f(res.fill.resolutionLoc, width * pr, height * pr);\n gl.uniform4f(res.fill.topColorLoc, topColor[0], topColor[1], topColor[2], topColor[3]);\n gl.uniform4f(res.fill.botColorLoc, botColor[0], botColor[1], botColor[2], botColor[3]);\n\n gl.bindVertexArray(res.fill.vao);\n uploadBuffer(gl, res.fill.posBuf, fillPos.subarray(0, fi));\n uploadBuffer(gl, res.fill.tBuf, fillT.subarray(0, ti));\n gl.drawArrays(gl.TRIANGLES, 0, fi / 2);\n gl.bindVertexArray(null);\n\n // ── Pass 2: line ──\n const lw = this._options.lineWidth * pr;\n const halfW = lw / 2;\n\n const linePosNeeded = numSeg * 6 * 2;\n if (this._linePos.length < linePosNeeded) this._linePos = new Float32Array(linePosNeeded);\n const linePos = this._linePos;\n let li = 0;\n\n prevX = indexToX(fromIdx) * pr;\n prevY = priceToY(store.close[fromIdx]) * pr;\n\n for (let i = fromIdx + 1; i <= toIdx && i < store.length; i++) {\n const curX = indexToX(i) * pr;\n const curY = priceToY(store.close[i]) * pr;\n const dx = curX - prevX;\n const dy = curY - prevY;\n const len = Math.sqrt(dx * dx + dy * dy);\n if (len > 0) {\n const nx = (-dy / len) * halfW;\n const ny = (dx / len) * halfW;\n\n // Quad as 2 triangles\n linePos[li++] = prevX + nx; linePos[li++] = prevY + ny;\n linePos[li++] = prevX - nx; linePos[li++] = prevY - ny;\n linePos[li++] = curX + nx; linePos[li++] = curY + ny;\n\n linePos[li++] = prevX - nx; linePos[li++] = prevY - ny;\n linePos[li++] = curX - nx; linePos[li++] = curY - ny;\n linePos[li++] = curX + nx; linePos[li++] = curY + ny;\n }\n prevX = curX;\n prevY = curY;\n }\n\n const lineColor = this._lineColor;\n\n gl.useProgram(res.line.program);\n gl.uniform2f(res.line.resolutionLoc, width * pr, height * pr);\n gl.uniform4f(res.line.colorLoc, lineColor[0], lineColor[1], lineColor[2], lineColor[3]);\n\n gl.bindVertexArray(res.line.vao);\n uploadBuffer(gl, res.line.posBuf, linePos.subarray(0, li));\n gl.drawArrays(gl.TRIANGLES, 0, li / 2);\n gl.bindVertexArray(null);\n }\n\n dispose(): void {\n for (const [gl, res] of this._resources) {\n gl.deleteProgram(res.fill.program);\n gl.deleteVertexArray(res.fill.vao);\n gl.deleteBuffer(res.fill.posBuf);\n gl.deleteBuffer(res.fill.tBuf);\n gl.deleteProgram(res.line.program);\n gl.deleteVertexArray(res.line.vao);\n gl.deleteBuffer(res.line.posBuf);\n }\n this._resources.clear();\n }\n}\n"],"mappings":"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"}
|
package/dist/index65.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
function e(e,n,t,o={}){const h=o.separator??",";if(0===e.length)return"";const i=e[0].store;if(0===i.length)return"";let s=t?.fromIdx??0,r=t?.toIdx??i.length-1;if(s=Math.max(0,s),r=Math.min(i.length-1,r),void 0!==o.from)for(;s<=r&&i.time[s]<o.from;)s++;if(void 0!==o.to)for(;r>=s&&i.time[r]>o.to;)r--;if(s>r)return"";const g=["Date","Open","High","Low","Close","Volume"];for(let l=1;l<e.length;l++){const n=e[l].label||`Series ${l+1}`;g.push(`${n} Open`,`${n} High`,`${n} Low`,`${n} Close`)}if(!1!==o.includeIndicators)for(const l of n)for(const e of l.outputs.keys())g.push(l.label?`${l.label} ${e}`:e);const c=[g.join(h)];for(let l=s;l<=r;l++){const t=i.time[l],s=[
|
|
2
|
+
/* @__PURE__ */new Date(1e3*t).toISOString(),String(i.open[l]),String(i.high[l]),String(i.low[l]),String(i.close[l]),String(i.volume[l])];for(let n=1;n<e.length;n++){const t=e[n].store;l<t.length?s.push(String(t.open[l]),String(t.high[l]),String(t.low[l]),String(t.close[l])):s.push("","","","")}if(!1!==o.includeIndicators)for(const e of n)for(const n of e.outputs.values()){const e=l<n.length?n[l]:NaN;s.push(isNaN(e)?"":String(e))}c.push(s.join(h))}return c.join("\n")}function n(e){const n=e.width,t=e.height;return['<?xml version="1.0" encoding="UTF-8"?>',`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="${n}" height="${t}" viewBox="0 0 ${n} ${t}">`,` <image width="${n}" height="${t}" xlink:href="${e.toDataURL("image/png")}" />`,"</svg>"].join("\n")}var t={letter:{width:612,height:792},a4:{width:595.28,height:841.89}};function o(e,n={}){const o=t[n.pageSize??"letter"],h="landscape"===(n.orientation??"landscape"),i=h?o.height:o.width,s=h?o.width:o.height,r=e.toDataURL("image/jpeg",.95).split(",")[1],g=atob(r),c=new Uint8Array(g.length);for(let t=0;t<g.length;t++)c[t]=g.charCodeAt(t);const l=36,p=i-72,a=s-72-(n.title?24:0),d=e.width/e.height;let u,f;d>p/a?(u=p,f=p/d):(f=a,u=a*d);const $=l+(p-u)/2,w=l+(a-f)/2,T=[],m=[];let b=0;function x(e,n){const t=T.length+1;let o;return o=`${t} 0 obj\n${e}\nendobj\n`,m.push(b),T.push(o),b+=(new TextEncoder).encode(o).length,n&&(b+=n.length+1),t}x("<< /Type /Catalog /Pages 2 0 R >>"),x(`<< /Type /Page /Parent ${x("<< /Type /Pages /Kids [3 0 R] /Count 1 >>")} 0 R /MediaBox [0 0 ${i} ${s}] /Contents 5 0 R /Resources << /XObject << /Img 4 0 R >> /Font << /F1 6 0 R >> >> >>`),x(`<< /Type /XObject /Subtype /Image /Width ${e.width} /Height ${e.height} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode /Length ${c.length} >>`);let j="";if(n.title){j+=`BT /F1 14 Tf 36 ${s-l-14} Td (${S=n.title,S.replace(/\\/g,"\\\\").replace(/\(/g,"\\(").replace(/\)/g,"\\)")}) Tj ET\n`}var S;j+=`q ${u} 0 0 ${f} ${$} ${w} cm /Img Do Q\n`;const y=(new TextEncoder).encode(j);x(`<< /Length ${y.length} >>`),x("<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>");const R="%PDF-1.4\n%âãÏÓ\n",v=[R],C=[];let E=(new TextEncoder).encode(R).length;const F="1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n";C.push(E),v.push(F),E+=(new TextEncoder).encode(F).length;const D="2 0 obj\n<< /Type /Pages /Kids [3 0 R] /Count 1 >>\nendobj\n";C.push(E),v.push(D),E+=(new TextEncoder).encode(D).length;const B=`3 0 obj\n<< /Type /Page /Parent 2 0 R /MediaBox [0 0 ${i} ${s}] /Contents 5 0 R /Resources << /XObject << /Img 4 0 R >> /Font << /F1 6 0 R >> >> >>\nendobj\n`;C.push(E),v.push(B),E+=(new TextEncoder).encode(B).length;const P=`4 0 obj\n<< /Type /XObject /Subtype /Image /Width ${e.width} /Height ${e.height} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode /Length ${c.length} >>\nstream\n`,I="\nendstream\nendobj\n";C.push(E),v.push(P),E+=(new TextEncoder).encode(P).length,v.push(c),E+=c.length,v.push(I),E+=(new TextEncoder).encode(I).length;const L=`5 0 obj\n<< /Length ${y.length} >>\nstream\n`,O="\nendstream\nendobj\n";C.push(E),v.push(L),E+=(new TextEncoder).encode(L).length,v.push(y),E+=y.length,v.push(O),E+=(new TextEncoder).encode(O).length;const H="6 0 obj\n<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>\nendobj\n";C.push(E),v.push(H),E+=(new TextEncoder).encode(H).length;const k=E,M=["xref",`0 ${C.length+1}`,"0000000000 65535 f ",...C.map(e=>`${String(e).padStart(10,"0")} 00000 n `)].join("\n")+"\n";v.push(M);const N=`trailer\n<< /Size ${C.length+1} /Root 1 0 R >>\nstartxref\n${k}\n%%EOF\n`;v.push(N);const U=v.map(e=>"string"==typeof e?(new TextEncoder).encode(e).buffer:e.buffer);return new Blob(U,{type:"application/pdf"})}export{e as exportCSV,o as exportPDF,n as exportSVG};
|
|
3
|
+
//# sourceMappingURL=index65.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index65.js","names":[],"sources":["../src/api/export.ts"],"sourcesContent":["import type { ColumnStore, VisibleRange } from '../core/types';\n\n// ─── CSV Export ─────────────────────────────────────────────────────────────\n\nexport interface CSVExportOptions {\n /** Include only bars within this date range (Unix timestamps in seconds). */\n from?: number;\n /** Include only bars within this date range (Unix timestamps in seconds). */\n to?: number;\n /** Column separator (default: ','). */\n separator?: string;\n /** Include indicator columns. */\n includeIndicators?: boolean;\n}\n\nexport interface SeriesInfo {\n label: string;\n store: ColumnStore;\n}\n\nexport interface IndicatorInfo {\n label: string;\n /** Map of output name -> Float64Array values aligned with source series. */\n outputs: Map<string, Float64Array>;\n}\n\n/**\n * Export visible OHLCV data as a CSV string.\n */\nexport function exportCSV(\n series: SeriesInfo[],\n indicators: IndicatorInfo[],\n range: VisibleRange | null,\n options: CSVExportOptions = {},\n): string {\n const sep = options.separator ?? ',';\n\n if (series.length === 0) return '';\n\n // Use the first series as the primary time source\n const primaryStore = series[0].store;\n if (primaryStore.length === 0) return '';\n\n // Determine index range\n let fromIdx = range?.fromIdx ?? 0;\n let toIdx = range?.toIdx ?? primaryStore.length - 1;\n fromIdx = Math.max(0, fromIdx);\n toIdx = Math.min(primaryStore.length - 1, toIdx);\n\n // Apply time-based filtering\n if (options.from !== undefined) {\n while (fromIdx <= toIdx && primaryStore.time[fromIdx] < options.from) fromIdx++;\n }\n if (options.to !== undefined) {\n while (toIdx >= fromIdx && primaryStore.time[toIdx] > options.to) toIdx--;\n }\n\n if (fromIdx > toIdx) return '';\n\n // Build header\n const headers: string[] = ['Date', 'Open', 'High', 'Low', 'Close', 'Volume'];\n\n // Add additional series columns\n for (let s = 1; s < series.length; s++) {\n const label = series[s].label || `Series ${s + 1}`;\n headers.push(`${label} Open`, `${label} High`, `${label} Low`, `${label} Close`);\n }\n\n // Add indicator columns\n if (options.includeIndicators !== false) {\n for (const ind of indicators) {\n for (const outputName of ind.outputs.keys()) {\n headers.push(ind.label ? `${ind.label} ${outputName}` : outputName);\n }\n }\n }\n\n const rows: string[] = [headers.join(sep)];\n\n for (let i = fromIdx; i <= toIdx; i++) {\n const time = primaryStore.time[i];\n const date = new Date(time * 1000).toISOString();\n const fields: string[] = [\n date,\n String(primaryStore.open[i]),\n String(primaryStore.high[i]),\n String(primaryStore.low[i]),\n String(primaryStore.close[i]),\n String(primaryStore.volume[i]),\n ];\n\n // Additional series\n for (let s = 1; s < series.length; s++) {\n const store = series[s].store;\n if (i < store.length) {\n fields.push(\n String(store.open[i]),\n String(store.high[i]),\n String(store.low[i]),\n String(store.close[i]),\n );\n } else {\n fields.push('', '', '', '');\n }\n }\n\n // Indicators\n if (options.includeIndicators !== false) {\n for (const ind of indicators) {\n for (const values of ind.outputs.values()) {\n const val = i < values.length ? values[i] : NaN;\n fields.push(isNaN(val) ? '' : String(val));\n }\n }\n }\n\n rows.push(fields.join(sep));\n }\n\n return rows.join('\\n');\n}\n\n// ─── SVG Export ─────────────────────────────────────────────────────────────\n\n/**\n * Generate an SVG string from a screenshot canvas.\n * The canvas pixel data is embedded as a base64 PNG <image> element within\n * an SVG wrapper, preserving the exact chart appearance including themes\n * and annotations.\n */\nexport function exportSVG(screenshotCanvas: HTMLCanvasElement): string {\n const w = screenshotCanvas.width;\n const h = screenshotCanvas.height;\n const dataURL = screenshotCanvas.toDataURL('image/png');\n\n return [\n `<?xml version=\"1.0\" encoding=\"UTF-8\"?>`,\n `<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"${w}\" height=\"${h}\" viewBox=\"0 0 ${w} ${h}\">`,\n ` <image width=\"${w}\" height=\"${h}\" xlink:href=\"${dataURL}\" />`,\n `</svg>`,\n ].join('\\n');\n}\n\n// ─── PDF Export ─────────────────────────────────────────────────────────────\n\nexport interface PDFExportOptions {\n /** Paper size (default: 'letter'). */\n pageSize?: 'letter' | 'a4';\n /** Page orientation (default: 'landscape'). */\n orientation?: 'portrait' | 'landscape';\n /** Optional title text at top of page. */\n title?: string;\n}\n\n// PDF page dimensions in points (1 point = 1/72 inch)\nconst PAGE_SIZES = {\n letter: { width: 612, height: 792 },\n a4: { width: 595.28, height: 841.89 },\n};\n\n/**\n * Generate a minimal PDF document containing the chart image.\n *\n * Uses a minimal PDF 1.4 generator (no external dependencies) that embeds\n * the chart as a JPEG image stream.\n */\nexport function exportPDF(\n screenshotCanvas: HTMLCanvasElement,\n options: PDFExportOptions = {},\n): Blob {\n const pageSize = PAGE_SIZES[options.pageSize ?? 'letter'];\n const isLandscape = (options.orientation ?? 'landscape') === 'landscape';\n const pageW = isLandscape ? pageSize.height : pageSize.width;\n const pageH = isLandscape ? pageSize.width : pageSize.height;\n\n // Get image data as JPEG\n const dataURL = screenshotCanvas.toDataURL('image/jpeg', 0.95);\n const base64 = dataURL.split(',')[1];\n const binaryStr = atob(base64);\n const imageBytes = new Uint8Array(binaryStr.length);\n for (let i = 0; i < binaryStr.length; i++) {\n imageBytes[i] = binaryStr.charCodeAt(i);\n }\n\n // Compute image placement (fit to page with margins)\n const margin = 36; // 0.5 inch\n const titleHeight = options.title ? 24 : 0;\n const availW = pageW - 2 * margin;\n const availH = pageH - 2 * margin - titleHeight;\n const imgAspect = screenshotCanvas.width / screenshotCanvas.height;\n const areaAspect = availW / availH;\n\n let imgW: number, imgH: number;\n if (imgAspect > areaAspect) {\n imgW = availW;\n imgH = availW / imgAspect;\n } else {\n imgH = availH;\n imgW = availH * imgAspect;\n }\n\n const imgX = margin + (availW - imgW) / 2;\n const imgY = margin + (availH - imgH) / 2;\n\n // Build minimal PDF\n const objects: string[] = [];\n const offsets: number[] = [];\n let currentOffset = 0;\n\n function addObject(content: string, stream?: Uint8Array): number {\n const id = objects.length + 1;\n let obj: string;\n if (stream) {\n obj = `${id} 0 obj\\n${content}\\nendobj\\n`;\n } else {\n obj = `${id} 0 obj\\n${content}\\nendobj\\n`;\n }\n offsets.push(currentOffset);\n objects.push(obj);\n currentOffset += new TextEncoder().encode(obj).length;\n if (stream) {\n currentOffset += stream.length + 1; // +1 for newline before endstream\n }\n return id;\n }\n\n // Object 1: Catalog\n const catalogId = addObject('<< /Type /Catalog /Pages 2 0 R >>');\n\n // Object 2: Pages\n const pagesId = addObject(`<< /Type /Pages /Kids [3 0 R] /Count 1 >>`);\n\n // Object 3: Page\n const pageId = addObject(\n `<< /Type /Page /Parent ${pagesId} 0 R /MediaBox [0 0 ${pageW} ${pageH}] /Contents 5 0 R /Resources << /XObject << /Img 4 0 R >> /Font << /F1 6 0 R >> >> >>`,\n );\n\n // Object 4: Image XObject (placeholder - we'll handle inline)\n const imageStreamHeader = `<< /Type /XObject /Subtype /Image /Width ${screenshotCanvas.width} /Height ${screenshotCanvas.height} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode /Length ${imageBytes.length} >>`;\n addObject(imageStreamHeader);\n\n // Object 5: Page content stream\n let contentStr = '';\n if (options.title) {\n const titleY = pageH - margin - 14;\n contentStr += `BT /F1 14 Tf ${margin} ${titleY} Td (${escapePDFString(options.title)}) Tj ET\\n`;\n }\n contentStr += `q ${imgW} 0 0 ${imgH} ${imgX} ${imgY} cm /Img Do Q\\n`;\n const contentBytes = new TextEncoder().encode(contentStr);\n addObject(`<< /Length ${contentBytes.length} >>`);\n\n // Object 6: Font\n addObject('<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>');\n\n // Now build the final PDF manually with binary streams\n const header = '%PDF-1.4\\n%\\xE2\\xE3\\xCF\\xD3\\n';\n const parts: (string | Uint8Array)[] = [header];\n\n // Re-calculate offsets properly\n const realOffsets: number[] = [];\n let pos = new TextEncoder().encode(header).length;\n\n // Object 1: Catalog\n const obj1 = `1 0 obj\\n<< /Type /Catalog /Pages 2 0 R >>\\nendobj\\n`;\n realOffsets.push(pos);\n parts.push(obj1);\n pos += new TextEncoder().encode(obj1).length;\n\n // Object 2: Pages\n const obj2 = `2 0 obj\\n<< /Type /Pages /Kids [3 0 R] /Count 1 >>\\nendobj\\n`;\n realOffsets.push(pos);\n parts.push(obj2);\n pos += new TextEncoder().encode(obj2).length;\n\n // Object 3: Page\n const obj3 = `3 0 obj\\n<< /Type /Page /Parent 2 0 R /MediaBox [0 0 ${pageW} ${pageH}] /Contents 5 0 R /Resources << /XObject << /Img 4 0 R >> /Font << /F1 6 0 R >> >> >>\\nendobj\\n`;\n realOffsets.push(pos);\n parts.push(obj3);\n pos += new TextEncoder().encode(obj3).length;\n\n // Object 4: Image\n const imgHeader = `4 0 obj\\n<< /Type /XObject /Subtype /Image /Width ${screenshotCanvas.width} /Height ${screenshotCanvas.height} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode /Length ${imageBytes.length} >>\\nstream\\n`;\n const imgFooter = `\\nendstream\\nendobj\\n`;\n realOffsets.push(pos);\n parts.push(imgHeader);\n pos += new TextEncoder().encode(imgHeader).length;\n parts.push(imageBytes);\n pos += imageBytes.length;\n parts.push(imgFooter);\n pos += new TextEncoder().encode(imgFooter).length;\n\n // Object 5: Content stream\n const obj5Header = `5 0 obj\\n<< /Length ${contentBytes.length} >>\\nstream\\n`;\n const obj5Footer = `\\nendstream\\nendobj\\n`;\n realOffsets.push(pos);\n parts.push(obj5Header);\n pos += new TextEncoder().encode(obj5Header).length;\n parts.push(contentBytes);\n pos += contentBytes.length;\n parts.push(obj5Footer);\n pos += new TextEncoder().encode(obj5Footer).length;\n\n // Object 6: Font\n const obj6 = `6 0 obj\\n<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>\\nendobj\\n`;\n realOffsets.push(pos);\n parts.push(obj6);\n pos += new TextEncoder().encode(obj6).length;\n\n // Cross-reference table\n const xrefStart = pos;\n const xref = [\n 'xref',\n `0 ${realOffsets.length + 1}`,\n '0000000000 65535 f ',\n ...realOffsets.map((off) => `${String(off).padStart(10, '0')} 00000 n `),\n ].join('\\n') + '\\n';\n parts.push(xref);\n\n // Trailer\n const trailer = `trailer\\n<< /Size ${realOffsets.length + 1} /Root 1 0 R >>\\nstartxref\\n${xrefStart}\\n%%EOF\\n`;\n parts.push(trailer);\n\n // Combine into Blob\n const blobParts: BlobPart[] = parts.map((p) =>\n typeof p === 'string' ? new TextEncoder().encode(p).buffer as ArrayBuffer : p.buffer as ArrayBuffer,\n );\n return new Blob(blobParts, { type: 'application/pdf' });\n}\n\nfunction escapePDFString(str: string): string {\n return str.replace(/\\\\/g, '\\\\\\\\').replace(/\\(/g, '\\\\(').replace(/\\)/g, '\\\\)');\n}\n"],"mappings":"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"}
|
package/dist/index66.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index66.js","names":[],"sources":["../src/core/price-line.ts"],"sourcesContent":["// ─── Price Lines ────────────────────────────────────────────────────────────\n\nexport interface PriceLineOptions {\n price: number;\n color: string;\n lineWidth: number;\n lineStyle: 'solid' | 'dashed' | 'dotted';\n title: string;\n axisLabelVisible: boolean;\n axisLabelColor?: string;\n axisLabelTextColor?: string;\n}\n\nexport class PriceLine {\n private _options: PriceLineOptions;\n private _requestRepaint: (() => void) | null;\n\n constructor(options: PriceLineOptions, requestRepaint?: () => void) {\n this._options = { ...options };\n this._requestRepaint = requestRepaint ?? null;\n }\n\n get options(): Readonly<PriceLineOptions> {\n return { ...this._options };\n }\n\n applyOptions(opts: Partial<PriceLineOptions>, requestRepaint?: () => void): void {\n Object.assign(this._options, opts);\n const repaint = requestRepaint ?? this._requestRepaint;\n if (repaint) repaint();\n }\n}\n"],"mappings":"AAaA,IAAa,EAAb,MAIE,WAAA,CAAY,EAA2B,GACrC,KAAK,SAAW,IAAK,GACrB,KAAK,gBAAkB,GAAkB,KAG3C,WAAI,GACF,MAAO,IAAK,KAAK,UAGnB,YAAA,CAAa,EAAiC,GAC5C,OAAO,OAAO,KAAK,SAAU,GAC7B,MAAM,EAAU,GAAkB,KAAK,gBACnC,GAAS"}
|
package/dist/index67.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{PriceLine as t}from"./index66.js";var i=class{constructor(t,i,e,s,a){this._primitives=[],this._markers=[],this._events=[],this._priceLines=[],this._visible=!0,this._dataChangedCallbacks=/* @__PURE__ */new Set,this._visibilityChangeCallbacks=/* @__PURE__ */new Set,this._type=t,this._dataLayer=i,this._priceScale=e,this._options=s,this._requestRepaint=a,this._visible=!1!==s.visible,s.data&&this._dataLayer.setData(s.data)}setData(t){this._dataLayer.setData(t),this._notifyPrimitives("full"),this._requestRepaint(),this._emitDataChanged()}update(t){this._dataLayer.update(t),this._notifyPrimitives("update"),this._requestRepaint(),this._emitDataChanged()}prependData(t){this._dataLayer.prepend(t),this._notifyPrimitives("full"),this._requestRepaint(),this._emitDataChanged()}barsInLogicalRange(t){const i=this._dataLayer.store,e=Math.max(0,Math.floor(t.from)),s=Math.min(i.length-1,Math.ceil(t.to));return{barsBefore:e,barsAfter:Math.max(0,i.length-1-s),from:i.length>0&&e<i.length?i.time[e]:0,to:i.length>0&&s>=0&&s<i.length?i.time[s]:0}}attachPrimitive(t){this._primitives.push(t),t.attached?.({requestUpdate:()=>this._requestRepaint()})}detachPrimitive(t){const i=this._primitives.indexOf(t);-1!==i&&(this._primitives.splice(i,1),t.detached?.())}applyOptions(t){const i=this._visible;if(this._options={...this._options,...t},void 0!==t.visible&&(this._visible=!1!==t.visible),t.data&&this._dataLayer.setData(t.data),this._requestRepaint(),void 0!==t.visible&&this._visible!==i)for(const e of this._visibilityChangeCallbacks)e(this._visible)}options(){return{...this._options}}priceScale(){return this._priceScale}dataByIndex(t){return this._dataLayer.barAt(t)}seriesType(){return this._type}setMarkers(t){this._markers=[...t].sort((t,i)=>t.time-i.time),this._requestRepaint()}getMarkers(){return[...this._markers]}setEvents(t){this._events=[...t].sort((t,i)=>t.time-i.time),this._requestRepaint()}getEvents(){return[...this._events]}createPriceLine(i){const e=new t(i,this._requestRepaint);return this._priceLines.push(e),this._requestRepaint(),e}removePriceLine(t){const i=this._priceLines.indexOf(t);-1!==i&&(this._priceLines.splice(i,1),this._requestRepaint())}getPriceLines(){return[...this._priceLines]}subscribeDataChanged(t){this._dataChangedCallbacks.add(t)}unsubscribeDataChanged(t){this._dataChangedCallbacks.delete(t)}subscribeVisibilityChange(t){this._visibilityChangeCallbacks.add(t)}unsubscribeVisibilityChange(t){this._visibilityChangeCallbacks.delete(t)}getDataLayer(){return this._dataLayer}getPrimitives(){return this._primitives}isVisible(){return this._visible}_notifyPrimitives(t){for(const i of this._primitives)i.updateAllViews?.()}_emitDataChanged(){for(const t of this._dataChangedCallbacks)t()}};export{i as SeriesApi};
|
|
2
|
+
//# sourceMappingURL=index67.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index67.js","names":[],"sources":["../src/api/series-api.ts"],"sourcesContent":["import type { Bar, ColumnData, SeriesType, ISeriesPrimitive, AttachedParams } from '../core/types';\nimport { DataLayer } from '../core/data-layer';\nimport type { PriceScale } from '../core/price-scale';\nimport type { SeriesMarker, ChartEvent } from '../core/series-markers';\nimport { PriceLine, type PriceLineOptions } from '../core/price-line';\nimport type { SeriesOptionsMap } from './options';\n\nexport type DataChangedCallback = () => void;\nexport type VisibilityChangeCallback = (visible: boolean) => void;\n\n// ─── ISeriesApi ─────────────────────────────────────────────────────────────\n\nexport interface ISeriesApi<T extends SeriesType> {\n /** Replace all data on this series. */\n setData(data: Bar[] | ColumnData): void;\n /** Append or update a single bar (real-time). */\n update(bar: Bar): void;\n /** Attach a custom series primitive (plugin). */\n attachPrimitive(primitive: ISeriesPrimitive): void;\n /** Detach a previously attached primitive. */\n detachPrimitive(primitive: ISeriesPrimitive): void;\n /** Update the series options. */\n applyOptions(options: Partial<SeriesOptionsMap[T]>): void;\n /** Return the current series options. */\n options(): SeriesOptionsMap[T];\n /** Return the associated price scale. */\n priceScale(): PriceScale;\n /** Return the bar at the given index, or null. */\n dataByIndex(index: number): Bar | null;\n /** The series type. */\n seriesType(): T;\n /** Set markers on this series. */\n setMarkers(markers: SeriesMarker[]): void;\n /** Get current markers. */\n getMarkers(): readonly SeriesMarker[];\n /** Set chart events on this series. */\n setEvents(events: ChartEvent[]): void;\n /** Get current chart events. */\n getEvents(): readonly ChartEvent[];\n /** Create a horizontal price line on this series. */\n createPriceLine(options: PriceLineOptions): PriceLine;\n /** Remove a price line. */\n removePriceLine(line: PriceLine): void;\n /** Get all price lines. */\n getPriceLines(): readonly PriceLine[];\n /** Prepend historical bars to the beginning of the series (for pagination). */\n prependData(data: Bar[] | ColumnData): void;\n /**\n * Return metadata about how many bars fall outside the given logical index range.\n * Useful for deciding when to load more historical data.\n */\n barsInLogicalRange(range: { from: number; to: number }): {\n barsBefore: number;\n barsAfter: number;\n from: number;\n to: number;\n };\n /** Subscribe to data changes (setData / update). */\n subscribeDataChanged(callback: DataChangedCallback): void;\n /** Unsubscribe from data changes. */\n unsubscribeDataChanged(callback: DataChangedCallback): void;\n /** Subscribe to visibility changes. */\n subscribeVisibilityChange(callback: VisibilityChangeCallback): void;\n /** Unsubscribe from visibility changes. */\n unsubscribeVisibilityChange(callback: VisibilityChangeCallback): void;\n}\n\n// ─── SeriesApi ──────────────────────────────────────────────────────────────\n\nexport class SeriesApi<T extends SeriesType> implements ISeriesApi<T> {\n private _type: T;\n private _dataLayer: DataLayer;\n private _priceScale: PriceScale;\n private _options: SeriesOptionsMap[T];\n private _primitives: ISeriesPrimitive[] = [];\n private _markers: SeriesMarker[] = [];\n private _events: ChartEvent[] = [];\n private _priceLines: PriceLine[] = [];\n private _requestRepaint: () => void;\n private _visible: boolean = true;\n private _dataChangedCallbacks: Set<DataChangedCallback> = new Set();\n private _visibilityChangeCallbacks: Set<VisibilityChangeCallback> = new Set();\n\n constructor(\n type: T,\n dataLayer: DataLayer,\n priceScale: PriceScale,\n options: SeriesOptionsMap[T],\n requestRepaint: () => void,\n ) {\n this._type = type;\n this._dataLayer = dataLayer;\n this._priceScale = priceScale;\n this._options = options;\n this._requestRepaint = requestRepaint;\n this._visible = options.visible !== false;\n\n // Load initial data if provided\n if (options.data) {\n this._dataLayer.setData(options.data);\n }\n }\n\n setData(data: Bar[] | ColumnData): void {\n this._dataLayer.setData(data);\n this._notifyPrimitives('full');\n this._requestRepaint();\n this._emitDataChanged();\n }\n\n update(bar: Bar): void {\n this._dataLayer.update(bar);\n this._notifyPrimitives('update');\n this._requestRepaint();\n this._emitDataChanged();\n }\n\n prependData(data: Bar[] | ColumnData): void {\n this._dataLayer.prepend(data);\n this._notifyPrimitives('full');\n this._requestRepaint();\n this._emitDataChanged();\n }\n\n barsInLogicalRange(range: { from: number; to: number }): {\n barsBefore: number;\n barsAfter: number;\n from: number;\n to: number;\n } {\n const store = this._dataLayer.store;\n const fromIdx = Math.max(0, Math.floor(range.from));\n const toIdx = Math.min(store.length - 1, Math.ceil(range.to));\n return {\n barsBefore: fromIdx,\n barsAfter: Math.max(0, store.length - 1 - toIdx),\n from:\n store.length > 0 && fromIdx < store.length ? store.time[fromIdx] : 0,\n to:\n store.length > 0 && toIdx >= 0 && toIdx < store.length\n ? store.time[toIdx]\n : 0,\n };\n }\n\n attachPrimitive(primitive: ISeriesPrimitive): void {\n this._primitives.push(primitive);\n const params: AttachedParams = {\n requestUpdate: () => this._requestRepaint(),\n };\n primitive.attached?.(params);\n }\n\n detachPrimitive(primitive: ISeriesPrimitive): void {\n const idx = this._primitives.indexOf(primitive);\n if (idx !== -1) {\n this._primitives.splice(idx, 1);\n primitive.detached?.();\n }\n }\n\n applyOptions(options: Partial<SeriesOptionsMap[T]>): void {\n const prevVisible = this._visible;\n this._options = { ...this._options, ...options };\n if (options.visible !== undefined) {\n this._visible = options.visible !== false;\n }\n if (options.data) {\n this._dataLayer.setData(options.data);\n }\n this._requestRepaint();\n\n if (options.visible !== undefined && this._visible !== prevVisible) {\n for (const cb of this._visibilityChangeCallbacks) cb(this._visible);\n }\n }\n\n options(): SeriesOptionsMap[T] {\n return { ...this._options };\n }\n\n priceScale(): PriceScale {\n return this._priceScale;\n }\n\n dataByIndex(index: number): Bar | null {\n return this._dataLayer.barAt(index);\n }\n\n seriesType(): T {\n return this._type;\n }\n\n setMarkers(markers: SeriesMarker[]): void {\n this._markers = [...markers].sort((a, b) => a.time - b.time);\n this._requestRepaint();\n }\n\n getMarkers(): readonly SeriesMarker[] {\n return [...this._markers];\n }\n\n setEvents(events: ChartEvent[]): void {\n this._events = [...events].sort((a, b) => a.time - b.time);\n this._requestRepaint();\n }\n\n getEvents(): readonly ChartEvent[] {\n return [...this._events];\n }\n\n createPriceLine(options: PriceLineOptions): PriceLine {\n const line = new PriceLine(options, this._requestRepaint);\n this._priceLines.push(line);\n this._requestRepaint();\n return line;\n }\n\n removePriceLine(line: PriceLine): void {\n const idx = this._priceLines.indexOf(line);\n if (idx !== -1) {\n this._priceLines.splice(idx, 1);\n this._requestRepaint();\n }\n }\n\n getPriceLines(): readonly PriceLine[] {\n return [...this._priceLines];\n }\n\n subscribeDataChanged(callback: DataChangedCallback): void {\n this._dataChangedCallbacks.add(callback);\n }\n\n unsubscribeDataChanged(callback: DataChangedCallback): void {\n this._dataChangedCallbacks.delete(callback);\n }\n\n subscribeVisibilityChange(callback: VisibilityChangeCallback): void {\n this._visibilityChangeCallbacks.add(callback);\n }\n\n unsubscribeVisibilityChange(callback: VisibilityChangeCallback): void {\n this._visibilityChangeCallbacks.delete(callback);\n }\n\n // ── Internal accessors ────────────────────────────────────────────────────\n\n getDataLayer(): DataLayer {\n return this._dataLayer;\n }\n\n getPrimitives(): readonly ISeriesPrimitive[] {\n return this._primitives;\n }\n\n isVisible(): boolean {\n return this._visible;\n }\n\n // ── Private ───────────────────────────────────────────────────────────────\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n private _notifyPrimitives(_scope: 'full' | 'update'): void {\n for (const p of this._primitives) {\n p.updateAllViews?.();\n }\n }\n\n private _emitDataChanged(): void {\n for (const cb of this._dataChangedCallbacks) cb();\n }\n}\n"],"mappings":"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"}
|
package/dist/index68.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var t=class{constructor(t,i,e){this._primitives=[],this.id=t,this._pane=i,this._requestRepaint=e}setHeight(t){this._pane.height=t,this._requestRepaint()}getHeight(){return this._pane.height}getPane(){return this._pane}attachPrimitive(t){this._primitives.push(t),t.attached?.({requestUpdate:()=>this._requestRepaint()})}detachPrimitive(t){const i=this._primitives.indexOf(t);-1!==i&&(this._primitives.splice(i,1),t.detached?.())}getPrimitives(){return this._primitives}};export{t as PaneApi};
|
|
2
|
+
//# sourceMappingURL=index68.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index68.js","names":[],"sources":["../src/api/pane-api.ts"],"sourcesContent":["import type { IPanePrimitive, AttachedParams } from '../core/types';\nimport type { Pane } from '../core/pane';\n\n// ─── IPaneApi ───────────────────────────────────────────────────────────────\n\nexport interface IPaneApi {\n /** Unique pane identifier. */\n readonly id: string;\n /** Set the pane height in CSS pixels. */\n setHeight(height: number): void;\n /** Get the pane height in CSS pixels. */\n getHeight(): number;\n /** Attach a pane primitive (plugin). */\n attachPrimitive(primitive: IPanePrimitive): void;\n /** Detach a pane primitive. */\n detachPrimitive(primitive: IPanePrimitive): void;\n}\n\n// ─── PaneApi ────────────────────────────────────────────────────────────────\n\nexport class PaneApi implements IPaneApi {\n public readonly id: string;\n private _pane: Pane;\n private _primitives: IPanePrimitive[] = [];\n private _requestRepaint: () => void;\n\n constructor(id: string, pane: Pane, requestRepaint: () => void) {\n this.id = id;\n this._pane = pane;\n this._requestRepaint = requestRepaint;\n }\n\n setHeight(height: number): void {\n this._pane.height = height;\n this._requestRepaint();\n }\n\n getHeight(): number {\n return this._pane.height;\n }\n\n /** Get the internal Pane instance. */\n getPane(): Pane {\n return this._pane;\n }\n\n attachPrimitive(primitive: IPanePrimitive): void {\n this._primitives.push(primitive);\n const params: AttachedParams = {\n requestUpdate: () => this._requestRepaint(),\n };\n primitive.attached?.(params);\n }\n\n detachPrimitive(primitive: IPanePrimitive): void {\n const idx = this._primitives.indexOf(primitive);\n if (idx !== -1) {\n this._primitives.splice(idx, 1);\n primitive.detached?.();\n }\n }\n\n getPrimitives(): readonly IPanePrimitive[] {\n return this._primitives;\n }\n}\n"],"mappings":"AAoBA,IAAa,EAAb,MAME,WAAA,CAAY,EAAY,EAAY,oBAHI,GAItC,KAAK,GAAK,EACV,KAAK,MAAQ,EACb,KAAK,gBAAkB,EAGzB,SAAA,CAAU,GACR,KAAK,MAAM,OAAS,EACpB,KAAK,kBAGP,SAAA,GACE,OAAO,KAAK,MAAM,OAIpB,OAAA,GACE,OAAO,KAAK,MAGd,eAAA,CAAgB,GACd,KAAK,YAAY,KAAK,GAItB,EAAU,WAHqB,CAC7B,cAAA,IAAqB,KAAK,oBAK9B,eAAA,CAAgB,GACd,MAAM,EAAM,KAAK,YAAY,QAAQ,IACzB,IAAR,IACF,KAAK,YAAY,OAAO,EAAK,GAC7B,EAAU,cAId,aAAA,GACE,OAAO,KAAK"}
|
package/dist/index69.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=class{constructor(e,t,i,s,r){this.internalSeries=[],this.autoCreatedPaneId=null,this._dataChangedCallback=null,this.id=e,this._type=t,this._options={...i},this._paneId=s,this._visible=!1!==i.visible,this._label=i.label??this._autoLabel(),this._removeCallback=r}indicatorType(){return this._type}applyOptions(e){this._options={...this._options,...e},void 0!==e.visible&&(this._visible=!1!==e.visible),void 0!==e.label&&(this._label=e.label??this._autoLabel())}options(){return{...this._options}}paneId(){return this._paneId}isVisible(){return this._visible}remove(){this._removeCallback()}label(){return this._label}_autoLabel(){const e=this._options.params??{};switch(this._type){case"sma":return`SMA ${e.period??20}`;case"ema":return`EMA ${e.period??20}`;case"rsi":return`RSI ${e.period??14}`;case"macd":return`MACD ${e.fastPeriod??12},${e.slowPeriod??26},${e.signalPeriod??9}`;case"bollinger":return`BB ${e.period??20},${e.stdDev??2}`;case"vwap":return"VWAP";case"stochastic":return`Stoch ${e.kPeriod??14},${e.dPeriod??3}`;case"atr":return`ATR ${e.period??14}`;case"adx":return`ADX ${e.period??14}`;case"obv":return"OBV";case"williams-r":return`W%R ${e.period??14}`;default:return this._type.toUpperCase()}}};export{e as IndicatorApi};
|
|
2
|
+
//# sourceMappingURL=index69.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index69.js","names":[],"sources":["../src/api/indicator-api.ts"],"sourcesContent":["import type { SeriesType } from '../core/types';\nimport type { ISeriesApi } from './series-api';\nimport type { IndicatorType, IndicatorOptions } from './options';\n\n// ─── IIndicatorApi ─────────────────────────────────────────────────────────\n\nexport interface IIndicatorApi {\n readonly id: string;\n indicatorType(): IndicatorType;\n applyOptions(options: Partial<IndicatorOptions>): void;\n options(): IndicatorOptions;\n paneId(): string;\n isVisible(): boolean;\n remove(): void;\n label(): string;\n}\n\n// ─── IndicatorApi ──────────────────────────────────────────────────────────\n\nexport class IndicatorApi implements IIndicatorApi {\n public readonly id: string;\n private _type: IndicatorType;\n private _options: IndicatorOptions;\n private _paneId: string;\n private _visible: boolean;\n private _label: string;\n\n /** The line/histogram series created internally for this indicator. */\n public internalSeries: ISeriesApi<SeriesType>[] = [];\n\n /** If we auto-created a pane for this indicator, track it for cleanup. */\n public autoCreatedPaneId: string | null = null;\n\n /** Called by remove() to clean up via ChartApi. */\n public _removeCallback: () => void;\n\n /** Subscription callback for source dataChanged, stored for unsubscribe. */\n public _dataChangedCallback: (() => void) | null = null;\n\n constructor(\n id: string,\n type: IndicatorType,\n options: IndicatorOptions,\n paneId: string,\n removeCallback: () => void,\n ) {\n this.id = id;\n this._type = type;\n this._options = { ...options };\n this._paneId = paneId;\n this._visible = options.visible !== false;\n this._label = options.label ?? this._autoLabel();\n this._removeCallback = removeCallback;\n }\n\n indicatorType(): IndicatorType {\n return this._type;\n }\n\n applyOptions(options: Partial<IndicatorOptions>): void {\n this._options = { ...this._options, ...options };\n if (options.visible !== undefined) {\n this._visible = options.visible !== false;\n }\n if (options.label !== undefined) {\n this._label = options.label ?? this._autoLabel();\n }\n }\n\n options(): IndicatorOptions {\n return { ...this._options };\n }\n\n paneId(): string {\n return this._paneId;\n }\n\n isVisible(): boolean {\n return this._visible;\n }\n\n remove(): void {\n this._removeCallback();\n }\n\n label(): string {\n return this._label;\n }\n\n // ── Private ───────────────────────────────────────────────────────────────\n\n private _autoLabel(): string {\n const params = this._options.params ?? {};\n switch (this._type) {\n case 'sma':\n return `SMA ${params.period ?? 20}`;\n case 'ema':\n return `EMA ${params.period ?? 20}`;\n case 'rsi':\n return `RSI ${params.period ?? 14}`;\n case 'macd':\n return `MACD ${params.fastPeriod ?? 12},${params.slowPeriod ?? 26},${params.signalPeriod ?? 9}`;\n case 'bollinger':\n return `BB ${params.period ?? 20},${params.stdDev ?? 2}`;\n case 'vwap':\n return 'VWAP';\n case 'stochastic':\n return `Stoch ${params.kPeriod ?? 14},${params.dPeriod ?? 3}`;\n case 'atr':\n return `ATR ${params.period ?? 14}`;\n case 'adx':\n return `ADX ${params.period ?? 14}`;\n case 'obv':\n return 'OBV';\n case 'williams-r':\n return `W%R ${params.period ?? 14}`;\n default:\n return (this._type as string).toUpperCase();\n }\n }\n}\n"],"mappings":"AAmBA,IAAa,EAAb,MAoBE,WAAA,CACE,EACA,EACA,EACA,EACA,uBAhBgD,0BAGR,+BAMS,KASjD,KAAK,GAAK,EACV,KAAK,MAAQ,EACb,KAAK,SAAW,IAAK,GACrB,KAAK,QAAU,EACf,KAAK,UAA+B,IAApB,EAAQ,QACxB,KAAK,OAAS,EAAQ,OAAS,KAAK,aACpC,KAAK,gBAAkB,EAGzB,aAAA,GACE,OAAO,KAAK,MAGd,YAAA,CAAa,GACX,KAAK,SAAW,IAAK,KAAK,YAAa,QACf,IAApB,EAAQ,UACV,KAAK,UAA+B,IAApB,EAAQ,cAEJ,IAAlB,EAAQ,QACV,KAAK,OAAS,EAAQ,OAAS,KAAK,cAIxC,OAAA,GACE,MAAO,IAAK,KAAK,UAGnB,MAAA,GACE,OAAO,KAAK,QAGd,SAAA,GACE,OAAO,KAAK,SAGd,MAAA,GACE,KAAK,kBAGP,KAAA,GACE,OAAO,KAAK,OAKd,UAAA,GACE,MAAM,EAAS,KAAK,SAAS,QAAU,CAAA,EACvC,OAAQ,KAAK,OACX,IAAK,MACH,MAAO,OAAO,EAAO,QAAU,KACjC,IAAK,MACH,MAAO,OAAO,EAAO,QAAU,KACjC,IAAK,MACH,MAAO,OAAO,EAAO,QAAU,KACjC,IAAK,OACH,MAAO,QAAQ,EAAO,YAAc,MAAM,EAAO,YAAc,MAAM,EAAO,cAAgB,IAC9F,IAAK,YACH,MAAO,MAAM,EAAO,QAAU,MAAM,EAAO,QAAU,IACvD,IAAK,OACH,MAAO,OACT,IAAK,aACH,MAAO,SAAS,EAAO,SAAW,MAAM,EAAO,SAAW,IAC5D,IAAK,MACH,MAAO,OAAO,EAAO,QAAU,KACjC,IAAK,MACH,MAAO,OAAO,EAAO,QAAU,KACjC,IAAK,MACH,MAAO,MACT,IAAK,aACH,MAAO,OAAO,EAAO,QAAU,KACjC,QACE,OAAQ,KAAK,MAAiB"}
|
package/dist/index7.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{barsToColumnStore as e,createColumnStore as t}from"./index2.js";import{MinMaxSegmentTree as s}from"./index6.js";var o=class{constructor(){this.store=t(2048),this.segmentTree=new s(2048)}setData(s){if(Array.isArray(s))this.store=e(s);else{const e=s.time.length,o=t(Math.max(Math.ceil(1.5*e),2048));o.length=e,o.time.set(s.time),o.open.set(s.open),o.high.set(s.high),o.low.set(s.low),o.close.set(s.close),o.volume.set(s.volume),this.store=o}this.segmentTree.build(this.store.high,this.store.low,this.store.length)}update(e){const{store:t}=this;if(t.length>0&&t.time[t.length-1]===e.time){const s=t.length-1;t.open[s]=e.open,t.high[s]=e.high,t.low[s]=e.low,t.close[s]=e.close,t.volume[s]=e.volume??0,this.segmentTree.update(s,e.high,e.low)}else{if(t.length>0&&e.time<t.time[t.length-1])throw new Error(`update(): bar.time (${e.time}) must be >= last bar time (${t.time[t.length-1]})`);t.length>=t.capacity&&this.grow();const s=t.length;this.store.time[s]=e.time,this.store.open[s]=e.open,this.store.high[s]=e.high,this.store.low[s]=e.low,this.store.close[s]=e.close,this.store.volume[s]=e.volume??0,this.store.length+=1,this.segmentTree.append(e.high,e.low)}}findIndex(e){const{store:t}=this;if(0===t.length)return 0;let s=0,o=t.length-1;for(;s<=o;){const h=s+o>>>1,r=t.time[h];if(r===e)return h;r<e?s=h+1:o=h-1}return s>=t.length?t.length-1:0===s?0:Math.abs(t.time[s]-e)<Math.abs(t.time[s-1]-e)?s:s-1}barAt(e){const{store:t}=this;return e<0||e>=t.length?null:{time:t.time[e],open:t.open[e],high:t.high[e],low:t.low[e],close:t.close[e],volume:t.volume[e]}}prepend(e){if(!Array.isArray(e)){const t=e.time.length;for(const s of["open","high","low","close","volume"])if(e[s].length!==t)throw new Error(`ColumnData field '${s}' has length ${e[s].length}, expected ${t}`)}const s=Array.isArray(e)?e:Array.from({length:e.time.length},(t,s)=>({time:e.time[s],open:e.open[s],high:e.high[s],low:e.low[s],close:e.close[s],volume:e.volume[s]}));if(0===s.length)return;for(let t=1;t<s.length;t++)if(s[t-1].time>=s[t].time)throw new Error("Prepended bars must be strictly increasing by time");const o=this.store.length;if(o>0&&s[s.length-1].time>=this.store.time[0])throw new Error("Prepended bars must be strictly older than existing data");const h=o+s.length,r=t(Math.max(Math.ceil(1.5*h),2048));r.length=h;for(let t=0;t<s.length;t++)r.time[t]=s[t].time,r.open[t]=s[t].open,r.high[t]=s[t].high,r.low[t]=s[t].low,r.close[t]=s[t].close,r.volume[t]=s[t].volume??0;for(const t of["time","open","high","low","close","volume"])r[t].set(this.store[t].subarray(0,o),s.length);this.store=r,this.segmentTree.build(this.store.high,this.store.low,this.store.length)}queryMinMax(e,t){return this.segmentTree.query(e,t)}grow(){const{store:e}=this,s=t(2*e.capacity);s.length=e.length,s.time.set(e.time.subarray(0,e.length)),s.open.set(e.open.subarray(0,e.length)),s.high.set(e.high.subarray(0,e.length)),s.low.set(e.low.subarray(0,e.length)),s.close.set(e.close.subarray(0,e.length)),s.volume.set(e.volume.subarray(0,e.length)),this.store=s}};export{o as DataLayer};
|
|
2
|
+
//# sourceMappingURL=index7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index7.js","names":[],"sources":["../src/core/data-layer.ts"],"sourcesContent":["import {\n type Bar,\n type ColumnData,\n type ColumnStore,\n barsToColumnStore,\n createColumnStore,\n} from './types';\nimport { MinMaxSegmentTree } from './segment-tree';\n\nexport class DataLayer {\n public store: ColumnStore;\n public readonly segmentTree: MinMaxSegmentTree;\n\n constructor() {\n this.store = createColumnStore(2048);\n this.segmentTree = new MinMaxSegmentTree(2048);\n }\n\n /** Load data. Accepts either an array of Bar objects or a ColumnData (typed arrays). */\n setData(data: Bar[] | ColumnData): void {\n if (Array.isArray(data)) {\n this.store = barsToColumnStore(data);\n } else {\n // ColumnData — copy into a new ColumnStore\n const len = data.time.length;\n const capacity = Math.max(Math.ceil(len * 1.5), 2048);\n const store = createColumnStore(capacity);\n store.length = len;\n store.time.set(data.time);\n store.open.set(data.open);\n store.high.set(data.high);\n store.low.set(data.low);\n store.close.set(data.close);\n store.volume.set(data.volume);\n this.store = store;\n }\n this.segmentTree.build(this.store.high, this.store.low, this.store.length);\n }\n\n /**\n * Upsert a single bar:\n * - If the timestamp matches the last bar, overwrite in-place.\n * - Otherwise append (growing the store if needed).\n */\n update(bar: Bar): void {\n const { store } = this;\n if (store.length > 0 && store.time[store.length - 1] === bar.time) {\n // Overwrite last bar\n const i = store.length - 1;\n store.open[i] = bar.open;\n store.high[i] = bar.high;\n store.low[i] = bar.low;\n store.close[i] = bar.close;\n store.volume[i] = bar.volume ?? 0;\n this.segmentTree.update(i, bar.high, bar.low);\n } else {\n // Guard: out-of-order bars would corrupt the binary search in findIndex()\n if (store.length > 0 && bar.time < store.time[store.length - 1]) {\n throw new Error(\n `update(): bar.time (${bar.time}) must be >= last bar time (${store.time[store.length - 1]})`,\n );\n }\n // Append\n if (store.length >= store.capacity) {\n this.grow();\n }\n const i = store.length;\n this.store.time[i] = bar.time;\n this.store.open[i] = bar.open;\n this.store.high[i] = bar.high;\n this.store.low[i] = bar.low;\n this.store.close[i] = bar.close;\n this.store.volume[i] = bar.volume ?? 0;\n this.store.length += 1;\n this.segmentTree.append(bar.high, bar.low);\n }\n }\n\n /**\n * Binary search for the index whose time is closest to `time`.\n * Result is clamped to [0, length-1].\n */\n findIndex(time: number): number {\n const { store } = this;\n if (store.length === 0) return 0;\n\n let lo = 0;\n let hi = store.length - 1;\n\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n const t = store.time[mid];\n if (t === time) return mid;\n if (t < time) lo = mid + 1;\n else hi = mid - 1;\n }\n\n // lo is the insertion point; nearest is lo or lo-1\n if (lo >= store.length) return store.length - 1;\n if (lo === 0) return 0;\n\n const diffLo = Math.abs(store.time[lo] - time);\n const diffHi = Math.abs(store.time[lo - 1] - time);\n return diffLo < diffHi ? lo : lo - 1;\n }\n\n /** Return the Bar at `index`, or null if out of bounds. */\n barAt(index: number): Bar | null {\n const { store } = this;\n if (index < 0 || index >= store.length) return null;\n return {\n time: store.time[index],\n open: store.open[index],\n high: store.high[index],\n low: store.low[index],\n close: store.close[index],\n volume: store.volume[index],\n };\n }\n\n /**\n * Prepend bars to the beginning of the store.\n * Accepts either an array of Bar objects or a ColumnData (typed arrays).\n * The prepended data must be strictly older than the existing data.\n */\n prepend(data: Bar[] | ColumnData): void {\n // Validate ColumnData column lengths before conversion\n if (!Array.isArray(data)) {\n const len = data.time.length;\n for (const field of ['open', 'high', 'low', 'close', 'volume'] as const) {\n if (data[field].length !== len) {\n throw new Error(`ColumnData field '${field}' has length ${data[field].length}, expected ${len}`);\n }\n }\n }\n\n const bars: Bar[] = Array.isArray(data)\n ? data\n : Array.from({ length: data.time.length }, (_, i) => ({\n time: data.time[i],\n open: data.open[i],\n high: data.high[i],\n low: data.low[i],\n close: data.close[i],\n volume: data.volume[i],\n }));\n\n if (bars.length === 0) return;\n\n // Validate that prepended bars are strictly increasing by time\n for (let i = 1; i < bars.length; i++) {\n if (bars[i - 1].time >= bars[i].time) {\n throw new Error('Prepended bars must be strictly increasing by time');\n }\n }\n const oldLen = this.store.length;\n if (oldLen > 0 && bars[bars.length - 1].time >= this.store.time[0]) {\n throw new Error('Prepended bars must be strictly older than existing data');\n }\n const newLen = oldLen + bars.length;\n const newCapacity = Math.max(Math.ceil(newLen * 1.5), 2048);\n const newStore = createColumnStore(newCapacity);\n newStore.length = newLen;\n\n // Copy new data at front\n for (let i = 0; i < bars.length; i++) {\n newStore.time[i] = bars[i].time;\n newStore.open[i] = bars[i].open;\n newStore.high[i] = bars[i].high;\n newStore.low[i] = bars[i].low;\n newStore.close[i] = bars[i].close;\n newStore.volume[i] = bars[i].volume ?? 0;\n }\n\n // Copy existing data after new data using typed array set\n for (const field of ['time', 'open', 'high', 'low', 'close', 'volume'] as const) {\n newStore[field].set(this.store[field].subarray(0, oldLen), bars.length);\n }\n\n this.store = newStore;\n this.segmentTree.build(this.store.high, this.store.low, this.store.length);\n }\n\n /**\n * Query the min low and max high in the range [fromIdx, toIdx] (inclusive).\n * O(log n) time via segment tree.\n */\n queryMinMax(fromIdx: number, toIdx: number): { min: number; max: number } {\n return this.segmentTree.query(fromIdx, toIdx);\n }\n\n /** Double the capacity of the store, preserving existing data. */\n private grow(): void {\n const { store } = this;\n const newCapacity = store.capacity * 2;\n const next = createColumnStore(newCapacity);\n next.length = store.length;\n next.time.set(store.time.subarray(0, store.length));\n next.open.set(store.open.subarray(0, store.length));\n next.high.set(store.high.subarray(0, store.length));\n next.low.set(store.low.subarray(0, store.length));\n next.close.set(store.close.subarray(0, store.length));\n next.volume.set(store.volume.subarray(0, store.length));\n this.store = next;\n }\n}\n"],"mappings":"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"}
|
package/dist/index70.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var r={layout:{backgroundColor:"#1a1a2e",textColor:"#d1d4dc"},crosshair:{vertLineColor:"#758696",horzLineColor:"#758696"},grid:{vertLinesColor:"rgba(255, 255, 255, 0.06)",horzLinesColor:"rgba(255, 255, 255, 0.06)"}},o={layout:{backgroundColor:"#0f0e17",textColor:"#a7a9be"},grid:{vertLinesColor:"rgba(255, 255, 255, 0.03)",horzLinesColor:"rgba(255, 255, 255, 0.03)"},crosshair:{vertLineColor:"#ff8906",horzLineColor:"#ff8906"}},e={layout:{backgroundColor:"#ffffff",textColor:"#333333"},crosshair:{vertLineColor:"#9598A1",horzLineColor:"#9598A1"},grid:{vertLinesColor:"rgba(0, 0, 0, 0.06)",horzLinesColor:"rgba(0, 0, 0, 0.06)"}},i={width:800,height:400,autoSize:!1,layout:{backgroundColor:"#1a1a2e",textColor:"#d1d4dc",fontSize:11,fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'},timeScale:{barSpacing:6,rightOffset:0,minBarSpacing:4,maxBarSpacing:50},crosshair:{vertLineColor:"#758696",vertLineWidth:1,vertLineDash:[4,4],horzLineColor:"#758696",horzLineWidth:1,horzLineDash:[4,4]},grid:{vertLinesVisible:!0,vertLinesColor:"rgba(255, 255, 255, 0.06)",horzLinesVisible:!0,horzLinesColor:"rgba(255, 255, 255, 0.06)"},lastPriceLine:{visible:!0},tooltip:{enabled:!0},watermark:{visible:!1,text:"",color:"rgba(255,255,255,0.06)",fontSize:48,horzAlign:"center",vertAlign:"center"},volume:{visible:!1,upColor:"rgba(34,171,148,0.24)",downColor:"rgba(247,82,95,0.24)",scaleMarginTop:.7},rightPriceScale:{visible:!0},leftPriceScale:{visible:!1},timeGaps:{visible:!1}},a=new Set(["sma","ema","bollinger","vwap","ichimoku","parabolic-sar","keltner","donchian","supertrend","vwma","linear-regression"]),t={sma:{period:20},ema:{period:20},rsi:{period:14},macd:{fastPeriod:12,slowPeriod:26,signalPeriod:9},bollinger:{period:20,stdDev:2},stochastic:{kPeriod:14,dPeriod:3},atr:{period:14},adx:{period:14},obv:{},vwap:{},"williams-r":{period:14},ichimoku:{tenkanPeriod:9,kijunPeriod:26,senkouPeriod:52},"parabolic-sar":{afStep:.02,afMax:.2},keltner:{emaPeriod:20,atrPeriod:10,multiplier:2},donchian:{period:20},cci:{period:20},"pivot-points":{},aroon:{period:25},"awesome-oscillator":{fastPeriod:5,slowPeriod:34},"chaikin-mf":{period:20},coppock:{wmaPeriod:10,longROC:14,shortROC:11},"elder-force":{period:13},trix:{period:15,signalPeriod:9},supertrend:{period:10,multiplier:3},vwma:{period:20},choppiness:{period:14},mfi:{period:14},roc:{period:12},"linear-regression":{period:20}};function l(r,o){const e={...r};for(const i of Object.keys(o)){const r=o[i];null==r||"object"!=typeof r||Array.isArray(r)||r instanceof Float64Array?void 0!==r&&(e[i]=r):e[i]=l(e[i]??{},r)}return e}export{o as COLORFUL_THEME,r as DARK_THEME,i as DEFAULT_CHART_OPTIONS,t as DEFAULT_INDICATOR_PARAMS,e as LIGHT_THEME,a as OVERLAY_INDICATORS,l as mergeOptions};
|
|
2
|
+
//# sourceMappingURL=index70.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index70.js","names":[],"sources":["../src/api/options.ts"],"sourcesContent":["import type { Bar, ColumnData, DeepPartial } from '../core/types';\nimport type { CandlestickRendererOptions } from '../renderers/candlestick';\nimport type { LineRendererOptions } from '../renderers/line';\nimport type { AreaRendererOptions } from '../renderers/area';\nimport type { BarOHLCRendererOptions } from '../renderers/bar-ohlc';\nimport type { BaselineRendererOptions } from '../renderers/baseline';\nimport type { HollowCandleRendererOptions } from '../renderers/hollow-candle';\nimport type { HistogramRendererOptions } from '../renderers/histogram';\nimport type { StepLineRendererOptions } from '../renderers/step-line';\nimport type { ColoredLineRendererOptions } from '../renderers/colored-line';\nimport type { ColoredMountainRendererOptions } from '../renderers/colored-mountain';\nimport type { HLCAreaRendererOptions } from '../renderers/hlc-area';\nimport type { HighLowRendererOptions } from '../renderers/high-low';\nimport type { ColumnRendererOptions } from '../renderers/column';\nimport type { VolumeCandleRendererOptions } from '../renderers/volume-candle';\nimport type { BaselineDeltaMountainRendererOptions } from '../renderers/baseline-delta-mountain';\nimport type { RenkoRendererOptions } from '../renderers/renko';\nimport type { KagiRendererOptions } from '../renderers/kagi';\nimport type { LineBreakRendererOptions } from '../renderers/line-break';\nimport type { PointFigureRendererOptions } from '../renderers/point-figure';\n\n// ─── Layout ─────────────────────────────────────────────────────────────────\n\nexport interface LayoutOptions {\n backgroundColor: string;\n textColor: string;\n fontSize: number;\n fontFamily: string;\n}\n\n// ─── TimeScale ──────────────────────────────────────────────────────────────\n\nexport interface TimeScaleApiOptions {\n barSpacing: number;\n rightOffset: number;\n minBarSpacing: number;\n maxBarSpacing: number;\n tickMarkFormatter?: (time: number, tickType: 'year' | 'month' | 'day' | 'time') => string;\n}\n\n// ─── Crosshair ──────────────────────────────────────────────────────────────\n\nexport interface CrosshairOptions {\n vertLineColor: string;\n vertLineWidth: number;\n vertLineDash: number[];\n horzLineColor: string;\n horzLineWidth: number;\n horzLineDash: number[];\n}\n\n// ─── Grid ───────────────────────────────────────────────────────────────────\n\nexport interface GridOptions {\n vertLinesVisible: boolean;\n vertLinesColor: string;\n horzLinesVisible: boolean;\n horzLinesColor: string;\n}\n\n// ─── Chart ──────────────────────────────────────────────────────────────────\n\nexport interface LastPriceLineOptions {\n visible: boolean;\n}\n\nexport interface TooltipOptions {\n enabled: boolean;\n}\n\nexport interface WatermarkOptions {\n visible: boolean;\n text: string;\n color: string;\n fontSize: number;\n horzAlign: 'left' | 'center' | 'right';\n vertAlign: 'top' | 'center' | 'bottom';\n}\n\nexport interface VolumeOverlayOptions {\n visible: boolean;\n upColor: string;\n downColor: string;\n scaleMarginTop: number;\n}\n\nexport interface PriceScaleOptions {\n visible: boolean;\n /** Scale mode: 'linear' (default) or 'logarithmic'. */\n mode?: import('../core/price-scale').PriceScaleMode;\n}\n\nexport interface TimeGapsOptions {\n visible: boolean;\n}\n\nexport type RendererType = 'canvas2d' | 'webgl';\n\nexport interface ChartOptions {\n symbol?: string;\n width: number;\n height: number;\n autoSize: boolean;\n layout: LayoutOptions;\n timeScale: TimeScaleApiOptions;\n crosshair: CrosshairOptions;\n grid: GridOptions;\n lastPriceLine: LastPriceLineOptions;\n tooltip: TooltipOptions;\n watermark: WatermarkOptions;\n volume: VolumeOverlayOptions;\n rightPriceScale: PriceScaleOptions;\n leftPriceScale: PriceScaleOptions;\n timeGaps: TimeGapsOptions;\n priceFormatter?: (price: number) => string;\n theme?: 'dark' | 'light' | 'colorful';\n locale?: string; // BCP 47 locale tag, e.g. 'en-US', 'de-DE'\n timezone?: string; // IANA timezone, e.g. 'America/New_York', 'UTC'\n currency?: string; // ISO 4217 currency code, e.g. 'USD', 'EUR'\n /** Text direction: 'ltr' (default) or 'rtl'. Set to 'auto' to detect from locale. */\n direction?: import('../core/rtl').TextDirection | 'auto';\n /**\n * Rendering backend. `'webgl'` uses WebGL2 for supported series types\n * (candlestick, line, area) and falls back to Canvas 2D for the rest.\n * Automatically falls back to `'canvas2d'` when WebGL is unavailable.\n *\n * **Note:** Only honored at chart creation time; cannot be changed via\n * `applyOptions()` after the chart is created.\n */\n renderer?: RendererType;\n}\n\nexport const DARK_THEME: DeepPartial<ChartOptions> = {\n layout: {\n backgroundColor: '#1a1a2e',\n textColor: '#d1d4dc',\n },\n crosshair: {\n vertLineColor: '#758696',\n horzLineColor: '#758696',\n },\n grid: {\n vertLinesColor: 'rgba(255, 255, 255, 0.06)',\n horzLinesColor: 'rgba(255, 255, 255, 0.06)',\n },\n};\n\nexport const COLORFUL_THEME: DeepPartial<ChartOptions> = {\n layout: {\n backgroundColor: '#0f0e17',\n textColor: '#a7a9be',\n },\n grid: {\n vertLinesColor: 'rgba(255, 255, 255, 0.03)',\n horzLinesColor: 'rgba(255, 255, 255, 0.03)',\n },\n crosshair: {\n vertLineColor: '#ff8906',\n horzLineColor: '#ff8906',\n },\n};\n\nexport const LIGHT_THEME: DeepPartial<ChartOptions> = {\n layout: {\n backgroundColor: '#ffffff',\n textColor: '#333333',\n },\n crosshair: {\n vertLineColor: '#9598A1',\n horzLineColor: '#9598A1',\n },\n grid: {\n vertLinesColor: 'rgba(0, 0, 0, 0.06)',\n horzLinesColor: 'rgba(0, 0, 0, 0.06)',\n },\n};\n\nexport const DEFAULT_CHART_OPTIONS: ChartOptions = {\n width: 800,\n height: 400,\n autoSize: false,\n layout: {\n backgroundColor: '#1a1a2e',\n textColor: '#d1d4dc',\n fontSize: 11,\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n },\n timeScale: {\n barSpacing: 6,\n rightOffset: 0,\n minBarSpacing: 4,\n maxBarSpacing: 50,\n },\n crosshair: {\n vertLineColor: '#758696',\n vertLineWidth: 1,\n vertLineDash: [4, 4],\n horzLineColor: '#758696',\n horzLineWidth: 1,\n horzLineDash: [4, 4],\n },\n grid: {\n vertLinesVisible: true,\n vertLinesColor: 'rgba(255, 255, 255, 0.06)',\n horzLinesVisible: true,\n horzLinesColor: 'rgba(255, 255, 255, 0.06)',\n },\n lastPriceLine: {\n visible: true,\n },\n tooltip: {\n enabled: true,\n },\n watermark: {\n visible: false,\n text: '',\n color: 'rgba(255,255,255,0.06)',\n fontSize: 48,\n horzAlign: 'center',\n vertAlign: 'center',\n },\n volume: {\n visible: false,\n upColor: 'rgba(34,171,148,0.24)',\n downColor: 'rgba(247,82,95,0.24)',\n scaleMarginTop: 0.7,\n },\n rightPriceScale: {\n visible: true,\n },\n leftPriceScale: {\n visible: false,\n },\n timeGaps: {\n visible: false,\n },\n};\n\n// ─── Series options ─────────────────────────────────────────────────────────\n\nexport interface BaseSeriesOptions {\n data?: Bar[] | ColumnData;\n priceScaleId?: string;\n visible?: boolean;\n paneId?: string;\n label?: string;\n}\n\nexport type CandlestickSeriesOptions = BaseSeriesOptions & Partial<CandlestickRendererOptions>;\nexport type LineSeriesOptions = BaseSeriesOptions & Partial<LineRendererOptions>;\nexport type AreaSeriesOptions = BaseSeriesOptions & Partial<AreaRendererOptions>;\nexport type BarSeriesOptions = BaseSeriesOptions & Partial<BarOHLCRendererOptions>;\nexport type BaselineSeriesOptions = BaseSeriesOptions & Partial<BaselineRendererOptions>;\nexport type HollowCandleSeriesOptions = BaseSeriesOptions & Partial<HollowCandleRendererOptions>;\nexport type HistogramSeriesOptions = BaseSeriesOptions & Partial<HistogramRendererOptions>;\nexport type StepLineSeriesOptions = BaseSeriesOptions & Partial<StepLineRendererOptions>;\nexport type ColoredLineSeriesOptions = BaseSeriesOptions & Partial<ColoredLineRendererOptions>;\nexport type ColoredMountainSeriesOptions = BaseSeriesOptions & Partial<ColoredMountainRendererOptions>;\nexport type HLCAreaSeriesOptions = BaseSeriesOptions & Partial<HLCAreaRendererOptions>;\nexport type HighLowSeriesOptions = BaseSeriesOptions & Partial<HighLowRendererOptions>;\nexport type ColumnSeriesOptions = BaseSeriesOptions & Partial<ColumnRendererOptions>;\nexport type VolumeCandleSeriesOptions = BaseSeriesOptions & Partial<VolumeCandleRendererOptions>;\nexport type BaselineDeltaMountainSeriesOptions = BaseSeriesOptions & Partial<BaselineDeltaMountainRendererOptions>;\nexport type RenkoSeriesOptions = BaseSeriesOptions & Partial<RenkoRendererOptions>;\nexport type KagiSeriesOptions = BaseSeriesOptions & Partial<KagiRendererOptions>;\nexport type LineBreakSeriesOptions = BaseSeriesOptions & Partial<LineBreakRendererOptions>;\nexport type PointFigureSeriesOptions = BaseSeriesOptions & Partial<PointFigureRendererOptions>;\n\nexport interface PaneOptions {\n height?: number;\n}\n\nexport interface SeriesOptionsMap {\n candlestick: CandlestickSeriesOptions;\n bar: BarSeriesOptions;\n line: LineSeriesOptions;\n area: AreaSeriesOptions;\n histogram: HistogramSeriesOptions;\n baseline: BaselineSeriesOptions;\n 'hollow-candle': HollowCandleSeriesOptions;\n 'heikin-ashi': CandlestickSeriesOptions;\n 'step-line': StepLineSeriesOptions;\n 'colored-line': ColoredLineSeriesOptions;\n 'colored-mountain': ColoredMountainSeriesOptions;\n 'hlc-area': HLCAreaSeriesOptions;\n 'high-low': HighLowSeriesOptions;\n column: ColumnSeriesOptions;\n 'volume-candle': VolumeCandleSeriesOptions;\n 'baseline-delta-mountain': BaselineDeltaMountainSeriesOptions;\n renko: RenkoSeriesOptions;\n kagi: KagiSeriesOptions;\n 'line-break': LineBreakSeriesOptions;\n 'point-figure': PointFigureSeriesOptions;\n}\n\n/** Discriminated union for the unified addSeries() API. */\nexport type SeriesOptions =\n | ({ type: 'candlestick' } & Partial<CandlestickSeriesOptions>)\n | ({ type: 'line' } & Partial<LineSeriesOptions>)\n | ({ type: 'area' } & Partial<AreaSeriesOptions>)\n | ({ type: 'bar' } & Partial<BarSeriesOptions>)\n | ({ type: 'baseline' } & Partial<BaselineSeriesOptions>)\n | ({ type: 'hollow-candle' } & Partial<HollowCandleSeriesOptions>)\n | ({ type: 'histogram' } & Partial<HistogramSeriesOptions>)\n | ({ type: 'heikin-ashi' } & Partial<CandlestickSeriesOptions>)\n | ({ type: 'step-line' } & Partial<StepLineSeriesOptions>)\n | ({ type: 'colored-line' } & Partial<ColoredLineSeriesOptions>)\n | ({ type: 'colored-mountain' } & Partial<ColoredMountainSeriesOptions>)\n | ({ type: 'hlc-area' } & Partial<HLCAreaSeriesOptions>)\n | ({ type: 'high-low' } & Partial<HighLowSeriesOptions>)\n | ({ type: 'column' } & Partial<ColumnSeriesOptions>)\n | ({ type: 'volume-candle' } & Partial<VolumeCandleSeriesOptions>)\n | ({ type: 'baseline-delta-mountain' } & Partial<BaselineDeltaMountainSeriesOptions>)\n | ({ type: 'renko' } & Partial<RenkoSeriesOptions>)\n | ({ type: 'kagi' } & Partial<KagiSeriesOptions>)\n | ({ type: 'line-break' } & Partial<LineBreakSeriesOptions>)\n | ({ type: 'point-figure' } & Partial<PointFigureSeriesOptions>);\n\n// ─── Indicators ────────────────────────────────────────────────────────────\n\nexport type IndicatorType = 'sma' | 'ema' | 'rsi' | 'macd' | 'bollinger'\n | 'vwap' | 'stochastic' | 'atr' | 'adx' | 'obv' | 'williams-r'\n | 'ichimoku' | 'parabolic-sar' | 'keltner' | 'donchian' | 'cci' | 'pivot-points'\n | 'aroon' | 'awesome-oscillator' | 'chaikin-mf' | 'coppock' | 'elder-force'\n | 'trix' | 'supertrend' | 'vwma' | 'choppiness' | 'mfi' | 'roc' | 'linear-regression';\n\nexport interface IndicatorOptions {\n source: import('./series-api').ISeriesApi<import('../core/types').SeriesType>;\n params?: Record<string, number>;\n paneId?: string;\n color?: string;\n lineWidth?: number;\n visible?: boolean;\n label?: string;\n /** Per-output color overrides, e.g. { upper: '#ff0', middle: '#0f0', lower: '#ff0' }. */\n colors?: Record<string, string>;\n /** Histogram up-bar color override (default: green). */\n histogramUpColor?: string;\n /** Histogram down-bar color override (default: red). */\n histogramDownColor?: string;\n}\n\nexport const OVERLAY_INDICATORS: Set<IndicatorType> = new Set([\n 'sma', 'ema', 'bollinger', 'vwap',\n 'ichimoku', 'parabolic-sar', 'keltner', 'donchian',\n 'supertrend', 'vwma', 'linear-regression',\n]);\n\nexport const DEFAULT_INDICATOR_PARAMS: Record<IndicatorType, Record<string, number>> = {\n sma: { period: 20 },\n ema: { period: 20 },\n rsi: { period: 14 },\n macd: { fastPeriod: 12, slowPeriod: 26, signalPeriod: 9 },\n bollinger: { period: 20, stdDev: 2 },\n stochastic: { kPeriod: 14, dPeriod: 3 },\n atr: { period: 14 },\n adx: { period: 14 },\n obv: {},\n vwap: {},\n 'williams-r': { period: 14 },\n ichimoku: { tenkanPeriod: 9, kijunPeriod: 26, senkouPeriod: 52 },\n 'parabolic-sar': { afStep: 0.02, afMax: 0.20 },\n keltner: { emaPeriod: 20, atrPeriod: 10, multiplier: 2 },\n donchian: { period: 20 },\n cci: { period: 20 },\n 'pivot-points': {},\n aroon: { period: 25 },\n 'awesome-oscillator': { fastPeriod: 5, slowPeriod: 34 },\n 'chaikin-mf': { period: 20 },\n coppock: { wmaPeriod: 10, longROC: 14, shortROC: 11 },\n 'elder-force': { period: 13 },\n trix: { period: 15, signalPeriod: 9 },\n supertrend: { period: 10, multiplier: 3 },\n vwma: { period: 20 },\n choppiness: { period: 14 },\n mfi: { period: 14 },\n roc: { period: 12 },\n 'linear-regression': { period: 20 },\n};\n\n// ─── Utility ────────────────────────────────────────────────────────────────\n\n/** Deep merge `overrides` into a copy of `defaults`. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function mergeOptions<T extends object>(\n defaults: T,\n overrides: DeepPartial<T>,\n): T {\n const result = { ...defaults } as Record<string, unknown>;\n for (const key of Object.keys(overrides)) {\n const val = (overrides as Record<string, unknown>)[key];\n if (\n val !== undefined &&\n val !== null &&\n typeof val === 'object' &&\n !Array.isArray(val) &&\n !(val instanceof Float64Array)\n ) {\n result[key] = mergeOptions(\n (result[key] ?? {}) as Record<string, unknown>,\n val as DeepPartial<Record<string, unknown>>,\n );\n } else if (val !== undefined) {\n result[key] = val;\n }\n }\n return result as T;\n}\n"],"mappings":"AAoIA,IAAa,EAAwC,CACnD,OAAQ,CACN,gBAAiB,UACjB,UAAW,WAEb,UAAW,CACT,cAAe,UACf,cAAe,WAEjB,KAAM,CACJ,eAAgB,4BAChB,eAAgB,8BAIP,EAA4C,CACvD,OAAQ,CACN,gBAAiB,UACjB,UAAW,WAEb,KAAM,CACJ,eAAgB,4BAChB,eAAgB,6BAElB,UAAW,CACT,cAAe,UACf,cAAe,YAIN,EAAyC,CACpD,OAAQ,CACN,gBAAiB,UACjB,UAAW,WAEb,UAAW,CACT,cAAe,UACf,cAAe,WAEjB,KAAM,CACJ,eAAgB,sBAChB,eAAgB,wBAIP,EAAsC,CACjD,MAAO,IACP,OAAQ,IACR,UAAU,EACV,OAAQ,CACN,gBAAiB,UACjB,UAAW,UACX,SAAU,GACV,WAAY,qEAEd,UAAW,CACT,WAAY,EACZ,YAAa,EACb,cAAe,EACf,cAAe,IAEjB,UAAW,CACT,cAAe,UACf,cAAe,EACf,aAAc,CAAC,EAAG,GAClB,cAAe,UACf,cAAe,EACf,aAAc,CAAC,EAAG,IAEpB,KAAM,CACJ,kBAAkB,EAClB,eAAgB,4BAChB,kBAAkB,EAClB,eAAgB,6BAElB,cAAe,CACb,SAAS,GAEX,QAAS,CACP,SAAS,GAEX,UAAW,CACT,SAAS,EACT,KAAM,GACN,MAAO,yBACP,SAAU,GACV,UAAW,SACX,UAAW,UAEb,OAAQ,CACN,SAAS,EACT,QAAS,wBACT,UAAW,uBACX,eAAgB,IAElB,gBAAiB,CACf,SAAS,GAEX,eAAgB,CACd,SAAS,GAEX,SAAU,CACR,SAAS,IA4GA,EAAyC,IAAI,IAAI,CAC5D,MAAO,MAAO,YAAa,OAC3B,WAAY,gBAAiB,UAAW,WACxC,aAAc,OAAQ,sBAGX,EAA0E,CACrF,IAAK,CAAE,OAAQ,IACf,IAAK,CAAE,OAAQ,IACf,IAAK,CAAE,OAAQ,IACf,KAAM,CAAE,WAAY,GAAI,WAAY,GAAI,aAAc,GACtD,UAAW,CAAE,OAAQ,GAAI,OAAQ,GACjC,WAAY,CAAE,QAAS,GAAI,QAAS,GACpC,IAAK,CAAE,OAAQ,IACf,IAAK,CAAE,OAAQ,IACf,IAAK,CAAA,EACL,KAAM,CAAA,EACN,aAAc,CAAE,OAAQ,IACxB,SAAU,CAAE,aAAc,EAAG,YAAa,GAAI,aAAc,IAC5D,gBAAiB,CAAE,OAAQ,IAAM,MAAO,IACxC,QAAS,CAAE,UAAW,GAAI,UAAW,GAAI,WAAY,GACrD,SAAU,CAAE,OAAQ,IACpB,IAAK,CAAE,OAAQ,IACf,eAAgB,CAAA,EAChB,MAAO,CAAE,OAAQ,IACjB,qBAAsB,CAAE,WAAY,EAAG,WAAY,IACnD,aAAc,CAAE,OAAQ,IACxB,QAAS,CAAE,UAAW,GAAI,QAAS,GAAI,SAAU,IACjD,cAAe,CAAE,OAAQ,IACzB,KAAM,CAAE,OAAQ,GAAI,aAAc,GAClC,WAAY,CAAE,OAAQ,GAAI,WAAY,GACtC,KAAM,CAAE,OAAQ,IAChB,WAAY,CAAE,OAAQ,IACtB,IAAK,CAAE,OAAQ,IACf,IAAK,CAAE,OAAQ,IACf,oBAAqB,CAAE,OAAQ,KAOjC,SAAgB,EACd,EACA,GAEA,MAAM,EAAS,IAAK,GACpB,IAAK,MAAM,KAAO,OAAO,KAAK,GAAY,CACxC,MAAM,EAAO,EAAsC,GAEjD,SAEe,iBAAR,GACN,MAAM,QAAQ,IACb,aAAe,kBAMA,IAAR,IACT,EAAO,GAAO,GALd,EAAO,GAAO,EACX,EAAO,IAAQ,CAAA,EAChB,GAMN,OAAO"}
|
package/dist/index71.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function r(r,t,e){const o=new Float64Array(t);for(let l=0;l<e-1;l++)o[l]=NaN;if(t<e){for(let r=e-1;r<t;r++)o[r]=NaN;return o}let f=0;for(let l=0;l<e;l++)f+=r[l];o[e-1]=f/e;for(let l=e;l<t;l++)f+=r[l]-r[l-e],o[l]=f/e;return o}export{r as computeSMA};
|
|
2
|
+
//# sourceMappingURL=index71.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index71.js","names":[],"sources":["../src/indicators/sma.ts"],"sourcesContent":["export function computeSMA(close: Float64Array, length: number, period: number): Float64Array {\n const result = new Float64Array(length);\n\n // Fill indices before period-1 with NaN\n for (let i = 0; i < period - 1; i++) {\n result[i] = NaN;\n }\n\n if (length < period) {\n for (let i = period - 1; i < length; i++) {\n result[i] = NaN;\n }\n return result;\n }\n\n // Compute initial sum for first window\n let sum = 0;\n for (let i = 0; i < period; i++) {\n sum += close[i];\n }\n result[period - 1] = sum / period;\n\n // Sliding window O(1) per bar\n for (let i = period; i < length; i++) {\n sum += close[i] - close[i - period];\n result[i] = sum / period;\n }\n\n return result;\n}\n"],"mappings":"AAAA,SAAgB,EAAW,EAAqB,EAAgB,GAC9D,MAAM,EAAS,IAAI,aAAa,GAGhC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAS,EAAG,IAC9B,EAAO,GAAK,IAGd,GAAI,EAAS,EAAQ,CACnB,IAAK,IAAI,EAAI,EAAS,EAAG,EAAI,EAAQ,IACnC,EAAO,GAAK,IAEd,OAAO,EAIT,IAAI,EAAM,EACV,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,IAC1B,GAAO,EAAM,GAEf,EAAO,EAAS,GAAK,EAAM,EAG3B,IAAK,IAAI,EAAI,EAAQ,EAAI,EAAQ,IAC/B,GAAO,EAAM,GAAK,EAAM,EAAI,GAC5B,EAAO,GAAK,EAAM,EAGpB,OAAO"}
|
package/dist/index72.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function t(t,r,e){const o=new Float64Array(r);for(let l=0;l<e-1;l++)o[l]=NaN;if(r<e){for(let t=e-1;t<r;t++)o[t]=NaN;return o}let n=0;for(let l=0;l<e;l++)n+=t[l];o[e-1]=n/e;const f=2/(e+1);for(let l=e;l<r;l++)o[l]=t[l]*f+o[l-1]*(1-f);return o}export{t as computeEMA};
|
|
2
|
+
//# sourceMappingURL=index72.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index72.js","names":[],"sources":["../src/indicators/ema.ts"],"sourcesContent":["export function computeEMA(close: Float64Array, length: number, period: number): Float64Array {\n const result = new Float64Array(length);\n\n // Fill indices before period-1 with NaN\n for (let i = 0; i < period - 1; i++) {\n result[i] = NaN;\n }\n\n if (length < period) {\n for (let i = period - 1; i < length; i++) {\n result[i] = NaN;\n }\n return result;\n }\n\n // First EMA value = SMA of first period values\n let sum = 0;\n for (let i = 0; i < period; i++) {\n sum += close[i];\n }\n result[period - 1] = sum / period;\n\n // k = 2 / (period + 1)\n const k = 2 / (period + 1);\n\n // Apply EMA formula\n for (let i = period; i < length; i++) {\n result[i] = close[i] * k + result[i - 1] * (1 - k);\n }\n\n return result;\n}\n"],"mappings":"AAAA,SAAgB,EAAW,EAAqB,EAAgB,GAC9D,MAAM,EAAS,IAAI,aAAa,GAGhC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAS,EAAG,IAC9B,EAAO,GAAK,IAGd,GAAI,EAAS,EAAQ,CACnB,IAAK,IAAI,EAAI,EAAS,EAAG,EAAI,EAAQ,IACnC,EAAO,GAAK,IAEd,OAAO,EAIT,IAAI,EAAM,EACV,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,IAC1B,GAAO,EAAM,GAEf,EAAO,EAAS,GAAK,EAAM,EAG3B,MAAM,EAAI,GAAK,EAAS,GAGxB,IAAK,IAAI,EAAI,EAAQ,EAAI,EAAQ,IAC/B,EAAO,GAAK,EAAM,GAAK,EAAI,EAAO,EAAI,IAAM,EAAI,GAGlD,OAAO"}
|
package/dist/index73.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function t(t,r,o){const e=new Float64Array(r);for(let l=0;l<o;l++)e[l]=NaN;if(r<=o)return e;let n=0,f=0;for(let l=1;l<=o;l++){const r=t[l]-t[l-1];r>0?n+=r:f+=-r}n/=o,f/=o,e[o]=0===f?100:100-100/(1+n/f);for(let l=o+1;l<r;l++){const r=t[l]-t[l-1];n=(n*(o-1)+(r>0?r:0))/o,f=(f*(o-1)+(r<0?-r:0))/o,e[l]=0===f?100:100-100/(1+n/f)}return e}export{t as computeRSI};
|
|
2
|
+
//# sourceMappingURL=index73.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index73.js","names":[],"sources":["../src/indicators/rsi.ts"],"sourcesContent":["export function computeRSI(close: Float64Array, length: number, period: number): Float64Array {\n const result = new Float64Array(length);\n\n // Fill indices 0 through period-1 with NaN (RSI undefined for first `period` values)\n for (let i = 0; i < period; i++) {\n result[i] = NaN;\n }\n\n if (length <= period) {\n return result;\n }\n\n // Compute initial avgGain / avgLoss from first `period` changes\n let avgGain = 0;\n let avgLoss = 0;\n\n for (let i = 1; i <= period; i++) {\n const change = close[i] - close[i - 1];\n if (change > 0) {\n avgGain += change;\n } else {\n avgLoss += -change;\n }\n }\n\n avgGain /= period;\n avgLoss /= period;\n\n // First RSI at index period\n if (avgLoss === 0) {\n result[period] = 100;\n } else {\n result[period] = 100 - 100 / (1 + avgGain / avgLoss);\n }\n\n // Wilder's smoothing for subsequent values\n for (let i = period + 1; i < length; i++) {\n const change = close[i] - close[i - 1];\n const gain = change > 0 ? change : 0;\n const loss = change < 0 ? -change : 0;\n\n avgGain = (avgGain * (period - 1) + gain) / period;\n avgLoss = (avgLoss * (period - 1) + loss) / period;\n\n if (avgLoss === 0) {\n result[i] = 100;\n } else {\n result[i] = 100 - 100 / (1 + avgGain / avgLoss);\n }\n }\n\n return result;\n}\n"],"mappings":"AAAA,SAAgB,EAAW,EAAqB,EAAgB,GAC9D,MAAM,EAAS,IAAI,aAAa,GAGhC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,IAC1B,EAAO,GAAK,IAGd,GAAI,GAAU,EACZ,OAAO,EAIT,IAAI,EAAU,EACV,EAAU,EAEd,IAAK,IAAI,EAAI,EAAG,GAAK,EAAQ,IAAK,CAChC,MAAM,EAAS,EAAM,GAAK,EAAM,EAAI,GAChC,EAAS,EACX,GAAW,EAEX,IAAY,EAIhB,GAAW,EACX,GAAW,EAIT,EAAO,GADO,IAAZ,EACe,IAEA,IAAM,KAAO,EAAI,EAAU,GAI9C,IAAK,IAAI,EAAI,EAAS,EAAG,EAAI,EAAQ,IAAK,CACxC,MAAM,EAAS,EAAM,GAAK,EAAM,EAAI,GAIpC,GAAW,GAAW,EAAS,IAHlB,EAAS,EAAI,EAAS,IAGS,EAC5C,GAAW,GAAW,EAAS,IAHlB,EAAS,GAAK,EAAS,IAGQ,EAG1C,EAAO,GADO,IAAZ,EACU,IAEA,IAAM,KAAO,EAAI,EAAU,GAI3C,OAAO"}
|
package/dist/index74.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{createColumnStore as o}from"./index2.js";function e(e){const l=e.length,n=o(Math.max(2*l,e.capacity));if(n.length=l,0===l)return n;n.time.set(e.time.subarray(0,l)),n.volume.set(e.volume.subarray(0,l)),n.close[0]=(e.open[0]+e.high[0]+e.low[0]+e.close[0])/4,n.open[0]=(e.open[0]+e.close[0])/2,n.high[0]=Math.max(e.high[0],n.open[0],n.close[0]),n.low[0]=Math.min(e.low[0],n.open[0],n.close[0]);for(let o=1;o<l;o++)n.close[o]=(e.open[o]+e.high[o]+e.low[o]+e.close[o])/4,n.open[o]=(n.open[o-1]+n.close[o-1])/2,n.high[o]=Math.max(e.high[o],n.open[o],n.close[o]),n.low[o]=Math.min(e.low[o],n.open[o],n.close[o]);return n}export{e as computeHeikinAshi};
|
|
2
|
+
//# sourceMappingURL=index74.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index74.js","names":[],"sources":["../src/transforms/heikin-ashi.ts"],"sourcesContent":["import type { ColumnStore } from '../core/types';\nimport { createColumnStore } from '../core/types';\n\nexport function computeHeikinAshi(store: ColumnStore): ColumnStore {\n const len = store.length;\n const ha = createColumnStore(Math.max(len * 2, store.capacity));\n ha.length = len;\n if (len === 0) return ha;\n\n ha.time.set(store.time.subarray(0, len));\n ha.volume.set(store.volume.subarray(0, len));\n\n ha.close[0] = (store.open[0] + store.high[0] + store.low[0] + store.close[0]) / 4;\n ha.open[0] = (store.open[0] + store.close[0]) / 2;\n ha.high[0] = Math.max(store.high[0], ha.open[0], ha.close[0]);\n ha.low[0] = Math.min(store.low[0], ha.open[0], ha.close[0]);\n\n for (let i = 1; i < len; i++) {\n ha.close[i] = (store.open[i] + store.high[i] + store.low[i] + store.close[i]) / 4;\n ha.open[i] = (ha.open[i - 1] + ha.close[i - 1]) / 2;\n ha.high[i] = Math.max(store.high[i], ha.open[i], ha.close[i]);\n ha.low[i] = Math.min(store.low[i], ha.open[i], ha.close[i]);\n }\n return ha;\n}\n"],"mappings":"gDAGA,SAAgB,EAAkB,GAChC,MAAM,EAAM,EAAM,OACZ,EAAK,EAAkB,KAAK,IAAU,EAAN,EAAS,EAAM,WAErD,GADA,EAAG,OAAS,EACA,IAAR,EAAW,OAAO,EAEtB,EAAG,KAAK,IAAI,EAAM,KAAK,SAAS,EAAG,IACnC,EAAG,OAAO,IAAI,EAAM,OAAO,SAAS,EAAG,IAEvC,EAAG,MAAM,IAAM,EAAM,KAAK,GAAK,EAAM,KAAK,GAAK,EAAM,IAAI,GAAK,EAAM,MAAM,IAAM,EAChF,EAAG,KAAK,IAAM,EAAM,KAAK,GAAK,EAAM,MAAM,IAAM,EAChD,EAAG,KAAK,GAAK,KAAK,IAAI,EAAM,KAAK,GAAI,EAAG,KAAK,GAAI,EAAG,MAAM,IAC1D,EAAG,IAAI,GAAK,KAAK,IAAI,EAAM,IAAI,GAAI,EAAG,KAAK,GAAI,EAAG,MAAM,IAExD,IAAK,IAAI,EAAI,EAAG,EAAI,EAAK,IACvB,EAAG,MAAM,IAAM,EAAM,KAAK,GAAK,EAAM,KAAK,GAAK,EAAM,IAAI,GAAK,EAAM,MAAM,IAAM,EAChF,EAAG,KAAK,IAAM,EAAG,KAAK,EAAI,GAAK,EAAG,MAAM,EAAI,IAAM,EAClD,EAAG,KAAK,GAAK,KAAK,IAAI,EAAM,KAAK,GAAI,EAAG,KAAK,GAAI,EAAG,MAAM,IAC1D,EAAG,IAAI,GAAK,KAAK,IAAI,EAAM,IAAI,GAAI,EAAG,KAAK,GAAI,EAAG,MAAM,IAE1D,OAAO"}
|
package/dist/index75.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{computeEMA as r}from"./index72.js";function t(t,o,a,n,e){const l=new Float64Array(o),i=new Float64Array(o),s=new Float64Array(o),f=r(t,o,a),c=r(t,o,n);for(let r=0;r<o;r++)l[r]=r<n-1?NaN:f[r]-c[r];const m=n-1+e-1;for(let r=0;r<m;r++)i[r]=NaN,s[r]=NaN;if(m>=o)return{macd:l,signal:i,histogram:s};let N=0;for(let r=n-1;r<=m;r++)N+=l[r];i[m]=N/e,s[m]=l[m]-i[m];const g=2/(e+1);for(let r=m+1;r<o;r++)i[r]=l[r]*g+i[r-1]*(1-g),s[r]=l[r]-i[r];return{macd:l,signal:i,histogram:s}}export{t as computeMACD};
|
|
2
|
+
//# sourceMappingURL=index75.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index75.js","names":[],"sources":["../src/indicators/macd.ts"],"sourcesContent":["import { computeEMA } from './ema';\n\nexport interface MACDResult {\n macd: Float64Array;\n signal: Float64Array;\n histogram: Float64Array;\n}\n\nexport function computeMACD(\n close: Float64Array,\n length: number,\n fastPeriod: number,\n slowPeriod: number,\n signalPeriod: number,\n): MACDResult {\n const macd = new Float64Array(length);\n const signal = new Float64Array(length);\n const histogram = new Float64Array(length);\n\n const fastEMA = computeEMA(close, length, fastPeriod);\n const slowEMA = computeEMA(close, length, slowPeriod);\n\n // MACD line = fastEMA - slowEMA; NaN before slowPeriod-1\n for (let i = 0; i < length; i++) {\n if (i < slowPeriod - 1) {\n macd[i] = NaN;\n } else {\n macd[i] = fastEMA[i] - slowEMA[i];\n }\n }\n\n // Signal = EMA of MACD values\n // First valid MACD is at index slowPeriod-1\n // First signal = SMA of first signalPeriod MACD values (starting at slowPeriod-1)\n const firstSignalIdx = slowPeriod - 1 + signalPeriod - 1;\n\n for (let i = 0; i < firstSignalIdx; i++) {\n signal[i] = NaN;\n histogram[i] = NaN;\n }\n\n if (firstSignalIdx >= length) {\n return { macd, signal, histogram };\n }\n\n // Compute initial signal SMA from first signalPeriod MACD values\n let sum = 0;\n for (let i = slowPeriod - 1; i <= firstSignalIdx; i++) {\n sum += macd[i];\n }\n signal[firstSignalIdx] = sum / signalPeriod;\n histogram[firstSignalIdx] = macd[firstSignalIdx] - signal[firstSignalIdx];\n\n const k = 2 / (signalPeriod + 1);\n\n for (let i = firstSignalIdx + 1; i < length; i++) {\n signal[i] = macd[i] * k + signal[i - 1] * (1 - k);\n histogram[i] = macd[i] - signal[i];\n }\n\n return { macd, signal, histogram };\n}\n"],"mappings":"0CAQA,SAAgB,EACd,EACA,EACA,EACA,EACA,GAEA,MAAM,EAAO,IAAI,aAAa,GACxB,EAAS,IAAI,aAAa,GAC1B,EAAY,IAAI,aAAa,GAE7B,EAAU,EAAW,EAAO,EAAQ,GACpC,EAAU,EAAW,EAAO,EAAQ,GAG1C,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,IAExB,EAAK,GADH,EAAI,EAAa,EACT,IAEA,EAAQ,GAAK,EAAQ,GAOnC,MAAM,EAAiB,EAAa,EAAI,EAAe,EAEvD,IAAK,IAAI,EAAI,EAAG,EAAI,EAAgB,IAClC,EAAO,GAAK,IACZ,EAAU,GAAK,IAGjB,GAAI,GAAkB,EACpB,MAAO,CAAE,OAAM,SAAQ,aAIzB,IAAI,EAAM,EACV,IAAK,IAAI,EAAI,EAAa,EAAG,GAAK,EAAgB,IAChD,GAAO,EAAK,GAEd,EAAO,GAAkB,EAAM,EAC/B,EAAU,GAAkB,EAAK,GAAkB,EAAO,GAE1D,MAAM,EAAI,GAAK,EAAe,GAE9B,IAAK,IAAI,EAAI,EAAiB,EAAG,EAAI,EAAQ,IAC3C,EAAO,GAAK,EAAK,GAAK,EAAI,EAAO,EAAI,IAAM,EAAI,GAC/C,EAAU,GAAK,EAAK,GAAK,EAAO,GAGlC,MAAO,CAAE,OAAM,SAAQ"}
|
package/dist/index76.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{computeSMA as t}from"./index71.js";function r(r,e,o,n){const l=new Float64Array(e),a=t(r,e,o),s=new Float64Array(e);for(let t=0;t<e;t++)if(t<o-1)l[t]=NaN,s[t]=NaN;else{const e=a[t];let c=0;for(let n=t-o+1;n<=t;n++){const t=r[n]-e;c+=t*t}const f=Math.sqrt(c/o);l[t]=e+n*f,s[t]=e-n*f}return{upper:l,middle:a,lower:s}}export{r as computeBollinger};
|
|
2
|
+
//# sourceMappingURL=index76.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index76.js","names":[],"sources":["../src/indicators/bollinger.ts"],"sourcesContent":["import { computeSMA } from './sma';\n\nexport interface BollingerResult {\n upper: Float64Array;\n middle: Float64Array;\n lower: Float64Array;\n}\n\nexport function computeBollinger(\n close: Float64Array,\n length: number,\n period: number,\n stdDev: number,\n): BollingerResult {\n const upper = new Float64Array(length);\n const middle = computeSMA(close, length, period);\n const lower = new Float64Array(length);\n\n for (let i = 0; i < length; i++) {\n if (i < period - 1) {\n upper[i] = NaN;\n lower[i] = NaN;\n } else {\n const mean = middle[i];\n // Compute population standard deviation over the window\n let variance = 0;\n for (let j = i - period + 1; j <= i; j++) {\n const diff = close[j] - mean;\n variance += diff * diff;\n }\n const sd = Math.sqrt(variance / period);\n upper[i] = mean + stdDev * sd;\n lower[i] = mean - stdDev * sd;\n }\n }\n\n return { upper, middle, lower };\n}\n"],"mappings":"0CAQA,SAAgB,EACd,EACA,EACA,EACA,GAEA,MAAM,EAAQ,IAAI,aAAa,GACzB,EAAS,EAAW,EAAO,EAAQ,GACnC,EAAQ,IAAI,aAAa,GAE/B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,IAC1B,GAAI,EAAI,EAAS,EACf,EAAM,GAAK,IACX,EAAM,GAAK,QACN,CACL,MAAM,EAAO,EAAO,GAEpB,IAAI,EAAW,EACf,IAAK,IAAI,EAAI,EAAI,EAAS,EAAG,GAAK,EAAG,IAAK,CACxC,MAAM,EAAO,EAAM,GAAK,EACxB,GAAY,EAAO,EAErB,MAAM,EAAK,KAAK,KAAK,EAAW,GAChC,EAAM,GAAK,EAAO,EAAS,EAC3B,EAAM,GAAK,EAAO,EAAS,EAI/B,MAAO,CAAE,QAAO,SAAQ"}
|
package/dist/index77.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index77.js","names":[],"sources":["../src/indicators/vwap.ts"],"sourcesContent":["export function computeVWAP(\n high: Float64Array,\n low: Float64Array,\n close: Float64Array,\n volume: Float64Array,\n length: number\n): Float64Array {\n const result = new Float64Array(length);\n\n let cumulativeTPV = 0; // sum of typicalPrice * volume\n let cumulativeVol = 0;\n\n for (let i = 0; i < length; i++) {\n const typicalPrice = (high[i] + low[i] + close[i]) / 3;\n cumulativeTPV += typicalPrice * volume[i];\n cumulativeVol += volume[i];\n\n if (cumulativeVol === 0) {\n result[i] = NaN;\n } else {\n result[i] = cumulativeTPV / cumulativeVol;\n }\n }\n\n return result;\n}\n"],"mappings":"AAAA,SAAgB,EACd,EACA,EACA,EACA,EACA,GAEA,MAAM,EAAS,IAAI,aAAa,GAEhC,IAAI,EAAgB,EAChB,EAAgB,EAEpB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,IAAK,CAE/B,IADsB,EAAK,GAAK,EAAI,GAAK,EAAM,IAAM,EACrB,EAAO,GACvC,GAAiB,EAAO,GAGtB,EAAO,GADa,IAAlB,EACU,IAEA,EAAgB,EAIhC,OAAO"}
|
package/dist/index78.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function t(t,o,r,e,l,n){const f=new Float64Array(e),a=new Float64Array(e);for(let N=0;N<l-1;N++)f[N]=NaN;const c=l+n-2;for(let N=0;N<c;N++)a[N]=NaN;for(let N=l-1;N<e;N++){let e=t[N],n=o[N];for(let r=N-l+1;r<=N;r++)t[r]>e&&(e=t[r]),o[r]<n&&(n=o[r]);const a=e-n;f[N]=0===a?0:(r[N]-n)/a*100}for(let N=c;N<e;N++){let t=0;for(let o=N-n+1;o<=N;o++)t+=f[o];a[N]=t/n}return{k:f,d:a}}export{t as computeStochastic};
|
|
2
|
+
//# sourceMappingURL=index78.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index78.js","names":[],"sources":["../src/indicators/stochastic.ts"],"sourcesContent":["export interface StochasticResult {\n k: Float64Array;\n d: Float64Array;\n}\n\nexport function computeStochastic(\n high: Float64Array,\n low: Float64Array,\n close: Float64Array,\n length: number,\n kPeriod: number,\n dPeriod: number\n): StochasticResult {\n const k = new Float64Array(length);\n const d = new Float64Array(length);\n\n // Fill NaN for indices where K is undefined: [0, kPeriod-2]\n for (let i = 0; i < kPeriod - 1; i++) {\n k[i] = NaN;\n }\n\n // Fill NaN for all d values: [0, kPeriod+dPeriod-3]\n const dStart = kPeriod + dPeriod - 2;\n for (let i = 0; i < dStart; i++) {\n d[i] = NaN;\n }\n\n // Compute %K\n for (let i = kPeriod - 1; i < length; i++) {\n let highestHigh = high[i];\n let lowestLow = low[i];\n\n for (let j = i - kPeriod + 1; j <= i; j++) {\n if (high[j] > highestHigh) highestHigh = high[j];\n if (low[j] < lowestLow) lowestLow = low[j];\n }\n\n const range = highestHigh - lowestLow;\n if (range === 0) {\n k[i] = 0;\n } else {\n k[i] = ((close[i] - lowestLow) / range) * 100;\n }\n }\n\n // Compute %D = SMA of %K over dPeriod\n // D is valid from index kPeriod-1 + dPeriod-1 = kPeriod+dPeriod-2\n for (let i = dStart; i < length; i++) {\n let sum = 0;\n for (let j = i - dPeriod + 1; j <= i; j++) {\n sum += k[j];\n }\n d[i] = sum / dPeriod;\n }\n\n return { k, d };\n}\n"],"mappings":"AAKA,SAAgB,EACd,EACA,EACA,EACA,EACA,EACA,GAEA,MAAM,EAAI,IAAI,aAAa,GACrB,EAAI,IAAI,aAAa,GAG3B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAU,EAAG,IAC/B,EAAE,GAAK,IAIT,MAAM,EAAS,EAAU,EAAU,EACnC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,IAC1B,EAAE,GAAK,IAIT,IAAK,IAAI,EAAI,EAAU,EAAG,EAAI,EAAQ,IAAK,CACzC,IAAI,EAAc,EAAK,GACnB,EAAY,EAAI,GAEpB,IAAK,IAAI,EAAI,EAAI,EAAU,EAAG,GAAK,EAAG,IAChC,EAAK,GAAK,IAAa,EAAc,EAAK,IAC1C,EAAI,GAAK,IAAW,EAAY,EAAI,IAG1C,MAAM,EAAQ,EAAc,EAE1B,EAAE,GADU,IAAV,EACK,GAEE,EAAM,GAAK,GAAa,EAAS,IAM9C,IAAK,IAAI,EAAI,EAAQ,EAAI,EAAQ,IAAK,CACpC,IAAI,EAAM,EACV,IAAK,IAAI,EAAI,EAAI,EAAU,EAAG,GAAK,EAAG,IACpC,GAAO,EAAE,GAEX,EAAE,GAAK,EAAM,EAGf,MAAO,CAAE,IAAG"}
|
package/dist/index79.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function t(t,a,r,e,o){const n=new Float64Array(e);for(let l=0;l<=o-1;l++)n[l]=NaN;if(e<=o)return n;let s=0;for(let l=1;l<=o;l++){const e=t[l]-a[l],o=Math.abs(t[l]-r[l-1]),n=Math.abs(a[l]-r[l-1]);s+=Math.max(e,o,n)}let h=s/o;n[o]=h;for(let l=o+1;l<e;l++){const e=t[l]-a[l],s=Math.abs(t[l]-r[l-1]),M=Math.abs(a[l]-r[l-1]);h=(h*(o-1)+Math.max(e,s,M))/o,n[l]=h}return n}export{t as computeATR};
|
|
2
|
+
//# sourceMappingURL=index79.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index79.js","names":[],"sources":["../src/indicators/atr.ts"],"sourcesContent":["export function computeATR(\n high: Float64Array,\n low: Float64Array,\n close: Float64Array,\n length: number,\n period: number\n): Float64Array {\n const result = new Float64Array(length);\n\n // NaN for indices [0, period-1]\n for (let i = 0; i <= period - 1; i++) {\n result[i] = NaN;\n }\n\n if (length <= period) {\n return result;\n }\n\n // Compute TRs for indices 1..period and average for first ATR at index period\n let sumTR = 0;\n for (let i = 1; i <= period; i++) {\n const hl = high[i] - low[i];\n const hpc = Math.abs(high[i] - close[i - 1]);\n const lpc = Math.abs(low[i] - close[i - 1]);\n sumTR += Math.max(hl, hpc, lpc);\n }\n\n let atr = sumTR / period;\n result[period] = atr;\n\n // Wilder smoothing: ATR = (prev * (period-1) + TR) / period\n for (let i = period + 1; i < length; i++) {\n const hl = high[i] - low[i];\n const hpc = Math.abs(high[i] - close[i - 1]);\n const lpc = Math.abs(low[i] - close[i - 1]);\n const tr = Math.max(hl, hpc, lpc);\n\n atr = (atr * (period - 1) + tr) / period;\n result[i] = atr;\n }\n\n return result;\n}\n"],"mappings":"AAAA,SAAgB,EACd,EACA,EACA,EACA,EACA,GAEA,MAAM,EAAS,IAAI,aAAa,GAGhC,IAAK,IAAI,EAAI,EAAG,GAAK,EAAS,EAAG,IAC/B,EAAO,GAAK,IAGd,GAAI,GAAU,EACZ,OAAO,EAIT,IAAI,EAAQ,EACZ,IAAK,IAAI,EAAI,EAAG,GAAK,EAAQ,IAAK,CAChC,MAAM,EAAK,EAAK,GAAK,EAAI,GACnB,EAAM,KAAK,IAAI,EAAK,GAAK,EAAM,EAAI,IACnC,EAAM,KAAK,IAAI,EAAI,GAAK,EAAM,EAAI,IACxC,GAAS,KAAK,IAAI,EAAI,EAAK,GAG7B,IAAI,EAAM,EAAQ,EAClB,EAAO,GAAU,EAGjB,IAAK,IAAI,EAAI,EAAS,EAAG,EAAI,EAAQ,IAAK,CACxC,MAAM,EAAK,EAAK,GAAK,EAAI,GACnB,EAAM,KAAK,IAAI,EAAK,GAAK,EAAM,EAAI,IACnC,EAAM,KAAK,IAAI,EAAI,GAAK,EAAM,EAAI,IAGxC,GAAO,GAAO,EAAS,GAFZ,KAAK,IAAI,EAAI,EAAK,IAEK,EAClC,EAAO,GAAK,EAGd,OAAO"}
|
package/dist/index8.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index8.js","names":[],"sources":["../src/core/chart-state.ts"],"sourcesContent":["import type { DeepPartial } from './types';\nimport type { ChartOptions, IndicatorType } from '../api/options';\nimport type { SeriesType } from './types';\nimport type { Periodicity } from './periodicity';\nimport type { MarketSession } from './market-session';\nimport type { SerializedDrawing } from '../drawings/base';\n\nexport const CHART_STATE_VERSION = 1;\n\nexport interface ChartState {\n version: number;\n options: DeepPartial<ChartOptions>;\n periodicity?: Periodicity;\n comparisonMode?: boolean;\n timeScale: { barSpacing: number; rightOffset: number };\n series: Array<{ id: string; type: SeriesType; options: Record<string, unknown> }>;\n indicators: Array<{ type: IndicatorType; sourceSeriesId: string; params: Record<string, number>; color?: string }>;\n panes: Array<{ id: string; height: number }>;\n drawings: SerializedDrawing[];\n marketSessions?: MarketSession[];\n sessionFilter?: string;\n visibleRange?: { from: number; to: number };\n}\n\nexport function validateChartState(state: unknown): state is ChartState {\n if (!state || typeof state !== 'object') return false;\n const s = state as Record<string, unknown>;\n if (s.version !== CHART_STATE_VERSION) return false;\n if (!Array.isArray(s.series)) return false;\n if (!s.timeScale || typeof s.timeScale !== 'object') return false;\n return true;\n}\n"],"mappings":"AAOA,IAAa,EAAsB,EAiBnC,SAAgB,EAAmB,GACjC,IAAK,GAA0B,iBAAV,EAAoB,OAAO,EAChD,MAAM,EAAI,EACV,OAAM,IAAF,EAAE,YACD,MAAM,QAAQ,EAAE,YAChB,EAAE,WAAoC,iBAAhB,EAAE"}
|
package/dist/index80.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function t(t,n,o,s,r){const e=new Float64Array(s),l=new Float64Array(s),h=new Float64Array(s);for(let a=0;a<r;a++)l[a]=NaN,h[a]=NaN;for(let a=0;a<2*r;a++)e[a]=NaN;if(s<=r)return{adx:e,plusDI:l,minusDI:h};let u=0,c=0,f=0;for(let a=1;a<=r;a++){const s=t[a]-t[a-1],r=n[a-1]-n[a],e=s>r&&s>0?s:0,l=r>s&&r>0?r:0,h=t[a]-n[a],M=Math.abs(t[a]-o[a-1]),i=Math.abs(n[a]-o[a-1]);u+=Math.max(h,M,i),c+=e,f+=l}const M=(t,a)=>0===a?0:t/a*100;l[r]=M(c,u),h[r]=M(f,u);const i=[],N=a(l[r],h[r]);i.push(N);for(let b=r+1;b<s;b++){const s=t[b]-t[b-1],N=n[b-1]-n[b],p=s>N&&s>0?s:0,x=N>s&&N>0?N:0,m=t[b]-n[b],D=Math.abs(t[b]-o[b-1]),I=Math.abs(n[b]-o[b-1]);u=u-u/r+Math.max(m,D,I),c=c-c/r+p,f=f-f/r+x,l[b]=M(c,u),h[b]=M(f,u);const w=a(l[b],h[b]);if(i.push(w),i.length===r){let t=0;for(const a of i)t+=a;e[b]=t/r}else i.length>r&&(e[b]=(e[b-1]*(r-1)+w)/r)}return{adx:e,plusDI:l,minusDI:h}}function a(t,a){const n=t+a;return 0===n?0:Math.abs(t-a)/n*100}export{t as computeADX};
|
|
2
|
+
//# sourceMappingURL=index80.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index80.js","names":[],"sources":["../src/indicators/adx.ts"],"sourcesContent":["export interface ADXResult {\n adx: Float64Array;\n plusDI: Float64Array;\n minusDI: Float64Array;\n}\n\nexport function computeADX(\n high: Float64Array,\n low: Float64Array,\n close: Float64Array,\n length: number,\n period: number\n): ADXResult {\n const adx = new Float64Array(length);\n const plusDI = new Float64Array(length);\n const minusDI = new Float64Array(length);\n\n // +DI / -DI NaN for [0, period-1]\n for (let i = 0; i < period; i++) {\n plusDI[i] = NaN;\n minusDI[i] = NaN;\n }\n\n // ADX NaN for [0, 2*period-1]\n for (let i = 0; i < 2 * period; i++) {\n adx[i] = NaN;\n }\n\n if (length <= period) {\n return { adx, plusDI, minusDI };\n }\n\n // Compute initial Wilder sums from indices 1..period\n let smoothedTR = 0;\n let smoothedPlusDM = 0;\n let smoothedMinusDM = 0;\n\n for (let i = 1; i <= period; i++) {\n const upMove = high[i] - high[i - 1];\n const downMove = low[i - 1] - low[i];\n\n const plusDM = upMove > downMove && upMove > 0 ? upMove : 0;\n const minusDM = downMove > upMove && downMove > 0 ? downMove : 0;\n\n const hl = high[i] - low[i];\n const hpc = Math.abs(high[i] - close[i - 1]);\n const lpc = Math.abs(low[i] - close[i - 1]);\n const tr = Math.max(hl, hpc, lpc);\n\n smoothedTR += tr;\n smoothedPlusDM += plusDM;\n smoothedMinusDM += minusDM;\n }\n\n // First +DI/-DI at index period\n const computeDI = (smoothedDM: number, smoothedTRVal: number): number =>\n smoothedTRVal === 0 ? 0 : (smoothedDM / smoothedTRVal) * 100;\n\n plusDI[period] = computeDI(smoothedPlusDM, smoothedTR);\n minusDI[period] = computeDI(smoothedMinusDM, smoothedTR);\n\n // Collect DX values to seed ADX\n const dxValues: number[] = [];\n const dx0 = computeDX(plusDI[period], minusDI[period]);\n dxValues.push(dx0);\n\n // Wilder smoothing for subsequent bars\n for (let i = period + 1; i < length; i++) {\n const upMove = high[i] - high[i - 1];\n const downMove = low[i - 1] - low[i];\n\n const plusDMi = upMove > downMove && upMove > 0 ? upMove : 0;\n const minusDMi = downMove > upMove && downMove > 0 ? downMove : 0;\n\n const hl = high[i] - low[i];\n const hpc = Math.abs(high[i] - close[i - 1]);\n const lpc = Math.abs(low[i] - close[i - 1]);\n const tr = Math.max(hl, hpc, lpc);\n\n smoothedTR = smoothedTR - smoothedTR / period + tr;\n smoothedPlusDM = smoothedPlusDM - smoothedPlusDM / period + plusDMi;\n smoothedMinusDM = smoothedMinusDM - smoothedMinusDM / period + minusDMi;\n\n plusDI[i] = computeDI(smoothedPlusDM, smoothedTR);\n minusDI[i] = computeDI(smoothedMinusDM, smoothedTR);\n\n const dxi = computeDX(plusDI[i], minusDI[i]);\n dxValues.push(dxi);\n\n // Once we have `period` DX values, compute first ADX\n if (dxValues.length === period) {\n let sumDX = 0;\n for (const v of dxValues) sumDX += v;\n adx[i] = sumDX / period;\n } else if (dxValues.length > period) {\n // Wilder smoothing of ADX\n adx[i] = (adx[i - 1] * (period - 1) + dxi) / period;\n }\n }\n\n return { adx, plusDI, minusDI };\n}\n\nfunction computeDX(pdi: number, mdi: number): number {\n const sum = pdi + mdi;\n if (sum === 0) return 0;\n return (Math.abs(pdi - mdi) / sum) * 100;\n}\n"],"mappings":"AAMA,SAAgB,EACd,EACA,EACA,EACA,EACA,GAEA,MAAM,EAAM,IAAI,aAAa,GACvB,EAAS,IAAI,aAAa,GAC1B,EAAU,IAAI,aAAa,GAGjC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,IAC1B,EAAO,GAAK,IACZ,EAAQ,GAAK,IAIf,IAAK,IAAI,EAAI,EAAG,EAAI,EAAI,EAAQ,IAC9B,EAAI,GAAK,IAGX,GAAI,GAAU,EACZ,MAAO,CAAE,MAAK,SAAQ,WAIxB,IAAI,EAAa,EACb,EAAiB,EACjB,EAAkB,EAEtB,IAAK,IAAI,EAAI,EAAG,GAAK,EAAQ,IAAK,CAChC,MAAM,EAAS,EAAK,GAAK,EAAK,EAAI,GAC5B,EAAW,EAAI,EAAI,GAAK,EAAI,GAE5B,EAAS,EAAS,GAAY,EAAS,EAAI,EAAS,EACpD,EAAU,EAAW,GAAU,EAAW,EAAI,EAAW,EAEzD,EAAK,EAAK,GAAK,EAAI,GACnB,EAAM,KAAK,IAAI,EAAK,GAAK,EAAM,EAAI,IACnC,EAAM,KAAK,IAAI,EAAI,GAAK,EAAM,EAAI,IAGxC,GAFW,KAAK,IAAI,EAAI,EAAK,GAG7B,GAAkB,EAClB,GAAmB,EAIrB,MAAM,EAAA,CAAa,EAAoB,IACnB,IAAlB,EAAsB,EAAK,EAAa,EAAiB,IAE3D,EAAO,GAAU,EAAU,EAAgB,GAC3C,EAAQ,GAAU,EAAU,EAAiB,GAG7C,MAAM,EAAqB,GACrB,EAAM,EAAU,EAAO,GAAS,EAAQ,IAC9C,EAAS,KAAK,GAGd,IAAK,IAAI,EAAI,EAAS,EAAG,EAAI,EAAQ,IAAK,CACxC,MAAM,EAAS,EAAK,GAAK,EAAK,EAAI,GAC5B,EAAW,EAAI,EAAI,GAAK,EAAI,GAE5B,EAAU,EAAS,GAAY,EAAS,EAAI,EAAS,EACrD,EAAW,EAAW,GAAU,EAAW,EAAI,EAAW,EAE1D,EAAK,EAAK,GAAK,EAAI,GACnB,EAAM,KAAK,IAAI,EAAK,GAAK,EAAM,EAAI,IACnC,EAAM,KAAK,IAAI,EAAI,GAAK,EAAM,EAAI,IAGxC,EAAa,EAAa,EAAa,EAF5B,KAAK,IAAI,EAAI,EAAK,GAG7B,EAAiB,EAAiB,EAAiB,EAAS,EAC5D,EAAkB,EAAkB,EAAkB,EAAS,EAE/D,EAAO,GAAK,EAAU,EAAgB,GACtC,EAAQ,GAAK,EAAU,EAAiB,GAExC,MAAM,EAAM,EAAU,EAAO,GAAI,EAAQ,IAIzC,GAHA,EAAS,KAAK,GAGV,EAAS,SAAW,EAAQ,CAC9B,IAAI,EAAQ,EACZ,IAAK,MAAM,KAAK,EAAU,GAAS,EACnC,EAAI,GAAK,EAAQ,OACR,EAAS,OAAS,IAE3B,EAAI,IAAM,EAAI,EAAI,IAAM,EAAS,GAAK,GAAO,GAIjD,MAAO,CAAE,MAAK,SAAQ,WAGxB,SAAS,EAAU,EAAa,GAC9B,MAAM,EAAM,EAAM,EAClB,OAAY,IAAR,EAAkB,EACd,KAAK,IAAI,EAAM,GAAO,EAAO"}
|