@363045841yyt/klinechart-core 0.8.11-alpha.0 → 0.8.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/alerts/createAlertController.d.ts +30 -0
- package/dist/alerts/createAlertController.d.ts.map +1 -0
- package/dist/alerts/createAlertController.js +261 -0
- package/dist/alerts/createAlertController.js.map +1 -0
- package/dist/alerts/index.d.ts +5 -0
- package/dist/alerts/index.d.ts.map +1 -0
- package/dist/alerts/index.js +4 -0
- package/dist/alerts/index.js.map +1 -0
- package/dist/alerts/predicates.d.ts +28 -0
- package/dist/alerts/predicates.d.ts.map +1 -0
- package/dist/alerts/predicates.js +211 -0
- package/dist/alerts/predicates.js.map +1 -0
- package/dist/alerts/rollingVolume.d.ts +15 -0
- package/dist/alerts/rollingVolume.d.ts.map +1 -0
- package/dist/alerts/rollingVolume.js +42 -0
- package/dist/alerts/rollingVolume.js.map +1 -0
- package/dist/alerts/ruleSchema.d.ts +42 -0
- package/dist/alerts/ruleSchema.d.ts.map +1 -0
- package/dist/alerts/ruleSchema.js +240 -0
- package/dist/alerts/ruleSchema.js.map +1 -0
- package/dist/alerts/types.d.ts +169 -0
- package/dist/alerts/types.d.ts.map +1 -0
- package/dist/alerts/types.js +24 -0
- package/dist/alerts/types.js.map +1 -0
- package/dist/chartTypes/heikinAshi.d.ts +49 -0
- package/dist/chartTypes/heikinAshi.d.ts.map +1 -0
- package/dist/chartTypes/heikinAshi.js +94 -0
- package/dist/chartTypes/heikinAshi.js.map +1 -0
- package/dist/chartTypes/index.d.ts +6 -0
- package/dist/chartTypes/index.d.ts.map +1 -0
- package/dist/chartTypes/index.js +5 -0
- package/dist/chartTypes/index.js.map +1 -0
- package/dist/chartTypes/pointAndFigure.d.ts +83 -0
- package/dist/chartTypes/pointAndFigure.d.ts.map +1 -0
- package/dist/chartTypes/pointAndFigure.js +159 -0
- package/dist/chartTypes/pointAndFigure.js.map +1 -0
- package/dist/chartTypes/rangeBars.d.ts +61 -0
- package/dist/chartTypes/rangeBars.d.ts.map +1 -0
- package/dist/chartTypes/rangeBars.js +181 -0
- package/dist/chartTypes/rangeBars.js.map +1 -0
- package/dist/chartTypes/renko.d.ts +94 -0
- package/dist/chartTypes/renko.d.ts.map +1 -0
- package/dist/chartTypes/renko.js +207 -0
- package/dist/chartTypes/renko.js.map +1 -0
- package/dist/chartTypes/types.d.ts +97 -0
- package/dist/chartTypes/types.d.ts.map +1 -0
- package/dist/chartTypes/types.js +39 -0
- package/dist/chartTypes/types.js.map +1 -0
- package/dist/components/anchoredVwap/computeAnchoredVwap.d.ts +76 -0
- package/dist/components/anchoredVwap/computeAnchoredVwap.d.ts.map +1 -0
- package/dist/components/anchoredVwap/computeAnchoredVwap.js +155 -0
- package/dist/components/anchoredVwap/computeAnchoredVwap.js.map +1 -0
- package/dist/components/anchoredVwap/createAnchoredVwapController.d.ts +28 -0
- package/dist/components/anchoredVwap/createAnchoredVwapController.d.ts.map +1 -0
- package/dist/components/anchoredVwap/createAnchoredVwapController.js +282 -0
- package/dist/components/anchoredVwap/createAnchoredVwapController.js.map +1 -0
- package/dist/components/anchoredVwap/index.d.ts +11 -0
- package/dist/components/anchoredVwap/index.d.ts.map +1 -0
- package/dist/components/anchoredVwap/index.js +10 -0
- package/dist/components/anchoredVwap/index.js.map +1 -0
- package/dist/components/anchoredVwap/types.d.ts +171 -0
- package/dist/components/anchoredVwap/types.d.ts.map +1 -0
- package/dist/components/anchoredVwap/types.js +25 -0
- package/dist/components/anchoredVwap/types.js.map +1 -0
- package/dist/components/crosshairSync/createCrosshairSync.d.ts +94 -0
- package/dist/components/crosshairSync/createCrosshairSync.d.ts.map +1 -0
- package/dist/components/crosshairSync/createCrosshairSync.js +118 -0
- package/dist/components/crosshairSync/createCrosshairSync.js.map +1 -0
- package/dist/components/crosshairSync/index.d.ts +2 -0
- package/dist/components/crosshairSync/index.d.ts.map +1 -0
- package/dist/components/crosshairSync/index.js +2 -0
- package/dist/components/crosshairSync/index.js.map +1 -0
- package/dist/components/footprint/aggressor.d.ts +89 -0
- package/dist/components/footprint/aggressor.d.ts.map +1 -0
- package/dist/components/footprint/aggressor.js +106 -0
- package/dist/components/footprint/aggressor.js.map +1 -0
- package/dist/components/footprint/createFootprintController.d.ts +29 -0
- package/dist/components/footprint/createFootprintController.d.ts.map +1 -0
- package/dist/components/footprint/createFootprintController.js +264 -0
- package/dist/components/footprint/createFootprintController.js.map +1 -0
- package/dist/components/footprint/index.d.ts +7 -0
- package/dist/components/footprint/index.d.ts.map +1 -0
- package/dist/components/footprint/index.js +4 -0
- package/dist/components/footprint/index.js.map +1 -0
- package/dist/components/footprint/perBarStats.d.ts +63 -0
- package/dist/components/footprint/perBarStats.d.ts.map +1 -0
- package/dist/components/footprint/perBarStats.js +123 -0
- package/dist/components/footprint/perBarStats.js.map +1 -0
- package/dist/components/footprint/types.d.ts +197 -0
- package/dist/components/footprint/types.d.ts.map +1 -0
- package/dist/components/footprint/types.js +23 -0
- package/dist/components/footprint/types.js.map +1 -0
- package/dist/components/mtfOverlay/alignToBaseIndex.d.ts +45 -0
- package/dist/components/mtfOverlay/alignToBaseIndex.d.ts.map +1 -0
- package/dist/components/mtfOverlay/alignToBaseIndex.js +92 -0
- package/dist/components/mtfOverlay/alignToBaseIndex.js.map +1 -0
- package/dist/components/mtfOverlay/createMtfController.d.ts +7 -0
- package/dist/components/mtfOverlay/createMtfController.d.ts.map +1 -0
- package/dist/components/mtfOverlay/createMtfController.js +134 -0
- package/dist/components/mtfOverlay/createMtfController.js.map +1 -0
- package/dist/components/mtfOverlay/index.d.ts +19 -0
- package/dist/components/mtfOverlay/index.d.ts.map +1 -0
- package/dist/components/mtfOverlay/index.js +18 -0
- package/dist/components/mtfOverlay/index.js.map +1 -0
- package/dist/components/mtfOverlay/resampleBars.d.ts +37 -0
- package/dist/components/mtfOverlay/resampleBars.d.ts.map +1 -0
- package/dist/components/mtfOverlay/resampleBars.js +93 -0
- package/dist/components/mtfOverlay/resampleBars.js.map +1 -0
- package/dist/components/mtfOverlay/types.d.ts +132 -0
- package/dist/components/mtfOverlay/types.d.ts.map +1 -0
- package/dist/components/mtfOverlay/types.js +22 -0
- package/dist/components/mtfOverlay/types.js.map +1 -0
- package/dist/components/orderBookHeatmap/createHeatmapController.d.ts +21 -0
- package/dist/components/orderBookHeatmap/createHeatmapController.d.ts.map +1 -0
- package/dist/components/orderBookHeatmap/createHeatmapController.js +234 -0
- package/dist/components/orderBookHeatmap/createHeatmapController.js.map +1 -0
- package/dist/components/orderBookHeatmap/createOrderBookState.d.ts +18 -0
- package/dist/components/orderBookHeatmap/createOrderBookState.d.ts.map +1 -0
- package/dist/components/orderBookHeatmap/createOrderBookState.js +102 -0
- package/dist/components/orderBookHeatmap/createOrderBookState.js.map +1 -0
- package/dist/components/orderBookHeatmap/deltaArchive.d.ts +25 -0
- package/dist/components/orderBookHeatmap/deltaArchive.d.ts.map +1 -0
- package/dist/components/orderBookHeatmap/deltaArchive.js +106 -0
- package/dist/components/orderBookHeatmap/deltaArchive.js.map +1 -0
- package/dist/components/orderBookHeatmap/index.d.ts +13 -0
- package/dist/components/orderBookHeatmap/index.d.ts.map +1 -0
- package/dist/components/orderBookHeatmap/index.js +12 -0
- package/dist/components/orderBookHeatmap/index.js.map +1 -0
- package/dist/components/orderBookHeatmap/logColorScale.d.ts +20 -0
- package/dist/components/orderBookHeatmap/logColorScale.d.ts.map +1 -0
- package/dist/components/orderBookHeatmap/logColorScale.js +71 -0
- package/dist/components/orderBookHeatmap/logColorScale.js.map +1 -0
- package/dist/components/orderBookHeatmap/snapshotRing.d.ts +16 -0
- package/dist/components/orderBookHeatmap/snapshotRing.d.ts.map +1 -0
- package/dist/components/orderBookHeatmap/snapshotRing.js +61 -0
- package/dist/components/orderBookHeatmap/snapshotRing.js.map +1 -0
- package/dist/components/orderBookHeatmap/types.d.ts +128 -0
- package/dist/components/orderBookHeatmap/types.d.ts.map +1 -0
- package/dist/components/orderBookHeatmap/types.js +16 -0
- package/dist/components/orderBookHeatmap/types.js.map +1 -0
- package/dist/components/volumeProfile/binning.d.ts +54 -0
- package/dist/components/volumeProfile/binning.d.ts.map +1 -0
- package/dist/components/volumeProfile/binning.js +123 -0
- package/dist/components/volumeProfile/binning.js.map +1 -0
- package/dist/components/volumeProfile/createVolumeProfileController.d.ts +31 -0
- package/dist/components/volumeProfile/createVolumeProfileController.d.ts.map +1 -0
- package/dist/components/volumeProfile/createVolumeProfileController.js +179 -0
- package/dist/components/volumeProfile/createVolumeProfileController.js.map +1 -0
- package/dist/components/volumeProfile/index.d.ts +6 -0
- package/dist/components/volumeProfile/index.d.ts.map +1 -0
- package/dist/components/volumeProfile/index.js +5 -0
- package/dist/components/volumeProfile/index.js.map +1 -0
- package/dist/components/volumeProfile/poc.d.ts +35 -0
- package/dist/components/volumeProfile/poc.d.ts.map +1 -0
- package/dist/components/volumeProfile/poc.js +51 -0
- package/dist/components/volumeProfile/poc.js.map +1 -0
- package/dist/components/volumeProfile/types.d.ts +138 -0
- package/dist/components/volumeProfile/types.d.ts.map +1 -0
- package/dist/components/volumeProfile/types.js +19 -0
- package/dist/components/volumeProfile/types.js.map +1 -0
- package/dist/components/volumeProfile/valueArea.d.ts +58 -0
- package/dist/components/volumeProfile/valueArea.d.ts.map +1 -0
- package/dist/components/volumeProfile/valueArea.js +172 -0
- package/dist/components/volumeProfile/valueArea.js.map +1 -0
- package/dist/controllers/createChartController.d.ts.map +1 -1
- package/dist/controllers/createChartController.js +22 -11
- package/dist/controllers/createChartController.js.map +1 -1
- package/dist/controllers/types.d.ts +3 -1
- package/dist/controllers/types.d.ts.map +1 -1
- package/dist/data-fetchers/baostock.d.ts.map +1 -1
- package/dist/data-fetchers/baostock.js +2 -1
- package/dist/data-fetchers/baostock.js.map +1 -1
- package/dist/data-fetchers/dataBuffer.effects.d.ts.map +1 -1
- package/dist/data-fetchers/dataBuffer.effects.js +2 -1
- package/dist/data-fetchers/dataBuffer.effects.js.map +1 -1
- package/dist/data-fetchers/fetcherDefinitionRegistry.d.ts.map +1 -1
- package/dist/data-fetchers/fetcherDefinitionRegistry.js +2 -1
- package/dist/data-fetchers/fetcherDefinitionRegistry.js.map +1 -1
- package/dist/data-fetchers/gotdx.js +4 -3
- package/dist/data-fetchers/gotdx.js.map +1 -1
- package/dist/data-fetchers/router.d.ts.map +1 -1
- package/dist/data-fetchers/router.js +4 -3
- package/dist/data-fetchers/router.js.map +1 -1
- package/dist/data-fetchers/tradingview.js +3 -2
- package/dist/data-fetchers/tradingview.js.map +1 -1
- package/dist/engine/chart.d.ts +13 -0
- package/dist/engine/chart.d.ts.map +1 -1
- package/dist/engine/chart.js +109 -0
- package/dist/engine/chart.js.map +1 -1
- package/dist/engine/data/chartDataManager.d.ts +1 -0
- package/dist/engine/data/chartDataManager.d.ts.map +1 -1
- package/dist/engine/data/chartDataManager.js +27 -4
- package/dist/engine/data/chartDataManager.js.map +1 -1
- package/dist/engine/drawing/toolConfig.d.ts.map +1 -1
- package/dist/engine/drawing/toolConfig.js +2 -1
- package/dist/engine/drawing/toolConfig.js.map +1 -1
- package/dist/engine/indicators/chartIndicatorManager.d.ts.map +1 -1
- package/dist/engine/indicators/chartIndicatorManager.js +2 -1
- package/dist/engine/indicators/chartIndicatorManager.js.map +1 -1
- package/dist/engine/indicators/indicatorDefinitionRegistry.d.ts.map +1 -1
- package/dist/engine/indicators/indicatorDefinitionRegistry.js +2 -1
- package/dist/engine/indicators/indicatorDefinitionRegistry.js.map +1 -1
- package/dist/engine/indicators/indicatorMetadata.d.ts.map +1 -1
- package/dist/engine/indicators/indicatorMetadata.js +2 -1
- package/dist/engine/indicators/indicatorMetadata.js.map +1 -1
- package/dist/engine/indicators/indicatorRegistry.d.ts.map +1 -1
- package/dist/engine/indicators/indicatorRegistry.js +6 -5
- package/dist/engine/indicators/indicatorRegistry.js.map +1 -1
- package/dist/engine/indicators/registerBuiltins.d.ts.map +1 -1
- package/dist/engine/indicators/registerBuiltins.js +2 -1
- package/dist/engine/indicators/registerBuiltins.js.map +1 -1
- package/dist/engine/indicators/scheduler.d.ts +6 -0
- package/dist/engine/indicators/scheduler.d.ts.map +1 -1
- package/dist/engine/indicators/scheduler.js +12 -0
- package/dist/engine/indicators/scheduler.js.map +1 -1
- package/dist/engine/indicators/soa.d.ts.map +1 -1
- package/dist/engine/indicators/soa.js +2 -1
- package/dist/engine/indicators/soa.js.map +1 -1
- package/dist/engine/indicators/stateComposer.d.ts.map +1 -1
- package/dist/engine/indicators/stateComposer.js +2 -1
- package/dist/engine/indicators/stateComposer.js.map +1 -1
- package/dist/engine/subPaneManager.d.ts.map +1 -1
- package/dist/engine/subPaneManager.js +2 -1
- package/dist/engine/subPaneManager.js.map +1 -1
- package/dist/engine/utils/chartZoomController.d.ts +2 -0
- package/dist/engine/utils/chartZoomController.d.ts.map +1 -1
- package/dist/engine/utils/chartZoomController.js +5 -1
- package/dist/engine/utils/chartZoomController.js.map +1 -1
- package/dist/errors-help.d.ts +72 -0
- package/dist/errors-help.d.ts.map +1 -0
- package/dist/errors-help.js +149 -0
- package/dist/errors-help.js.map +1 -0
- package/dist/errors.d.ts +64 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +61 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -1
- package/dist/indicators/alma.d.ts +27 -0
- package/dist/indicators/alma.d.ts.map +1 -0
- package/dist/indicators/alma.js +36 -0
- package/dist/indicators/alma.js.map +1 -0
- package/dist/indicators/awesomeOscillator.d.ts +19 -0
- package/dist/indicators/awesomeOscillator.d.ts.map +1 -0
- package/dist/indicators/awesomeOscillator.js +36 -0
- package/dist/indicators/awesomeOscillator.js.map +1 -0
- package/dist/indicators/dpo.d.ts +17 -0
- package/dist/indicators/dpo.d.ts.map +1 -0
- package/dist/indicators/dpo.js +24 -0
- package/dist/indicators/dpo.js.map +1 -0
- package/dist/indicators/fisherTransform.d.ts +26 -0
- package/dist/indicators/fisherTransform.d.ts.map +1 -0
- package/dist/indicators/fisherTransform.js +44 -0
- package/dist/indicators/fisherTransform.js.map +1 -0
- package/dist/indicators/frama.d.ts +25 -0
- package/dist/indicators/frama.d.ts.map +1 -0
- package/dist/indicators/frama.js +61 -0
- package/dist/indicators/frama.js.map +1 -0
- package/dist/indicators/index.d.ts +24 -0
- package/dist/indicators/index.d.ts.map +1 -0
- package/dist/indicators/index.js +26 -0
- package/dist/indicators/index.js.map +1 -0
- package/dist/indicators/lsma.d.ts +21 -0
- package/dist/indicators/lsma.d.ts.map +1 -0
- package/dist/indicators/lsma.js +37 -0
- package/dist/indicators/lsma.js.map +1 -0
- package/dist/indicators/schaffTrendCycle.d.ts +24 -0
- package/dist/indicators/schaffTrendCycle.d.ts.map +1 -0
- package/dist/indicators/schaffTrendCycle.js +70 -0
- package/dist/indicators/schaffTrendCycle.js.map +1 -0
- package/dist/indicators/stochRSI.d.ts +24 -0
- package/dist/indicators/stochRSI.d.ts.map +1 -0
- package/dist/indicators/stochRSI.js +86 -0
- package/dist/indicators/stochRSI.js.map +1 -0
- package/dist/indicators/t3.d.ts +31 -0
- package/dist/indicators/t3.d.ts.map +1 -0
- package/dist/indicators/t3.js +63 -0
- package/dist/indicators/t3.js.map +1 -0
- package/dist/indicators/ultimateOscillator.d.ts +26 -0
- package/dist/indicators/ultimateOscillator.d.ts.map +1 -0
- package/dist/indicators/ultimateOscillator.js +59 -0
- package/dist/indicators/ultimateOscillator.js.map +1 -0
- package/dist/indicators/vidya.d.ts +24 -0
- package/dist/indicators/vidya.d.ts.map +1 -0
- package/dist/indicators/vidya.js +54 -0
- package/dist/indicators/vidya.js.map +1 -0
- package/dist/indicators/zlema.d.ts +16 -0
- package/dist/indicators/zlema.d.ts.map +1 -0
- package/dist/indicators/zlema.js +26 -0
- package/dist/indicators/zlema.js.map +1 -0
- package/dist/input/gesture.d.ts +125 -0
- package/dist/input/gesture.d.ts.map +1 -0
- package/dist/input/gesture.js +249 -0
- package/dist/input/gesture.js.map +1 -0
- package/dist/input/index.d.ts +9 -0
- package/dist/input/index.d.ts.map +1 -0
- package/dist/input/index.js +9 -0
- package/dist/input/index.js.map +1 -0
- package/dist/input/keyboard.d.ts +140 -0
- package/dist/input/keyboard.d.ts.map +1 -0
- package/dist/input/keyboard.js +260 -0
- package/dist/input/keyboard.js.map +1 -0
- package/dist/mcp/chartBridge.d.ts +2 -2
- package/dist/mcp/chartBridge.d.ts.map +1 -1
- package/dist/mcp/chartBridge.js +27 -21
- package/dist/mcp/chartBridge.js.map +1 -1
- package/dist/plugin/PluginHost.d.ts +0 -3
- package/dist/plugin/PluginHost.d.ts.map +1 -1
- package/dist/plugin/PluginHost.js +7 -3
- package/dist/plugin/PluginHost.js.map +1 -1
- package/dist/plugin/PluginRegistry.d.ts +0 -3
- package/dist/plugin/PluginRegistry.d.ts.map +1 -1
- package/dist/plugin/PluginRegistry.js +5 -1
- package/dist/plugin/PluginRegistry.js.map +1 -1
- package/dist/render/Renderer.d.ts +116 -0
- package/dist/render/Renderer.d.ts.map +1 -0
- package/dist/render/Renderer.js +31 -0
- package/dist/render/Renderer.js.map +1 -0
- package/dist/render/SurfaceBackend.d.ts +83 -0
- package/dist/render/SurfaceBackend.d.ts.map +1 -0
- package/dist/render/SurfaceBackend.js +27 -0
- package/dist/render/SurfaceBackend.js.map +1 -0
- package/dist/render/index.d.ts +12 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +11 -0
- package/dist/render/index.js.map +1 -0
- package/dist/renderer-tier/detectRendererTier.d.ts +57 -0
- package/dist/renderer-tier/detectRendererTier.d.ts.map +1 -0
- package/dist/renderer-tier/detectRendererTier.js +143 -0
- package/dist/renderer-tier/detectRendererTier.js.map +1 -0
- package/dist/renderer-tier/index.d.ts +12 -0
- package/dist/renderer-tier/index.d.ts.map +1 -0
- package/dist/renderer-tier/index.js +12 -0
- package/dist/renderer-tier/index.js.map +1 -0
- package/dist/renderer-tier/selectBackend.d.ts +106 -0
- package/dist/renderer-tier/selectBackend.d.ts.map +1 -0
- package/dist/renderer-tier/selectBackend.js +113 -0
- package/dist/renderer-tier/selectBackend.js.map +1 -0
- package/dist/renderer-tier/types.d.ts +50 -0
- package/dist/renderer-tier/types.d.ts.map +1 -0
- package/dist/renderer-tier/types.js +24 -0
- package/dist/renderer-tier/types.js.map +1 -0
- package/dist/replay/createReplayController.d.ts +3 -0
- package/dist/replay/createReplayController.d.ts.map +1 -0
- package/dist/replay/createReplayController.js +251 -0
- package/dist/replay/createReplayController.js.map +1 -0
- package/dist/replay/index.d.ts +5 -0
- package/dist/replay/index.d.ts.map +1 -0
- package/dist/replay/index.js +3 -0
- package/dist/replay/index.js.map +1 -0
- package/dist/replay/timeline.d.ts +50 -0
- package/dist/replay/timeline.d.ts.map +1 -0
- package/dist/replay/timeline.js +104 -0
- package/dist/replay/timeline.js.map +1 -0
- package/dist/replay/types.d.ts +94 -0
- package/dist/replay/types.d.ts.map +1 -0
- package/dist/replay/types.js +21 -0
- package/dist/replay/types.js.map +1 -0
- package/dist/scale/anchoredZoom.d.ts +64 -0
- package/dist/scale/anchoredZoom.d.ts.map +1 -0
- package/dist/scale/anchoredZoom.js +67 -0
- package/dist/scale/anchoredZoom.js.map +1 -0
- package/dist/scale/createPriceScale.d.ts +49 -0
- package/dist/scale/createPriceScale.d.ts.map +1 -0
- package/dist/scale/createPriceScale.js +175 -0
- package/dist/scale/createPriceScale.js.map +1 -0
- package/dist/scale/createTimeScale.d.ts +27 -0
- package/dist/scale/createTimeScale.d.ts.map +1 -0
- package/dist/scale/createTimeScale.js +139 -0
- package/dist/scale/createTimeScale.js.map +1 -0
- package/dist/scale/index.d.ts +6 -0
- package/dist/scale/index.d.ts.map +1 -0
- package/dist/scale/index.js +5 -0
- package/dist/scale/index.js.map +1 -0
- package/dist/scale/originShift.d.ts +69 -0
- package/dist/scale/originShift.d.ts.map +1 -0
- package/dist/scale/originShift.js +41 -0
- package/dist/scale/originShift.js.map +1 -0
- package/dist/scale/types.d.ts +90 -0
- package/dist/scale/types.d.ts.map +1 -0
- package/dist/scale/types.js +17 -0
- package/dist/scale/types.js.map +1 -0
- package/dist/scene/createScene.d.ts +22 -0
- package/dist/scene/createScene.d.ts.map +1 -0
- package/dist/scene/createScene.js +114 -0
- package/dist/scene/createScene.js.map +1 -0
- package/dist/scene/index.d.ts +13 -0
- package/dist/scene/index.d.ts.map +1 -0
- package/dist/scene/index.js +11 -0
- package/dist/scene/index.js.map +1 -0
- package/dist/scene/layerRegistry.d.ts +83 -0
- package/dist/scene/layerRegistry.d.ts.map +1 -0
- package/dist/scene/layerRegistry.js +43 -0
- package/dist/scene/layerRegistry.js.map +1 -0
- package/dist/scene/types.d.ts +128 -0
- package/dist/scene/types.d.ts.map +1 -0
- package/dist/scene/types.js +21 -0
- package/dist/scene/types.js.map +1 -0
- package/dist/scheduler/createFrameBudget.d.ts +91 -0
- package/dist/scheduler/createFrameBudget.d.ts.map +1 -0
- package/dist/scheduler/createFrameBudget.js +232 -0
- package/dist/scheduler/createFrameBudget.js.map +1 -0
- package/dist/scheduler/index.d.ts +2 -0
- package/dist/scheduler/index.d.ts.map +1 -0
- package/dist/scheduler/index.js +2 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/tokens/themeToCssVars.d.ts.map +1 -1
- package/dist/tokens/themeToCssVars.js +2 -28
- package/dist/tokens/themeToCssVars.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
- package/src/__bench__/indicators.bench.ts +215 -0
- package/src/__bench__/orderBookHeatmap.bench.ts +68 -0
- package/src/__bench__/scale.bench.ts +80 -0
- package/src/__bench__/signal.bench.ts +41 -0
- package/src/__bench__/volumeProfile.bench.ts +66 -0
- package/src/__tests__/errors-help.test.ts +184 -0
- package/src/__tests__/errors.test.ts +187 -0
- package/src/alerts/__tests__/controller.test.ts +231 -0
- package/src/alerts/__tests__/predicates.test.ts +374 -0
- package/src/alerts/__tests__/ruleSchema.test.ts +180 -0
- package/src/alerts/createAlertController.ts +312 -0
- package/src/alerts/index.ts +18 -0
- package/src/alerts/predicates.ts +231 -0
- package/src/alerts/rollingVolume.ts +51 -0
- package/src/alerts/ruleSchema.ts +278 -0
- package/src/alerts/types.ts +177 -0
- package/src/chartTypes/__tests__/heikinAshi.test.ts +122 -0
- package/src/chartTypes/__tests__/pointAndFigure.test.ts +167 -0
- package/src/chartTypes/__tests__/rangeBars.test.ts +146 -0
- package/src/chartTypes/__tests__/renko.test.ts +160 -0
- package/src/chartTypes/heikinAshi.ts +116 -0
- package/src/chartTypes/index.ts +5 -0
- package/src/chartTypes/pointAndFigure.ts +278 -0
- package/src/chartTypes/rangeBars.ts +303 -0
- package/src/chartTypes/renko.ts +311 -0
- package/src/chartTypes/types.ts +99 -0
- package/src/components/anchoredVwap/__tests__/computeAnchoredVwap.test.ts +331 -0
- package/src/components/anchoredVwap/__tests__/controller.test.ts +430 -0
- package/src/components/anchoredVwap/computeAnchoredVwap.ts +174 -0
- package/src/components/anchoredVwap/createAnchoredVwapController.ts +358 -0
- package/src/components/anchoredVwap/index.ts +17 -0
- package/src/components/anchoredVwap/types.ts +187 -0
- package/src/components/crosshairSync/__tests__/crosshairSync.test.ts +261 -0
- package/src/components/crosshairSync/createCrosshairSync.ts +187 -0
- package/src/components/crosshairSync/index.ts +5 -0
- package/src/components/footprint/__tests__/aggressor.test.ts +127 -0
- package/src/components/footprint/__tests__/controller.test.ts +130 -0
- package/src/components/footprint/__tests__/perBarStats.test.ts +114 -0
- package/src/components/footprint/aggressor.ts +165 -0
- package/src/components/footprint/createFootprintController.ts +338 -0
- package/src/components/footprint/index.ts +21 -0
- package/src/components/footprint/perBarStats.ts +137 -0
- package/src/components/footprint/types.ts +232 -0
- package/src/components/mtfOverlay/__tests__/alignToBaseIndex.test.ts +103 -0
- package/src/components/mtfOverlay/__tests__/controller.test.ts +172 -0
- package/src/components/mtfOverlay/__tests__/resampleBars.test.ts +106 -0
- package/src/components/mtfOverlay/alignToBaseIndex.ts +108 -0
- package/src/components/mtfOverlay/createMtfController.ts +180 -0
- package/src/components/mtfOverlay/index.ts +26 -0
- package/src/components/mtfOverlay/resampleBars.ts +134 -0
- package/src/components/mtfOverlay/types.ts +148 -0
- package/src/components/orderBookHeatmap/__tests__/controller.test.ts +237 -0
- package/src/components/orderBookHeatmap/__tests__/deltaArchive.test.ts +88 -0
- package/src/components/orderBookHeatmap/__tests__/logColorScale.test.ts +69 -0
- package/src/components/orderBookHeatmap/__tests__/orderBookState.test.ts +113 -0
- package/src/components/orderBookHeatmap/__tests__/snapshotRing.test.ts +53 -0
- package/src/components/orderBookHeatmap/computeShader.wgsl.md +130 -0
- package/src/components/orderBookHeatmap/createHeatmapController.ts +273 -0
- package/src/components/orderBookHeatmap/createOrderBookState.ts +116 -0
- package/src/components/orderBookHeatmap/deltaArchive.ts +113 -0
- package/src/components/orderBookHeatmap/index.ts +25 -0
- package/src/components/orderBookHeatmap/logColorScale.ts +77 -0
- package/src/components/orderBookHeatmap/snapshotRing.ts +65 -0
- package/src/components/orderBookHeatmap/types.ts +168 -0
- package/src/components/volumeProfile/__tests__/binning.test.ts +133 -0
- package/src/components/volumeProfile/__tests__/poc.test.ts +44 -0
- package/src/components/volumeProfile/__tests__/valueArea.test.ts +177 -0
- package/src/components/volumeProfile/binning.ts +133 -0
- package/src/components/volumeProfile/createVolumeProfileController.ts +213 -0
- package/src/components/volumeProfile/index.ts +12 -0
- package/src/components/volumeProfile/poc.ts +53 -0
- package/src/components/volumeProfile/types.ts +148 -0
- package/src/components/volumeProfile/valueArea.ts +187 -0
- package/src/controllers/createChartController.ts +23 -10
- package/src/controllers/types.ts +5 -1
- package/src/data-fetchers/baostock.ts +2 -1
- package/src/data-fetchers/dataBuffer.effects.ts +3 -1
- package/src/data-fetchers/fetcherDefinitionRegistry.ts +2 -1
- package/src/data-fetchers/gotdx.ts +4 -3
- package/src/data-fetchers/router.ts +6 -3
- package/src/data-fetchers/tradingview.ts +3 -2
- package/src/engine/chart.ts +126 -3
- package/src/engine/data/chartDataManager.ts +26 -4
- package/src/engine/drawing/toolConfig.ts +2 -1
- package/src/engine/indicators/chartIndicatorManager.ts +2 -1
- package/src/engine/indicators/indicatorDefinitionRegistry.ts +2 -1
- package/src/engine/indicators/indicatorMetadata.ts +2 -1
- package/src/engine/indicators/indicatorRegistry.ts +6 -5
- package/src/engine/indicators/registerBuiltins.ts +2 -1
- package/src/engine/indicators/scheduler.ts +15 -0
- package/src/engine/indicators/soa.ts +2 -1
- package/src/engine/indicators/stateComposer.ts +2 -1
- package/src/engine/subPaneManager.ts +2 -1
- package/src/engine/utils/chartZoomController.ts +7 -1
- package/src/errors-help.ts +218 -0
- package/src/errors.ts +128 -0
- package/src/index.ts +37 -0
- package/src/indicators/__tests__/maFamily.test.ts +159 -0
- package/src/indicators/__tests__/oscillators.test.ts +150 -0
- package/src/indicators/alma.ts +61 -0
- package/src/indicators/awesomeOscillator.ts +54 -0
- package/src/indicators/dpo.ts +37 -0
- package/src/indicators/fisherTransform.ts +63 -0
- package/src/indicators/frama.ts +87 -0
- package/src/indicators/index.ts +39 -0
- package/src/indicators/lsma.ts +58 -0
- package/src/indicators/schaffTrendCycle.ts +92 -0
- package/src/indicators/stochRSI.ts +108 -0
- package/src/indicators/t3.ts +96 -0
- package/src/indicators/ultimateOscillator.ts +83 -0
- package/src/indicators/vidya.ts +80 -0
- package/src/indicators/zlema.ts +41 -0
- package/src/input/__tests__/gesture.test.ts +271 -0
- package/src/input/__tests__/keyboard.test.ts +317 -0
- package/src/input/gesture.ts +357 -0
- package/src/input/index.ts +26 -0
- package/src/input/keyboard.ts +373 -0
- package/src/mcp/chartBridge.ts +98 -72
- package/src/plugin/PluginHost.ts +4 -3
- package/src/plugin/PluginRegistry.ts +2 -1
- package/src/render/Renderer.ts +127 -0
- package/src/render/SurfaceBackend.ts +94 -0
- package/src/render/__tests__/contract.test.ts +176 -0
- package/src/render/index.ts +27 -0
- package/src/renderer-tier/__tests__/detectRendererTier.test.ts +180 -0
- package/src/renderer-tier/__tests__/selectBackend.test.ts +253 -0
- package/src/renderer-tier/detectRendererTier.ts +168 -0
- package/src/renderer-tier/index.ts +30 -0
- package/src/renderer-tier/selectBackend.ts +201 -0
- package/src/renderer-tier/types.ts +59 -0
- package/src/replay/__tests__/controller.test.ts +309 -0
- package/src/replay/__tests__/timeline.test.ts +99 -0
- package/src/replay/createReplayController.ts +302 -0
- package/src/replay/index.ts +15 -0
- package/src/replay/timeline.ts +106 -0
- package/src/replay/types.ts +107 -0
- package/src/scale/__tests__/anchoredZoom.test.ts +125 -0
- package/src/scale/__tests__/originShift.test.ts +97 -0
- package/src/scale/__tests__/priceScale.test.ts +219 -0
- package/src/scale/__tests__/timeScale.test.ts +119 -0
- package/src/scale/anchoredZoom.ts +104 -0
- package/src/scale/createPriceScale.ts +226 -0
- package/src/scale/createTimeScale.ts +150 -0
- package/src/scale/index.ts +9 -0
- package/src/scale/originShift.ts +111 -0
- package/src/scale/types.ts +100 -0
- package/src/scene/__tests__/layerRegistry.test.ts +207 -0
- package/src/scene/__tests__/scene.test.ts +411 -0
- package/src/scene/createScene.ts +117 -0
- package/src/scene/index.ts +29 -0
- package/src/scene/layerRegistry.ts +117 -0
- package/src/scene/types.ts +143 -0
- package/src/scheduler/__tests__/createFrameBudget.test.ts +315 -0
- package/src/scheduler/createFrameBudget.ts +316 -0
- package/src/scheduler/index.ts +7 -0
- package/src/tokens/themeToCssVars.ts +3 -1
- package/src/version.ts +1 -1
- package/dist/data-fetchers/gotdx/gotdx.d.ts +0 -7
- package/dist/data-fetchers/gotdx/gotdx.d.ts.map +0 -1
- package/dist/data-fetchers/gotdx/gotdx.js +0 -7
- package/dist/data-fetchers/gotdx/gotdx.js.map +0 -1
- package/src/data-fetchers/gotdx/gotdx.ts +0 -6
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Volume Profile controller — framework-agnostic, signal-based.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the dispose-guard pattern from `createIndicatorSelectorController`
|
|
5
|
+
* so React/Vue/Angular adapters bridge identically. The controller is pure
|
|
6
|
+
* data — no DOM, no rendering, no canvas. It plays the same role as
|
|
7
|
+
* `src/core/indicators/volumeProfileState.ts` (the maintainer's legacy state
|
|
8
|
+
* module) but with the new reactive contract; the legacy state file and the
|
|
9
|
+
* legacy renderer at `src/core/renderers/Indicator/volumeProfile.ts` are
|
|
10
|
+
* intentionally NOT touched (per branch policy).
|
|
11
|
+
*
|
|
12
|
+
* Flow on `ingest`:
|
|
13
|
+
* 1. Walk the bars once to learn `[minLow, maxHigh]`.
|
|
14
|
+
* 2. Derive `binMin`/`binSize` from that range + config.binCount.
|
|
15
|
+
* 3. Allocate a fresh `Float64Array(binCount)` (or reuse if size unchanged).
|
|
16
|
+
* 4. For each bar, call `binBarToBuckets` (typical-price or proportional).
|
|
17
|
+
* 5. `findPOCIndex` → `computeValueArea` → assemble `VolumeProfileState`.
|
|
18
|
+
*
|
|
19
|
+
* Non-goals:
|
|
20
|
+
* - Incremental ingest. `ingest` always recomputes from scratch. The
|
|
21
|
+
* incremental path comes with the WebGPU compute shader (see
|
|
22
|
+
* `computeShader.wgsl.md`).
|
|
23
|
+
* - Auto-binning by tick size. The current heuristic (range / binCount) is
|
|
24
|
+
* adequate for visual profiles; tick-snapped binning is a future option.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { createSignal, type Signal } from '../../reactivity'
|
|
28
|
+
import { binBarToBuckets } from './binning'
|
|
29
|
+
import { findPOCIndex } from './poc'
|
|
30
|
+
import { computeValueArea } from './valueArea'
|
|
31
|
+
import type {
|
|
32
|
+
VolumeProfileBar,
|
|
33
|
+
VolumeProfileConfig,
|
|
34
|
+
VolumeProfileController,
|
|
35
|
+
VolumeProfileState,
|
|
36
|
+
} from './types'
|
|
37
|
+
|
|
38
|
+
const DEFAULT_CONFIG: VolumeProfileConfig = {
|
|
39
|
+
binCount: 100,
|
|
40
|
+
binningMode: 'typical-price',
|
|
41
|
+
valueAreaPercent: 0.7,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Smallest binSize we will use. Prevents a degenerate "all bars same price"
|
|
45
|
+
// input from producing a division-by-zero. The value is arbitrary but small
|
|
46
|
+
// enough that real markets never hit it.
|
|
47
|
+
const MIN_BIN_SIZE = 1e-12
|
|
48
|
+
|
|
49
|
+
export interface VolumeProfileControllerInit {
|
|
50
|
+
config?: Partial<VolumeProfileConfig>
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function createVolumeProfileController(
|
|
54
|
+
init?: VolumeProfileControllerInit,
|
|
55
|
+
): VolumeProfileController {
|
|
56
|
+
// -------------------------------------------------------------------
|
|
57
|
+
// Signals
|
|
58
|
+
// -------------------------------------------------------------------
|
|
59
|
+
const initialConfig: VolumeProfileConfig = {
|
|
60
|
+
...DEFAULT_CONFIG,
|
|
61
|
+
...(init?.config ?? {}),
|
|
62
|
+
}
|
|
63
|
+
// Defensive clamp: percent in [0, 1], binCount >= 1.
|
|
64
|
+
if (initialConfig.valueAreaPercent < 0) initialConfig.valueAreaPercent = 0
|
|
65
|
+
if (initialConfig.valueAreaPercent > 1) initialConfig.valueAreaPercent = 1
|
|
66
|
+
if (initialConfig.binCount < 1) initialConfig.binCount = 1
|
|
67
|
+
|
|
68
|
+
const config: Signal<VolumeProfileConfig> = createSignal(initialConfig)
|
|
69
|
+
const state: Signal<VolumeProfileState | null> =
|
|
70
|
+
createSignal<VolumeProfileState | null>(null)
|
|
71
|
+
|
|
72
|
+
// -------------------------------------------------------------------
|
|
73
|
+
// ingest — full recompute
|
|
74
|
+
// -------------------------------------------------------------------
|
|
75
|
+
function ingest(bars: ReadonlyArray<VolumeProfileBar>): void {
|
|
76
|
+
const cfg = config.peek()
|
|
77
|
+
|
|
78
|
+
if (bars.length === 0) {
|
|
79
|
+
state.set(null)
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// First pass: range of the data.
|
|
84
|
+
let minLow = Infinity
|
|
85
|
+
let maxHigh = -Infinity
|
|
86
|
+
for (let i = 0; i < bars.length; i++) {
|
|
87
|
+
const b = bars[i]
|
|
88
|
+
if (b === undefined) continue
|
|
89
|
+
if (b.low < minLow) minLow = b.low
|
|
90
|
+
if (b.high > maxHigh) maxHigh = b.high
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!Number.isFinite(minLow) || !Number.isFinite(maxHigh)) {
|
|
94
|
+
state.set(null)
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const range = maxHigh - minLow
|
|
99
|
+
// Degenerate range: every bar at the same price. We still want a
|
|
100
|
+
// non-zero binSize so the math works; centre a tiny window on the
|
|
101
|
+
// price so the single bucket captures everything.
|
|
102
|
+
const binSize =
|
|
103
|
+
range > MIN_BIN_SIZE ? range / cfg.binCount : MIN_BIN_SIZE
|
|
104
|
+
const binMin = minLow
|
|
105
|
+
|
|
106
|
+
// Allocate or reuse the buckets. Reuse only if the size matches —
|
|
107
|
+
// changing `binCount` via `setConfig` requires a fresh array.
|
|
108
|
+
const prev = state.peek()
|
|
109
|
+
const buckets =
|
|
110
|
+
prev !== null && prev.buckets.length === cfg.binCount
|
|
111
|
+
? prev.buckets
|
|
112
|
+
: new Float64Array(cfg.binCount)
|
|
113
|
+
// Zero it (whether reused or freshly allocated) — `fill(0)` is cheap
|
|
114
|
+
// on typed arrays.
|
|
115
|
+
buckets.fill(0)
|
|
116
|
+
|
|
117
|
+
// Second pass: drop volume into buckets.
|
|
118
|
+
for (let i = 0; i < bars.length; i++) {
|
|
119
|
+
const b = bars[i]
|
|
120
|
+
if (b === undefined) continue
|
|
121
|
+
binBarToBuckets(
|
|
122
|
+
b,
|
|
123
|
+
buckets,
|
|
124
|
+
binMin,
|
|
125
|
+
binSize,
|
|
126
|
+
cfg.binCount,
|
|
127
|
+
cfg.binningMode,
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// POC + VA.
|
|
132
|
+
const pocIdx = findPOCIndex(buckets)
|
|
133
|
+
// findPOCIndex returns -1 only on empty arrays — guarded above.
|
|
134
|
+
const va = computeValueArea(
|
|
135
|
+
buckets,
|
|
136
|
+
pocIdx < 0 ? 0 : pocIdx,
|
|
137
|
+
cfg.valueAreaPercent,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
// Prices: each bucket spans `[binMin + i*binSize, binMin + (i+1)*binSize)`.
|
|
141
|
+
// We report POC as the bucket *center*, VAH as the upper bucket's high
|
|
142
|
+
// edge, VAL as the lower bucket's low edge — this matches how a
|
|
143
|
+
// renderer wants to draw them: POC as a centerline, VAH/VAL as
|
|
144
|
+
// envelope edges.
|
|
145
|
+
const pocPrice = binMin + (va.pocIndex + 0.5) * binSize
|
|
146
|
+
const vahPrice = binMin + (va.vahIndex + 1) * binSize
|
|
147
|
+
const valPrice = binMin + va.valIndex * binSize
|
|
148
|
+
|
|
149
|
+
const next: VolumeProfileState = {
|
|
150
|
+
buckets,
|
|
151
|
+
binMin,
|
|
152
|
+
binSize,
|
|
153
|
+
poc: pocPrice,
|
|
154
|
+
vah: vahPrice,
|
|
155
|
+
val: valPrice,
|
|
156
|
+
totalVolume: va.totalVolume,
|
|
157
|
+
vaVolume: va.vaVolume,
|
|
158
|
+
}
|
|
159
|
+
state.set(next)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// -------------------------------------------------------------------
|
|
163
|
+
// setConfig — patch + invalidate
|
|
164
|
+
// -------------------------------------------------------------------
|
|
165
|
+
function setConfig(next: Partial<VolumeProfileConfig>): void {
|
|
166
|
+
const cur = config.peek()
|
|
167
|
+
const merged: VolumeProfileConfig = { ...cur, ...next }
|
|
168
|
+
// Re-apply the defensive clamps.
|
|
169
|
+
if (merged.valueAreaPercent < 0) merged.valueAreaPercent = 0
|
|
170
|
+
if (merged.valueAreaPercent > 1) merged.valueAreaPercent = 1
|
|
171
|
+
if (merged.binCount < 1) merged.binCount = 1
|
|
172
|
+
|
|
173
|
+
// If binCount changed, the existing buckets are stale (different
|
|
174
|
+
// resolution) — clear state so callers know to re-ingest. Other
|
|
175
|
+
// field changes leave the data untouched until next ingest.
|
|
176
|
+
if (merged.binCount !== cur.binCount) {
|
|
177
|
+
state.set(null)
|
|
178
|
+
}
|
|
179
|
+
config.set(merged)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// -------------------------------------------------------------------
|
|
183
|
+
// reset — clear state, keep config
|
|
184
|
+
// -------------------------------------------------------------------
|
|
185
|
+
function reset(): void {
|
|
186
|
+
state.set(null)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// -------------------------------------------------------------------
|
|
190
|
+
// dispose — silence mutators (same pattern as IndicatorSelectorController)
|
|
191
|
+
// -------------------------------------------------------------------
|
|
192
|
+
let disposed = false
|
|
193
|
+
function dispose(): void {
|
|
194
|
+
if (disposed) return
|
|
195
|
+
disposed = true
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function guard<T extends (...args: never[]) => unknown>(fn: T): T {
|
|
199
|
+
return ((...args: Parameters<T>): ReturnType<T> => {
|
|
200
|
+
if (disposed) return undefined as ReturnType<T>
|
|
201
|
+
return fn(...args) as ReturnType<T>
|
|
202
|
+
}) as T
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
config,
|
|
207
|
+
state,
|
|
208
|
+
ingest: guard(ingest),
|
|
209
|
+
setConfig: guard(setConfig),
|
|
210
|
+
reset: guard(reset),
|
|
211
|
+
dispose,
|
|
212
|
+
}
|
|
213
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
BinningMode,
|
|
3
|
+
VolumeProfileConfig,
|
|
4
|
+
VolumeProfileState,
|
|
5
|
+
VolumeProfileBar,
|
|
6
|
+
VolumeProfileController,
|
|
7
|
+
ValueAreaResult,
|
|
8
|
+
} from './types'
|
|
9
|
+
export { binBarToBuckets } from './binning'
|
|
10
|
+
export { findPOCIndex } from './poc'
|
|
11
|
+
export { computeValueArea } from './valueArea'
|
|
12
|
+
export { createVolumeProfileController } from './createVolumeProfileController'
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Point of Control — argmax over the bucket histogram.
|
|
3
|
+
*
|
|
4
|
+
* The POC is the single bucket with the largest total volume. It is the seed
|
|
5
|
+
* for the Value Area expansion (`valueArea.ts`) and the most-referenced level
|
|
6
|
+
* on a volume profile chart.
|
|
7
|
+
*
|
|
8
|
+
* Tie-breaker policy (important — make sure it stays stable):
|
|
9
|
+
* When two or more buckets share the maximum, the **lowest index wins**.
|
|
10
|
+
*
|
|
11
|
+
* Rationale: argmax under ties is otherwise undefined, which leads to
|
|
12
|
+
* non-deterministic state across runs and breaks snapshot tests. Returning
|
|
13
|
+
* the lowest index is also the convention KLineCharts and the maintainer's
|
|
14
|
+
* legacy renderer follow, so the visual placement of the POC line is
|
|
15
|
+
* consistent across our data model and the existing renderer.
|
|
16
|
+
*
|
|
17
|
+
* Edge case: an empty array returns `-1`. Callers (the controller) treat
|
|
18
|
+
* that as "no profile" and emit `state = null`. We pick -1 (not 0) so the
|
|
19
|
+
* empty case is impossible to confuse with "argmax happens to be bucket 0".
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Returns the index of the largest bucket. Ties resolve to the lowest index.
|
|
24
|
+
* Returns -1 if `buckets.length === 0`.
|
|
25
|
+
*
|
|
26
|
+
* Single pass, branch-light, O(n).
|
|
27
|
+
*
|
|
28
|
+
* @internal — building block used by the corresponding controller
|
|
29
|
+
* factory. Reachable today via the top-level `@klinechart-quant/core`
|
|
30
|
+
* barrel but **NOT part of the supported public API**. typedoc / api-
|
|
31
|
+
* extractor hide it from generated docs. Prefer the controller
|
|
32
|
+
* factory (e.g. `createVolumeProfileController`) for stable user code.
|
|
33
|
+
* Closes API audit BLOCKER-002 (export * leakage taxonomy).
|
|
34
|
+
*/
|
|
35
|
+
export function findPOCIndex(buckets: Float64Array): number {
|
|
36
|
+
const n = buckets.length
|
|
37
|
+
if (n === 0) return -1
|
|
38
|
+
|
|
39
|
+
let bestIdx = 0
|
|
40
|
+
let bestVol = buckets[0] ?? 0
|
|
41
|
+
|
|
42
|
+
// Walk buckets[1..]; strictly-greater wins, equal does NOT (keeps the
|
|
43
|
+
// earliest index — the documented tie-breaker).
|
|
44
|
+
for (let i = 1; i < n; i++) {
|
|
45
|
+
const v = buckets[i] ?? 0
|
|
46
|
+
if (v > bestVol) {
|
|
47
|
+
bestVol = v
|
|
48
|
+
bestIdx = i
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return bestIdx
|
|
53
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Volume Profile — public type contract.
|
|
3
|
+
*
|
|
4
|
+
* Volume Profile aggregates traded volume by **price** (not time), producing a
|
|
5
|
+
* horizontal histogram pinned to the price axis. Traders read it for
|
|
6
|
+
* accumulation zones (POC), the 70% Value Area (VAH/VAL — CME convention),
|
|
7
|
+
* and developing support/resistance.
|
|
8
|
+
*
|
|
9
|
+
* This module owns the **data model + math only**. Rendering belongs to the
|
|
10
|
+
* `@klinechart-quant/core` Renderer/Scene layer (or the maintainer's legacy
|
|
11
|
+
* renderer at `src/core/renderers/Indicator/volumeProfile.ts`, which is kept
|
|
12
|
+
* untouched per branch policy).
|
|
13
|
+
*
|
|
14
|
+
* See `docs/ROADMAP.md` §3.1 for the algorithm rationale and §0 for the
|
|
15
|
+
* controller layering this fits into. See `computeShader.wgsl.md` for the
|
|
16
|
+
* planned WebGPU compute path of the heavy `binBarToBuckets` work.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { Signal } from '../../reactivity'
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* How a bar's volume is distributed across price buckets.
|
|
23
|
+
*
|
|
24
|
+
* - `typical-price` — the fast default. The entire bar volume is dropped into
|
|
25
|
+
* the single bucket containing (high+low+close)/3. O(1) per bar.
|
|
26
|
+
* - `proportional` — accurate. The bar volume is split across every bucket
|
|
27
|
+
* that overlaps `[low, high]`, proportional to that bucket's price-range
|
|
28
|
+
* overlap with the bar. O(buckets-spanned) per bar.
|
|
29
|
+
*
|
|
30
|
+
* The trade-off is laid out in `docs/ROADMAP.md` §3.1: typical-price is what
|
|
31
|
+
* you want for live profile rendering at frame rate; proportional is what you
|
|
32
|
+
* want for "true" historical profiles and TPO-style work.
|
|
33
|
+
*/
|
|
34
|
+
export type BinningMode = 'typical-price' | 'proportional'
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Inputs to the controller. All fields are deliberately required at the
|
|
38
|
+
* controller surface — `createVolumeProfileController` fills missing fields
|
|
39
|
+
* from sensible defaults so callers can pass `{}`.
|
|
40
|
+
*/
|
|
41
|
+
export interface VolumeProfileConfig {
|
|
42
|
+
/** Number of price buckets (histogram resolution). Typical 50–200. */
|
|
43
|
+
binCount: number
|
|
44
|
+
/** Per-bar binning strategy. See `BinningMode`. */
|
|
45
|
+
binningMode: BinningMode
|
|
46
|
+
/**
|
|
47
|
+
* Fraction of total volume that must be inside the Value Area, in [0, 1].
|
|
48
|
+
* CME convention is 0.70. Set 1.0 to use the full range, set to e.g. 0.95
|
|
49
|
+
* for institution-style "value extended" envelopes.
|
|
50
|
+
*/
|
|
51
|
+
valueAreaPercent: number
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The reactive output. `null` while no bars have been ingested.
|
|
56
|
+
*
|
|
57
|
+
* Prices are absolute (real, not normalised) so renderers can place them on
|
|
58
|
+
* the same Y axis as candles. `buckets` is a `Float64Array` rather than
|
|
59
|
+
* `number[]` for two reasons: (1) contiguous memory layout for cache-friendly
|
|
60
|
+
* argmax / VA scans, and (2) it is the same format we'll upload to a GPU
|
|
61
|
+
* storage buffer once the WebGPU compute path lands (see `computeShader.wgsl.md`).
|
|
62
|
+
*/
|
|
63
|
+
export interface VolumeProfileState {
|
|
64
|
+
/** Histogram. `buckets[i]` is the total volume in bucket i. */
|
|
65
|
+
buckets: Float64Array
|
|
66
|
+
/** Low-edge price of bucket 0. */
|
|
67
|
+
binMin: number
|
|
68
|
+
/** Price width of one bucket. `buckets.length * binSize = total price span`. */
|
|
69
|
+
binSize: number
|
|
70
|
+
/** Point of Control — center price of the highest-volume bucket. */
|
|
71
|
+
poc: number
|
|
72
|
+
/** Value Area High — upper edge price of the VAH bucket. */
|
|
73
|
+
vah: number
|
|
74
|
+
/** Value Area Low — lower edge price of the VAL bucket. */
|
|
75
|
+
val: number
|
|
76
|
+
/** Sum of every bucket. */
|
|
77
|
+
totalVolume: number
|
|
78
|
+
/** Volume inside the closed Value Area `[valIndex, vahIndex]`. */
|
|
79
|
+
vaVolume: number
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Minimum bar shape consumed by `ingest`. Matches the cross-renderer KLineData
|
|
84
|
+
* subset used elsewhere in core. We intentionally do NOT require `open` or
|
|
85
|
+
* `timestamp` so callers can stream from any source.
|
|
86
|
+
*/
|
|
87
|
+
export interface VolumeProfileBar {
|
|
88
|
+
high: number
|
|
89
|
+
low: number
|
|
90
|
+
close: number
|
|
91
|
+
volume: number
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Framework-agnostic controller — mirrors `IndicatorSelectorController`'s
|
|
96
|
+
* shape (signals for state, plain functions for mutations, idempotent
|
|
97
|
+
* `dispose`).
|
|
98
|
+
*/
|
|
99
|
+
export interface VolumeProfileController {
|
|
100
|
+
/** Current config; re-emits when `setConfig` is called. */
|
|
101
|
+
readonly config: Signal<VolumeProfileConfig>
|
|
102
|
+
/** Current state; `null` until the first ingest. */
|
|
103
|
+
readonly state: Signal<VolumeProfileState | null>
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Recompute the profile from a fresh bar slice. Idempotent: calling this
|
|
107
|
+
* twice with the same bars yields the same state (it is NOT cumulative —
|
|
108
|
+
* the prior buckets are discarded). Incremental ingestion will land with
|
|
109
|
+
* the GPU compute path; see `computeShader.wgsl.md`.
|
|
110
|
+
*/
|
|
111
|
+
ingest(bars: ReadonlyArray<VolumeProfileBar>): void
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Patch the config. If `binCount` changes the buckets are re-sized on the
|
|
115
|
+
* next `ingest` (state is cleared immediately because the old buckets are
|
|
116
|
+
* now meaningless under the new resolution).
|
|
117
|
+
*/
|
|
118
|
+
setConfig(next: Partial<VolumeProfileConfig>): void
|
|
119
|
+
|
|
120
|
+
/** Clear state to null (does not change config). */
|
|
121
|
+
reset(): void
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Stop emitting. Subsequent calls to ingest/setConfig/reset are silent
|
|
125
|
+
* no-ops; previously-attached subscribers receive no further
|
|
126
|
+
* notifications. Idempotent.
|
|
127
|
+
*/
|
|
128
|
+
dispose(): void
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Result of the Value Area greedy expansion. Indices are inclusive bucket
|
|
133
|
+
* indices; prices are derived by the controller using `binMin + binSize * i`.
|
|
134
|
+
*/
|
|
135
|
+
export interface ValueAreaResult {
|
|
136
|
+
/** Upper bucket index (inclusive). */
|
|
137
|
+
vahIndex: number
|
|
138
|
+
/** Lower bucket index (inclusive). */
|
|
139
|
+
valIndex: number
|
|
140
|
+
/** Argmax bucket index used as the seed. */
|
|
141
|
+
pocIndex: number
|
|
142
|
+
/** Total of all buckets. */
|
|
143
|
+
totalVolume: number
|
|
144
|
+
/** Sum of `buckets[i]` for `i in [valIndex, vahIndex]`. */
|
|
145
|
+
vaVolume: number
|
|
146
|
+
/** `vaVolume / totalVolume`. 0 when `totalVolume` is 0. */
|
|
147
|
+
vaPercent: number
|
|
148
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Value Area greedy expansion — VAH / VAL computation around the POC.
|
|
3
|
+
*
|
|
4
|
+
* Algorithm (CME-traditional, see `docs/ROADMAP.md` §3.1):
|
|
5
|
+
* 1. Seed the Value Area with the POC bucket.
|
|
6
|
+
* 2. Compute the target volume `target = totalVolume * percent`.
|
|
7
|
+
* 3. Repeatedly grow the VA by **one** of its boundary's neighbours:
|
|
8
|
+
* compare the volume of `buckets[vahIdx + 1]` (upper neighbour) and
|
|
9
|
+
* `buckets[valIdx - 1]` (lower neighbour); annex the side with the
|
|
10
|
+
* larger volume.
|
|
11
|
+
* 4. If one side has no neighbour left (boundary of the histogram), only
|
|
12
|
+
* the other side is available.
|
|
13
|
+
* 5. Stop when `vaVolume >= target` or both sides are exhausted.
|
|
14
|
+
*
|
|
15
|
+
* Tie-breakers (critical — get these wrong and the test plan fails):
|
|
16
|
+
*
|
|
17
|
+
* (A) When `upper.vol == lower.vol`, expand toward the POC. "Toward the
|
|
18
|
+
* POC" means: pick the side whose current boundary is **closer** to
|
|
19
|
+
* `pocIndex`. The intuition is that a symmetric tie should grow the
|
|
20
|
+
* VA evenly around the POC instead of drifting whichever way the
|
|
21
|
+
* comparison happens to land first. This matches the spirit of the
|
|
22
|
+
* CME spec, which expects the VA to be "balanced around POC" when
|
|
23
|
+
* data is symmetric, and it's the choice the maintainer's legacy
|
|
24
|
+
* renderer makes by default.
|
|
25
|
+
*
|
|
26
|
+
* (B) When `upper.vol == lower.vol` AND both boundaries are equidistant
|
|
27
|
+
* from POC, prefer the **upper** side. This is documented because it
|
|
28
|
+
* is otherwise underspecified; the rationale is that an upper-side
|
|
29
|
+
* preference matches the default direction of price discovery on
|
|
30
|
+
* most assets (markets tend to break up out of balance).
|
|
31
|
+
*
|
|
32
|
+
* (C) The CME-style "two-bucket lookahead" tie-breaker is intentionally
|
|
33
|
+
* NOT implemented in this pass — it adds complexity for a tiny
|
|
34
|
+
* difference in result and is not required by the test plan. It can
|
|
35
|
+
* be added behind a `tieBreaker: 'lookahead'` option later without
|
|
36
|
+
* breaking the API.
|
|
37
|
+
*
|
|
38
|
+
* Edge cases:
|
|
39
|
+
* - Empty / all-zero buckets ⇒ `vah = val = poc`, `vaVolume = 0`,
|
|
40
|
+
* `vaPercent = 0`. No expansion happens.
|
|
41
|
+
* - Single non-zero bucket ⇒ `vah = val = poc` already covers it.
|
|
42
|
+
* - POC at index 0 ⇒ only the upper neighbour exists.
|
|
43
|
+
* - POC at index N-1 ⇒ only the lower neighbour exists.
|
|
44
|
+
* - `targetPercent >= 1.0` ⇒ the loop expands until the full range is
|
|
45
|
+
* swept, yielding `valIdx = 0`, `vahIdx = N-1`.
|
|
46
|
+
* - `targetPercent <= 0` ⇒ the loop never runs; only the POC bucket is in
|
|
47
|
+
* the VA.
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
import type { ValueAreaResult } from './types'
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @internal — building block used by `createVolumeProfileController`. Reachable today
|
|
54
|
+
* via the top-level `@klinechart-quant/core` barrel but **NOT
|
|
55
|
+
* part of the supported public API**. typedoc / api-extractor
|
|
56
|
+
* hide it from generated docs. Prefer the controller factory
|
|
57
|
+
* for stable user code. Closes API audit BLOCKER-002.
|
|
58
|
+
*/
|
|
59
|
+
export function computeValueArea(
|
|
60
|
+
buckets: Float64Array,
|
|
61
|
+
pocIndex: number,
|
|
62
|
+
targetPercent: number,
|
|
63
|
+
): ValueAreaResult {
|
|
64
|
+
const n = buckets.length
|
|
65
|
+
|
|
66
|
+
// -------------------------------------------------------------------
|
|
67
|
+
// Empty histogram → degenerate result.
|
|
68
|
+
// -------------------------------------------------------------------
|
|
69
|
+
if (n === 0) {
|
|
70
|
+
return {
|
|
71
|
+
vahIndex: 0,
|
|
72
|
+
valIndex: 0,
|
|
73
|
+
pocIndex: 0,
|
|
74
|
+
totalVolume: 0,
|
|
75
|
+
vaVolume: 0,
|
|
76
|
+
vaPercent: 0,
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Clamp pocIndex defensively. The controller always passes a valid
|
|
81
|
+
// value, but valueArea.ts is also exported for direct use.
|
|
82
|
+
const poc = pocIndex < 0 ? 0 : pocIndex >= n ? n - 1 : pocIndex
|
|
83
|
+
|
|
84
|
+
// -------------------------------------------------------------------
|
|
85
|
+
// Total volume — single pass.
|
|
86
|
+
// -------------------------------------------------------------------
|
|
87
|
+
let totalVolume = 0
|
|
88
|
+
for (let i = 0; i < n; i++) {
|
|
89
|
+
totalVolume += buckets[i] ?? 0
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Zero-volume case → degenerate result, VA collapses to POC.
|
|
93
|
+
if (totalVolume === 0) {
|
|
94
|
+
return {
|
|
95
|
+
vahIndex: poc,
|
|
96
|
+
valIndex: poc,
|
|
97
|
+
pocIndex: poc,
|
|
98
|
+
totalVolume: 0,
|
|
99
|
+
vaVolume: 0,
|
|
100
|
+
vaPercent: 0,
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// -------------------------------------------------------------------
|
|
105
|
+
// Seed the Value Area with the POC bucket.
|
|
106
|
+
// -------------------------------------------------------------------
|
|
107
|
+
let valIdx = poc
|
|
108
|
+
let vahIdx = poc
|
|
109
|
+
let vaVolume = buckets[poc] ?? 0
|
|
110
|
+
|
|
111
|
+
const pct = targetPercent < 0 ? 0 : targetPercent > 1 ? 1 : targetPercent
|
|
112
|
+
const target = totalVolume * pct
|
|
113
|
+
|
|
114
|
+
// Already covered (rare — happens when POC bucket alone is > target%).
|
|
115
|
+
// Still proceeds via the loop guard.
|
|
116
|
+
|
|
117
|
+
// -------------------------------------------------------------------
|
|
118
|
+
// Greedy expansion.
|
|
119
|
+
// -------------------------------------------------------------------
|
|
120
|
+
while (vaVolume < target) {
|
|
121
|
+
const canUp = vahIdx < n - 1
|
|
122
|
+
const canDown = valIdx > 0
|
|
123
|
+
|
|
124
|
+
if (!canUp && !canDown) break // exhausted entire histogram
|
|
125
|
+
|
|
126
|
+
// Single-side: only one direction has a neighbour.
|
|
127
|
+
if (canUp && !canDown) {
|
|
128
|
+
vahIdx += 1
|
|
129
|
+
vaVolume += buckets[vahIdx] ?? 0
|
|
130
|
+
continue
|
|
131
|
+
}
|
|
132
|
+
if (!canUp && canDown) {
|
|
133
|
+
valIdx -= 1
|
|
134
|
+
vaVolume += buckets[valIdx] ?? 0
|
|
135
|
+
continue
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const upVol = buckets[vahIdx + 1] ?? 0
|
|
139
|
+
const downVol = buckets[valIdx - 1] ?? 0
|
|
140
|
+
|
|
141
|
+
let goUp: boolean
|
|
142
|
+
|
|
143
|
+
if (upVol > downVol) {
|
|
144
|
+
goUp = true
|
|
145
|
+
} else if (downVol > upVol) {
|
|
146
|
+
goUp = false
|
|
147
|
+
} else {
|
|
148
|
+
// ----- Tie: expand toward POC (see (A)/(B) in header). -----
|
|
149
|
+
// Distance from each *current* boundary to the POC. The
|
|
150
|
+
// boundary that's farther from POC is on the "long" side; we
|
|
151
|
+
// pull the VA back toward POC by extending the *closer*
|
|
152
|
+
// boundary (i.e. the side that has further to travel before
|
|
153
|
+
// it leaves POC's neighbourhood).
|
|
154
|
+
//
|
|
155
|
+
// Equivalently: pick the boundary whose distance to POC is
|
|
156
|
+
// smaller — that side still has room to grow "around" POC,
|
|
157
|
+
// the other side has already drifted.
|
|
158
|
+
const distUp = vahIdx - poc // >= 0
|
|
159
|
+
const distDown = poc - valIdx // >= 0
|
|
160
|
+
if (distUp < distDown) {
|
|
161
|
+
goUp = true
|
|
162
|
+
} else if (distDown < distUp) {
|
|
163
|
+
goUp = false
|
|
164
|
+
} else {
|
|
165
|
+
// Equidistant — documented upper-side preference (B).
|
|
166
|
+
goUp = true
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (goUp) {
|
|
171
|
+
vahIdx += 1
|
|
172
|
+
vaVolume += buckets[vahIdx] ?? 0
|
|
173
|
+
} else {
|
|
174
|
+
valIdx -= 1
|
|
175
|
+
vaVolume += buckets[valIdx] ?? 0
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
vahIndex: vahIdx,
|
|
181
|
+
valIndex: valIdx,
|
|
182
|
+
pocIndex: poc,
|
|
183
|
+
totalVolume,
|
|
184
|
+
vaVolume,
|
|
185
|
+
vaPercent: totalVolume === 0 ? 0 : vaVolume / totalVolume,
|
|
186
|
+
}
|
|
187
|
+
}
|