@363045841yyt/klinechart-core 0.8.11-alpha.1 → 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,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Footprint Chart — public type contract.
|
|
3
|
+
*
|
|
4
|
+
* A Footprint chart expands each candle internally to show, at every price
|
|
5
|
+
* level, how much aggressive buying (lifting the ASK) and aggressive selling
|
|
6
|
+
* (hitting the BID) traded. It is the core tool of "order flow" reading:
|
|
7
|
+
* traders use it to answer "did this bar rise because there were real buyers,
|
|
8
|
+
* or only because sellers withdrew?".
|
|
9
|
+
*
|
|
10
|
+
* This module owns the **data model + classification math only**. Rendering
|
|
11
|
+
* belongs to the `@klinechart-quant/core` Renderer/Scene layer; the planned
|
|
12
|
+
* GPU compute path is sketched in `computeShader.wgsl.md`.
|
|
13
|
+
*
|
|
14
|
+
* See `docs/ROADMAP.md` §3.3 (Footprint) for the algorithm rationale and §0
|
|
15
|
+
* for how this controller fits the seven-module core layering.
|
|
16
|
+
*
|
|
17
|
+
* Cross-references:
|
|
18
|
+
* - `aggressor.ts` — buy/sell classification (explicit, tick rule, Lee-Ready)
|
|
19
|
+
* - `perBarStats.ts` — delta, cumulative delta, diagonal imbalance
|
|
20
|
+
* - `createFootprintController.ts` — streaming controller (Signal<bars>)
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import type { Signal } from '../../reactivity'
|
|
24
|
+
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Aggressor classification — shared with `aggressor.ts`
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Which side of the resting book a trade hit.
|
|
31
|
+
*
|
|
32
|
+
* - 'buy' — aggressor lifted the ASK (resting seller was passive)
|
|
33
|
+
* - 'sell' — aggressor hit the BID (resting buyer was passive)
|
|
34
|
+
*
|
|
35
|
+
* Note: this is the **aggressor**'s side, NOT the "buyer"'s side. Binance's
|
|
36
|
+
* `isBuyerMaker=true` means the buyer was the maker (passive) and so the
|
|
37
|
+
* aggressor is the seller — see `classifyExplicit` in `aggressor.ts`.
|
|
38
|
+
*/
|
|
39
|
+
export type AggressorSide = 'buy' | 'sell'
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* A classification's confidence flag.
|
|
43
|
+
*
|
|
44
|
+
* - `inferred: false` — derived from an explicit exchange flag (zero error)
|
|
45
|
+
* - `inferred: true` — derived from a heuristic (tick rule or Lee-Ready);
|
|
46
|
+
* the consumer should mark this as approximate so it
|
|
47
|
+
* can be visually distinguished and excluded from
|
|
48
|
+
* strict order-flow analytics
|
|
49
|
+
*
|
|
50
|
+
* Every classifier in `aggressor.ts` must set this honestly. We rely on it
|
|
51
|
+
* downstream when surfacing "(estimated)" warnings on bars whose flow was
|
|
52
|
+
* inferred — this is the explicit boundary mandated by ROADMAP §3.3.
|
|
53
|
+
*/
|
|
54
|
+
export interface AggressorWithConfidence {
|
|
55
|
+
side: AggressorSide
|
|
56
|
+
inferred: boolean
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// Trade inputs
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* A single trade print. The minimum shape needed for footprint aggregation.
|
|
65
|
+
*
|
|
66
|
+
* `timestamp` is epoch ms (chosen because `Math.floor(ts / barIntervalMs)`
|
|
67
|
+
* cleanly produces a bar index). `size` is in base units (BTC, AAPL shares,
|
|
68
|
+
* not USD value).
|
|
69
|
+
*/
|
|
70
|
+
export interface Trade {
|
|
71
|
+
timestamp: number
|
|
72
|
+
price: number
|
|
73
|
+
size: number
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* A trade carrying the exchange's aggressor flag. Binance-style:
|
|
78
|
+
* `isBuyerMaker=true` ⇒ the buyer was the passive maker, so the SELLER was
|
|
79
|
+
* the aggressor. Optional — if the exchange does not include it the
|
|
80
|
+
* controller falls back to the configured heuristic classifier.
|
|
81
|
+
*/
|
|
82
|
+
export interface TradeWithFlag extends Trade {
|
|
83
|
+
isBuyerMaker?: boolean
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
// Bar shape
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* One price level inside a footprint bar.
|
|
92
|
+
*
|
|
93
|
+
* Cells are sorted by `price` ascending. `askVol` and `bidVol` are gross
|
|
94
|
+
* (not net) — the delta is computed separately.
|
|
95
|
+
*/
|
|
96
|
+
export interface FootprintBarCell {
|
|
97
|
+
/** representative price of the bin (quantised to tickSize). */
|
|
98
|
+
price: number
|
|
99
|
+
/** volume of trades classified as `buy` (aggressor lifted the ASK). */
|
|
100
|
+
askVol: number
|
|
101
|
+
/** volume of trades classified as `sell` (aggressor hit the BID). */
|
|
102
|
+
bidVol: number
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Direction of a diagonal imbalance — see `perBarStats.ts` for the math.
|
|
107
|
+
*/
|
|
108
|
+
export type ImbalanceDirection = 'buy-imbalance' | 'sell-imbalance'
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* One imbalance flag inside a bar.
|
|
112
|
+
*
|
|
113
|
+
* `priceIndex` is the index into `FootprintBar.cells` of the dominant side
|
|
114
|
+
* (not the cell it was compared against). `ratio` is `dominant / weaker`
|
|
115
|
+
* (always ≥ the configured threshold; capped at `Number.POSITIVE_INFINITY`
|
|
116
|
+
* when the weaker side is zero — see `computeDiagonalImbalances`).
|
|
117
|
+
*/
|
|
118
|
+
export interface FootprintImbalance {
|
|
119
|
+
priceIndex: number
|
|
120
|
+
direction: ImbalanceDirection
|
|
121
|
+
ratio: number
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* The materialised view of one bar (the unit a renderer consumes).
|
|
126
|
+
*
|
|
127
|
+
* All fields are derived from the controller's internal streaming aggregate;
|
|
128
|
+
* `cells` and `imbalances` are recomputed lazily on `bars` signal read.
|
|
129
|
+
*/
|
|
130
|
+
export interface FootprintBar {
|
|
131
|
+
/** stable index = `Math.floor(timestamp / barIntervalMs)`. */
|
|
132
|
+
barIndex: number
|
|
133
|
+
/** inclusive start of the bar window (epoch ms). */
|
|
134
|
+
startTime: number
|
|
135
|
+
/** exclusive end of the bar window (epoch ms). */
|
|
136
|
+
endTime: number
|
|
137
|
+
/** per-price-level cells, ascending by `price`. */
|
|
138
|
+
cells: ReadonlyArray<FootprintBarCell>
|
|
139
|
+
/** Σ(askVol − bidVol) across cells. Positive ⇒ buyers led. */
|
|
140
|
+
delta: number
|
|
141
|
+
/** Σ(askVol + bidVol). */
|
|
142
|
+
totalVolume: number
|
|
143
|
+
/** diagonal imbalance flags; usually 0–5 per bar. */
|
|
144
|
+
imbalances: ReadonlyArray<FootprintImbalance>
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ---------------------------------------------------------------------------
|
|
148
|
+
// Configuration
|
|
149
|
+
// ---------------------------------------------------------------------------
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Controller config. All fields required at the controller surface — the
|
|
153
|
+
* factory fills missing fields with sensible defaults so callers can pass
|
|
154
|
+
* a partial.
|
|
155
|
+
*/
|
|
156
|
+
export interface FootprintConfig {
|
|
157
|
+
/** quantise trade prices to this tick size (e.g. 0.01 for BTCUSDT). */
|
|
158
|
+
tickSize: number
|
|
159
|
+
/** ms per bar (e.g. 60_000 for 1m). */
|
|
160
|
+
barIntervalMs: number
|
|
161
|
+
/**
|
|
162
|
+
* Diagonal imbalance threshold. Default 3 — i.e. a cell must have at
|
|
163
|
+
* least 3× the volume of its diagonal counterpart to flag.
|
|
164
|
+
*/
|
|
165
|
+
imbalanceRatio: number
|
|
166
|
+
/**
|
|
167
|
+
* Classifier to fall back to when a trade has no explicit
|
|
168
|
+
* `isBuyerMaker` flag.
|
|
169
|
+
*
|
|
170
|
+
* - 'tick-rule' — price-change rule; default. Doesn't need bid/ask.
|
|
171
|
+
* - 'lee-ready' — uses bid/ask; controller's `ingestTrade` must
|
|
172
|
+
* receive `bid` and `ask` for this path.
|
|
173
|
+
*/
|
|
174
|
+
fallbackClassifier: 'tick-rule' | 'lee-ready'
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
// Controller interface
|
|
179
|
+
// ---------------------------------------------------------------------------
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Framework-agnostic controller — mirrors `IndicatorSelectorController`'s
|
|
183
|
+
* shape (signals for state, plain functions for mutations, idempotent
|
|
184
|
+
* `dispose`).
|
|
185
|
+
*/
|
|
186
|
+
export interface FootprintController {
|
|
187
|
+
/** Current config; re-emits when `setConfig` is called. */
|
|
188
|
+
readonly config: Signal<FootprintConfig>
|
|
189
|
+
/** Materialised bars, ascending by `barIndex`. Empty before first trade. */
|
|
190
|
+
readonly bars: Signal<ReadonlyArray<FootprintBar>>
|
|
191
|
+
/**
|
|
192
|
+
* Cumulative delta series, parallel to `bars`. `cumulativeDelta[i]`
|
|
193
|
+
* corresponds to `bars[i]`.
|
|
194
|
+
*/
|
|
195
|
+
readonly cumulativeDelta: Signal<ReadonlyArray<number>>
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Ingest one trade — canonical method, aligned with the cross-controller
|
|
199
|
+
* `ingest()` convention (VolumeProfile, OrderBookHeatmap). `bid`/`ask` are
|
|
200
|
+
* optional and only consulted when the trade lacks an explicit
|
|
201
|
+
* `isBuyerMaker` flag AND the configured fallback is `lee-ready`.
|
|
202
|
+
*
|
|
203
|
+
* Closes API-audit BLOCKER-001 (5-verb intake proliferation) by
|
|
204
|
+
* harmonising on `ingest` as the stream-accumulator verb across
|
|
205
|
+
* `VolumeProfile`, `OrderBookHeatmap`, and `Footprint`.
|
|
206
|
+
*/
|
|
207
|
+
ingest(trade: TradeWithFlag, bid?: number, ask?: number): void
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* @deprecated since 0.1.0-alpha.1 — use {@link FootprintController.ingest}.
|
|
211
|
+
* Kept as a non-removing alias for at least 6 months for migration. Will
|
|
212
|
+
* be removed in 0.2.0.
|
|
213
|
+
*/
|
|
214
|
+
ingestTrade(trade: TradeWithFlag, bid?: number, ask?: number): void
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Patch the config. Changing `barIntervalMs` or `tickSize` invalidates
|
|
218
|
+
* the buckets so the state is cleared. Changing only `imbalanceRatio`
|
|
219
|
+
* just re-materialises on the next read.
|
|
220
|
+
*/
|
|
221
|
+
setConfig(next: Partial<FootprintConfig>): void
|
|
222
|
+
|
|
223
|
+
/** Clear all bars and cumulative delta. Does not change config. */
|
|
224
|
+
reset(): void
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Stop emitting. Subsequent calls to ingest/setConfig/reset are silent
|
|
228
|
+
* no-ops; previously-attached subscribers receive no further
|
|
229
|
+
* notifications. Idempotent.
|
|
230
|
+
*/
|
|
231
|
+
dispose(): void
|
|
232
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* alignToBaseIndex tests — forward fill + strict no-lookahead.
|
|
3
|
+
*
|
|
4
|
+
* The lookahead test is the load-bearing one: a naive implementation that
|
|
5
|
+
* uses `floor(t / targetIntervalMs) * targetIntervalMs` to pick the bar
|
|
6
|
+
* would expose future state. This file pins that out.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, it, expect } from 'vitest'
|
|
10
|
+
import { alignToBaseIndex } from '../alignToBaseIndex'
|
|
11
|
+
|
|
12
|
+
const HOUR = 60 * 60_000
|
|
13
|
+
const MIN_5 = 5 * 60_000
|
|
14
|
+
|
|
15
|
+
const ts = (ms: number): { timestamp: number } => ({ timestamp: ms })
|
|
16
|
+
|
|
17
|
+
describe('alignToBaseIndex — basic behavior', () => {
|
|
18
|
+
it('empty base bars → []', () => {
|
|
19
|
+
expect(alignToBaseIndex([], [ts(0)], [42], HOUR)).toEqual([])
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('empty higher-tf series → all nulls', () => {
|
|
23
|
+
const base = [ts(0), ts(MIN_5), ts(2 * MIN_5)]
|
|
24
|
+
expect(alignToBaseIndex(base, [], [], HOUR)).toEqual([null, null, null])
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('throws if higherTfBars and higherTfValues length differ', () => {
|
|
28
|
+
expect(() => alignToBaseIndex([ts(0)], [ts(0)], [1, 2], HOUR)).toThrow(/length/)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('throws on non-positive targetIntervalMs', () => {
|
|
32
|
+
expect(() => alignToBaseIndex([ts(0)], [ts(0)], [1], 0)).toThrow(/positive/)
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
describe('alignToBaseIndex — no-lookahead (critical)', () => {
|
|
37
|
+
it('base bar at hbar.timestamp reads that hbar value', () => {
|
|
38
|
+
const hbars = [ts(HOUR)] // hbar opens at 09:00 in arbitrary epoch terms
|
|
39
|
+
const values = [100]
|
|
40
|
+
const base = [ts(HOUR)]
|
|
41
|
+
expect(alignToBaseIndex(base, hbars, values, HOUR)).toEqual([100])
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('base bar 1ms BEFORE hbar.timestamp gets null (no lookahead)', () => {
|
|
45
|
+
const hbars = [ts(HOUR)]
|
|
46
|
+
const values = [100]
|
|
47
|
+
const base = [ts(HOUR - 1)]
|
|
48
|
+
expect(alignToBaseIndex(base, hbars, values, HOUR)).toEqual([null])
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('base bar deep inside hbar interval reads that hbar value', () => {
|
|
52
|
+
const hbars = [ts(HOUR)]
|
|
53
|
+
const values = [100]
|
|
54
|
+
const base = [ts(HOUR + 30 * 60_000)] // 30 min into the hour
|
|
55
|
+
expect(alignToBaseIndex(base, hbars, values, HOUR)).toEqual([100])
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('base bar at hbar.timestamp + targetIntervalMs (next bucket open) reads NEXT hbar', () => {
|
|
59
|
+
const hbars = [ts(HOUR), ts(2 * HOUR)]
|
|
60
|
+
const values = [100, 200]
|
|
61
|
+
const base = [ts(2 * HOUR)]
|
|
62
|
+
expect(alignToBaseIndex(base, hbars, values, HOUR)).toEqual([200])
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
describe('alignToBaseIndex — forward fill across many base bars', () => {
|
|
67
|
+
it('a 1h hbar covers all 12 of the 5m base bars inside it', () => {
|
|
68
|
+
const hbars = [ts(HOUR)]
|
|
69
|
+
const values = ['hot']
|
|
70
|
+
const base: { timestamp: number }[] = []
|
|
71
|
+
for (let i = 0; i < 12; i++) base.push(ts(HOUR + i * MIN_5))
|
|
72
|
+
const out = alignToBaseIndex(base, hbars, values, HOUR)
|
|
73
|
+
expect(out).toEqual(new Array(12).fill('hot'))
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('multiple hbars switch correctly at boundaries', () => {
|
|
77
|
+
const hbars = [ts(HOUR), ts(2 * HOUR), ts(3 * HOUR)]
|
|
78
|
+
const values = ['a', 'b', 'c']
|
|
79
|
+
const base = [
|
|
80
|
+
ts(HOUR),
|
|
81
|
+
ts(HOUR + 30 * 60_000),
|
|
82
|
+
ts(2 * HOUR),
|
|
83
|
+
ts(2 * HOUR + 30 * 60_000),
|
|
84
|
+
ts(3 * HOUR),
|
|
85
|
+
]
|
|
86
|
+
expect(alignToBaseIndex(base, hbars, values, HOUR)).toEqual(['a', 'a', 'b', 'b', 'c'])
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('gap in hbars — base bars in the gap forward-fill the prior hbar', () => {
|
|
90
|
+
// hbar1 at 09:00, hbar2 at 11:00. base bar at 10:30 → forward-fill 'a'.
|
|
91
|
+
const hbars = [ts(HOUR), ts(3 * HOUR)]
|
|
92
|
+
const values = ['a', 'b']
|
|
93
|
+
const base = [ts(2 * HOUR + 30 * 60_000)]
|
|
94
|
+
expect(alignToBaseIndex(base, hbars, values, HOUR)).toEqual(['a'])
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('leading base bars before first hbar are all null', () => {
|
|
98
|
+
const hbars = [ts(HOUR)]
|
|
99
|
+
const values = ['x']
|
|
100
|
+
const base = [ts(0), ts(MIN_5), ts(HOUR)]
|
|
101
|
+
expect(alignToBaseIndex(base, hbars, values, HOUR)).toEqual([null, null, 'x'])
|
|
102
|
+
})
|
|
103
|
+
})
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MTF controller tests — series CRUD, recompute on mutation, EMA on a 1h
|
|
3
|
+
* overlay against 5m bars.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
7
|
+
import { createMtfController } from '../createMtfController'
|
|
8
|
+
import type { BaseBar, ResampledBar } from '../types'
|
|
9
|
+
|
|
10
|
+
const MIN = 60_000
|
|
11
|
+
const FIVE_MIN = 5 * MIN
|
|
12
|
+
const HOUR = 60 * MIN
|
|
13
|
+
|
|
14
|
+
function bar(tsMs: number, c: number, v = 10): BaseBar {
|
|
15
|
+
return { timestamp: tsMs, open: c, high: c, low: c, close: c, volume: v }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** A trivial "last close" compute fn for asserting against. */
|
|
19
|
+
const lastClose = (rs: ReadonlyArray<ResampledBar>): number[] => rs.map((r) => r.close)
|
|
20
|
+
|
|
21
|
+
describe('createMtfController — CRUD + recompute', () => {
|
|
22
|
+
it('addSeries returns id and series signal fires', () => {
|
|
23
|
+
const ctl = createMtfController({
|
|
24
|
+
initialBars: [bar(0, 100), bar(FIVE_MIN, 101)],
|
|
25
|
+
baseIntervalMs: FIVE_MIN,
|
|
26
|
+
})
|
|
27
|
+
const listener = vi.fn()
|
|
28
|
+
ctl.series.subscribe(listener)
|
|
29
|
+
const id = ctl.addSeries({
|
|
30
|
+
id: 'lastClose-1h',
|
|
31
|
+
label: 'last close 1h',
|
|
32
|
+
targetIntervalMs: HOUR,
|
|
33
|
+
compute: lastClose,
|
|
34
|
+
})
|
|
35
|
+
expect(id).toBe('lastClose-1h')
|
|
36
|
+
expect(listener).toHaveBeenCalled()
|
|
37
|
+
expect(ctl.series()).toHaveLength(1)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('addSeries with duplicate id throws', () => {
|
|
41
|
+
const ctl = createMtfController({
|
|
42
|
+
initialBars: [bar(0, 100)],
|
|
43
|
+
baseIntervalMs: FIVE_MIN,
|
|
44
|
+
})
|
|
45
|
+
ctl.addSeries({ id: 'a', label: 'a', targetIntervalMs: HOUR, compute: lastClose })
|
|
46
|
+
expect(() =>
|
|
47
|
+
ctl.addSeries({ id: 'a', label: 'a2', targetIntervalMs: HOUR, compute: lastClose }),
|
|
48
|
+
).toThrow(/already in use/)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('addSeries with targetIntervalMs not a multiple of baseIntervalMs throws', () => {
|
|
52
|
+
const ctl = createMtfController({
|
|
53
|
+
initialBars: [bar(0, 100)],
|
|
54
|
+
baseIntervalMs: FIVE_MIN,
|
|
55
|
+
})
|
|
56
|
+
expect(() =>
|
|
57
|
+
ctl.addSeries({ id: 'a', label: 'a', targetIntervalMs: 7 * MIN, compute: lastClose }),
|
|
58
|
+
).toThrow(/multiple/)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('removeSeries returns true if found, false otherwise', () => {
|
|
62
|
+
const ctl = createMtfController({
|
|
63
|
+
initialBars: [bar(0, 100)],
|
|
64
|
+
baseIntervalMs: FIVE_MIN,
|
|
65
|
+
})
|
|
66
|
+
ctl.addSeries({ id: 'a', label: 'a', targetIntervalMs: HOUR, compute: lastClose })
|
|
67
|
+
expect(ctl.removeSeries('a')).toBe(true)
|
|
68
|
+
expect(ctl.removeSeries('a')).toBe(false)
|
|
69
|
+
expect(ctl.series()).toHaveLength(0)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('updateSeries patches compute fn and re-runs it', () => {
|
|
73
|
+
const ctl = createMtfController({
|
|
74
|
+
initialBars: [bar(0, 100), bar(FIVE_MIN, 200)],
|
|
75
|
+
baseIntervalMs: FIVE_MIN,
|
|
76
|
+
})
|
|
77
|
+
ctl.addSeries({ id: 'a', label: 'a', targetIntervalMs: FIVE_MIN, compute: lastClose })
|
|
78
|
+
const beforeValues = ctl.series()[0]!.alignedValues
|
|
79
|
+
expect(beforeValues).toEqual([100, 200])
|
|
80
|
+
ctl.updateSeries('a', { compute: (rs) => rs.map(() => 42) })
|
|
81
|
+
expect(ctl.series()[0]!.alignedValues).toEqual([42, 42])
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
describe('createMtfController — alignment correctness', () => {
|
|
86
|
+
it('lifts a 1h compute onto 5m base bars (12 base bars share one hbar value)', () => {
|
|
87
|
+
const base: BaseBar[] = []
|
|
88
|
+
for (let i = 0; i < 12; i++) base.push(bar(i * FIVE_MIN, 100 + i))
|
|
89
|
+
const ctl = createMtfController({
|
|
90
|
+
initialBars: base,
|
|
91
|
+
baseIntervalMs: FIVE_MIN,
|
|
92
|
+
})
|
|
93
|
+
ctl.addSeries({
|
|
94
|
+
id: 'a',
|
|
95
|
+
label: 'last close 1h',
|
|
96
|
+
targetIntervalMs: HOUR,
|
|
97
|
+
compute: lastClose,
|
|
98
|
+
})
|
|
99
|
+
// All 12 base bars should see the same value — the close of the
|
|
100
|
+
// single 1h resampled bar covering 0..59 min, which is base[11].close = 111
|
|
101
|
+
const aligned = ctl.series()[0]!.alignedValues
|
|
102
|
+
expect(aligned).toEqual(new Array(12).fill(111))
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
it('appendBaseBar extends aligned series by exactly one entry', () => {
|
|
106
|
+
const base: BaseBar[] = [bar(0, 100)]
|
|
107
|
+
const ctl = createMtfController({ initialBars: base, baseIntervalMs: FIVE_MIN })
|
|
108
|
+
ctl.addSeries({
|
|
109
|
+
id: 'a',
|
|
110
|
+
label: 'a',
|
|
111
|
+
targetIntervalMs: FIVE_MIN,
|
|
112
|
+
compute: lastClose,
|
|
113
|
+
})
|
|
114
|
+
expect(ctl.series()[0]!.alignedValues).toEqual([100])
|
|
115
|
+
ctl.appendBaseBar(bar(FIVE_MIN, 200))
|
|
116
|
+
expect(ctl.series()[0]!.alignedValues).toEqual([100, 200])
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
it('two series at different higher TFs co-exist independently', () => {
|
|
120
|
+
const base: BaseBar[] = []
|
|
121
|
+
for (let i = 0; i < 12; i++) base.push(bar(i * FIVE_MIN, 100 + i))
|
|
122
|
+
const ctl = createMtfController({ initialBars: base, baseIntervalMs: FIVE_MIN })
|
|
123
|
+
ctl.addSeries({ id: '5m', label: '5m', targetIntervalMs: FIVE_MIN, compute: lastClose })
|
|
124
|
+
ctl.addSeries({ id: '1h', label: '1h', targetIntervalMs: HOUR, compute: lastClose })
|
|
125
|
+
|
|
126
|
+
const series = ctl.series()
|
|
127
|
+
expect(series).toHaveLength(2)
|
|
128
|
+
const fiveM = series.find((s) => s.definition.id === '5m')!
|
|
129
|
+
const oneH = series.find((s) => s.definition.id === '1h')!
|
|
130
|
+
// 5m series: each base bar reads its own close
|
|
131
|
+
expect(fiveM.alignedValues).toEqual(base.map((b) => b.close))
|
|
132
|
+
// 1h series: all 12 read the close of the single 1h bar = 111
|
|
133
|
+
expect(oneH.alignedValues).toEqual(new Array(12).fill(111))
|
|
134
|
+
})
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
describe('createMtfController — config + lifecycle', () => {
|
|
138
|
+
it('setBaseBars rebuilds all series', () => {
|
|
139
|
+
const ctl = createMtfController({
|
|
140
|
+
initialBars: [bar(0, 100)],
|
|
141
|
+
baseIntervalMs: FIVE_MIN,
|
|
142
|
+
})
|
|
143
|
+
ctl.addSeries({ id: 'a', label: 'a', targetIntervalMs: FIVE_MIN, compute: lastClose })
|
|
144
|
+
expect(ctl.series()[0]!.alignedValues).toEqual([100])
|
|
145
|
+
ctl.setBaseBars([bar(0, 1), bar(FIVE_MIN, 2)], FIVE_MIN)
|
|
146
|
+
expect(ctl.series()[0]!.alignedValues).toEqual([1, 2])
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
it('setBaseBars throws if an existing series target no longer cleanly divides', () => {
|
|
150
|
+
const ctl = createMtfController({
|
|
151
|
+
initialBars: [bar(0, 100)],
|
|
152
|
+
baseIntervalMs: FIVE_MIN,
|
|
153
|
+
})
|
|
154
|
+
ctl.addSeries({ id: 'a', label: 'a', targetIntervalMs: HOUR, compute: lastClose })
|
|
155
|
+
// Changing base to 7-minute bars makes 1h (3_600_000) no longer divisible by 7m (420_000)
|
|
156
|
+
expect(() => ctl.setBaseBars([bar(0, 1)], 7 * MIN)).toThrow(/cleanly divide/)
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('dispose silences subsequent mutators', () => {
|
|
160
|
+
const ctl = createMtfController({
|
|
161
|
+
initialBars: [bar(0, 100)],
|
|
162
|
+
baseIntervalMs: FIVE_MIN,
|
|
163
|
+
})
|
|
164
|
+
const listener = vi.fn()
|
|
165
|
+
ctl.series.subscribe(listener)
|
|
166
|
+
ctl.dispose()
|
|
167
|
+
const beforeCalls = listener.mock.calls.length
|
|
168
|
+
ctl.addSeries({ id: 'a', label: 'a', targetIntervalMs: FIVE_MIN, compute: lastClose })
|
|
169
|
+
ctl.appendBaseBar(bar(FIVE_MIN, 200))
|
|
170
|
+
expect(listener.mock.calls.length).toBe(beforeCalls)
|
|
171
|
+
})
|
|
172
|
+
})
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* resampleBars tests — bucketing math, partial bars, gap handling.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect } from 'vitest'
|
|
6
|
+
import { resampleBars } from '../resampleBars'
|
|
7
|
+
import type { BaseBar } from '../types'
|
|
8
|
+
|
|
9
|
+
const min = 60_000
|
|
10
|
+
const hour = 60 * min
|
|
11
|
+
|
|
12
|
+
function bar(tsMs: number, o: number, h: number, l: number, c: number, v = 100): BaseBar {
|
|
13
|
+
return { timestamp: tsMs, open: o, high: h, low: l, close: c, volume: v }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
describe('resampleBars — input validation', () => {
|
|
17
|
+
it('throws when targetIntervalMs is not a multiple of baseIntervalMs', () => {
|
|
18
|
+
// 1.5 min is not an integer multiple of 1 min
|
|
19
|
+
expect(() => resampleBars([], min, min + 30_000)).toThrow(/integer multiple/)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('throws on non-positive intervals', () => {
|
|
23
|
+
expect(() => resampleBars([], 0, hour)).toThrow(/positive/)
|
|
24
|
+
expect(() => resampleBars([], min, -hour)).toThrow(/positive/)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('returns [] for empty input', () => {
|
|
28
|
+
expect(resampleBars([], min, hour)).toEqual([])
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('targetIntervalMs === baseIntervalMs returns 1-to-1 wrapped bars', () => {
|
|
32
|
+
const bars = [bar(0, 1, 2, 0.5, 1.5), bar(min, 1.5, 3, 1, 2)]
|
|
33
|
+
const out = resampleBars(bars, min, min)
|
|
34
|
+
expect(out).toHaveLength(2)
|
|
35
|
+
expect(out[0]!.sourceStart).toBe(0)
|
|
36
|
+
expect(out[0]!.sourceEnd).toBe(0)
|
|
37
|
+
expect(out[0]!.open).toBe(1)
|
|
38
|
+
expect(out[1]!.sourceStart).toBe(1)
|
|
39
|
+
})
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
describe('resampleBars — aggregation rules', () => {
|
|
43
|
+
it('60 1m bars → 1 1h bar with correct OHLCV', () => {
|
|
44
|
+
const bars: BaseBar[] = []
|
|
45
|
+
for (let i = 0; i < 60; i++) {
|
|
46
|
+
bars.push(bar(i * min, 100 + i, 101 + i, 99 + i, 100 + i + 0.5, 10))
|
|
47
|
+
}
|
|
48
|
+
const out = resampleBars(bars, min, hour)
|
|
49
|
+
expect(out).toHaveLength(1)
|
|
50
|
+
expect(out[0]!.open).toBe(100)
|
|
51
|
+
expect(out[0]!.close).toBe(159.5)
|
|
52
|
+
expect(out[0]!.high).toBe(160) // 101 + 59
|
|
53
|
+
expect(out[0]!.low).toBe(99)
|
|
54
|
+
expect(out[0]!.volume).toBe(600)
|
|
55
|
+
expect(out[0]!.sourceStart).toBe(0)
|
|
56
|
+
expect(out[0]!.sourceEnd).toBe(59)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('60 1m bars → 12 5m bars', () => {
|
|
60
|
+
const bars: BaseBar[] = []
|
|
61
|
+
for (let i = 0; i < 60; i++) {
|
|
62
|
+
bars.push(bar(i * min, 100, 101, 99, 100, 10))
|
|
63
|
+
}
|
|
64
|
+
const out = resampleBars(bars, min, 5 * min)
|
|
65
|
+
expect(out).toHaveLength(12)
|
|
66
|
+
for (const b of out) {
|
|
67
|
+
expect(b.volume).toBe(50)
|
|
68
|
+
expect(b.sourceEnd - b.sourceStart + 1).toBe(5)
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('partial final bucket is emitted (forming-bar visibility)', () => {
|
|
73
|
+
// 65 1m bars → 1 full 1h + 1 partial 1h (5 minutes)
|
|
74
|
+
const bars: BaseBar[] = []
|
|
75
|
+
for (let i = 0; i < 65; i++) {
|
|
76
|
+
bars.push(bar(i * min, 100, 101, 99, 100, 10))
|
|
77
|
+
}
|
|
78
|
+
const out = resampleBars(bars, min, hour)
|
|
79
|
+
expect(out).toHaveLength(2)
|
|
80
|
+
expect(out[1]!.sourceStart).toBe(60)
|
|
81
|
+
expect(out[1]!.sourceEnd).toBe(64)
|
|
82
|
+
expect(out[1]!.volume).toBe(50)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('single base bar produces a single (partial) output bar', () => {
|
|
86
|
+
const out = resampleBars([bar(0, 1, 2, 0.5, 1.5)], min, hour)
|
|
87
|
+
expect(out).toHaveLength(1)
|
|
88
|
+
expect(out[0]!.sourceStart).toBe(0)
|
|
89
|
+
expect(out[0]!.sourceEnd).toBe(0)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
it('input gap does not create a synthetic bucket; the missing minute is just absent', () => {
|
|
93
|
+
// 09:30, 09:31, [skip 09:32], 09:33, 09:34 → all fold into the same 5m bucket starting 09:30
|
|
94
|
+
const bars = [
|
|
95
|
+
bar(0, 100, 100, 100, 100, 10),
|
|
96
|
+
bar(min, 100, 100, 100, 100, 10),
|
|
97
|
+
bar(3 * min, 100, 100, 100, 100, 10),
|
|
98
|
+
bar(4 * min, 100, 100, 100, 100, 10),
|
|
99
|
+
]
|
|
100
|
+
const out = resampleBars(bars, min, 5 * min)
|
|
101
|
+
expect(out).toHaveLength(1)
|
|
102
|
+
expect(out[0]!.volume).toBe(40) // 4 bars × 10
|
|
103
|
+
expect(out[0]!.sourceStart).toBe(0)
|
|
104
|
+
expect(out[0]!.sourceEnd).toBe(3)
|
|
105
|
+
})
|
|
106
|
+
})
|