@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,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for `createFrameBudget`.
|
|
3
|
+
*
|
|
4
|
+
* The clock is injected via `opts.now`, so timing assertions are exact:
|
|
5
|
+
* we advance a counter manually and the scheduler reads from it.
|
|
6
|
+
*
|
|
7
|
+
* Coverage:
|
|
8
|
+
* 1. Construction validates targetMs / historySize / maxQueueSize.
|
|
9
|
+
* 2. submit:
|
|
10
|
+
* - rejects empty id with KLineChartError(INVALID_PARAM)
|
|
11
|
+
* - queues into correct priority tier (queueDepth updates)
|
|
12
|
+
* - coalesces same-id submission (the later wins)
|
|
13
|
+
* - re-buckets when coalesce changes priority
|
|
14
|
+
* - drops oldest low/medium under maxQueueSize pressure
|
|
15
|
+
* - never drops high under pressure
|
|
16
|
+
* 3. flush:
|
|
17
|
+
* - runs all queued tasks if deadline is generous
|
|
18
|
+
* - stops at deadline (remaining stay queued)
|
|
19
|
+
* - runs high before medium before low (priority ordering)
|
|
20
|
+
* - within a tier, FIFO
|
|
21
|
+
* - returns the number of tasks run
|
|
22
|
+
* - throw in task is caught + dropped, others continue
|
|
23
|
+
* 4. beginFrame / endFrame:
|
|
24
|
+
* - validate finite timestamps
|
|
25
|
+
* - recentFrameMs is the rolling average over historySize frames
|
|
26
|
+
* - overruns increments only when dur > targetMs
|
|
27
|
+
* 5. clear / dispose.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import { describe, it, expect } from 'vitest'
|
|
31
|
+
|
|
32
|
+
import { createFrameBudget, type FrameTask } from '..'
|
|
33
|
+
import { isKLineChartError } from '../../errors'
|
|
34
|
+
|
|
35
|
+
function fakeClock(): {
|
|
36
|
+
now: () => number
|
|
37
|
+
advance: (ms: number) => void
|
|
38
|
+
set: (t: number) => void
|
|
39
|
+
} {
|
|
40
|
+
let t = 0
|
|
41
|
+
return {
|
|
42
|
+
now: () => t,
|
|
43
|
+
advance: (ms: number) => {
|
|
44
|
+
t += ms
|
|
45
|
+
},
|
|
46
|
+
set: (next: number) => {
|
|
47
|
+
t = next
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function record(id: string, store: string[], priority: FrameTask['priority'] = 'medium'): FrameTask {
|
|
53
|
+
return { id, priority, work: () => store.push(id) }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// Construction
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
|
|
60
|
+
describe('createFrameBudget — validation', () => {
|
|
61
|
+
it('rejects non-positive targetMs', () => {
|
|
62
|
+
for (const v of [0, -1, Number.NaN]) {
|
|
63
|
+
try {
|
|
64
|
+
createFrameBudget({ targetMs: v })
|
|
65
|
+
expect.fail(`expected throw for ${v}`)
|
|
66
|
+
} catch (e) {
|
|
67
|
+
expect(isKLineChartError(e, 'INVALID_PARAM')).toBe(true)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('rejects non-positive-integer historySize', () => {
|
|
73
|
+
for (const v of [0, -1, 1.5]) {
|
|
74
|
+
try {
|
|
75
|
+
createFrameBudget({ historySize: v })
|
|
76
|
+
expect.fail(`expected throw for ${v}`)
|
|
77
|
+
} catch (e) {
|
|
78
|
+
expect(isKLineChartError(e, 'INVALID_PARAM')).toBe(true)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('rejects non-positive-integer maxQueueSize', () => {
|
|
84
|
+
try {
|
|
85
|
+
createFrameBudget({ maxQueueSize: 0 })
|
|
86
|
+
expect.fail('expected throw')
|
|
87
|
+
} catch (e) {
|
|
88
|
+
expect(isKLineChartError(e, 'INVALID_PARAM')).toBe(true)
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
it('exposes targetMs verbatim', () => {
|
|
93
|
+
expect(createFrameBudget({ targetMs: 8 }).targetMs).toBe(8)
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
// submit
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
describe('submit', () => {
|
|
102
|
+
it('rejects empty id', () => {
|
|
103
|
+
const fb = createFrameBudget()
|
|
104
|
+
try {
|
|
105
|
+
fb.submit({ id: '', priority: 'low', work: () => {} })
|
|
106
|
+
expect.fail('expected throw')
|
|
107
|
+
} catch (e) {
|
|
108
|
+
expect(isKLineChartError(e, 'INVALID_PARAM')).toBe(true)
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
it('queueDepth tracks submissions across tiers', () => {
|
|
113
|
+
const fb = createFrameBudget()
|
|
114
|
+
const seen: string[] = []
|
|
115
|
+
fb.submit(record('a', seen, 'high'))
|
|
116
|
+
fb.submit(record('b', seen, 'medium'))
|
|
117
|
+
fb.submit(record('c', seen, 'low'))
|
|
118
|
+
expect(fb.queueDepth.peek()).toBe(3)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('coalesces same-id submission (later wins)', () => {
|
|
122
|
+
const fb = createFrameBudget()
|
|
123
|
+
const seen: string[] = []
|
|
124
|
+
fb.submit({ id: 'x', priority: 'low', work: () => seen.push('first') })
|
|
125
|
+
fb.submit({ id: 'x', priority: 'low', work: () => seen.push('second') })
|
|
126
|
+
const clk = fakeClock()
|
|
127
|
+
// Cheap test: a fresh budget with default now — flush with a far deadline.
|
|
128
|
+
fb.flush(Number.POSITIVE_INFINITY)
|
|
129
|
+
expect(seen).toEqual(['second'])
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
it('re-buckets when coalesce changes priority', () => {
|
|
133
|
+
const seen: string[] = []
|
|
134
|
+
const fb = createFrameBudget({ now: fakeClock().now })
|
|
135
|
+
fb.submit({ id: 'x', priority: 'low', work: () => seen.push('low') })
|
|
136
|
+
fb.submit({ id: 'x', priority: 'high', work: () => seen.push('high') })
|
|
137
|
+
fb.submit(record('y', seen, 'medium'))
|
|
138
|
+
fb.flush(Number.POSITIVE_INFINITY)
|
|
139
|
+
// x runs first (it's now high), then y.
|
|
140
|
+
expect(seen).toEqual(['high', 'y'])
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('drops oldest low under maxQueueSize pressure', () => {
|
|
144
|
+
const seen: string[] = []
|
|
145
|
+
const fb = createFrameBudget({ maxQueueSize: 2 })
|
|
146
|
+
fb.submit(record('a', seen, 'low'))
|
|
147
|
+
fb.submit(record('b', seen, 'low'))
|
|
148
|
+
fb.submit(record('c', seen, 'high'))
|
|
149
|
+
fb.flush(Number.POSITIVE_INFINITY)
|
|
150
|
+
// 'a' was the oldest low; it got dropped to make room for 'c'.
|
|
151
|
+
expect(seen).toEqual(['c', 'b'])
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it('never drops high under pressure', () => {
|
|
155
|
+
const seen: string[] = []
|
|
156
|
+
const fb = createFrameBudget({ maxQueueSize: 2 })
|
|
157
|
+
fb.submit(record('a', seen, 'high'))
|
|
158
|
+
fb.submit(record('b', seen, 'high'))
|
|
159
|
+
fb.submit(record('c', seen, 'high'))
|
|
160
|
+
fb.flush(Number.POSITIVE_INFINITY)
|
|
161
|
+
// All 3 high tasks present; the cap was exceeded but high
|
|
162
|
+
// is never dropped (producer-is-misbehaving signal).
|
|
163
|
+
expect(seen).toEqual(['a', 'b', 'c'])
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
// ---------------------------------------------------------------------------
|
|
168
|
+
// flush
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
|
|
171
|
+
describe('flush', () => {
|
|
172
|
+
it('runs high before medium before low (priority)', () => {
|
|
173
|
+
const seen: string[] = []
|
|
174
|
+
const fb = createFrameBudget()
|
|
175
|
+
fb.submit(record('low1', seen, 'low'))
|
|
176
|
+
fb.submit(record('med1', seen, 'medium'))
|
|
177
|
+
fb.submit(record('hi1', seen, 'high'))
|
|
178
|
+
fb.submit(record('hi2', seen, 'high'))
|
|
179
|
+
fb.submit(record('med2', seen, 'medium'))
|
|
180
|
+
fb.flush(Number.POSITIVE_INFINITY)
|
|
181
|
+
expect(seen).toEqual(['hi1', 'hi2', 'med1', 'med2', 'low1'])
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
it('within a tier, runs FIFO', () => {
|
|
185
|
+
const seen: string[] = []
|
|
186
|
+
const fb = createFrameBudget()
|
|
187
|
+
for (const id of ['a', 'b', 'c', 'd']) {
|
|
188
|
+
fb.submit(record(id, seen, 'medium'))
|
|
189
|
+
}
|
|
190
|
+
fb.flush(Number.POSITIVE_INFINITY)
|
|
191
|
+
expect(seen).toEqual(['a', 'b', 'c', 'd'])
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
it('stops at deadline; remaining tasks stay queued', () => {
|
|
195
|
+
const seen: string[] = []
|
|
196
|
+
const clk = fakeClock()
|
|
197
|
+
const fb = createFrameBudget({ now: clk.now })
|
|
198
|
+
for (let i = 0; i < 5; i++) {
|
|
199
|
+
fb.submit({
|
|
200
|
+
id: `t${i}`,
|
|
201
|
+
priority: 'medium',
|
|
202
|
+
work: () => {
|
|
203
|
+
seen.push(`t${i}`)
|
|
204
|
+
clk.advance(2) // each task costs 2ms
|
|
205
|
+
},
|
|
206
|
+
})
|
|
207
|
+
}
|
|
208
|
+
// Deadline at 5ms — 2 tasks complete (4ms), the 3rd would push us
|
|
209
|
+
// to 6ms but clock check happens BEFORE running each task. After
|
|
210
|
+
// 2 tasks, the next iteration sees now() = 4 < 5 — runs the 3rd
|
|
211
|
+
// (push to 6). After that, now() = 6 >= 5 — stop.
|
|
212
|
+
const done = fb.flush(5)
|
|
213
|
+
expect(done).toBe(3)
|
|
214
|
+
expect(seen).toEqual(['t0', 't1', 't2'])
|
|
215
|
+
expect(fb.queueDepth.peek()).toBe(2)
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
it('returns 0 if deadline already passed', () => {
|
|
219
|
+
const clk = fakeClock()
|
|
220
|
+
clk.set(100)
|
|
221
|
+
const fb = createFrameBudget({ now: clk.now })
|
|
222
|
+
fb.submit(record('a', [], 'high'))
|
|
223
|
+
expect(fb.flush(50)).toBe(0)
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
it('a throwing task is dropped; others continue', () => {
|
|
227
|
+
const seen: string[] = []
|
|
228
|
+
const fb = createFrameBudget()
|
|
229
|
+
fb.submit({ id: 'a', priority: 'high', work: () => seen.push('a') })
|
|
230
|
+
fb.submit({
|
|
231
|
+
id: 'bad',
|
|
232
|
+
priority: 'high',
|
|
233
|
+
work: () => {
|
|
234
|
+
throw new Error('boom')
|
|
235
|
+
},
|
|
236
|
+
})
|
|
237
|
+
fb.submit({ id: 'c', priority: 'high', work: () => seen.push('c') })
|
|
238
|
+
const done = fb.flush(Number.POSITIVE_INFINITY)
|
|
239
|
+
expect(done).toBe(2) // a + c, not bad
|
|
240
|
+
expect(seen).toEqual(['a', 'c'])
|
|
241
|
+
})
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
// ---------------------------------------------------------------------------
|
|
245
|
+
// beginFrame / endFrame
|
|
246
|
+
// ---------------------------------------------------------------------------
|
|
247
|
+
|
|
248
|
+
describe('beginFrame / endFrame', () => {
|
|
249
|
+
it('validates finite timestamps', () => {
|
|
250
|
+
const fb = createFrameBudget()
|
|
251
|
+
for (const m of ['beginFrame', 'endFrame'] as const) {
|
|
252
|
+
try {
|
|
253
|
+
fb[m](Number.NaN)
|
|
254
|
+
expect.fail('expected throw')
|
|
255
|
+
} catch (e) {
|
|
256
|
+
expect(isKLineChartError(e, 'INVALID_PARAM')).toBe(true)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
it('recentFrameMs is the rolling average over historySize frames', () => {
|
|
262
|
+
const fb = createFrameBudget({ historySize: 3 })
|
|
263
|
+
// 3 frames at 10ms each → avg 10
|
|
264
|
+
for (let i = 0; i < 3; i++) {
|
|
265
|
+
fb.beginFrame(i * 16)
|
|
266
|
+
fb.endFrame(i * 16 + 10)
|
|
267
|
+
}
|
|
268
|
+
expect(fb.recentFrameMs.peek()).toBe(10)
|
|
269
|
+
// Push one 20ms frame; rolling window drops the oldest.
|
|
270
|
+
fb.beginFrame(48)
|
|
271
|
+
fb.endFrame(68)
|
|
272
|
+
// window: [10, 10, 20] → avg ≈ 13.33
|
|
273
|
+
expect(fb.recentFrameMs.peek()).toBeCloseTo((10 + 10 + 20) / 3, 5)
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
it('overruns increments only when frame > targetMs', () => {
|
|
277
|
+
const fb = createFrameBudget({ targetMs: 16 })
|
|
278
|
+
// 10ms frame — not an overrun
|
|
279
|
+
fb.beginFrame(0)
|
|
280
|
+
fb.endFrame(10)
|
|
281
|
+
expect(fb.overruns.peek()).toBe(0)
|
|
282
|
+
// 18ms frame — overrun
|
|
283
|
+
fb.beginFrame(16)
|
|
284
|
+
fb.endFrame(34)
|
|
285
|
+
expect(fb.overruns.peek()).toBe(1)
|
|
286
|
+
// Exactly at targetMs — not an overrun (> strict)
|
|
287
|
+
fb.beginFrame(32)
|
|
288
|
+
fb.endFrame(48)
|
|
289
|
+
expect(fb.overruns.peek()).toBe(1)
|
|
290
|
+
})
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
// ---------------------------------------------------------------------------
|
|
294
|
+
// clear / dispose
|
|
295
|
+
// ---------------------------------------------------------------------------
|
|
296
|
+
|
|
297
|
+
describe('clear', () => {
|
|
298
|
+
it('drops all queued tasks', () => {
|
|
299
|
+
const fb = createFrameBudget()
|
|
300
|
+
fb.submit(record('a', [], 'high'))
|
|
301
|
+
fb.submit(record('b', [], 'low'))
|
|
302
|
+
fb.clear()
|
|
303
|
+
expect(fb.queueDepth.peek()).toBe(0)
|
|
304
|
+
})
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
describe('dispose', () => {
|
|
308
|
+
it('makes submit / flush / frame markers no-ops', () => {
|
|
309
|
+
const fb = createFrameBudget()
|
|
310
|
+
fb.dispose()
|
|
311
|
+
expect(() => fb.submit(record('a', [], 'high'))).not.toThrow()
|
|
312
|
+
expect(fb.queueDepth.peek()).toBe(0)
|
|
313
|
+
expect(fb.flush(Number.POSITIVE_INFINITY)).toBe(0)
|
|
314
|
+
})
|
|
315
|
+
})
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frame budget scheduler — adaptive workload manager.
|
|
3
|
+
*
|
|
4
|
+
* Real-time finance charts share a constraint with games and trading
|
|
5
|
+
* terminals: the renderer has a wall-clock budget per frame (16.67 ms
|
|
6
|
+
* at 60 fps, 6.94 ms at 144 fps), and exceeding it means dropped frames.
|
|
7
|
+
* Work that doesn't fit gets deferred to the next frame, but the work
|
|
8
|
+
* *queue* must not grow without bound — a stale indicator update is
|
|
9
|
+
* worse than a missed update.
|
|
10
|
+
*
|
|
11
|
+
* This module owns the policy. Consumers submit prioritised tasks;
|
|
12
|
+
* `flush(deadline)` drains as many as fit; the rest stay queued until
|
|
13
|
+
* the next call. A rolling-average frame-time signal lets components
|
|
14
|
+
* back off proactively rather than waiting for budget exhaustion.
|
|
15
|
+
*
|
|
16
|
+
* Pure data: no requestAnimationFrame, no performance.now() side effects.
|
|
17
|
+
* The host (browser / Node test / Deno) supplies the clock via a `now`
|
|
18
|
+
* function. Default: `performance.now()` if available, else `Date.now()`.
|
|
19
|
+
*
|
|
20
|
+
* const budget = createFrameBudget({ targetMs: 16 })
|
|
21
|
+
*
|
|
22
|
+
* // Host's rAF loop:
|
|
23
|
+
* function tick(t) {
|
|
24
|
+
* budget.beginFrame(t)
|
|
25
|
+
* budget.submit({ id: 'indicators', priority: 'high', work: recompute })
|
|
26
|
+
* budget.submit({ id: 'labels', priority: 'low', work: drawLabels })
|
|
27
|
+
* budget.flush(t + budget.targetMs)
|
|
28
|
+
* budget.endFrame(performance.now())
|
|
29
|
+
* requestAnimationFrame(tick)
|
|
30
|
+
* }
|
|
31
|
+
*
|
|
32
|
+
* // Consumers can read the load signal to back off:
|
|
33
|
+
* if (budget.recentFrameMs() > 18) skipLowPriorityWork()
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import { createSignal, type Signal } from '../reactivity'
|
|
37
|
+
import { KLineChartError } from '../errors'
|
|
38
|
+
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Public shape
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
export type TaskPriority = 'high' | 'medium' | 'low'
|
|
44
|
+
|
|
45
|
+
export interface FrameTask {
|
|
46
|
+
/** Stable id. Duplicate submissions with the same id are coalesced — the
|
|
47
|
+
* later submission's `work` and `priority` win. */
|
|
48
|
+
readonly id: string
|
|
49
|
+
readonly priority: TaskPriority
|
|
50
|
+
/** Synchronous unit of work. Throws are caught and logged but do NOT
|
|
51
|
+
* abort the frame; the task is dropped. */
|
|
52
|
+
readonly work: () => void
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface FrameBudgetOptions {
|
|
56
|
+
/** Target frame budget in milliseconds. Default 16 (≈60 fps). */
|
|
57
|
+
readonly targetMs?: number
|
|
58
|
+
/** Rolling window for `recentFrameMs`. Default 60 frames (1 s at 60 fps). */
|
|
59
|
+
readonly historySize?: number
|
|
60
|
+
/**
|
|
61
|
+
* Clock function. Default: `performance.now()` if available, else
|
|
62
|
+
* `Date.now()`. Injected for tests so timing is deterministic.
|
|
63
|
+
*/
|
|
64
|
+
readonly now?: () => number
|
|
65
|
+
/**
|
|
66
|
+
* Maximum queued tasks. Older low/medium tasks are dropped when the
|
|
67
|
+
* queue exceeds this. Default 256 — high enough that legitimate
|
|
68
|
+
* workloads never hit it, low enough that runaway producers fail loud.
|
|
69
|
+
*/
|
|
70
|
+
readonly maxQueueSize?: number
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface FrameBudget {
|
|
74
|
+
readonly targetMs: number
|
|
75
|
+
/** Current rolling-average frame time in ms. */
|
|
76
|
+
readonly recentFrameMs: Signal<number>
|
|
77
|
+
/** Number of tasks currently queued (not yet flushed). */
|
|
78
|
+
readonly queueDepth: Signal<number>
|
|
79
|
+
/** Frames whose work exceeded targetMs (cumulative). */
|
|
80
|
+
readonly overruns: Signal<number>
|
|
81
|
+
|
|
82
|
+
/** Mark the start of a frame. Pass `performance.now()` (or test clock). */
|
|
83
|
+
beginFrame(t: number): void
|
|
84
|
+
/** Queue a task. Coalesces on id (later submission wins). */
|
|
85
|
+
submit(task: FrameTask): void
|
|
86
|
+
/**
|
|
87
|
+
* Drain queued tasks until the deadline (absolute timestamp in the
|
|
88
|
+
* `now`-clock's scale). Returns the number of tasks completed.
|
|
89
|
+
*
|
|
90
|
+
* Tasks run in priority order: all `high` first, then `medium`, then
|
|
91
|
+
* `low`. Within a priority, FIFO. A task that throws is caught and
|
|
92
|
+
* dropped; remaining tasks continue.
|
|
93
|
+
*/
|
|
94
|
+
flush(deadlineAbs: number): number
|
|
95
|
+
/** Mark the end of a frame. Updates `recentFrameMs` + overrun count. */
|
|
96
|
+
endFrame(t: number): void
|
|
97
|
+
/** Drop all queued tasks. */
|
|
98
|
+
clear(): void
|
|
99
|
+
dispose(): void
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const PRIORITY_ORDER: ReadonlyArray<TaskPriority> = ['high', 'medium', 'low']
|
|
103
|
+
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// Internals
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
|
|
108
|
+
function defaultNow(): number {
|
|
109
|
+
const perf = (globalThis as { performance?: { now?: () => number } }).performance
|
|
110
|
+
if (typeof perf?.now === 'function') return perf.now()
|
|
111
|
+
return Date.now()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
// Factory
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
|
|
118
|
+
export function createFrameBudget(opts: FrameBudgetOptions = {}): FrameBudget {
|
|
119
|
+
const targetMs = opts.targetMs ?? 16
|
|
120
|
+
const historySize = opts.historySize ?? 60
|
|
121
|
+
const maxQueueSize = opts.maxQueueSize ?? 256
|
|
122
|
+
const now = opts.now ?? defaultNow
|
|
123
|
+
|
|
124
|
+
if (!(targetMs > 0) || !Number.isFinite(targetMs)) {
|
|
125
|
+
throw new KLineChartError('INVALID_PARAM', `createFrameBudget: targetMs must be > 0, got ${targetMs}`)
|
|
126
|
+
}
|
|
127
|
+
if (!(historySize > 0) || !Number.isInteger(historySize)) {
|
|
128
|
+
throw new KLineChartError(
|
|
129
|
+
'INVALID_PARAM',
|
|
130
|
+
`createFrameBudget: historySize must be a positive integer, got ${historySize}`,
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
if (!(maxQueueSize > 0) || !Number.isInteger(maxQueueSize)) {
|
|
134
|
+
throw new KLineChartError(
|
|
135
|
+
'INVALID_PARAM',
|
|
136
|
+
`createFrameBudget: maxQueueSize must be a positive integer, got ${maxQueueSize}`,
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const recentFrameMs = createSignal(0)
|
|
141
|
+
const queueDepth = createSignal(0)
|
|
142
|
+
const overruns = createSignal(0)
|
|
143
|
+
|
|
144
|
+
// One queue per priority; preserves FIFO inside a tier.
|
|
145
|
+
const queues: Record<TaskPriority, FrameTask[]> = {
|
|
146
|
+
high: [],
|
|
147
|
+
medium: [],
|
|
148
|
+
low: [],
|
|
149
|
+
}
|
|
150
|
+
// Reverse lookup so coalesce-by-id is O(1).
|
|
151
|
+
const byId = new Map<string, { tier: TaskPriority; index: number }>()
|
|
152
|
+
|
|
153
|
+
const frameTimes: number[] = []
|
|
154
|
+
let frameStart = 0
|
|
155
|
+
let disposed = false
|
|
156
|
+
|
|
157
|
+
function publishDepth(): void {
|
|
158
|
+
queueDepth.set(queues.high.length + queues.medium.length + queues.low.length)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function totalQueued(): number {
|
|
162
|
+
return queues.high.length + queues.medium.length + queues.low.length
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function dropOldestLowOrMedium(): void {
|
|
166
|
+
// Prefer dropping low first, then medium. We never drop high.
|
|
167
|
+
if (queues.low.length > 0) {
|
|
168
|
+
const dropped = queues.low.shift()!
|
|
169
|
+
byId.delete(dropped.id)
|
|
170
|
+
return
|
|
171
|
+
}
|
|
172
|
+
if (queues.medium.length > 0) {
|
|
173
|
+
const dropped = queues.medium.shift()!
|
|
174
|
+
byId.delete(dropped.id)
|
|
175
|
+
return
|
|
176
|
+
}
|
|
177
|
+
// Only high tasks remain. We don't drop high tasks for queue
|
|
178
|
+
// pressure; the producer is misbehaving. Surface via overruns
|
|
179
|
+
// signal so the host can decide.
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function submit(task: FrameTask): void {
|
|
183
|
+
if (disposed) return
|
|
184
|
+
if (task.id === '' || typeof task.id !== 'string') {
|
|
185
|
+
throw new KLineChartError(
|
|
186
|
+
'INVALID_PARAM',
|
|
187
|
+
`FrameBudget.submit: task.id must be a non-empty string`,
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
// Coalesce by id — replace existing entry.
|
|
191
|
+
const existing = byId.get(task.id)
|
|
192
|
+
if (existing !== undefined) {
|
|
193
|
+
queues[existing.tier][existing.index] = task
|
|
194
|
+
// The tier might be changing; if it is, we need to re-bucket.
|
|
195
|
+
if (existing.tier !== task.priority) {
|
|
196
|
+
// Mark old slot as a tombstone (we can't splice cheaply mid-iteration
|
|
197
|
+
// in some paths). The flush loop tolerates undefined entries.
|
|
198
|
+
;(queues[existing.tier] as Array<FrameTask | undefined>)[existing.index] = undefined
|
|
199
|
+
queues[task.priority].push(task)
|
|
200
|
+
byId.set(task.id, {
|
|
201
|
+
tier: task.priority,
|
|
202
|
+
index: queues[task.priority].length - 1,
|
|
203
|
+
})
|
|
204
|
+
}
|
|
205
|
+
publishDepth()
|
|
206
|
+
return
|
|
207
|
+
}
|
|
208
|
+
// Enforce maxQueueSize by dropping older low/medium first.
|
|
209
|
+
while (totalQueued() >= maxQueueSize) {
|
|
210
|
+
dropOldestLowOrMedium()
|
|
211
|
+
// If only high tasks left and we're still at the cap, bail.
|
|
212
|
+
if (totalQueued() >= maxQueueSize && queues.low.length === 0 && queues.medium.length === 0) {
|
|
213
|
+
break
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
queues[task.priority].push(task)
|
|
217
|
+
byId.set(task.id, {
|
|
218
|
+
tier: task.priority,
|
|
219
|
+
index: queues[task.priority].length - 1,
|
|
220
|
+
})
|
|
221
|
+
publishDepth()
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function flush(deadlineAbs: number): number {
|
|
225
|
+
if (disposed) return 0
|
|
226
|
+
let completed = 0
|
|
227
|
+
for (const tier of PRIORITY_ORDER) {
|
|
228
|
+
const q = queues[tier] as Array<FrameTask | undefined>
|
|
229
|
+
while (q.length > 0) {
|
|
230
|
+
if (now() >= deadlineAbs) {
|
|
231
|
+
// Compact the tier so later flushes skip tombstones.
|
|
232
|
+
queues[tier] = q.filter((t): t is FrameTask => t !== undefined)
|
|
233
|
+
// Rebuild byId indices for this tier.
|
|
234
|
+
for (let i = 0; i < queues[tier].length; i++) {
|
|
235
|
+
const t = queues[tier][i]!
|
|
236
|
+
byId.set(t.id, { tier, index: i })
|
|
237
|
+
}
|
|
238
|
+
publishDepth()
|
|
239
|
+
return completed
|
|
240
|
+
}
|
|
241
|
+
const task = q.shift()
|
|
242
|
+
if (task === undefined) continue // tombstone
|
|
243
|
+
byId.delete(task.id)
|
|
244
|
+
try {
|
|
245
|
+
task.work()
|
|
246
|
+
completed++
|
|
247
|
+
} catch {
|
|
248
|
+
// Task threw; drop it. We don't propagate — one
|
|
249
|
+
// bad task must not poison the frame.
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
publishDepth()
|
|
254
|
+
return completed
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function beginFrame(t: number): void {
|
|
258
|
+
if (disposed) return
|
|
259
|
+
if (!Number.isFinite(t)) {
|
|
260
|
+
throw new KLineChartError(
|
|
261
|
+
'INVALID_PARAM',
|
|
262
|
+
`FrameBudget.beginFrame: t must be finite, got ${t}`,
|
|
263
|
+
)
|
|
264
|
+
}
|
|
265
|
+
frameStart = t
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function endFrame(t: number): void {
|
|
269
|
+
if (disposed) return
|
|
270
|
+
if (!Number.isFinite(t)) {
|
|
271
|
+
throw new KLineChartError(
|
|
272
|
+
'INVALID_PARAM',
|
|
273
|
+
`FrameBudget.endFrame: t must be finite, got ${t}`,
|
|
274
|
+
)
|
|
275
|
+
}
|
|
276
|
+
const dur = Math.max(0, t - frameStart)
|
|
277
|
+
frameTimes.push(dur)
|
|
278
|
+
while (frameTimes.length > historySize) frameTimes.shift()
|
|
279
|
+
let sum = 0
|
|
280
|
+
for (const v of frameTimes) sum += v
|
|
281
|
+
recentFrameMs.set(sum / frameTimes.length)
|
|
282
|
+
if (dur > targetMs) overruns.set(overruns.peek() + 1)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function clear(): void {
|
|
286
|
+
if (disposed) return
|
|
287
|
+
queues.high = []
|
|
288
|
+
queues.medium = []
|
|
289
|
+
queues.low = []
|
|
290
|
+
byId.clear()
|
|
291
|
+
publishDepth()
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function dispose(): void {
|
|
295
|
+
if (disposed) return
|
|
296
|
+
disposed = true
|
|
297
|
+
queues.high = []
|
|
298
|
+
queues.medium = []
|
|
299
|
+
queues.low = []
|
|
300
|
+
byId.clear()
|
|
301
|
+
frameTimes.length = 0
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return {
|
|
305
|
+
targetMs,
|
|
306
|
+
recentFrameMs,
|
|
307
|
+
queueDepth,
|
|
308
|
+
overruns,
|
|
309
|
+
beginFrame,
|
|
310
|
+
submit,
|
|
311
|
+
flush,
|
|
312
|
+
endFrame,
|
|
313
|
+
clear,
|
|
314
|
+
dispose,
|
|
315
|
+
}
|
|
316
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { KLineChartError } from '../errors'
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Theme → CSS custom-property emitter.
|
|
3
5
|
*
|
|
@@ -103,7 +105,7 @@ export function themeToCssVars(
|
|
|
103
105
|
if (!prefix.startsWith('--')) {
|
|
104
106
|
// Misuse caught here is much friendlier than the silent no-op CSS
|
|
105
107
|
// would give downstream.
|
|
106
|
-
throw new
|
|
108
|
+
throw new KLineChartError('INVALID_PARAM',
|
|
107
109
|
`themeToCssVars: prefix must start with '--', got ${JSON.stringify(prefix)}`,
|
|
108
110
|
)
|
|
109
111
|
}
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = "0.8.
|
|
1
|
+
export const VERSION = "0.8.12"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"gotdx.d.ts","sourceRoot":"","sources":["../../../src/data-fetchers/gotdx/gotdx.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,UAAU,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"gotdx.js","sourceRoot":"","sources":["../../../src/data-fetchers/gotdx/gotdx.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,UAAU,CAAA"}
|