@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,97 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { createOriginShiftPolicy } from '../originShift'
|
|
3
|
+
|
|
4
|
+
describe('createOriginShiftPolicy', () => {
|
|
5
|
+
it('starts with ref equal to initialRef', () => {
|
|
6
|
+
const p = createOriginShiftPolicy(67000)
|
|
7
|
+
expect(p.ref).toBe(67000)
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
it('shift(value) returns value - ref', () => {
|
|
11
|
+
const p = createOriginShiftPolicy(67000)
|
|
12
|
+
expect(p.shift(67000.5)).toBeCloseTo(0.5, 10)
|
|
13
|
+
expect(p.shift(66999.25)).toBeCloseTo(-0.75, 10)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('below threshold → no rebase (uses required 0.005 normalized drift, threshold default 0.01)', () => {
|
|
17
|
+
// Visible range 100, mid drifts to 100.5 → drift = 0.5, normalized 0.005 (= 0.5 / 100).
|
|
18
|
+
// Default threshold 0.01 → 0.005 is BELOW → no rebase.
|
|
19
|
+
const p = createOriginShiftPolicy(100)
|
|
20
|
+
const changed = p.maybeRebaseline(100.5, 100)
|
|
21
|
+
expect(changed).toBe(false)
|
|
22
|
+
expect(p.ref).toBe(100)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('above threshold → rebase to new mid (uses required 0.02 normalized drift)', () => {
|
|
26
|
+
// Visible range 100, mid drifts to 102 → drift 2, normalized 0.02 (= 2 / 100).
|
|
27
|
+
// 0.02 > 0.01 → REBASE.
|
|
28
|
+
const p = createOriginShiftPolicy(100)
|
|
29
|
+
const changed = p.maybeRebaseline(102, 100)
|
|
30
|
+
expect(changed).toBe(true)
|
|
31
|
+
expect(p.ref).toBe(102)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('threshold === 0 → always rebases when there is any drift', () => {
|
|
35
|
+
const p = createOriginShiftPolicy(50, 0)
|
|
36
|
+
// Any drift at all triggers the rebase.
|
|
37
|
+
expect(p.maybeRebaseline(50.0001, 100)).toBe(true)
|
|
38
|
+
expect(p.ref).toBe(50.0001)
|
|
39
|
+
// ...but a zero-drift call still doesn't rebase (division yields 0, which
|
|
40
|
+
// is not > 0).
|
|
41
|
+
expect(p.maybeRebaseline(50.0001, 100)).toBe(false)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('threshold === 1 → never rebases for any in-range drift', () => {
|
|
45
|
+
const p = createOriginShiftPolicy(50, 1)
|
|
46
|
+
// Even a near-full-range drift can't exceed 1.
|
|
47
|
+
expect(p.maybeRebaseline(149, 100)).toBe(false)
|
|
48
|
+
expect(p.ref).toBe(50)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('multiple maybeRebaseline calls produce monotonic ref tracking the drift', () => {
|
|
52
|
+
const p = createOriginShiftPolicy(0, 0.01)
|
|
53
|
+
const history: number[] = []
|
|
54
|
+
|
|
55
|
+
// Walk the mid forward in 0.02 * range steps; each step crosses the threshold.
|
|
56
|
+
let mid = 0
|
|
57
|
+
const range = 100
|
|
58
|
+
for (let i = 0; i < 10; i++) {
|
|
59
|
+
mid += 0.02 * range // +2 per step → 0.02 normalized → above threshold
|
|
60
|
+
if (p.maybeRebaseline(mid, range)) history.push(p.ref)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
expect(history.length).toBe(10)
|
|
64
|
+
// All recorded refs must be strictly increasing.
|
|
65
|
+
for (let i = 1; i < history.length; i++) {
|
|
66
|
+
expect(history[i]).toBeGreaterThan(history[i - 1])
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('degenerate range (currentRange <= 0) refuses to rebase', () => {
|
|
71
|
+
const p = createOriginShiftPolicy(50)
|
|
72
|
+
expect(p.maybeRebaseline(60, 0)).toBe(false)
|
|
73
|
+
expect(p.maybeRebaseline(60, -10)).toBe(false)
|
|
74
|
+
expect(p.ref).toBe(50)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('non-finite inputs do not corrupt ref', () => {
|
|
78
|
+
const p = createOriginShiftPolicy(50)
|
|
79
|
+
expect(p.maybeRebaseline(Number.NaN, 100)).toBe(false)
|
|
80
|
+
expect(p.maybeRebaseline(60, Number.POSITIVE_INFINITY)).toBe(false)
|
|
81
|
+
expect(p.ref).toBe(50)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('rejects non-finite initialRef and negative threshold', () => {
|
|
85
|
+
expect(() => createOriginShiftPolicy(Number.NaN)).toThrow(/finite/)
|
|
86
|
+
expect(() => createOriginShiftPolicy(0, -0.1)).toThrow(/threshold/)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('exactly at threshold → does NOT rebase (strict `>`)', () => {
|
|
90
|
+
// Important contract: the comparison is `>`, not `>=`. A drift of
|
|
91
|
+
// exactly 1% of range should sit on the fence and not trigger.
|
|
92
|
+
const p = createOriginShiftPolicy(100, 0.01)
|
|
93
|
+
const changed = p.maybeRebaseline(101, 100) // normalized 0.01 === threshold
|
|
94
|
+
expect(changed).toBe(false)
|
|
95
|
+
expect(p.ref).toBe(100)
|
|
96
|
+
})
|
|
97
|
+
})
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
+
import { createPriceScale } from '../createPriceScale'
|
|
3
|
+
|
|
4
|
+
describe('createPriceScale — linear mode', () => {
|
|
5
|
+
it('forward & inverse linear round-trip', () => {
|
|
6
|
+
const s = createPriceScale({
|
|
7
|
+
initialMode: 'linear',
|
|
8
|
+
initialVisibleMin: 100,
|
|
9
|
+
initialVisibleMax: 200,
|
|
10
|
+
initialHeight: 400,
|
|
11
|
+
})
|
|
12
|
+
for (const p of [100, 120.5, 150, 180.25, 200]) {
|
|
13
|
+
expect(s.yToPrice(s.priceToY(p))).toBeCloseTo(p, 8)
|
|
14
|
+
}
|
|
15
|
+
for (const y of [0, 100, 200, 300, 400]) {
|
|
16
|
+
expect(s.priceToY(s.yToPrice(y))).toBeCloseTo(y, 8)
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('linear: max maps to y=0 and min maps to y=height (Y grows downward)', () => {
|
|
21
|
+
const s = createPriceScale({
|
|
22
|
+
initialMode: 'linear',
|
|
23
|
+
initialVisibleMin: 100,
|
|
24
|
+
initialVisibleMax: 200,
|
|
25
|
+
initialHeight: 400,
|
|
26
|
+
})
|
|
27
|
+
expect(s.priceToY(200)).toBeCloseTo(0, 10)
|
|
28
|
+
expect(s.priceToY(100)).toBeCloseTo(400, 10)
|
|
29
|
+
expect(s.priceToY(150)).toBeCloseTo(200, 10)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('setHeight changes the mapping proportionally', () => {
|
|
33
|
+
const s = createPriceScale({
|
|
34
|
+
initialMode: 'linear',
|
|
35
|
+
initialVisibleMin: 0,
|
|
36
|
+
initialVisibleMax: 100,
|
|
37
|
+
initialHeight: 400,
|
|
38
|
+
})
|
|
39
|
+
expect(s.priceToY(50)).toBeCloseTo(200, 10)
|
|
40
|
+
s.setHeight(800)
|
|
41
|
+
expect(s.priceToY(50)).toBeCloseTo(400, 10)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('degenerate range (min === max) is clamped to center, not NaN', () => {
|
|
45
|
+
const s = createPriceScale({
|
|
46
|
+
initialMode: 'linear',
|
|
47
|
+
initialVisibleMin: 100,
|
|
48
|
+
initialVisibleMax: 100,
|
|
49
|
+
initialHeight: 400,
|
|
50
|
+
})
|
|
51
|
+
// Documented behaviour: anything maps to the geometric middle of the canvas.
|
|
52
|
+
expect(s.priceToY(100)).toBe(200)
|
|
53
|
+
expect(s.priceToY(50)).toBe(200) // still pinned to middle
|
|
54
|
+
expect(s.priceToY(150)).toBe(200)
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
describe('createPriceScale — log mode', () => {
|
|
59
|
+
it('forward & inverse log round-trip', () => {
|
|
60
|
+
const s = createPriceScale({
|
|
61
|
+
initialMode: 'log',
|
|
62
|
+
initialVisibleMin: 1,
|
|
63
|
+
initialVisibleMax: 1000,
|
|
64
|
+
initialHeight: 600,
|
|
65
|
+
})
|
|
66
|
+
for (const p of [1, 10, 100, 333.33, 1000]) {
|
|
67
|
+
expect(s.yToPrice(s.priceToY(p))).toBeCloseTo(p, 6)
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('log: equal log-distances produce equal pixel distances', () => {
|
|
72
|
+
// 1 → 10 → 100 → 1000 are each one decade apart.
|
|
73
|
+
// In log mode they must be at equal Y intervals.
|
|
74
|
+
const s = createPriceScale({
|
|
75
|
+
initialMode: 'log',
|
|
76
|
+
initialVisibleMin: 1,
|
|
77
|
+
initialVisibleMax: 1000,
|
|
78
|
+
initialHeight: 600,
|
|
79
|
+
})
|
|
80
|
+
const y1 = s.priceToY(1)
|
|
81
|
+
const y10 = s.priceToY(10)
|
|
82
|
+
const y100 = s.priceToY(100)
|
|
83
|
+
const y1000 = s.priceToY(1000)
|
|
84
|
+
const d1 = y1 - y10
|
|
85
|
+
const d2 = y10 - y100
|
|
86
|
+
const d3 = y100 - y1000
|
|
87
|
+
expect(d1).toBeCloseTo(d2, 8)
|
|
88
|
+
expect(d2).toBeCloseTo(d3, 8)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('setMode("log") rejects when visibleMin <= 0', () => {
|
|
92
|
+
const s = createPriceScale({
|
|
93
|
+
initialMode: 'linear',
|
|
94
|
+
initialVisibleMin: 0, // not OK for log
|
|
95
|
+
initialVisibleMax: 100,
|
|
96
|
+
})
|
|
97
|
+
expect(() => s.setMode('log')).toThrow(/visibleMin > 0/)
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it('constructor rejects log + non-positive min', () => {
|
|
101
|
+
expect(() =>
|
|
102
|
+
createPriceScale({ initialMode: 'log', initialVisibleMin: 0, initialVisibleMax: 100 }),
|
|
103
|
+
).toThrow(/log/)
|
|
104
|
+
expect(() =>
|
|
105
|
+
createPriceScale({ initialMode: 'log', initialVisibleMin: -5, initialVisibleMax: 100 }),
|
|
106
|
+
).toThrow(/log/)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('setVisibleRange in log mode rejects non-positive min', () => {
|
|
110
|
+
const s = createPriceScale({
|
|
111
|
+
initialMode: 'log',
|
|
112
|
+
initialVisibleMin: 1,
|
|
113
|
+
initialVisibleMax: 100,
|
|
114
|
+
})
|
|
115
|
+
expect(() => s.setVisibleRange(0, 100)).toThrow(/log/)
|
|
116
|
+
expect(() => s.setVisibleRange(-1, 100)).toThrow(/log/)
|
|
117
|
+
})
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
describe('createPriceScale — origin shift integration', () => {
|
|
121
|
+
it('toShiftedFp32 returns p - originShiftRef', () => {
|
|
122
|
+
const s = createPriceScale({
|
|
123
|
+
initialMode: 'linear',
|
|
124
|
+
initialVisibleMin: 66950,
|
|
125
|
+
initialVisibleMax: 67050,
|
|
126
|
+
initialHeight: 400,
|
|
127
|
+
})
|
|
128
|
+
// Origin starts at midpoint = 67000.
|
|
129
|
+
expect(s.originShiftRef.peek()).toBe(67000)
|
|
130
|
+
expect(s.toShiftedFp32(67000.5)).toBeCloseTo(0.5, 10)
|
|
131
|
+
expect(s.toShiftedFp32(66999.5)).toBeCloseTo(-0.5, 10)
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('setVisibleRange triggers maybeRebaseline when drift > threshold', () => {
|
|
135
|
+
const s = createPriceScale({
|
|
136
|
+
initialMode: 'linear',
|
|
137
|
+
initialVisibleMin: 100,
|
|
138
|
+
initialVisibleMax: 200,
|
|
139
|
+
initialHeight: 400,
|
|
140
|
+
originShiftThreshold: 0.01, // 1%
|
|
141
|
+
})
|
|
142
|
+
const refBefore = s.originShiftRef.peek() // = 150
|
|
143
|
+
|
|
144
|
+
// Shift mid by 0.005 of range — BELOW threshold, no rebase.
|
|
145
|
+
s.setVisibleRange(100.5, 200.5) // new mid 150.5, drift 0.5, range 100, normalized 0.005
|
|
146
|
+
expect(s.originShiftRef.peek()).toBe(refBefore)
|
|
147
|
+
|
|
148
|
+
// Shift mid by 0.02 of range — ABOVE threshold, rebase.
|
|
149
|
+
s.setVisibleRange(102, 202) // new mid 152, drift from old ref 150 = 2, normalized 0.02
|
|
150
|
+
expect(s.originShiftRef.peek()).toBe(152)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('signal subscriptions fire on visible-range and mode changes', () => {
|
|
154
|
+
const s = createPriceScale({ initialVisibleMin: 1, initialVisibleMax: 100 })
|
|
155
|
+
const onMin = vi.fn()
|
|
156
|
+
const onMax = vi.fn()
|
|
157
|
+
const onMode = vi.fn()
|
|
158
|
+
s.visibleMin.subscribe(onMin)
|
|
159
|
+
s.visibleMax.subscribe(onMax)
|
|
160
|
+
s.mode.subscribe(onMode)
|
|
161
|
+
|
|
162
|
+
s.setVisibleRange(2, 200)
|
|
163
|
+
expect(onMin).toHaveBeenCalledTimes(1)
|
|
164
|
+
expect(onMax).toHaveBeenCalledTimes(1)
|
|
165
|
+
|
|
166
|
+
s.setMode('log')
|
|
167
|
+
expect(onMode).toHaveBeenCalledTimes(1)
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
it('originShiftRef signal updates when a rebase fires', () => {
|
|
171
|
+
const s = createPriceScale({
|
|
172
|
+
initialVisibleMin: 100,
|
|
173
|
+
initialVisibleMax: 200,
|
|
174
|
+
originShiftThreshold: 0.01,
|
|
175
|
+
})
|
|
176
|
+
const onRef = vi.fn()
|
|
177
|
+
s.originShiftRef.subscribe(onRef)
|
|
178
|
+
|
|
179
|
+
s.setVisibleRange(100.5, 200.5) // below threshold
|
|
180
|
+
expect(onRef).not.toHaveBeenCalled()
|
|
181
|
+
|
|
182
|
+
s.setVisibleRange(105, 205) // above threshold
|
|
183
|
+
expect(onRef).toHaveBeenCalledTimes(1)
|
|
184
|
+
})
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
describe('createPriceScale — validation & lifecycle', () => {
|
|
188
|
+
it('setVisibleRange rejects non-finite or inverted bounds', () => {
|
|
189
|
+
const s = createPriceScale()
|
|
190
|
+
expect(() => s.setVisibleRange(Number.NaN, 1)).toThrow(/finite/)
|
|
191
|
+
expect(() => s.setVisibleRange(100, 50)).toThrow(/max/)
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
it('setHeight rejects non-positive values', () => {
|
|
195
|
+
const s = createPriceScale()
|
|
196
|
+
expect(() => s.setHeight(0)).toThrow(/> 0/)
|
|
197
|
+
expect(() => s.setHeight(-1)).toThrow(/> 0/)
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
it('dispose silences subsequent writes (silent no-op, reads still work)', () => {
|
|
201
|
+
// API audit BLOCKER-004: harmonized to silent-no-op (matches the
|
|
202
|
+
// convention used by every other @klinechart-quant/core controller).
|
|
203
|
+
const s = createPriceScale({ initialVisibleMin: 0, initialVisibleMax: 100, initialHeight: 400 })
|
|
204
|
+
const minBefore = s.visibleMin()
|
|
205
|
+
const heightBefore = s.height()
|
|
206
|
+
const modeBefore = s.mode()
|
|
207
|
+
s.dispose()
|
|
208
|
+
// Mutators return undefined silently — no throw.
|
|
209
|
+
s.setVisibleRange(10, 110)
|
|
210
|
+
s.setHeight(200)
|
|
211
|
+
s.setMode('log')
|
|
212
|
+
// State frozen at pre-dispose values.
|
|
213
|
+
expect(s.visibleMin()).toBe(minBefore)
|
|
214
|
+
expect(s.height()).toBe(heightBefore)
|
|
215
|
+
expect(s.mode()).toBe(modeBefore)
|
|
216
|
+
// Pure math still returns sensible numbers.
|
|
217
|
+
expect(s.priceToY(50)).toBeCloseTo(200, 10)
|
|
218
|
+
})
|
|
219
|
+
})
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
+
import { createTimeScale } from '../createTimeScale'
|
|
3
|
+
|
|
4
|
+
describe('createTimeScale', () => {
|
|
5
|
+
it('barIndexToX and xToBarIndex are exact inverses', () => {
|
|
6
|
+
const s = createTimeScale({
|
|
7
|
+
initialFirstVisibleIndex: 12.5,
|
|
8
|
+
initialBarWidth: 9,
|
|
9
|
+
initialLeftPadding: 60,
|
|
10
|
+
})
|
|
11
|
+
for (const i of [0, 1, 17, 99, -3, 12.5, 100.25]) {
|
|
12
|
+
expect(s.xToBarIndex(s.barIndexToX(i))).toBeCloseTo(i, 10)
|
|
13
|
+
}
|
|
14
|
+
for (const x of [0, 60, 123.4, 1000, -50]) {
|
|
15
|
+
expect(s.barIndexToX(s.xToBarIndex(x))).toBeCloseTo(x, 10)
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('setBarWidth re-derives the X mapping correctly', () => {
|
|
20
|
+
const s = createTimeScale({
|
|
21
|
+
initialFirstVisibleIndex: 0,
|
|
22
|
+
initialBarWidth: 10,
|
|
23
|
+
initialLeftPadding: 0,
|
|
24
|
+
})
|
|
25
|
+
expect(s.barIndexToX(5)).toBe(50)
|
|
26
|
+
s.setBarWidth(20)
|
|
27
|
+
expect(s.barIndexToX(5)).toBe(100)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('fractional firstVisibleIndex works in both directions', () => {
|
|
31
|
+
const s = createTimeScale({
|
|
32
|
+
initialFirstVisibleIndex: 10.25,
|
|
33
|
+
initialBarWidth: 8,
|
|
34
|
+
initialLeftPadding: 60,
|
|
35
|
+
})
|
|
36
|
+
// bar 11 should be at (11 - 10.25) * 8 + 60 = 0.75 * 8 + 60 = 66
|
|
37
|
+
expect(s.barIndexToX(11)).toBeCloseTo(66, 10)
|
|
38
|
+
// and the inverse round-trips
|
|
39
|
+
expect(s.xToBarIndex(66)).toBeCloseTo(11, 10)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('with calendar present: timeToBarIndex returns the right index for known timestamps', () => {
|
|
43
|
+
const s = createTimeScale()
|
|
44
|
+
const barTimestamps = [1_700_000_000_000, 1_700_000_060_000, 1_700_000_120_000, 1_700_000_180_000]
|
|
45
|
+
s.setCalendar({ barTimestamps })
|
|
46
|
+
|
|
47
|
+
expect(s.timeToBarIndex(barTimestamps[0])).toBe(0)
|
|
48
|
+
expect(s.timeToBarIndex(barTimestamps[2])).toBe(2)
|
|
49
|
+
expect(s.timeToBarIndex(barTimestamps[3])).toBe(3)
|
|
50
|
+
// Midway between bars 1 and 2:
|
|
51
|
+
const mid = (barTimestamps[1] + barTimestamps[2]) / 2
|
|
52
|
+
expect(s.timeToBarIndex(mid)).toBeCloseTo(1.5, 10)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('barIndexToTime linearly interpolates for fractional indices', () => {
|
|
56
|
+
const s = createTimeScale()
|
|
57
|
+
const barTimestamps = [1_000, 2_000, 4_000]
|
|
58
|
+
s.setCalendar({ barTimestamps })
|
|
59
|
+
|
|
60
|
+
expect(s.barIndexToTime(0)).toBe(1_000)
|
|
61
|
+
expect(s.barIndexToTime(2)).toBe(4_000)
|
|
62
|
+
// bar 1.5 → halfway between 2000 and 4000 → 3000
|
|
63
|
+
expect(s.barIndexToTime(1.5)).toBe(3_000)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('without calendar: timeToBarIndex and barIndexToTime return null', () => {
|
|
67
|
+
const s = createTimeScale()
|
|
68
|
+
expect(s.timeToBarIndex(1_700_000_000_000)).toBeNull()
|
|
69
|
+
expect(s.barIndexToTime(0)).toBeNull()
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('calendar: out-of-range queries return null (no extrapolation)', () => {
|
|
73
|
+
const s = createTimeScale()
|
|
74
|
+
s.setCalendar({ barTimestamps: [100, 200, 300] })
|
|
75
|
+
expect(s.timeToBarIndex(50)).toBeNull()
|
|
76
|
+
expect(s.timeToBarIndex(400)).toBeNull()
|
|
77
|
+
expect(s.barIndexToTime(-1)).toBeNull()
|
|
78
|
+
expect(s.barIndexToTime(3.5)).toBeNull()
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('signals fire on setters and dispose silences writes', () => {
|
|
82
|
+
const s = createTimeScale({ initialFirstVisibleIndex: 0, initialBarWidth: 10, initialLeftPadding: 0 })
|
|
83
|
+
const onFvi = vi.fn()
|
|
84
|
+
const onBw = vi.fn()
|
|
85
|
+
const onLp = vi.fn()
|
|
86
|
+
s.firstVisibleIndex.subscribe(onFvi)
|
|
87
|
+
s.barWidth.subscribe(onBw)
|
|
88
|
+
s.leftPadding.subscribe(onLp)
|
|
89
|
+
|
|
90
|
+
s.setFirstVisibleIndex(5)
|
|
91
|
+
s.setBarWidth(12)
|
|
92
|
+
s.setLeftPadding(30)
|
|
93
|
+
expect(onFvi).toHaveBeenCalledTimes(1)
|
|
94
|
+
expect(onBw).toHaveBeenCalledTimes(1)
|
|
95
|
+
expect(onLp).toHaveBeenCalledTimes(1)
|
|
96
|
+
|
|
97
|
+
// dispose: subsequent writes silently no-op (API audit BLOCKER-004
|
|
98
|
+
// harmonization — every controller in core now silences post-dispose).
|
|
99
|
+
s.dispose()
|
|
100
|
+
s.setFirstVisibleIndex(0)
|
|
101
|
+
s.setBarWidth(8)
|
|
102
|
+
// State frozen at pre-dispose values.
|
|
103
|
+
expect(s.firstVisibleIndex()).toBe(5)
|
|
104
|
+
expect(s.barWidth()).toBe(12)
|
|
105
|
+
// Math still works after dispose — it's pure peek().
|
|
106
|
+
// After the writes above: firstVisibleIndex=5, barWidth=12, leftPadding=30
|
|
107
|
+
// → barIndexToX(0) = (0 - 5) * 12 + 30 = -30
|
|
108
|
+
expect(s.barIndexToX(0)).toBe(-30)
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('rejects non-positive barWidth in both constructor and setter', () => {
|
|
112
|
+
expect(() => createTimeScale({ initialBarWidth: 0 })).toThrow(/BarWidth/)
|
|
113
|
+
expect(() => createTimeScale({ initialBarWidth: -3 })).toThrow(/BarWidth/)
|
|
114
|
+
|
|
115
|
+
const s = createTimeScale()
|
|
116
|
+
expect(() => s.setBarWidth(0)).toThrow(/> 0/)
|
|
117
|
+
expect(() => s.setBarWidth(-1)).toThrow(/> 0/)
|
|
118
|
+
})
|
|
119
|
+
})
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anchored zoom — ROADMAP §1.3.
|
|
3
|
+
*
|
|
4
|
+
* Why this exists in its own file: the "data point under the mouse stays under
|
|
5
|
+
* the mouse" guarantee is the single most-felt detail of chart UX. Getting it
|
|
6
|
+
* mathematically right (so the screen-pixel offset survives sequential zooms
|
|
7
|
+
* within sub-pixel error) is the only path to a feel that matches TradingView.
|
|
8
|
+
*
|
|
9
|
+
* Forward equation, before zoom:
|
|
10
|
+
*
|
|
11
|
+
* mouseX = (i_anchor - firstVisibleIndex) * barWidth + leftPadding
|
|
12
|
+
*
|
|
13
|
+
* Solve for `i_anchor` first (this is the bar index the user is pointing at):
|
|
14
|
+
*
|
|
15
|
+
* i_anchor = (mouseX - leftPadding) / barWidth + firstVisibleIndex
|
|
16
|
+
*
|
|
17
|
+
* Then pick the new bar width and solve the same equation for the new first
|
|
18
|
+
* visible index so that `mouseX` still maps to `i_anchor`:
|
|
19
|
+
*
|
|
20
|
+
* barWidth' = clamp(barWidth * zoomFactor, minBarWidth, maxBarWidth)
|
|
21
|
+
* firstVisibleIndex' = i_anchor - (mouseX - leftPadding) / barWidth'
|
|
22
|
+
*
|
|
23
|
+
* Two non-obvious cases worth flagging:
|
|
24
|
+
*
|
|
25
|
+
* 1. **zoomFactor === 1** is a true no-op; we short-circuit so floating-point
|
|
26
|
+
* round-trips don't sneak a sub-ULP drift into the state on every mouse-move.
|
|
27
|
+
*
|
|
28
|
+
* 2. **barWidth' got clamped** (user keeps wheeling at the min/max). Once the
|
|
29
|
+
* clamp engages we re-derive `firstVisibleIndex` from the clamped width.
|
|
30
|
+
* The anchor is preserved at the clamped width, which means the visible
|
|
31
|
+
* anchor point will *drift in screen X by the same amount the wheel tried
|
|
32
|
+
* to push the bar width past the clamp*. This is the expected behavior —
|
|
33
|
+
* it's how the user feels "the chart can't zoom any further" rather than
|
|
34
|
+
* watching the wheel become a silent dead-zone.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
export interface AnchoredZoomOptions {
|
|
38
|
+
/** Screen X (logical px) where the wheel event fired. */
|
|
39
|
+
mouseX: number
|
|
40
|
+
/** Logical px on the left edge before bar 0. */
|
|
41
|
+
leftPadding: number
|
|
42
|
+
/** Current `firstVisibleIndex` (fractional). */
|
|
43
|
+
firstVisibleIndex: number
|
|
44
|
+
/** Current `barWidth` in logical px. */
|
|
45
|
+
barWidth: number
|
|
46
|
+
/** > 1 zoom in (wheel up), < 1 zoom out, === 1 no-op. */
|
|
47
|
+
zoomFactor: number
|
|
48
|
+
/** Lower clamp for the resulting bar width. Default 0.5 logical px. */
|
|
49
|
+
minBarWidth?: number
|
|
50
|
+
/** Upper clamp for the resulting bar width. Default 200 logical px. */
|
|
51
|
+
maxBarWidth?: number
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface AnchoredZoomResult {
|
|
55
|
+
firstVisibleIndex: number
|
|
56
|
+
barWidth: number
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const DEFAULT_MIN_BAR_WIDTH = 0.5
|
|
60
|
+
const DEFAULT_MAX_BAR_WIDTH = 200
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @internal — building block used by `createTimeScale / interaction handlers`. Reachable today
|
|
64
|
+
* via the top-level `@klinechart-quant/core` barrel but **NOT
|
|
65
|
+
* part of the supported public API**. typedoc / api-extractor
|
|
66
|
+
* hide it from generated docs. Prefer the controller factory
|
|
67
|
+
* for stable user code. Closes API audit BLOCKER-002.
|
|
68
|
+
*/
|
|
69
|
+
export function computeAnchoredZoom(opts: AnchoredZoomOptions): AnchoredZoomResult {
|
|
70
|
+
const {
|
|
71
|
+
mouseX,
|
|
72
|
+
leftPadding,
|
|
73
|
+
firstVisibleIndex,
|
|
74
|
+
barWidth,
|
|
75
|
+
zoomFactor,
|
|
76
|
+
minBarWidth = DEFAULT_MIN_BAR_WIDTH,
|
|
77
|
+
maxBarWidth = DEFAULT_MAX_BAR_WIDTH,
|
|
78
|
+
} = opts
|
|
79
|
+
|
|
80
|
+
// No-op short-circuit — avoid round-trip rounding when not zooming.
|
|
81
|
+
if (zoomFactor === 1) {
|
|
82
|
+
return { firstVisibleIndex, barWidth }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Defensive: a non-positive or non-finite current barWidth would blow up the
|
|
86
|
+
// inverse formula. The TimeScale itself never lets barWidth reach 0, but we
|
|
87
|
+
// belt-and-brace it here so the function is total.
|
|
88
|
+
if (!Number.isFinite(barWidth) || barWidth <= 0) {
|
|
89
|
+
return { firstVisibleIndex, barWidth }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const dx = mouseX - leftPadding
|
|
93
|
+
const iAnchor = dx / barWidth + firstVisibleIndex
|
|
94
|
+
|
|
95
|
+
const rawNewBarWidth = barWidth * zoomFactor
|
|
96
|
+
const newBarWidth = Math.min(Math.max(rawNewBarWidth, minBarWidth), maxBarWidth)
|
|
97
|
+
|
|
98
|
+
const newFirstVisibleIndex = iAnchor - dx / newBarWidth
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
firstVisibleIndex: newFirstVisibleIndex,
|
|
102
|
+
barWidth: newBarWidth,
|
|
103
|
+
}
|
|
104
|
+
}
|