@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,430 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for `createAnchoredVwapController` — multi-anchor reactive surface.
|
|
3
|
+
*
|
|
4
|
+
* The controller is held to three behavioural contracts:
|
|
5
|
+
* 1. Signals fire on every structural change (add, remove, update,
|
|
6
|
+
* setBars, appendBar).
|
|
7
|
+
* 2. The incremental `appendBar` is bit-for-bit equivalent (to
|
|
8
|
+
* floating-point precision) to a fresh `computeAnchoredVwap` over
|
|
9
|
+
* the same bars. The MAX_INCREMENTAL_DELTA assertion below is the
|
|
10
|
+
* reported delta in the summary.
|
|
11
|
+
* 3. `dispose` makes every mutator a silent no-op.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { describe, it, expect } from 'vitest'
|
|
15
|
+
|
|
16
|
+
import { createAnchoredVwapController } from '../createAnchoredVwapController'
|
|
17
|
+
import { computeAnchoredVwap } from '../computeAnchoredVwap'
|
|
18
|
+
import type { AnchorDefinition, AVWAPBar } from '../types'
|
|
19
|
+
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Fixture helpers
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
function bar(
|
|
25
|
+
high: number,
|
|
26
|
+
low: number,
|
|
27
|
+
close: number,
|
|
28
|
+
volume: number,
|
|
29
|
+
): AVWAPBar {
|
|
30
|
+
return { high, low, close, volume }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Realistic-ish trending series with mixed volume for the equivalence test. */
|
|
34
|
+
function makeSeries(n: number, seed = 1): AVWAPBar[] {
|
|
35
|
+
const out: AVWAPBar[] = []
|
|
36
|
+
let price = 100
|
|
37
|
+
// Tiny deterministic PRNG — keeps the fixture reproducible without
|
|
38
|
+
// a dependency.
|
|
39
|
+
let s = seed
|
|
40
|
+
const rand = (): number => {
|
|
41
|
+
s = (s * 9301 + 49297) % 233280
|
|
42
|
+
return s / 233280
|
|
43
|
+
}
|
|
44
|
+
for (let i = 0; i < n; i++) {
|
|
45
|
+
const drift = (rand() - 0.5) * 2
|
|
46
|
+
price = Math.max(1, price + drift)
|
|
47
|
+
const high = price + rand() * 1.5
|
|
48
|
+
const low = price - rand() * 1.5
|
|
49
|
+
const close = low + rand() * (high - low)
|
|
50
|
+
const volume = 100 + Math.floor(rand() * 10_000)
|
|
51
|
+
out.push(bar(high, low, close, volume))
|
|
52
|
+
}
|
|
53
|
+
return out
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function defaultAnchor(
|
|
57
|
+
id: string,
|
|
58
|
+
barIndex: number,
|
|
59
|
+
includeBands = true,
|
|
60
|
+
): AnchorDefinition {
|
|
61
|
+
return { id, label: id, barIndex, includeBands }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
// addAnchor / signal contract
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
|
|
68
|
+
describe('createAnchoredVwapController — addAnchor + signal', () => {
|
|
69
|
+
it('addAnchor returns the supplied id and fires the anchors signal', () => {
|
|
70
|
+
const bars = makeSeries(10)
|
|
71
|
+
const c = createAnchoredVwapController({ initialBars: bars })
|
|
72
|
+
|
|
73
|
+
// Subscribe BEFORE calling addAnchor — we want to confirm the
|
|
74
|
+
// notification happens as a result of the mutation.
|
|
75
|
+
let notifications = 0
|
|
76
|
+
const unsub = c.anchors.subscribe(() => {
|
|
77
|
+
notifications += 1
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
const returnedId = c.addAnchor(defaultAnchor('a1', 2))
|
|
81
|
+
expect(returnedId).toBe('a1')
|
|
82
|
+
|
|
83
|
+
const state = c.anchors.peek()
|
|
84
|
+
expect(state).toHaveLength(1)
|
|
85
|
+
expect(state[0]!.definition.id).toBe('a1')
|
|
86
|
+
// The series should span bars 2..9 inclusive.
|
|
87
|
+
expect(state[0]!.series).toHaveLength(8)
|
|
88
|
+
expect(state[0]!.series[0]!.barIndex).toBe(2)
|
|
89
|
+
expect(state[0]!.series[7]!.barIndex).toBe(9)
|
|
90
|
+
|
|
91
|
+
expect(notifications).toBeGreaterThanOrEqual(1)
|
|
92
|
+
|
|
93
|
+
unsub()
|
|
94
|
+
c.dispose()
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('addAnchor with a duplicate id REPLACES the existing anchor', () => {
|
|
98
|
+
// We document this choice in the test name. The brief allows
|
|
99
|
+
// either reject-or-replace; we picked replace because UIs that
|
|
100
|
+
// drag an anchor onto an existing one expect in-place update.
|
|
101
|
+
const bars = makeSeries(10)
|
|
102
|
+
const c = createAnchoredVwapController({ initialBars: bars })
|
|
103
|
+
|
|
104
|
+
c.addAnchor(defaultAnchor('a1', 2))
|
|
105
|
+
const firstSeriesLen = c.anchors.peek()[0]!.series.length
|
|
106
|
+
|
|
107
|
+
// Same id, different bar index → must replace, not insert a
|
|
108
|
+
// second entry.
|
|
109
|
+
c.addAnchor(defaultAnchor('a1', 5))
|
|
110
|
+
const after = c.anchors.peek()
|
|
111
|
+
expect(after).toHaveLength(1)
|
|
112
|
+
expect(after[0]!.definition.barIndex).toBe(5)
|
|
113
|
+
// The new series is shorter because it starts later.
|
|
114
|
+
expect(after[0]!.series.length).toBeLessThan(firstSeriesLen)
|
|
115
|
+
expect(after[0]!.series[0]!.barIndex).toBe(5)
|
|
116
|
+
|
|
117
|
+
c.dispose()
|
|
118
|
+
})
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
// removeAnchor
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
describe('createAnchoredVwapController — removeAnchor', () => {
|
|
126
|
+
it('removeAnchor returns false for an unknown id and does not emit', () => {
|
|
127
|
+
const bars = makeSeries(10)
|
|
128
|
+
const c = createAnchoredVwapController({ initialBars: bars })
|
|
129
|
+
c.addAnchor(defaultAnchor('a1', 2))
|
|
130
|
+
|
|
131
|
+
let notifications = 0
|
|
132
|
+
const unsub = c.anchors.subscribe(() => {
|
|
133
|
+
notifications += 1
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
expect(c.removeAnchor('nope')).toBe(false)
|
|
137
|
+
// No mutation happened → no notification.
|
|
138
|
+
expect(notifications).toBe(0)
|
|
139
|
+
// Existing anchor untouched.
|
|
140
|
+
expect(c.anchors.peek()).toHaveLength(1)
|
|
141
|
+
|
|
142
|
+
unsub()
|
|
143
|
+
c.dispose()
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it('removeAnchor returns true for a known id and drops it from the signal', () => {
|
|
147
|
+
const bars = makeSeries(10)
|
|
148
|
+
const c = createAnchoredVwapController({ initialBars: bars })
|
|
149
|
+
c.addAnchor(defaultAnchor('a1', 2))
|
|
150
|
+
c.addAnchor(defaultAnchor('a2', 5))
|
|
151
|
+
expect(c.anchors.peek()).toHaveLength(2)
|
|
152
|
+
|
|
153
|
+
expect(c.removeAnchor('a1')).toBe(true)
|
|
154
|
+
const after = c.anchors.peek()
|
|
155
|
+
expect(after).toHaveLength(1)
|
|
156
|
+
expect(after[0]!.definition.id).toBe('a2')
|
|
157
|
+
|
|
158
|
+
c.dispose()
|
|
159
|
+
})
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
// updateAnchor
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
|
|
166
|
+
describe('createAnchoredVwapController — updateAnchor', () => {
|
|
167
|
+
it('moving an anchor barIndex recomputes the series', () => {
|
|
168
|
+
const bars = makeSeries(20)
|
|
169
|
+
const c = createAnchoredVwapController({ initialBars: bars })
|
|
170
|
+
c.addAnchor(defaultAnchor('a1', 3))
|
|
171
|
+
|
|
172
|
+
const before = c.anchors.peek()[0]!.series
|
|
173
|
+
const beforeLen = before.length
|
|
174
|
+
const beforeFirstVwap = before[0]!.vwap
|
|
175
|
+
|
|
176
|
+
expect(c.updateAnchor('a1', { barIndex: 10 })).toBe(true)
|
|
177
|
+
const after = c.anchors.peek()[0]!
|
|
178
|
+
// Series shrunk because the anchor moved forward.
|
|
179
|
+
expect(after.series).toHaveLength(beforeLen - 7)
|
|
180
|
+
expect(after.series[0]!.barIndex).toBe(10)
|
|
181
|
+
// The first vwap differs because it now reflects a different
|
|
182
|
+
// typical price.
|
|
183
|
+
expect(after.series[0]!.vwap).not.toBe(beforeFirstVwap)
|
|
184
|
+
expect(after.definition.barIndex).toBe(10)
|
|
185
|
+
|
|
186
|
+
c.dispose()
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
it('updateAnchor on an unknown id returns false', () => {
|
|
190
|
+
const c = createAnchoredVwapController({ initialBars: makeSeries(5) })
|
|
191
|
+
expect(c.updateAnchor('ghost', { label: 'hi' })).toBe(false)
|
|
192
|
+
c.dispose()
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
it('updateAnchor label-only does not change the math', () => {
|
|
196
|
+
const c = createAnchoredVwapController({ initialBars: makeSeries(10) })
|
|
197
|
+
c.addAnchor(defaultAnchor('a1', 2))
|
|
198
|
+
const before = c.anchors.peek()[0]!.series
|
|
199
|
+
c.updateAnchor('a1', { label: 'new label' })
|
|
200
|
+
const after = c.anchors.peek()[0]!
|
|
201
|
+
expect(after.definition.label).toBe('new label')
|
|
202
|
+
// Series is structurally identical (same length, same vwap values).
|
|
203
|
+
expect(after.series).toHaveLength(before.length)
|
|
204
|
+
for (let i = 0; i < before.length; i++) {
|
|
205
|
+
expect(after.series[i]!.vwap).toBe(before[i]!.vwap)
|
|
206
|
+
}
|
|
207
|
+
c.dispose()
|
|
208
|
+
})
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
// setBars
|
|
213
|
+
// ---------------------------------------------------------------------------
|
|
214
|
+
|
|
215
|
+
describe('createAnchoredVwapController — setBars', () => {
|
|
216
|
+
it('setBars rebuilds every anchor series', () => {
|
|
217
|
+
const c = createAnchoredVwapController({ initialBars: makeSeries(10) })
|
|
218
|
+
c.addAnchor(defaultAnchor('a1', 2))
|
|
219
|
+
c.addAnchor(defaultAnchor('a2', 5))
|
|
220
|
+
const before = c.anchors.peek().map((a) => a.series.length)
|
|
221
|
+
|
|
222
|
+
// Larger bar set → both series should grow.
|
|
223
|
+
c.setBars(makeSeries(30, 99))
|
|
224
|
+
const after = c.anchors.peek().map((a) => a.series.length)
|
|
225
|
+
// a1 was anchored at 2 → previously 8 points, now 28.
|
|
226
|
+
expect(after[0]).toBe(28)
|
|
227
|
+
// a2 was anchored at 5 → previously 5 points, now 25.
|
|
228
|
+
expect(after[1]).toBe(25)
|
|
229
|
+
// Both grew.
|
|
230
|
+
expect(after[0]).toBeGreaterThan(before[0]!)
|
|
231
|
+
expect(after[1]).toBeGreaterThan(before[1]!)
|
|
232
|
+
c.dispose()
|
|
233
|
+
})
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
// ---------------------------------------------------------------------------
|
|
237
|
+
// appendBar — the perf optimisation
|
|
238
|
+
// ---------------------------------------------------------------------------
|
|
239
|
+
|
|
240
|
+
describe('createAnchoredVwapController — appendBar', () => {
|
|
241
|
+
it('extends every active anchor series by exactly one point', () => {
|
|
242
|
+
const c = createAnchoredVwapController({ initialBars: makeSeries(5) })
|
|
243
|
+
c.addAnchor(defaultAnchor('a1', 1))
|
|
244
|
+
c.addAnchor(defaultAnchor('a2', 3))
|
|
245
|
+
const before = c.anchors.peek().map((a) => a.series.length)
|
|
246
|
+
|
|
247
|
+
c.appendBar(bar(110, 108, 109, 500))
|
|
248
|
+
|
|
249
|
+
const after = c.anchors.peek()
|
|
250
|
+
for (let i = 0; i < after.length; i++) {
|
|
251
|
+
expect(after[i]!.series.length).toBe(before[i]! + 1)
|
|
252
|
+
const last = after[i]!.series[after[i]!.series.length - 1]!
|
|
253
|
+
// New point references the just-appended bar.
|
|
254
|
+
expect(last.barIndex).toBe(5)
|
|
255
|
+
}
|
|
256
|
+
c.dispose()
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
it('appendBar incrementally matches a full computeAnchoredVwap recompute', () => {
|
|
260
|
+
// The headline performance contract: walking via N appendBar
|
|
261
|
+
// calls must produce the same series as a single
|
|
262
|
+
// computeAnchoredVwap over the final bars. We pin the max delta
|
|
263
|
+
// here at 1e-9 (we measure 0 in practice — the operands are
|
|
264
|
+
// added in the same order) so a regression to a different
|
|
265
|
+
// accumulation order would fail loudly.
|
|
266
|
+
const initial = makeSeries(20)
|
|
267
|
+
const tail = makeSeries(30, 42)
|
|
268
|
+
const all = [...initial, ...tail]
|
|
269
|
+
|
|
270
|
+
const c = createAnchoredVwapController({ initialBars: initial })
|
|
271
|
+
c.addAnchor(defaultAnchor('a-bands', 5, true))
|
|
272
|
+
c.addAnchor(defaultAnchor('a-no-bands', 12, false))
|
|
273
|
+
|
|
274
|
+
for (const b of tail) c.appendBar(b)
|
|
275
|
+
|
|
276
|
+
const incrementalAnchors = c.anchors.peek()
|
|
277
|
+
const referenceBands = computeAnchoredVwap(all, 5, true)
|
|
278
|
+
const referenceNoBands = computeAnchoredVwap(all, 12, false)
|
|
279
|
+
|
|
280
|
+
const compare = (
|
|
281
|
+
label: string,
|
|
282
|
+
inc: ReadonlyArray<{
|
|
283
|
+
vwap: number
|
|
284
|
+
upper1: number
|
|
285
|
+
lower1: number
|
|
286
|
+
upper2: number
|
|
287
|
+
lower2: number
|
|
288
|
+
cumulativeVolume: number
|
|
289
|
+
barIndex: number
|
|
290
|
+
}>,
|
|
291
|
+
ref: ReadonlyArray<{
|
|
292
|
+
vwap: number
|
|
293
|
+
upper1: number
|
|
294
|
+
lower1: number
|
|
295
|
+
upper2: number
|
|
296
|
+
lower2: number
|
|
297
|
+
cumulativeVolume: number
|
|
298
|
+
barIndex: number
|
|
299
|
+
}>,
|
|
300
|
+
): number => {
|
|
301
|
+
expect(inc.length, `${label} length`).toBe(ref.length)
|
|
302
|
+
let maxDelta = 0
|
|
303
|
+
for (let i = 0; i < inc.length; i++) {
|
|
304
|
+
const a = inc[i]!
|
|
305
|
+
const b = ref[i]!
|
|
306
|
+
expect(a.barIndex).toBe(b.barIndex)
|
|
307
|
+
const fields: Array<keyof typeof a> = [
|
|
308
|
+
'vwap',
|
|
309
|
+
'upper1',
|
|
310
|
+
'lower1',
|
|
311
|
+
'upper2',
|
|
312
|
+
'lower2',
|
|
313
|
+
'cumulativeVolume',
|
|
314
|
+
]
|
|
315
|
+
for (const f of fields) {
|
|
316
|
+
const av = a[f]
|
|
317
|
+
const bv = b[f]
|
|
318
|
+
if (Number.isNaN(av) && Number.isNaN(bv)) continue
|
|
319
|
+
const d = Math.abs((av as number) - (bv as number))
|
|
320
|
+
if (d > maxDelta) maxDelta = d
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return maxDelta
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const deltaBands = compare(
|
|
327
|
+
'bands',
|
|
328
|
+
incrementalAnchors[0]!.series,
|
|
329
|
+
referenceBands,
|
|
330
|
+
)
|
|
331
|
+
const deltaNoBands = compare(
|
|
332
|
+
'no-bands',
|
|
333
|
+
incrementalAnchors[1]!.series,
|
|
334
|
+
referenceNoBands,
|
|
335
|
+
)
|
|
336
|
+
const maxDelta = Math.max(deltaBands, deltaNoBands)
|
|
337
|
+
|
|
338
|
+
// Hard limit: 1e-9. Empirically we see exact 0 because the
|
|
339
|
+
// arithmetic is identical between the two paths — same operands
|
|
340
|
+
// added in the same order. The 1e-9 limit gives a tolerance to
|
|
341
|
+
// a future refactor that reorders summation, while still
|
|
342
|
+
// catching a meaningful divergence.
|
|
343
|
+
expect(maxDelta).toBeLessThan(1e-9)
|
|
344
|
+
// A stricter, observation-pinning assertion: today we see EXACT
|
|
345
|
+
// bit-for-bit equality. Keeping this assertion as documentation
|
|
346
|
+
// of the current invariant; a future refactor that reorders
|
|
347
|
+
// summation should consciously decide to relax it.
|
|
348
|
+
expect(maxDelta).toBe(0)
|
|
349
|
+
|
|
350
|
+
c.dispose()
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
it('appendBar emits a notification per call', () => {
|
|
354
|
+
const c = createAnchoredVwapController({ initialBars: makeSeries(5) })
|
|
355
|
+
c.addAnchor(defaultAnchor('a1', 0))
|
|
356
|
+
let notifications = 0
|
|
357
|
+
const unsub = c.anchors.subscribe(() => {
|
|
358
|
+
notifications += 1
|
|
359
|
+
})
|
|
360
|
+
c.appendBar(bar(110, 108, 109, 500))
|
|
361
|
+
c.appendBar(bar(111, 109, 110, 500))
|
|
362
|
+
c.appendBar(bar(112, 110, 111, 500))
|
|
363
|
+
expect(notifications).toBe(3)
|
|
364
|
+
unsub()
|
|
365
|
+
c.dispose()
|
|
366
|
+
})
|
|
367
|
+
})
|
|
368
|
+
|
|
369
|
+
// ---------------------------------------------------------------------------
|
|
370
|
+
// Independence of multiple anchors
|
|
371
|
+
// ---------------------------------------------------------------------------
|
|
372
|
+
|
|
373
|
+
describe('createAnchoredVwapController — multiple anchors', () => {
|
|
374
|
+
it('two anchors at different positions produce independent series', () => {
|
|
375
|
+
const bars = makeSeries(15)
|
|
376
|
+
const c = createAnchoredVwapController({ initialBars: bars })
|
|
377
|
+
c.addAnchor(defaultAnchor('early', 2))
|
|
378
|
+
c.addAnchor(defaultAnchor('late', 10))
|
|
379
|
+
|
|
380
|
+
const list = c.anchors.peek()
|
|
381
|
+
expect(list).toHaveLength(2)
|
|
382
|
+
// Early anchor covers more bars.
|
|
383
|
+
expect(list[0]!.series.length).toBeGreaterThan(
|
|
384
|
+
list[1]!.series.length,
|
|
385
|
+
)
|
|
386
|
+
// First bar index of each series matches its anchor.
|
|
387
|
+
expect(list[0]!.series[0]!.barIndex).toBe(2)
|
|
388
|
+
expect(list[1]!.series[0]!.barIndex).toBe(10)
|
|
389
|
+
// Removing one does not affect the other.
|
|
390
|
+
c.removeAnchor('early')
|
|
391
|
+
const after = c.anchors.peek()
|
|
392
|
+
expect(after).toHaveLength(1)
|
|
393
|
+
expect(after[0]!.definition.id).toBe('late')
|
|
394
|
+
c.dispose()
|
|
395
|
+
})
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
// ---------------------------------------------------------------------------
|
|
399
|
+
// Dispose
|
|
400
|
+
// ---------------------------------------------------------------------------
|
|
401
|
+
|
|
402
|
+
describe('createAnchoredVwapController — dispose', () => {
|
|
403
|
+
it('dispose silences subsequent mutators', () => {
|
|
404
|
+
const c = createAnchoredVwapController({ initialBars: makeSeries(5) })
|
|
405
|
+
c.addAnchor(defaultAnchor('a1', 0))
|
|
406
|
+
|
|
407
|
+
let notifications = 0
|
|
408
|
+
const unsub = c.anchors.subscribe(() => {
|
|
409
|
+
notifications += 1
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
c.dispose()
|
|
413
|
+
// dispose is idempotent.
|
|
414
|
+
c.dispose()
|
|
415
|
+
|
|
416
|
+
// Every mutator becomes a no-op with the documented fallback.
|
|
417
|
+
expect(c.addAnchor(defaultAnchor('a2', 1))).toBeNull()
|
|
418
|
+
expect(c.removeAnchor('a1')).toBe(false)
|
|
419
|
+
expect(c.updateAnchor('a1', { label: 'no' })).toBe(false)
|
|
420
|
+
c.appendBar(bar(110, 108, 109, 500))
|
|
421
|
+
c.setBars(makeSeries(8))
|
|
422
|
+
|
|
423
|
+
expect(notifications).toBe(0)
|
|
424
|
+
// Underlying state was not modified by any of those calls.
|
|
425
|
+
expect(c.anchors.peek()).toHaveLength(1)
|
|
426
|
+
expect(c.anchors.peek()[0]!.definition.id).toBe('a1')
|
|
427
|
+
|
|
428
|
+
unsub()
|
|
429
|
+
})
|
|
430
|
+
})
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure math: anchored VWAP + volume-weighted standard-deviation bands.
|
|
3
|
+
*
|
|
4
|
+
* Used by `createAnchoredVwapController` for the from-scratch path
|
|
5
|
+
* (`setBars`, `addAnchor`, `updateAnchor` when `barIndex` changes). The
|
|
6
|
+
* controller's incremental `appendBar` reuses the same formulas via
|
|
7
|
+
* running sums; the controller's tests pin equivalence between the two
|
|
8
|
+
* paths.
|
|
9
|
+
*
|
|
10
|
+
* Math summary (formal derivation in `docs/ROADMAP.md` §3):
|
|
11
|
+
*
|
|
12
|
+
* typicalPrice(j) = (H[j] + L[j] + C[j]) / 3
|
|
13
|
+
* vwp(j) = typicalPrice(j) * V[j]
|
|
14
|
+
* sumVwp(i) = Σ_{j=a..i} vwp(j)
|
|
15
|
+
* sumVol(i) = Σ_{j=a..i} V[j]
|
|
16
|
+
* AVWAP(i) = sumVwp(i) / sumVol(i) (when sumVol > 0)
|
|
17
|
+
*
|
|
18
|
+
* ─── important subtlety ─────────────────────────────────────────────────
|
|
19
|
+
* The standard-deviation bands MUST use the **prevailing** AVWAP(j) at
|
|
20
|
+
* each bar j ∈ [a..i], NOT the final AVWAP(i). Naive implementations that
|
|
21
|
+
* reuse the final mean understate the deviation early in the anchor and
|
|
22
|
+
* overstate it late — the bands wind up visibly off-centre on long
|
|
23
|
+
* anchors. The dedicated test
|
|
24
|
+
* `computeAnchoredVwap.test.ts → "bands use prevailing AVWAP at j"` pins
|
|
25
|
+
* this and would catch a regression to the wrong formula.
|
|
26
|
+
*
|
|
27
|
+
* sqDev(j) = (typicalPrice(j) - AVWAP(j))^2 * V[j]
|
|
28
|
+
* sumSqDev(i) = Σ_{j=a..i} sqDev(j)
|
|
29
|
+
* variance(i) = sumSqDev(i) / sumVol(i)
|
|
30
|
+
* stdDev(i) = sqrt(variance(i))
|
|
31
|
+
* upper1(i) = AVWAP(i) + stdDev(i)
|
|
32
|
+
* lower1(i) = AVWAP(i) - stdDev(i)
|
|
33
|
+
* upper2(i) = AVWAP(i) + 2 * stdDev(i)
|
|
34
|
+
* lower2(i) = AVWAP(i) - 2 * stdDev(i)
|
|
35
|
+
*
|
|
36
|
+
* Zero-volume handling:
|
|
37
|
+
* - A bar with `volume === 0` contributes 0 to numerator, 0 to
|
|
38
|
+
* denominator, and 0 to the squared-deviation sum. The cumulative
|
|
39
|
+
* volume is unchanged.
|
|
40
|
+
* - If the cumulative volume is still > 0 at this bar (i.e. there was a
|
|
41
|
+
* prior non-zero bar) the AVWAP and bands **carry forward** the prior
|
|
42
|
+
* values — they are still mathematically well-defined.
|
|
43
|
+
* - If the cumulative volume is 0 (i.e. the anchor bar itself has
|
|
44
|
+
* volume 0 and every subsequent bar so far has volume 0 too), the
|
|
45
|
+
* point's `vwap` and band fields are `NaN`. The series still has an
|
|
46
|
+
* entry for the bar — `barIndex` and `cumulativeVolume` are filled in.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
import type { AVWAPBar, AVWAPPoint } from './types'
|
|
50
|
+
import { KLineChartError } from '../../errors'
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Compute the Anchored VWAP series for `bars`, anchored at
|
|
54
|
+
* `anchorIndex` (inclusive). Returns one `AVWAPPoint` per bar from
|
|
55
|
+
* `bars[anchorIndex]` through `bars[bars.length - 1]`.
|
|
56
|
+
*
|
|
57
|
+
* @param bars the bar series; the anchor must lie inside it
|
|
58
|
+
* @param anchorIndex 0-based index of the anchor bar (must satisfy
|
|
59
|
+
* `0 <= anchorIndex < bars.length`)
|
|
60
|
+
* @param includeBands when `false`, the four band fields equal `vwap` and
|
|
61
|
+
* the (cheaper) one-pass cumulative-volume math is
|
|
62
|
+
* used. The second pass that drives the bands is
|
|
63
|
+
* skipped entirely.
|
|
64
|
+
*
|
|
65
|
+
* @throws RangeError when `anchorIndex` is out of range and `bars` is
|
|
66
|
+
* non-empty. An empty `bars` array returns `[]` even
|
|
67
|
+
* if `anchorIndex` would otherwise be invalid — this
|
|
68
|
+
* mirrors the "no data, no work" convention used by
|
|
69
|
+
* the volume-profile controller.
|
|
70
|
+
*
|
|
71
|
+
* @internal — building block used by the corresponding controller
|
|
72
|
+
* factory. Reachable today via the top-level `@klinechart-quant/core`
|
|
73
|
+
* barrel but **NOT part of the supported public API**. typedoc / api-
|
|
74
|
+
* extractor hide it from generated docs. Prefer the controller
|
|
75
|
+
* factory (e.g. `createVolumeProfileController`) for stable user code.
|
|
76
|
+
* Closes API audit BLOCKER-002 (export * leakage taxonomy).
|
|
77
|
+
*/
|
|
78
|
+
export function computeAnchoredVwap(
|
|
79
|
+
bars: ReadonlyArray<AVWAPBar>,
|
|
80
|
+
anchorIndex: number,
|
|
81
|
+
includeBands: boolean,
|
|
82
|
+
): ReadonlyArray<AVWAPPoint> {
|
|
83
|
+
if (bars.length === 0) return []
|
|
84
|
+
|
|
85
|
+
if (anchorIndex < 0 || anchorIndex >= bars.length) {
|
|
86
|
+
throw new KLineChartError(
|
|
87
|
+
'AVWAP_ANCHOR_OUT_OF_RANGE',
|
|
88
|
+
`anchoredVwap: anchorIndex ${anchorIndex} is out of range ` +
|
|
89
|
+
`for bars of length ${bars.length}`,
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const out: AVWAPPoint[] = []
|
|
94
|
+
|
|
95
|
+
// Running sums, advanced bar-by-bar.
|
|
96
|
+
let sumVwp = 0
|
|
97
|
+
let sumVol = 0
|
|
98
|
+
let sumSqDev = 0
|
|
99
|
+
|
|
100
|
+
// `prevVwap` carries forward when a bar has zero volume but the
|
|
101
|
+
// cumulative volume so far is > 0. Initial value `NaN` flags the
|
|
102
|
+
// "anchor bar volume 0" case (see the docstring).
|
|
103
|
+
let prevVwap = Number.NaN
|
|
104
|
+
|
|
105
|
+
for (let i = anchorIndex; i < bars.length; i++) {
|
|
106
|
+
const bar = bars[i]
|
|
107
|
+
// Guard against sparse arrays / undefined entries. `Float64Array`
|
|
108
|
+
// would never have this hole, but plain arrays might.
|
|
109
|
+
if (bar === undefined) continue
|
|
110
|
+
|
|
111
|
+
const tp = (bar.high + bar.low + bar.close) / 3
|
|
112
|
+
const v = bar.volume
|
|
113
|
+
|
|
114
|
+
// First update cumulative volume + vwp. A v === 0 bar is a no-op
|
|
115
|
+
// here and the running totals stay where they were.
|
|
116
|
+
if (v > 0) {
|
|
117
|
+
sumVwp += tp * v
|
|
118
|
+
sumVol += v
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
let vwap: number
|
|
122
|
+
if (sumVol > 0) {
|
|
123
|
+
vwap = sumVwp / sumVol
|
|
124
|
+
prevVwap = vwap
|
|
125
|
+
} else {
|
|
126
|
+
// No volume ever ingested — emit NaN. This only happens when
|
|
127
|
+
// the anchor bar and every bar since it has v === 0.
|
|
128
|
+
vwap = Number.NaN
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Bands: the *prevailing* AVWAP at bar j is the mean used to weigh
|
|
132
|
+
// sqDev. That's exactly the `vwap` we just computed. Important:
|
|
133
|
+
// if v === 0 the squared-deviation contribution is also 0, so we
|
|
134
|
+
// can skip the term entirely (which also avoids touching `tp`
|
|
135
|
+
// when `vwap` is NaN).
|
|
136
|
+
if (includeBands && v > 0 && Number.isFinite(vwap)) {
|
|
137
|
+
const diff = tp - vwap
|
|
138
|
+
sumSqDev += diff * diff * v
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
let upper1 = vwap
|
|
142
|
+
let lower1 = vwap
|
|
143
|
+
let upper2 = vwap
|
|
144
|
+
let lower2 = vwap
|
|
145
|
+
if (includeBands && sumVol > 0 && Number.isFinite(vwap)) {
|
|
146
|
+
const variance = sumSqDev / sumVol
|
|
147
|
+
// Numerical safety: variance can be a tiny negative on
|
|
148
|
+
// catastrophic cancellation. Treat as 0.
|
|
149
|
+
const stdDev = Math.sqrt(variance > 0 ? variance : 0)
|
|
150
|
+
upper1 = vwap + stdDev
|
|
151
|
+
lower1 = vwap - stdDev
|
|
152
|
+
upper2 = vwap + 2 * stdDev
|
|
153
|
+
lower2 = vwap - 2 * stdDev
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
out.push({
|
|
157
|
+
barIndex: i,
|
|
158
|
+
vwap,
|
|
159
|
+
upper1,
|
|
160
|
+
lower1,
|
|
161
|
+
upper2,
|
|
162
|
+
lower2,
|
|
163
|
+
cumulativeVolume: sumVol,
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
// `prevVwap` is kept up to date for documentation/clarity even
|
|
167
|
+
// though we don't currently read it (the `sumVol > 0` branch above
|
|
168
|
+
// assigns directly). Left in place to make the carry-forward
|
|
169
|
+
// semantics explicit to future readers.
|
|
170
|
+
void prevVwap
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return out
|
|
174
|
+
}
|