gloomberb 0.11.2 → 0.12.0
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/README.md +7 -4
- package/README.zh-CN.md +4 -2
- package/package.json +28 -1
- package/src/api-client/auth.ts +10 -0
- package/src/api-client/data.ts +108 -1
- package/src/api-client/index.test.ts +127 -0
- package/src/api-client/index.ts +134 -1
- package/src/api-client/normalizers.ts +39 -0
- package/src/api-client/paths.ts +85 -1
- package/src/api-client/types.ts +220 -0
- package/src/app/pane-runtime/index.tsx +15 -12
- package/src/app/pane-runtime/layout-placement.test.ts +27 -0
- package/src/app/pane-runtime/layout-placement.ts +13 -0
- package/src/app/pane-runtime/plugin-bindings.ts +62 -0
- package/src/app.tsx +60 -18
- package/src/architecture/browser-entry-graph.test.ts +96 -0
- package/src/brokers/profile-form.test.ts +25 -27
- package/src/brokers/test-broker.ts +68 -0
- package/src/capabilities/chart-series.ts +3 -2
- package/src/cli/commands/market.ts +2 -2
- package/src/cli/commands/plugins.ts +39 -11
- package/src/cli/desktop-pane-shot.ts +285 -16
- package/src/cli/index.ts +1 -1
- package/src/cli/pane-functions/capabilities.ts +61 -31
- package/src/cli/pane-functions/catalog.ts +16 -4
- package/src/cli/pane-functions/discovery.ts +1 -0
- package/src/cli/pane-functions/headless.test.ts +247 -0
- package/src/cli/pane-functions/headless.ts +423 -0
- package/src/cli/pane-functions/index.test.ts +9 -0
- package/src/cli/pane-functions/index.ts +6 -2
- package/src/cli/pane-functions/options.ts +27 -2
- package/src/cli/pane-functions/report.ts +4 -0
- package/src/cli/pane-functions/resolver.ts +26 -8
- package/src/cli/pane-functions/screenshot.test.ts +76 -0
- package/src/cli/pane-functions/screenshot.ts +236 -20
- package/src/cli/registry.ts +0 -22
- package/src/cli/restore-plugins.ts +34 -0
- package/src/cli/result.ts +7 -10
- package/src/components/chart/{static/chart → composite}/axis-overlays.test.tsx +3 -3
- package/src/components/chart/{static/chart → composite}/axis-overlays.tsx +6 -11
- package/src/components/chart/{static/chart → composite}/bitmap.ts +17 -3
- package/src/components/chart/composite/composite-chart.test.tsx +68 -20
- package/src/components/chart/composite/composite-chart.tsx +301 -204
- package/src/components/chart/composite/format.ts +8 -2
- package/src/components/chart/composite/interactions.test.ts +68 -102
- package/src/components/chart/composite/interactions.ts +214 -264
- package/src/components/chart/composite/price-axis-labels.test.ts +21 -0
- package/src/components/chart/{price-axis-labels.tsx → composite/price-axis-labels.tsx} +9 -4
- package/src/components/chart/composite/scene.ts +57 -3
- package/src/components/chart/composite/text-renderer.ts +3 -2
- package/src/components/chart/composite/time-scale.ts +138 -57
- package/src/components/chart/composite/types.ts +25 -1
- package/src/components/chart/core/data.ts +9 -13
- package/src/components/chart/core/date-window.ts +7 -1
- package/src/components/chart/core/pointer.ts +3 -0
- package/src/components/chart/core/types.ts +0 -45
- package/src/components/chart/native/chart-rasterizer.ts +0 -1
- package/src/components/chart/native/kitty/index.test.ts +0 -188
- package/src/components/chart/native/raster/crosshair.ts +6 -5
- package/src/components/chart/native/raster/primitives.ts +0 -23
- package/src/components/chart/native/renderer-selection.ts +81 -31
- package/src/components/chart/static/{chart/surface.test.tsx → chart-surface.test.tsx} +28 -80
- package/src/components/chart/static/chart-surface.tsx +150 -0
- package/src/components/chart/static/index.ts +8 -0
- package/src/components/chart/static/multi-line-chart-surface.tsx +51 -166
- package/src/components/chart/static/scatter-chart-surface.test.ts +30 -0
- package/src/components/chart/static/scatter-chart-surface.tsx +135 -34
- package/src/components/chart/static/series.ts +49 -0
- package/src/components/command-bar/action-runtime.ts +1 -3
- package/src/components/command-bar/assist/model.test.ts +17 -2
- package/src/components/command-bar/assist/model.ts +40 -9
- package/src/components/command-bar/commands/direct/index.ts +1 -1
- package/src/components/command-bar/commands/direct/runtime.ts +1 -1
- package/src/components/command-bar/commands/registry.ts +0 -11
- package/src/components/command-bar/helpers.test.ts +2 -2
- package/src/components/command-bar/helpers.ts +2 -6
- package/src/components/command-bar/keyboard-shortcuts.ts +0 -11
- package/src/components/command-bar/list/badge.test.ts +54 -0
- package/src/components/command-bar/list/badge.ts +62 -0
- package/src/components/command-bar/list/model.test.ts +103 -0
- package/src/components/command-bar/list/model.ts +61 -4
- package/src/components/command-bar/list/view.test.tsx +113 -0
- package/src/components/command-bar/list/view.tsx +147 -131
- package/src/components/command-bar/pane-templates/workflow.ts +1 -1
- package/src/components/command-bar/panel/body.tsx +51 -65
- package/src/components/command-bar/panel/index.tsx +48 -13
- package/src/components/command-bar/panel/layout.test.ts +139 -0
- package/src/components/command-bar/panel/layout.ts +65 -28
- package/src/components/command-bar/panel/native-surface.ts +24 -0
- package/src/components/command-bar/panel/prompt-binding.ts +54 -0
- package/src/components/command-bar/panel/runtime.ts +6 -3
- package/src/components/command-bar/panel/state.ts +41 -7
- package/src/components/command-bar/panel/types.ts +7 -1
- package/src/components/command-bar/routes/root/provider-search.ts +34 -15
- package/src/components/command-bar/routes/root/results.test.ts +161 -0
- package/src/components/command-bar/routes/root/results.ts +30 -28
- package/src/components/command-bar/routes/root/runtime.ts +37 -20
- package/src/components/command-bar/routes/root/search-providers.test.tsx +224 -0
- package/src/components/command-bar/routes/root/search-providers.ts +205 -0
- package/src/components/command-bar/routes/root/selection.ts +1 -12
- package/src/components/command-bar/routes/root/shortcuts.test.ts +8 -8
- package/src/components/command-bar/routes/ticker-search/actions.ts +10 -9
- package/src/components/command-bar/routes/ticker-search/results.test.ts +54 -1
- package/src/components/command-bar/routes/ticker-search/results.ts +60 -19
- package/src/components/command-bar/routes/ticker-search/route.ts +1 -0
- package/src/components/command-bar/routing/actions.ts +1 -81
- package/src/components/command-bar/routing/launch-request.ts +1 -1
- package/src/components/command-bar/routing/list-state.ts +6 -21
- package/src/components/command-bar/selection-runtime.ts +1 -1
- package/src/components/command-bar/surface/assist.test.tsx +14 -10
- package/src/components/command-bar/surface/environment.ts +8 -1
- package/src/components/command-bar/surface/index.test.tsx +84 -68
- package/src/components/command-bar/surface/index.tsx +33 -36
- package/src/components/command-bar/surface/test-harness.tsx +15 -3
- package/src/components/command-bar/theme-picker.tsx +43 -15
- package/src/components/command-bar/view-model.test.ts +53 -8
- package/src/components/command-bar/view-model.ts +43 -14
- package/src/components/command-bar/workflow/tickers.ts +1 -0
- package/src/components/command-bar/workflow/types.ts +1 -1
- package/src/components/data-table/export.test.ts +21 -0
- package/src/components/data-table/export.ts +21 -0
- package/src/components/data-table/view.test.tsx +45 -6
- package/src/components/data-table/view.tsx +55 -9
- package/src/components/index.ts +10 -2
- package/src/components/input-search-bar.test.tsx +36 -2
- package/src/components/input-search-bar.tsx +18 -1
- package/src/components/layout/header.test.tsx +57 -10
- package/src/components/layout/header.tsx +292 -149
- package/src/components/layout/market-summary.test.ts +81 -0
- package/src/components/layout/market-summary.ts +109 -0
- package/src/components/layout/shell/chrome.ts +96 -1
- package/src/components/layout/shell/index.tsx +11 -3
- package/src/components/layout/shell/menu.ts +9 -0
- package/src/components/layout/shell/pane/actions.ts +29 -0
- package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
- package/src/components/layout/shell/shortcuts.ts +3 -0
- package/src/components/layout/status-bar.test.tsx +9 -8
- package/src/components/layout/status-bar.tsx +85 -54
- package/src/components/onboarding/onboarding-frame.tsx +2 -26
- package/src/components/price-sparkline/index.ts +61 -34
- package/src/components/price-sparkline/view.tsx +1 -1
- package/src/components/sign-in-gate.test.tsx +128 -0
- package/src/components/sign-in-gate.tsx +149 -0
- package/src/components/speedometer-gauge/desktop.tsx +2 -12
- package/src/components/ticker/badge/list.tsx +17 -3
- package/src/components/ticker/list-table-view.tsx +6 -3
- package/src/components/ui/data-table/index.tsx +22 -4
- package/src/components/ui/data-table/opentui/index.tsx +165 -120
- package/src/components/ui/frame.tsx +28 -0
- package/src/components/ui/index.ts +3 -0
- package/src/components/ui/native-select.tsx +20 -10
- package/src/components/ui/select-button.tsx +138 -0
- package/src/components/ui/status.tsx +2 -2
- package/src/components/ui/table-layout.ts +1 -1
- package/src/components/use-double-click-activation.ts +7 -3
- package/src/core/app-services.ts +3 -3
- package/src/data/config/chart-settings.ts +4 -4
- package/src/data/config/layout.ts +12 -6
- package/src/data/config/store/index.test.ts +97 -0
- package/src/data/config/store/migrations.ts +41 -0
- package/src/data/config/store/normalize.ts +5 -3
- package/src/i18n/es.ts +6 -2
- package/src/i18n/ja.ts +6 -2
- package/src/i18n/ko.ts +6 -2
- package/src/i18n/zh-cn.ts +6 -2
- package/src/i18n/zh-tw.ts +6 -2
- package/src/layout-marketplace/gallery-terminal.tsx +126 -96
- package/src/layout-marketplace/gallery.test.tsx +65 -1
- package/src/layout-marketplace/pane-imagery.ts +1 -0
- package/src/layout-marketplace/payload.test.ts +17 -0
- package/src/layout-marketplace/payload.ts +40 -5
- package/src/market-data/coordinator/index.ts +3 -2
- package/src/market-data/coordinator/quotes.ts +173 -66
- package/src/market-data/coordinator/subscriptions.test.ts +215 -37
- package/src/pane-settings.ts +1 -1
- package/src/plugins/builtin/analytics/pane-model.ts +1 -1
- package/src/plugins/builtin/analytics/view.tsx +1 -1
- package/src/plugins/builtin/broker-manager/index.test.tsx +3 -2
- package/src/plugins/builtin/broker-manager/model.test.ts +2 -2
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +16 -2
- package/src/plugins/builtin/chart-composer/cli-options.ts +12 -9
- package/src/plugins/builtin/chart-composer/pane.tsx +22 -8
- package/src/plugins/builtin/chart-composer/settings.ts +2 -13
- package/src/plugins/builtin/chat/content/composer.tsx +8 -4
- package/src/plugins/builtin/cloud/auth-dialog.tsx +14 -228
- package/src/plugins/builtin/cloud/auth-form.tsx +277 -0
- package/src/plugins/builtin/cloud/plugin.tsx +1 -0
- package/src/plugins/builtin/composite-plugins.ts +16 -1
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
- package/src/plugins/builtin/correlation/relationship/pane.tsx +2 -6
- package/src/plugins/builtin/correlation/relationship/view-model.ts +2 -2
- package/src/plugins/builtin/credit-conditions/index.test.tsx +12 -6
- package/src/plugins/builtin/credit-conditions/index.tsx +2 -21
- package/src/plugins/builtin/dividend-yield/index.tsx +1 -0
- package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
- package/src/plugins/builtin/earnings/index.tsx +1 -0
- package/src/plugins/builtin/earnings-calls/data.ts +223 -0
- package/src/plugins/builtin/earnings-calls/format.ts +49 -0
- package/src/plugins/builtin/earnings-calls/index.tsx +69 -0
- package/src/plugins/builtin/earnings-calls/pane.tsx +756 -0
- package/src/plugins/builtin/earnings-calls/prose.test.ts +36 -0
- package/src/plugins/builtin/earnings-calls/prose.ts +59 -0
- package/src/plugins/builtin/earnings-calls/transcript-view.tsx +334 -0
- package/src/plugins/builtin/econ/detail-view.tsx +1 -2
- package/src/plugins/builtin/econ/fred-series-map.ts +16 -1
- package/src/plugins/builtin/econ/index.tsx +3 -1
- package/src/plugins/builtin/econ-statistics/cache.ts +4 -0
- package/src/plugins/builtin/econ-statistics/client.ts +92 -0
- package/src/plugins/builtin/econ-statistics/defs.ts +66 -0
- package/src/plugins/builtin/econ-statistics/detail.tsx +154 -0
- package/src/plugins/builtin/econ-statistics/headless.test.ts +54 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +171 -0
- package/src/plugins/builtin/econ-statistics/index.tsx +54 -0
- package/src/plugins/builtin/econ-statistics/pane.tsx +356 -0
- package/src/plugins/builtin/econ-statistics/stats.ts +522 -0
- package/src/plugins/builtin/econ-statistics/transform.test.ts +86 -0
- package/src/plugins/builtin/econ-statistics/transform.ts +85 -0
- package/src/plugins/builtin/econ-statistics/trend.ts +57 -0
- package/src/plugins/builtin/econ-statistics/view.ts +90 -0
- package/src/plugins/builtin/fear-greed/charts.tsx +7 -18
- package/src/plugins/builtin/fear-greed/data.ts +6 -1
- package/src/plugins/builtin/futures/index.tsx +1 -0
- package/src/plugins/builtin/fx-matrix/index.tsx +1 -0
- package/src/plugins/builtin/help/index.tsx +4 -0
- package/src/plugins/builtin/holders/index.tsx +1 -0
- package/src/plugins/builtin/insider/index.tsx +1 -0
- package/src/plugins/builtin/ipo-calendar/index.tsx +1 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
- package/src/plugins/builtin/kelly-sizer/sections.tsx +2 -3
- package/src/plugins/builtin/market-halts/index.tsx +1 -0
- package/src/plugins/builtin/market-movers/index.tsx +1 -0
- package/src/plugins/builtin/market-valuation/align.ts +122 -0
- package/src/plugins/builtin/market-valuation/cache.ts +32 -0
- package/src/plugins/builtin/market-valuation/chart-projection.ts +217 -0
- package/src/plugins/builtin/market-valuation/chart-series.ts +89 -0
- package/src/plugins/builtin/market-valuation/client.test.ts +141 -0
- package/src/plugins/builtin/market-valuation/client.ts +116 -0
- package/src/plugins/builtin/market-valuation/defs.ts +251 -0
- package/src/plugins/builtin/market-valuation/detail.tsx +159 -0
- package/src/plugins/builtin/market-valuation/headless.test.ts +58 -0
- package/src/plugins/builtin/market-valuation/headless.ts +170 -0
- package/src/plugins/builtin/market-valuation/index.tsx +64 -0
- package/src/plugins/builtin/market-valuation/indicators.ts +422 -0
- package/src/plugins/builtin/market-valuation/model.test.ts +350 -0
- package/src/plugins/builtin/market-valuation/model.ts +8 -0
- package/src/plugins/builtin/market-valuation/pane.test.tsx +247 -0
- package/src/plugins/builtin/market-valuation/pane.tsx +344 -0
- package/src/plugins/builtin/market-valuation/series.ts +12 -0
- package/src/plugins/builtin/market-valuation/settings.ts +38 -0
- package/src/plugins/builtin/market-valuation/sources.ts +130 -0
- package/src/plugins/builtin/market-valuation/trend.ts +89 -0
- package/src/plugins/builtin/market-valuation/view.ts +137 -0
- package/src/plugins/builtin/market-valuation/zone-scale/desktop.tsx +123 -0
- package/src/plugins/builtin/market-valuation/zone-scale/index.tsx +12 -0
- package/src/plugins/builtin/market-valuation/zone-scale/model.ts +60 -0
- package/src/plugins/builtin/market-valuation/zone-scale/terminal.tsx +94 -0
- package/src/plugins/builtin/news/wire/breaking/filters.test.ts +99 -0
- package/src/plugins/builtin/news/wire/breaking/filters.ts +110 -0
- package/src/plugins/builtin/news/wire/breaking/notifications.test.ts +157 -53
- package/src/plugins/builtin/news/wire/breaking/notifications.ts +91 -25
- package/src/plugins/builtin/news/wire/index.tsx +31 -44
- package/src/plugins/builtin/options/analytics.test.ts +83 -0
- package/src/plugins/builtin/options/analytics.ts +110 -0
- package/src/plugins/builtin/options/index.tsx +18 -2
- package/src/plugins/builtin/options/table.ts +121 -51
- package/src/plugins/builtin/options/types.ts +22 -15
- package/src/plugins/builtin/options/view.test.tsx +53 -1
- package/src/plugins/builtin/options/view.tsx +92 -41
- package/src/plugins/builtin/plugin-marketplace/feed.ts +80 -0
- package/src/plugins/builtin/plugin-marketplace/index.tsx +31 -0
- package/src/plugins/builtin/plugin-marketplace/model.test.ts +200 -0
- package/src/plugins/builtin/plugin-marketplace/model.ts +204 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +385 -0
- package/src/plugins/builtin/plugin-marketplace/store.ts +46 -0
- package/src/plugins/builtin/plugin-module.test.ts +2 -4
- package/src/plugins/builtin/plugin-module.ts +9 -8
- package/src/plugins/builtin/portfolio-list/index.tsx +1 -0
- package/src/plugins/builtin/research/index.tsx +4 -0
- package/src/plugins/builtin/research-search/command-bar-search.test.ts +81 -0
- package/src/plugins/builtin/research-search/command-bar-search.ts +175 -0
- package/src/plugins/builtin/research-search/data.ts +109 -0
- package/src/plugins/builtin/research-search/document-view.test.tsx +75 -0
- package/src/plugins/builtin/research-search/document-view.tsx +254 -0
- package/src/plugins/builtin/research-search/filter-bar.tsx +62 -0
- package/src/plugins/builtin/research-search/focus-handoff.ts +47 -0
- package/src/plugins/builtin/research-search/index.tsx +85 -0
- package/src/plugins/builtin/research-search/model.test.ts +40 -0
- package/src/plugins/builtin/research-search/model.ts +291 -0
- package/src/plugins/builtin/research-search/pane.test.tsx +241 -0
- package/src/plugins/builtin/research-search/pane.tsx +678 -0
- package/src/plugins/builtin/research-search/saved-view.tsx +171 -0
- package/src/plugins/builtin/research-search/snippet-text.tsx +35 -0
- package/src/plugins/builtin/research-search/snippet.test.ts +78 -0
- package/src/plugins/builtin/research-search/snippet.ts +134 -0
- package/src/plugins/builtin/scanner/flow-model.test.ts +11 -1
- package/src/plugins/builtin/scanner/flow-model.ts +29 -1
- package/src/plugins/builtin/scanner/flow-pane.tsx +78 -22
- package/src/plugins/builtin/scanner/index.ts +2 -0
- package/src/plugins/builtin/sec/index.tsx +1 -0
- package/src/plugins/builtin/sectors/index.tsx +1 -0
- package/src/plugins/builtin/shared/series-cache.ts +93 -0
- package/src/plugins/builtin/short-interest/index.tsx +1 -0
- package/src/plugins/builtin/short-interest/pane.tsx +1 -1
- package/src/plugins/builtin/thirteenf/index.tsx +1 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +3 -5
- package/src/plugins/builtin/ticker-detail/index.tsx +2 -14
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +1 -1
- package/src/plugins/builtin/treasury-auctions/index.tsx +1 -0
- package/src/plugins/builtin/volatility/index.tsx +1 -1
- package/src/plugins/builtin/world-indices/index.tsx +1 -0
- package/src/plugins/builtin/world-venue-map/index.ts +27 -0
- package/src/plugins/builtin/world-venue-map/map.desktop.test.tsx +106 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +481 -0
- package/src/plugins/builtin/world-venue-map/model.test.ts +85 -0
- package/src/plugins/builtin/world-venue-map/model.ts +268 -0
- package/src/plugins/builtin/world-venue-map/pane.tsx +300 -0
- package/src/plugins/builtin/world-venue-map/world-outlines.ts +2 -0
- package/src/plugins/builtin/yield-curve/index.tsx +1 -1
- package/src/plugins/bundle.test.ts +109 -0
- package/src/plugins/bundle.ts +139 -0
- package/src/plugins/catalog-backend.ts +6 -44
- package/src/plugins/catalog-browser.test.ts +1 -0
- package/src/plugins/catalog-browser.ts +12 -0
- package/src/plugins/catalog-manifest.test.ts +43 -0
- package/src/plugins/catalog-manifest.ts +92 -0
- package/src/plugins/catalog-ui.ts +20 -4
- package/src/plugins/catalog.ts +9 -2
- package/src/plugins/current-target.ts +28 -0
- package/src/plugins/host-contract.ts +37 -0
- package/src/plugins/host-link.ts +158 -0
- package/src/plugins/host-modules.ts +61 -0
- package/src/plugins/loader.ts +41 -22
- package/src/plugins/ownership.ts +1 -0
- package/src/plugins/prediction-markets/index.tsx +1 -0
- package/src/plugins/registry/context.ts +3 -0
- package/src/plugins/registry/contributions.ts +27 -0
- package/src/plugins/registry/index.test.ts +25 -0
- package/src/plugins/registry/index.ts +8 -0
- package/src/plugins/registry/pane-settings.test.ts +53 -0
- package/src/plugins/registry/pane-settings.ts +29 -3
- package/src/plugins/seed.test.ts +83 -0
- package/src/plugins/seed.ts +80 -0
- package/src/public/broker.ts +31 -0
- package/src/public/market-data.ts +9 -0
- package/src/public/pane-hooks.ts +57 -0
- package/src/public/public-api.test.ts +285 -0
- package/src/public/react.ts +62 -0
- package/src/public/test-support.ts +23 -0
- package/src/public/time-series.ts +8 -0
- package/src/public/utils.ts +77 -0
- package/src/remote/layout-helpers.ts +6 -8
- package/src/remote/resources.ts +2 -0
- package/src/remote/schema.ts +1 -0
- package/src/remote/semantic-tree.test.tsx +105 -0
- package/src/remote/semantic-tree.tsx +53 -35
- package/src/renderers/browser/main.tsx +6 -0
- package/src/renderers/browser/ui-host.tsx +11 -0
- package/src/renderers/cloudflare/worker.test.ts +19 -0
- package/src/renderers/cloudflare/worker.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -2
- package/src/renderers/electrobun/bun/external-plugins.ts +140 -0
- package/src/renderers/electrobun/bun/index.ts +6 -2
- package/src/renderers/electrobun/shared/protocol.ts +25 -0
- package/src/renderers/electrobun/view/build-assets.ts +0 -1
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +51 -1
- package/src/renderers/electrobun/view/external-plugins.test.ts +45 -0
- package/src/renderers/electrobun/view/external-plugins.ts +63 -0
- package/src/renderers/electrobun/view/host/ascii-text.test.ts +48 -0
- package/src/renderers/electrobun/view/host/ascii-text.ts +11 -1
- package/src/renderers/electrobun/view/host/chart-surface.tsx +38 -32
- package/src/renderers/electrobun/view/host/mouse.ts +16 -2
- package/src/renderers/electrobun/view/main.tsx +27 -2
- package/src/renderers/electrobun/view/styles.css +5 -0
- package/src/renderers/electrobun/view/toast-host.tsx +18 -0
- package/src/renderers/electrobun/view/ui-host.tsx +3 -0
- package/src/renderers/opentui/chart-surface.tsx +5 -1
- package/src/renderers/opentui/host.tsx +20 -2
- package/src/renderers/opentui/interaction-performance.test.ts +79 -0
- package/src/renderers/opentui/interaction-performance.ts +188 -0
- package/src/renderers/opentui/start.tsx +26 -1
- package/src/renderers/opentui/test-utils.tsx +13 -0
- package/src/renderers/opentui/toast-host.tsx +26 -2
- package/src/renderers/opentui/ui-host.tsx +1 -0
- package/src/sources/provider-router/search.test.ts +191 -0
- package/src/sources/provider-router/search.ts +92 -39
- package/src/state/app/context/index.tsx +2 -0
- package/src/state/app/context/selector.test.tsx +33 -1
- package/src/state/hooks/quote-streaming.test.tsx +93 -0
- package/src/state/hooks/quote-streaming.ts +106 -30
- package/src/state/pane-table-export-registry.ts +50 -0
- package/src/theme/color-utils.ts +1 -1
- package/src/theme/colors.ts +50 -0
- package/src/theme/themes.test.ts +15 -2
- package/src/theme/themes.ts +19 -1
- package/src/tickers/search/index.test.ts +26 -0
- package/src/tickers/search/index.ts +42 -17
- package/src/tickers/search/ranking.ts +14 -0
- package/src/time-series/chart-data.test.ts +216 -0
- package/src/time-series/range.ts +12 -0
- package/src/time-series/resolution.test.ts +25 -26
- package/src/time-series/resolution.ts +44 -25
- package/src/time-series/resolve.ts +7 -0
- package/src/time-series/spec.ts +5 -5
- package/src/time-series/types.ts +3 -1
- package/src/time-series/use-chart-resolution.ts +5 -0
- package/src/types/config.ts +123 -3
- package/src/types/data-provider.ts +11 -0
- package/src/types/headless.ts +161 -0
- package/src/types/plugin.ts +104 -20
- package/src/ui/host.tsx +19 -1
- package/src/ui/index.tsx +1 -0
- package/src/ui/toast.tsx +8 -4
- package/src/utils/csv.test.ts +13 -0
- package/src/utils/csv.ts +37 -0
- package/src/utils/format.ts +35 -0
- package/src/utils/fuzzy-search.test.ts +94 -0
- package/src/utils/fuzzy-search.ts +81 -22
- package/src/utils/save-text-file.test.ts +24 -0
- package/src/utils/save-text-file.ts +36 -0
- package/src/utils/shortcut-labels.ts +14 -0
- package/src/components/chart/core/axis-format.ts +0 -157
- package/src/components/chart/core/index.test.ts +0 -1075
- package/src/components/chart/core/projection.ts +0 -357
- package/src/components/chart/core/render-utils.ts +0 -4
- package/src/components/chart/core/renderer.ts +0 -244
- package/src/components/chart/core/scene.ts +0 -180
- package/src/components/chart/core/time-axis.ts +0 -330
- package/src/components/chart/cursor-motion.ts +0 -47
- package/src/components/chart/indicators/types.ts +0 -26
- package/src/components/chart/market-session.ts +0 -176
- package/src/components/chart/multi-line/renderer.test.ts +0 -83
- package/src/components/chart/multi-line/renderer.ts +0 -161
- package/src/components/chart/multi-line/scene.ts +0 -188
- package/src/components/chart/native/raster/layout.ts +0 -129
- package/src/components/chart/native/raster/price-chart.ts +0 -244
- package/src/components/chart/rendering/chart-draw.ts +0 -270
- package/src/components/chart/rendering/geometry.ts +0 -95
- package/src/components/chart/rendering/pixel-buffer.ts +0 -267
- package/src/components/chart/scatter-chart-renderer.test.ts +0 -31
- package/src/components/chart/scatter-chart-renderer.ts +0 -223
- package/src/components/chart/static/chart/surface.tsx +0 -358
- package/src/components/command-bar/routes/root/article-results.test.ts +0 -83
- package/src/components/command-bar/routes/root/article-results.ts +0 -55
- package/src/plugins/builtin/news/wire/article-search.test.ts +0 -72
- package/src/plugins/builtin/news/wire/article-search.ts +0 -140
- package/src/plugins/builtin/substack/api/auth.ts +0 -185
- package/src/plugins/builtin/substack/api/cache.ts +0 -82
- package/src/plugins/builtin/substack/api/loaders.ts +0 -170
- package/src/plugins/builtin/substack/api/store.ts +0 -186
- package/src/plugins/builtin/substack/api/types.ts +0 -42
- package/src/plugins/builtin/substack/api.test.ts +0 -298
- package/src/plugins/builtin/substack/article-detail.tsx +0 -397
- package/src/plugins/builtin/substack/article-stack.tsx +0 -133
- package/src/plugins/builtin/substack/content.ts +0 -478
- package/src/plugins/builtin/substack/feed-tabs.tsx +0 -44
- package/src/plugins/builtin/substack/index.tsx +0 -49
- package/src/plugins/builtin/substack/login-view.tsx +0 -126
- package/src/plugins/builtin/substack/model.test.ts +0 -155
- package/src/plugins/builtin/substack/normalize.ts +0 -343
- package/src/plugins/builtin/substack/pane-footer.ts +0 -52
- package/src/plugins/builtin/substack/pane-state.ts +0 -170
- package/src/plugins/builtin/substack/pane.tsx +0 -547
- package/src/plugins/builtin/substack/read-state.ts +0 -30
- package/src/plugins/builtin/substack/table.ts +0 -111
- package/src/plugins/builtin/substack/types.ts +0 -71
- package/src/plugins/builtin/substack/utils.ts +0 -131
- package/src/plugins/builtin/ticker-detail/data-panes/provider-search.tsx +0 -229
- package/src/plugins/ibkr/account-cache.test.ts +0 -102
- package/src/plugins/ibkr/account-cache.ts +0 -24
- package/src/plugins/ibkr/broker-adapter.ts +0 -286
- package/src/plugins/ibkr/config.test.ts +0 -79
- package/src/plugins/ibkr/config.ts +0 -250
- package/src/plugins/ibkr/dialogs.tsx +0 -40
- package/src/plugins/ibkr/flex/index.test.ts +0 -264
- package/src/plugins/ibkr/flex/index.ts +0 -367
- package/src/plugins/ibkr/flex/statement-client.ts +0 -235
- package/src/plugins/ibkr/fundamental-parser.ts +0 -149
- package/src/plugins/ibkr/gateway/account-loaders.ts +0 -266
- package/src/plugins/ibkr/gateway/account-summary.ts +0 -164
- package/src/plugins/ibkr/gateway/client-lock.ts +0 -154
- package/src/plugins/ibkr/gateway/connection-events.ts +0 -114
- package/src/plugins/ibkr/gateway/connection.ts +0 -152
- package/src/plugins/ibkr/gateway/contracts.ts +0 -132
- package/src/plugins/ibkr/gateway/fundamentals.ts +0 -83
- package/src/plugins/ibkr/gateway/helpers.ts +0 -33
- package/src/plugins/ibkr/gateway/history-requests.ts +0 -158
- package/src/plugins/ibkr/gateway/history.ts +0 -120
- package/src/plugins/ibkr/gateway/instrument-lookup.ts +0 -117
- package/src/plugins/ibkr/gateway/market-data.ts +0 -345
- package/src/plugins/ibkr/gateway/order-execution.ts +0 -218
- package/src/plugins/ibkr/gateway/orders.ts +0 -63
- package/src/plugins/ibkr/gateway/price-normalization.test.ts +0 -44
- package/src/plugins/ibkr/gateway/price-normalization.ts +0 -50
- package/src/plugins/ibkr/gateway/quote-stream-controller.ts +0 -203
- package/src/plugins/ibkr/gateway/quote-stream.ts +0 -171
- package/src/plugins/ibkr/gateway/selection.ts +0 -51
- package/src/plugins/ibkr/gateway/service/index.test.ts +0 -675
- package/src/plugins/ibkr/gateway/service/index.ts +0 -429
- package/src/plugins/ibkr/gateway/service/lifecycle.ts +0 -191
- package/src/plugins/ibkr/gateway/service/manager.ts +0 -52
- package/src/plugins/ibkr/gateway/service/market-data.ts +0 -48
- package/src/plugins/ibkr/gateway/service/native-loader.ts +0 -12
- package/src/plugins/ibkr/gateway/service/native.ts +0 -543
- package/src/plugins/ibkr/gateway/timeouts.ts +0 -13
- package/src/plugins/ibkr/gateway/types.ts +0 -27
- package/src/plugins/ibkr/index.test.tsx +0 -162
- package/src/plugins/ibkr/index.tsx +0 -159
- package/src/plugins/ibkr/instance-selection.test.ts +0 -120
- package/src/plugins/ibkr/instance-selection.ts +0 -36
- package/src/plugins/ibkr/portfolio-performance.test.ts +0 -32
- package/src/plugins/ibkr/portfolio-performance.ts +0 -129
- package/src/plugins/ibkr/trade/badge.tsx +0 -28
- package/src/plugins/ibkr/trade/dialogs.tsx +0 -44
- package/src/plugins/ibkr/trade/preview-panel.tsx +0 -130
- package/src/plugins/ibkr/trade/tab/actions.tsx +0 -443
- package/src/plugins/ibkr/trade/tab/field-editors.tsx +0 -79
- package/src/plugins/ibkr/trade/tab/footer.ts +0 -53
- package/src/plugins/ibkr/trade/tab/header.tsx +0 -167
- package/src/plugins/ibkr/trade/tab/index.test.tsx +0 -178
- package/src/plugins/ibkr/trade/tab/index.tsx +0 -298
- package/src/plugins/ibkr/trade/tab/model.ts +0 -159
- package/src/plugins/ibkr/trade/tab/order-request.ts +0 -64
- package/src/plugins/ibkr/trade/tab/shortcuts.ts +0 -89
- package/src/plugins/ibkr/trade/tab/state-sync.ts +0 -86
- package/src/plugins/ibkr/trade/ticket-panel.tsx +0 -301
- package/src/plugins/ibkr/trade/utils.test.ts +0 -175
- package/src/plugins/ibkr/trade/utils.ts +0 -144
- package/src/plugins/ibkr/trading/pane-view.tsx +0 -237
- package/src/plugins/ibkr/trading/pane.tsx +0 -332
- package/src/plugins/ibkr/trading/state.test.ts +0 -109
- package/src/plugins/ibkr/trading/state.ts +0 -335
|
@@ -49,12 +49,31 @@ function pointTimestampForScale(
|
|
|
49
49
|
: timestamp;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
interface NormalizedSourcePoint {
|
|
53
53
|
point: TimeSeriesPoint;
|
|
54
54
|
timestamp: number;
|
|
55
55
|
value: number | null;
|
|
56
|
-
}
|
|
57
|
-
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface NormalizedPointsCache {
|
|
59
|
+
points: readonly TimeSeriesPoint[];
|
|
60
|
+
pointCount: number;
|
|
61
|
+
last: TimeSeriesPoint | undefined;
|
|
62
|
+
lastTimestamp: number | null;
|
|
63
|
+
lastValue: number | null;
|
|
64
|
+
byPlacement: Map<boolean, NormalizedSourcePoint[]>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Every scene build normalises each series several times over; a viewport
|
|
68
|
+
// change must not re-sort thousands of unchanged points. Live ticks mutate
|
|
69
|
+
// the last point in place, so the cache also keys on its time and value.
|
|
70
|
+
const normalizedPointsCache = new WeakMap<ResolvedSeries, NormalizedPointsCache>();
|
|
71
|
+
|
|
72
|
+
function computeNormalizedSourcePoints(
|
|
73
|
+
series: ResolvedSeries,
|
|
74
|
+
timeScale?: CompositeTimeScale,
|
|
75
|
+
): NormalizedSourcePoint[] {
|
|
76
|
+
const bySourceTimestamp = new Map<number, NormalizedSourcePoint>();
|
|
58
77
|
for (const point of series.points) {
|
|
59
78
|
const sourceTimestamp = pointTime(point);
|
|
60
79
|
const timestamp = pointTimestampForScale(series, point, timeScale);
|
|
@@ -71,6 +90,41 @@ function normalizedSourcePoints(series: ResolvedSeries, timeScale?: CompositeTim
|
|
|
71
90
|
));
|
|
72
91
|
}
|
|
73
92
|
|
|
93
|
+
function normalizedSourcePoints(
|
|
94
|
+
series: ResolvedSeries,
|
|
95
|
+
timeScale?: CompositeTimeScale,
|
|
96
|
+
): NormalizedSourcePoint[] {
|
|
97
|
+
const effectiveTimes = timeScale?.kind === "market" && !series.timeBasis;
|
|
98
|
+
const last = series.points[series.points.length - 1];
|
|
99
|
+
const lastTimestamp = last ? pointTime(last) : null;
|
|
100
|
+
const lastValue = last ? resolveTimeSeriesPointValue(last) : null;
|
|
101
|
+
let cached = normalizedPointsCache.get(series);
|
|
102
|
+
if (
|
|
103
|
+
!cached
|
|
104
|
+
|| cached.points !== series.points
|
|
105
|
+
|| cached.pointCount !== series.points.length
|
|
106
|
+
|| cached.last !== last
|
|
107
|
+
|| cached.lastTimestamp !== lastTimestamp
|
|
108
|
+
|| cached.lastValue !== lastValue
|
|
109
|
+
) {
|
|
110
|
+
cached = {
|
|
111
|
+
points: series.points,
|
|
112
|
+
pointCount: series.points.length,
|
|
113
|
+
last,
|
|
114
|
+
lastTimestamp,
|
|
115
|
+
lastValue,
|
|
116
|
+
byPlacement: new Map(),
|
|
117
|
+
};
|
|
118
|
+
normalizedPointsCache.set(series, cached);
|
|
119
|
+
}
|
|
120
|
+
let normalized = cached.byPlacement.get(effectiveTimes);
|
|
121
|
+
if (!normalized) {
|
|
122
|
+
normalized = computeNormalizedSourcePoints(series, timeScale);
|
|
123
|
+
cached.byPlacement.set(effectiveTimes, normalized);
|
|
124
|
+
}
|
|
125
|
+
return normalized;
|
|
126
|
+
}
|
|
127
|
+
|
|
74
128
|
function normalizedPoints(series: ResolvedSeries): Array<{
|
|
75
129
|
point: TimeSeriesPoint;
|
|
76
130
|
timestamp: number;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { compositeAxisTicks } from "./format";
|
|
1
|
+
import { compositeAxisTicks, type CompositeAxisValueFormatter } from "./format";
|
|
2
2
|
import type { CompositeViewportRange } from "./interactions";
|
|
3
3
|
import { resolveCompositeObservationWidth } from "./rasterizer";
|
|
4
4
|
import { buildCompositeColumnLayout, type CompositeColumnLayout } from "./column-layout";
|
|
@@ -274,10 +274,11 @@ export function renderCompositeAxisText(
|
|
|
274
274
|
height: number,
|
|
275
275
|
width: number,
|
|
276
276
|
side: "left" | "right",
|
|
277
|
+
format?: CompositeAxisValueFormatter,
|
|
277
278
|
): string[] {
|
|
278
279
|
const rows = Array.from({ length: Math.max(1, height) }, () => " ".repeat(Math.max(0, width)));
|
|
279
280
|
if (!domain || width <= 0) return rows;
|
|
280
|
-
for (const tick of compositeAxisTicks(domain)) {
|
|
281
|
+
for (const tick of compositeAxisTicks(domain, 3, format)) {
|
|
281
282
|
const row = clamp(Math.round(tick.ratio * Math.max(height - 1, 0)), 0, Math.max(height - 1, 0));
|
|
282
283
|
const label = tick.label.length > width ? tick.label.slice(0, width) : tick.label;
|
|
283
284
|
rows[row] = side === "left" ? label.padStart(width) : label.padEnd(width);
|
|
@@ -2,8 +2,27 @@ import type { ResolvedSeries } from "../../../time-series/types";
|
|
|
2
2
|
import type { CompositeTimeScale } from "./types";
|
|
3
3
|
|
|
4
4
|
const DAY_MS = 24 * 60 * 60 * 1_000;
|
|
5
|
+
const QUARTER_HOUR_MS = 15 * 60 * 1_000;
|
|
5
6
|
const MINIMUM_SLOT_FRACTION = 0.25;
|
|
6
7
|
const dateFormatters = new Map<string, Intl.DateTimeFormat>();
|
|
8
|
+
// Session dates are looked up once per quarter hour, not once per bar: a day
|
|
9
|
+
// of one-minute bars asks the same question hundreds of times.
|
|
10
|
+
const sessionDateBuckets = new Map<string, Map<number, string>>();
|
|
11
|
+
const SESSION_DATE_BUCKET_LIMIT = 200_000;
|
|
12
|
+
|
|
13
|
+
type MarketAnchors = Extract<CompositeTimeScale, { kind: "market" }>["anchors"];
|
|
14
|
+
|
|
15
|
+
interface CachedMarketAnchors {
|
|
16
|
+
points: readonly ResolvedSeries["points"][number][];
|
|
17
|
+
pointCount: number;
|
|
18
|
+
lastTimestamp: number | null;
|
|
19
|
+
timeZone: string;
|
|
20
|
+
configuredCadence: number | undefined;
|
|
21
|
+
cadenceMs: number;
|
|
22
|
+
anchors: MarketAnchors;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const anchorCache = new WeakMap<ResolvedSeries, CachedMarketAnchors>();
|
|
7
26
|
|
|
8
27
|
function finiteTimestamp(value: Date): number | null {
|
|
9
28
|
const timestamp = value.getTime();
|
|
@@ -31,7 +50,7 @@ function formatterFor(timeZone: string): Intl.DateTimeFormat {
|
|
|
31
50
|
return formatter;
|
|
32
51
|
}
|
|
33
52
|
|
|
34
|
-
function
|
|
53
|
+
function formatSessionDate(timestamp: number, timeZone: string): string {
|
|
35
54
|
try {
|
|
36
55
|
const parts = formatterFor(timeZone).formatToParts(new Date(timestamp));
|
|
37
56
|
const year = parts.find((part) => part.type === "year")?.value;
|
|
@@ -44,6 +63,23 @@ function sessionDate(timestamp: number, timeZone: string): string {
|
|
|
44
63
|
return new Date(timestamp).toISOString().slice(0, 10);
|
|
45
64
|
}
|
|
46
65
|
|
|
66
|
+
function sessionDate(timestamp: number, timeZone: string): string {
|
|
67
|
+
// Every IANA offset is a multiple of fifteen minutes, so local midnight
|
|
68
|
+
// always lands on a bucket edge and one bucket never spans two sessions.
|
|
69
|
+
let buckets = sessionDateBuckets.get(timeZone);
|
|
70
|
+
if (!buckets) {
|
|
71
|
+
buckets = new Map();
|
|
72
|
+
sessionDateBuckets.set(timeZone, buckets);
|
|
73
|
+
}
|
|
74
|
+
const bucket = Math.floor(timestamp / QUARTER_HOUR_MS);
|
|
75
|
+
const cached = buckets.get(bucket);
|
|
76
|
+
if (cached !== undefined) return cached;
|
|
77
|
+
const date = formatSessionDate(timestamp, timeZone);
|
|
78
|
+
if (buckets.size >= SESSION_DATE_BUCKET_LIMIT) buckets.clear();
|
|
79
|
+
buckets.set(bucket, date);
|
|
80
|
+
return date;
|
|
81
|
+
}
|
|
82
|
+
|
|
47
83
|
function median(values: readonly number[]): number | null {
|
|
48
84
|
const sorted = values.filter((value) => Number.isFinite(value) && value > 0)
|
|
49
85
|
.sort((left, right) => left - right);
|
|
@@ -55,7 +91,7 @@ function median(values: readonly number[]): number | null {
|
|
|
55
91
|
}
|
|
56
92
|
|
|
57
93
|
function lowerBoundAnchor(
|
|
58
|
-
anchors:
|
|
94
|
+
anchors: MarketAnchors,
|
|
59
95
|
timestamp: number,
|
|
60
96
|
): number {
|
|
61
97
|
let low = 0;
|
|
@@ -69,7 +105,7 @@ function lowerBoundAnchor(
|
|
|
69
105
|
}
|
|
70
106
|
|
|
71
107
|
function positionForTimestamp(
|
|
72
|
-
scale: Extract<CompositeTimeScale, { kind: "market" }>,
|
|
108
|
+
scale: Pick<Extract<CompositeTimeScale, { kind: "market" }>, "anchors" | "cadenceMs">,
|
|
73
109
|
timestamp: number,
|
|
74
110
|
): number {
|
|
75
111
|
const { anchors, cadenceMs } = scale;
|
|
@@ -90,69 +126,134 @@ function positionForTimestamp(
|
|
|
90
126
|
+ (next.position - previous.position) * ((timestamp - previous.timestamp) / elapsed);
|
|
91
127
|
}
|
|
92
128
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
const anchorTimestamps = anchorSeries ? uniqueSeriesTimestamps(anchorSeries) : [];
|
|
100
|
-
if (!anchorSeries?.timeBasis || anchorTimestamps.length === 0) {
|
|
101
|
-
return { kind: "calendar", startTime, endTime };
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const { timeZone } = anchorSeries.timeBasis;
|
|
129
|
+
function buildMarketAnchors(series: ResolvedSeries, timeZone: string): {
|
|
130
|
+
cadenceMs: number;
|
|
131
|
+
anchors: MarketAnchors;
|
|
132
|
+
} {
|
|
133
|
+
const anchorTimestamps = uniqueSeriesTimestamps(series);
|
|
134
|
+
const sessionDates = anchorTimestamps.map((timestamp) => sessionDate(timestamp, timeZone));
|
|
105
135
|
const sameSessionGaps: number[] = [];
|
|
106
136
|
const allGaps: number[] = [];
|
|
107
137
|
for (let index = 1; index < anchorTimestamps.length; index += 1) {
|
|
108
|
-
const
|
|
109
|
-
const next = anchorTimestamps[index]!;
|
|
110
|
-
const gap = next - previous;
|
|
138
|
+
const gap = anchorTimestamps[index]! - anchorTimestamps[index - 1]!;
|
|
111
139
|
if (gap <= 0) continue;
|
|
112
140
|
allGaps.push(gap);
|
|
113
|
-
if (
|
|
114
|
-
sameSessionGaps.push(gap);
|
|
115
|
-
}
|
|
141
|
+
if (sessionDates[index - 1] === sessionDates[index]) sameSessionGaps.push(gap);
|
|
116
142
|
}
|
|
117
|
-
const configuredCadence =
|
|
143
|
+
const configuredCadence = series.timeBasis?.cadenceMs;
|
|
118
144
|
const cadenceMs = typeof configuredCadence === "number"
|
|
119
145
|
&& Number.isFinite(configuredCadence)
|
|
120
146
|
&& configuredCadence > 0
|
|
121
147
|
? configuredCadence
|
|
122
148
|
: median(sameSessionGaps) ?? median(allGaps) ?? DAY_MS;
|
|
123
149
|
|
|
124
|
-
const anchors:
|
|
150
|
+
const anchors: MarketAnchors = [];
|
|
125
151
|
let position = 0;
|
|
126
152
|
anchorTimestamps.forEach((timestamp, index) => {
|
|
127
153
|
if (index > 0) {
|
|
128
154
|
const previous = anchorTimestamps[index - 1]!;
|
|
129
|
-
|
|
130
|
-
position += sameSession
|
|
155
|
+
position += sessionDates[index - 1] === sessionDates[index]
|
|
131
156
|
? Math.max((timestamp - previous) / cadenceMs, MINIMUM_SLOT_FRACTION)
|
|
132
157
|
: 1;
|
|
133
158
|
}
|
|
134
159
|
anchors.push({ timestamp, position });
|
|
135
160
|
});
|
|
161
|
+
return { cadenceMs, anchors };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Anchor slots for a market series, cached on the series object. Live ticks
|
|
166
|
+
* mutate the last point in place, so the cache also keys on the point count
|
|
167
|
+
* and the last timestamp.
|
|
168
|
+
*/
|
|
169
|
+
function resolveMarketAnchors(
|
|
170
|
+
series: ResolvedSeries,
|
|
171
|
+
): { cadenceMs: number; anchors: MarketAnchors; timeZone: string } | null {
|
|
172
|
+
if (!series.timeBasis || series.timeBasis.kind !== "market") return null;
|
|
173
|
+
const { timeZone, cadenceMs: configuredCadence } = series.timeBasis;
|
|
174
|
+
const lastTimestamp = series.points.length > 0
|
|
175
|
+
? finiteTimestamp(series.points[series.points.length - 1]!.date)
|
|
176
|
+
: null;
|
|
177
|
+
const cached = anchorCache.get(series);
|
|
178
|
+
if (
|
|
179
|
+
cached
|
|
180
|
+
&& cached.points === series.points
|
|
181
|
+
&& cached.pointCount === series.points.length
|
|
182
|
+
&& cached.lastTimestamp === lastTimestamp
|
|
183
|
+
&& cached.timeZone === timeZone
|
|
184
|
+
&& cached.configuredCadence === configuredCadence
|
|
185
|
+
) {
|
|
186
|
+
return { cadenceMs: cached.cadenceMs, anchors: cached.anchors, timeZone };
|
|
187
|
+
}
|
|
188
|
+
const built = buildMarketAnchors(series, timeZone);
|
|
189
|
+
anchorCache.set(series, {
|
|
190
|
+
points: series.points,
|
|
191
|
+
pointCount: series.points.length,
|
|
192
|
+
lastTimestamp,
|
|
193
|
+
timeZone,
|
|
194
|
+
configuredCadence,
|
|
195
|
+
cadenceMs: built.cadenceMs,
|
|
196
|
+
anchors: built.anchors,
|
|
197
|
+
});
|
|
198
|
+
return { ...built, timeZone };
|
|
199
|
+
}
|
|
136
200
|
|
|
137
|
-
|
|
201
|
+
export function buildCompositeTimeScale(
|
|
202
|
+
timelineSeries: readonly ResolvedSeries[],
|
|
203
|
+
startTime: number,
|
|
204
|
+
endTime: number,
|
|
205
|
+
): CompositeTimeScale {
|
|
206
|
+
const anchorSeries = timelineSeries.find((series) => series.timeBasis?.kind === "market");
|
|
207
|
+
const resolved = anchorSeries ? resolveMarketAnchors(anchorSeries) : null;
|
|
208
|
+
if (!anchorSeries || !resolved || resolved.anchors.length === 0) {
|
|
209
|
+
return { kind: "calendar", startTime, endTime };
|
|
210
|
+
}
|
|
211
|
+
const { cadenceMs, anchors } = resolved;
|
|
212
|
+
const startPosition = positionForTimestamp({ anchors, cadenceMs }, startTime);
|
|
213
|
+
const endPosition = positionForTimestamp({ anchors, cadenceMs }, endTime);
|
|
214
|
+
return {
|
|
138
215
|
kind: "market",
|
|
139
216
|
startTime,
|
|
140
217
|
endTime,
|
|
141
218
|
anchorSeriesId: anchorSeries.id,
|
|
142
219
|
cadenceMs,
|
|
143
220
|
anchors,
|
|
144
|
-
startPosition: 0,
|
|
145
|
-
endPosition: 1,
|
|
146
|
-
};
|
|
147
|
-
const startPosition = positionForTimestamp(provisional, startTime);
|
|
148
|
-
const endPosition = positionForTimestamp(provisional, endTime);
|
|
149
|
-
return {
|
|
150
|
-
...provisional,
|
|
151
221
|
startPosition,
|
|
152
222
|
endPosition: endPosition > startPosition ? endPosition : startPosition + 1,
|
|
153
223
|
};
|
|
154
224
|
}
|
|
155
225
|
|
|
226
|
+
/** Slot position of a timestamp on a market scale, or wall-clock time on a calendar scale. */
|
|
227
|
+
export function compositeTimePosition(scale: CompositeTimeScale, timestamp: number): number {
|
|
228
|
+
return scale.kind === "calendar" ? timestamp : positionForTimestamp(scale, timestamp);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Inverse of `compositeTimePosition`. */
|
|
232
|
+
export function compositeTimeAtPosition(scale: CompositeTimeScale, position: number): number {
|
|
233
|
+
if (scale.kind === "calendar") return position;
|
|
234
|
+
const anchors = scale.anchors;
|
|
235
|
+
let low = 0;
|
|
236
|
+
let high = anchors.length;
|
|
237
|
+
while (low < high) {
|
|
238
|
+
const middle = low + Math.floor((high - low) / 2);
|
|
239
|
+
if (anchors[middle]!.position < position) low = middle + 1;
|
|
240
|
+
else high = middle;
|
|
241
|
+
}
|
|
242
|
+
const next = anchors[low];
|
|
243
|
+
const previous = anchors[low - 1];
|
|
244
|
+
if (!previous) {
|
|
245
|
+
return anchors[0]!.timestamp + (position - anchors[0]!.position) * scale.cadenceMs;
|
|
246
|
+
}
|
|
247
|
+
if (!next) {
|
|
248
|
+
const last = anchors.at(-1)!;
|
|
249
|
+
return last.timestamp + (position - last.position) * scale.cadenceMs;
|
|
250
|
+
}
|
|
251
|
+
const positionSpan = next.position - previous.position;
|
|
252
|
+
if (positionSpan <= 0) return previous.timestamp;
|
|
253
|
+
return previous.timestamp
|
|
254
|
+
+ (next.timestamp - previous.timestamp) * ((position - previous.position) / positionSpan);
|
|
255
|
+
}
|
|
256
|
+
|
|
156
257
|
export function projectCompositeTimestamp(
|
|
157
258
|
scale: CompositeTimeScale,
|
|
158
259
|
timestamp: number,
|
|
@@ -190,28 +291,8 @@ export function unprojectCompositeTimestamp(
|
|
|
190
291
|
if (scale.kind === "calendar") {
|
|
191
292
|
return scale.startTime + (scale.endTime - scale.startTime) * safeRatio;
|
|
192
293
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
let high = anchors.length;
|
|
198
|
-
while (low < high) {
|
|
199
|
-
const middle = low + Math.floor((high - low) / 2);
|
|
200
|
-
if (anchors[middle]!.position < targetPosition) low = middle + 1;
|
|
201
|
-
else high = middle;
|
|
202
|
-
}
|
|
203
|
-
const next = anchors[low];
|
|
204
|
-
const previous = anchors[low - 1];
|
|
205
|
-
if (!previous) {
|
|
206
|
-
return anchors[0]!.timestamp + (targetPosition - anchors[0]!.position) * scale.cadenceMs;
|
|
207
|
-
}
|
|
208
|
-
if (!next) {
|
|
209
|
-
const last = anchors.at(-1)!;
|
|
210
|
-
return last.timestamp + (targetPosition - last.position) * scale.cadenceMs;
|
|
211
|
-
}
|
|
212
|
-
const positionSpan = next.position - previous.position;
|
|
213
|
-
if (positionSpan <= 0) return previous.timestamp;
|
|
214
|
-
return previous.timestamp
|
|
215
|
-
+ (next.timestamp - previous.timestamp)
|
|
216
|
-
* ((targetPosition - previous.position) / positionSpan);
|
|
294
|
+
return compositeTimeAtPosition(
|
|
295
|
+
scale,
|
|
296
|
+
scale.startPosition + (scale.endPosition - scale.startPosition) * safeRatio,
|
|
297
|
+
);
|
|
217
298
|
}
|
|
@@ -111,6 +111,23 @@ export interface BuildCompositeChartSceneOptions {
|
|
|
111
111
|
timelineSeries?: ResolvedSeries[];
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
export interface CompositeChartXMarker {
|
|
115
|
+
id: string;
|
|
116
|
+
xRatio: number;
|
|
117
|
+
label?: string;
|
|
118
|
+
color?: string;
|
|
119
|
+
lineChar?: string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Replaces the date axis for charts whose x is not time: a fraction, a tenor, a return. */
|
|
123
|
+
export interface CompositeChartXAxis {
|
|
124
|
+
/** Evenly spread labels drawn instead of date ticks. */
|
|
125
|
+
labels?: readonly string[];
|
|
126
|
+
/** Vertical guide lines through the plot, captioned below the axis. */
|
|
127
|
+
markers?: readonly CompositeChartXMarker[];
|
|
128
|
+
formatCursor?: (xRatio: number) => string;
|
|
129
|
+
}
|
|
130
|
+
|
|
114
131
|
export interface CompositeChartProps {
|
|
115
132
|
series: ResolvedSeries[];
|
|
116
133
|
/** Optional legend model; can include hidden series that are not plotted. */
|
|
@@ -122,6 +139,13 @@ export interface CompositeChartProps {
|
|
|
122
139
|
height: number;
|
|
123
140
|
focused?: boolean;
|
|
124
141
|
interactive?: boolean;
|
|
142
|
+
/** False keeps the hover cursor but removes pan, zoom, tools, and navigation keys. */
|
|
143
|
+
navigable?: boolean;
|
|
144
|
+
/** Overrides the unit-derived tick and cursor labels on both value axes. */
|
|
145
|
+
formatAxisValue?: (value: number, domain: CompositeAxisDomain) => string;
|
|
146
|
+
xAxis?: CompositeChartXAxis;
|
|
147
|
+
/** Tagged onto the plot's semantic node so remote clients can find this chart. */
|
|
148
|
+
remoteKind?: string;
|
|
125
149
|
/** Permit panning into an older unloaded window so the owner can backfill it. */
|
|
126
150
|
allowHistoricalBackfill?: boolean;
|
|
127
151
|
cursorDate?: Date | null;
|
|
@@ -148,7 +172,7 @@ export interface CompositeChartProps {
|
|
|
148
172
|
/** Reports a user-created viewport, or null when the user resets to the authored viewport. */
|
|
149
173
|
onViewportChange?: (
|
|
150
174
|
viewport: { start: Date; end: Date } | null,
|
|
151
|
-
interaction: "pan" | "reset" | "
|
|
175
|
+
interaction: "pan" | "reset" | "zoom",
|
|
152
176
|
) => void;
|
|
153
177
|
onActivate?: () => void;
|
|
154
178
|
onToggleSeries?: (seriesId: string) => void;
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
ChartProjection,
|
|
11
|
-
ProjectChartDataOptions,
|
|
12
|
-
ProjectedChartPoint,
|
|
13
|
-
} from "./projection";
|
|
1
|
+
/** One observation of a simple, non-navigable chart: a value with optional bar extremes. */
|
|
2
|
+
export interface ProjectedChartPoint {
|
|
3
|
+
date: Date;
|
|
4
|
+
open: number;
|
|
5
|
+
high: number;
|
|
6
|
+
low: number;
|
|
7
|
+
close: number;
|
|
8
|
+
volume: number;
|
|
9
|
+
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { PricePoint } from "../../../types/financials";
|
|
2
|
-
import type { TimeRange
|
|
2
|
+
import type { TimeRange } from "./types";
|
|
3
|
+
|
|
4
|
+
export interface VisibleWindow {
|
|
5
|
+
points: PricePoint[];
|
|
6
|
+
startIdx: number;
|
|
7
|
+
endIdx: number;
|
|
8
|
+
}
|
|
3
9
|
import type { DateWindowRange } from "../../../time-series/date-window";
|
|
4
10
|
import { subtractTimeRange } from "../../../time-series/date-window";
|
|
5
11
|
|
|
@@ -1,26 +1,11 @@
|
|
|
1
|
-
import type { PricePoint } from "../../../types/financials";
|
|
2
1
|
export type { ChartResolution, TimeRange } from "../../../time-series/range";
|
|
3
2
|
|
|
4
3
|
export type ChartRenderMode = "area" | "line" | "candles" | "ohlc" | "hlc";
|
|
5
|
-
export type ChartAxisMode = "price" | "percent";
|
|
6
4
|
export type ChartRendererPreference = "auto" | "kitty" | "braille";
|
|
7
5
|
export type ResolvedChartRenderer = "kitty" | "braille";
|
|
8
|
-
export type ChartSessionBackgroundKind = "pre" | "post";
|
|
9
6
|
|
|
10
7
|
export const CHART_RENDERER_PREFERENCES: ChartRendererPreference[] = ["auto", "kitty", "braille"];
|
|
11
8
|
|
|
12
|
-
export interface Pixel {
|
|
13
|
-
color: string;
|
|
14
|
-
layer: number;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface PixelBuffer {
|
|
18
|
-
width: number;
|
|
19
|
-
height: number; // virtual pixel rows (4x terminal rows for braille rendering)
|
|
20
|
-
pixels: (Pixel | null)[][]; // [y][x] = pixel with color and layer, or null
|
|
21
|
-
backgrounds: (string | null)[][];
|
|
22
|
-
}
|
|
23
|
-
|
|
24
9
|
export interface ChartColors {
|
|
25
10
|
lineColor: string;
|
|
26
11
|
fillColor: string;
|
|
@@ -35,33 +20,3 @@ export interface ChartColors {
|
|
|
35
20
|
preMarketBgColor: string;
|
|
36
21
|
postMarketBgColor: string;
|
|
37
22
|
}
|
|
38
|
-
|
|
39
|
-
export interface ChartMarketSession {
|
|
40
|
-
timeZone: string;
|
|
41
|
-
regularStartMinutes: number;
|
|
42
|
-
regularEndMinutes: number;
|
|
43
|
-
preMarketStartMinutes: number;
|
|
44
|
-
postMarketEndMinutes: number;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export interface ChartSessionBackgroundSpan {
|
|
48
|
-
kind: ChartSessionBackgroundKind;
|
|
49
|
-
startIndex: number;
|
|
50
|
-
endIndex: number;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export interface VisibleWindow {
|
|
54
|
-
points: PricePoint[];
|
|
55
|
-
startIdx: number;
|
|
56
|
-
endIdx: number;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
import type { OverlayPoint, OscillatorPoint, MacdResult, BollingerResult } from "../indicators/types";
|
|
60
|
-
|
|
61
|
-
export interface ChartIndicatorOverlays {
|
|
62
|
-
smaLines: { period: number; points: OverlayPoint[]; color: string }[];
|
|
63
|
-
emaLines: { period: number; points: OverlayPoint[]; color: string }[];
|
|
64
|
-
bollinger: (BollingerResult & { color: string }) | null;
|
|
65
|
-
rsi: OscillatorPoint[] | null;
|
|
66
|
-
macd: MacdResult | null;
|
|
67
|
-
}
|