gloomberb 0.10.4 → 0.11.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/LICENSE +1 -1
- package/README.md +30 -3
- package/README.zh-CN.md +1 -1
- package/package.json +5 -5
- package/src/api-client/auth.ts +34 -0
- package/src/api-client/data.ts +25 -0
- package/src/api-client/index.test.ts +81 -0
- package/src/api-client/index.ts +37 -0
- package/src/api-client/request.test.ts +30 -0
- package/src/api-client/request.ts +44 -20
- package/src/api-client/socket-health.test.ts +79 -0
- package/src/api-client/socket.ts +108 -5
- package/src/api-client/types.ts +139 -0
- package/src/app/global-shortcuts.test.tsx +144 -9
- package/src/app/global-shortcuts.ts +33 -11
- package/src/app/runtime/broker-import.ts +39 -5
- package/src/app/runtime/startup.ts +7 -1
- package/src/app/runtime/update.ts +26 -1
- package/src/app.tsx +36 -19
- package/src/brokers/broker-ticker-sync.ts +3 -8
- package/src/brokers/sync-broker-instance.test.ts +59 -0
- package/src/brokers/sync-broker-instance.ts +37 -13
- package/src/capabilities/chart-series.ts +318 -0
- package/src/capabilities/factories.ts +46 -0
- package/src/capabilities/index.ts +1 -0
- package/src/capabilities/registry.test.ts +135 -0
- package/src/capabilities/registry.ts +31 -4
- package/src/capabilities/types.ts +52 -0
- package/src/cli/commands/overview.ts +2 -2
- package/src/cli/desktop-pane-shot.ts +2 -0
- package/src/cli/entry.ts +11 -1
- package/src/cli/native-smoke.ts +5 -0
- package/src/cli/pane-functions/catalog.ts +4 -0
- package/src/cli/pane-functions/data.ts +6 -1
- package/src/cli/pane-functions/discovery.ts +76 -10
- package/src/cli/pane-functions/report.test.ts +76 -0
- package/src/cli/pane-functions/report.ts +7 -1
- package/src/cli/pane-functions/resolver.ts +4 -1
- package/src/cli/pane-functions/screenshot.test.ts +56 -3
- package/src/cli/pane-functions/screenshot.ts +68 -5
- package/src/components/chart/composite/composite-chart.test.tsx +54 -0
- package/src/components/chart/composite/composite-chart.tsx +92 -15
- package/src/components/chart/composite/downsample.test.ts +136 -0
- package/src/components/chart/composite/downsample.ts +208 -0
- package/src/components/chart/composite/panel-series.test.ts +66 -0
- package/src/components/chart/composite/panel-series.ts +101 -0
- package/src/components/chart/multi-line/renderer.ts +1 -0
- package/src/components/chart/native/kitty/index.test.ts +25 -3
- package/src/components/chart/native/kitty/support.ts +37 -3
- package/src/components/chart/native/use-chart-text-fallback.ts +19 -0
- package/src/components/chart/static/chart/surface.tsx +43 -12
- package/src/components/chart/static/multi-line-chart-surface.tsx +41 -5
- package/src/components/command-bar/commands/direct/index.ts +18 -0
- package/src/components/command-bar/commands/registry.ts +14 -0
- package/src/components/command-bar/routes/root/article-results.test.ts +83 -0
- package/src/components/command-bar/routes/root/article-results.ts +55 -0
- package/src/components/command-bar/routes/root/command-items.ts +3 -0
- package/src/components/command-bar/routes/root/provider-search.ts +7 -3
- package/src/components/command-bar/routes/root/results.ts +38 -11
- package/src/components/command-bar/routes/root/runtime.ts +6 -2
- package/src/components/command-bar/routes/ticker-search/actions.ts +1 -1
- package/src/components/command-bar/routes/ticker-search/results.test.ts +34 -0
- package/src/components/command-bar/routes/ticker-search/results.ts +4 -6
- package/src/components/command-bar/routes/ticker-search/route.ts +2 -2
- package/src/components/command-bar/routing/list-state.ts +2 -1
- package/src/components/command-bar/surface/assist.test.tsx +13 -6
- package/src/components/command-bar/surface/index.test.tsx +65 -0
- package/src/components/command-bar/surface/index.tsx +35 -0
- package/src/components/command-bar/view-model.test.ts +43 -0
- package/src/components/command-bar/view-model.ts +41 -4
- package/src/components/command-bar/workflow/collection-actions.test.ts +94 -0
- package/src/components/command-bar/workflow/collection-actions.ts +14 -3
- package/src/components/command-bar/workflow/ops.test.ts +136 -0
- package/src/components/command-bar/workflow/ops.ts +71 -1
- package/src/components/index.ts +1 -1
- package/src/components/layout/header.test.tsx +35 -0
- package/src/components/layout/header.tsx +101 -9
- package/src/components/layout/pane/cycle-order.test.ts +0 -1
- package/src/components/layout/pane/footer/index.test.tsx +19 -19
- package/src/components/layout/pane/header.tsx +2 -13
- package/src/components/layout/shell/index.tsx +3 -0
- package/src/components/layout/status-bar.test.tsx +36 -1
- package/src/components/layout/status-bar.tsx +48 -2
- package/src/components/onboarding/account-step/chooser-panel.tsx +27 -50
- package/src/components/onboarding/account-step/form-panel.tsx +85 -29
- package/src/components/onboarding/account-step/index.tsx +10 -1
- package/src/components/onboarding/account-step/model.ts +3 -3
- package/src/components/onboarding/account-step/qr-panel.tsx +68 -0
- package/src/components/onboarding/account-step/signed-in-panel.tsx +4 -7
- package/src/components/onboarding/onboarding-frame.tsx +517 -0
- package/src/components/onboarding/onboarding-steps.tsx +0 -264
- package/src/components/onboarding/onboarding-wizard.test.tsx +626 -200
- package/src/components/onboarding/onboarding-wizard.tsx +848 -266
- package/src/components/onboarding/portfolio-step/broker-fields-panel.tsx +81 -51
- package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +14 -20
- package/src/components/onboarding/portfolio-step/broker-sync-panel.tsx +8 -11
- package/src/components/onboarding/portfolio-step/choose-panel.tsx +18 -22
- package/src/components/onboarding/portfolio-step/index.tsx +3 -0
- package/src/components/onboarding/portfolio-step/types.ts +3 -0
- package/src/components/onboarding/wizard-account.ts +38 -3
- package/src/components/onboarding/wizard-broker-sync.ts +45 -67
- package/src/components/onboarding/wizard-model.ts +18 -2
- package/src/components/ui/data-table/opentui/index.tsx +29 -9
- package/src/components/ui/data-table/types.ts +2 -0
- package/src/components/ui/external-link.tsx +4 -2
- package/src/components/ui/loading.tsx +1 -1
- package/src/components/ui/status.tsx +76 -4
- package/src/components/ui/table-layout.test.ts +24 -0
- package/src/components/ui/table-layout.ts +90 -23
- package/src/components/ui/tabs.tsx +86 -4
- package/src/core/app-services.ts +14 -3
- package/src/core/connection-health.test.ts +143 -0
- package/src/core/connection-health.ts +295 -0
- package/src/core/state/app/layout-reducer.ts +34 -0
- package/src/core/state/app/layout.ts +21 -0
- package/src/core/state/app/state.ts +10 -0
- package/src/core/state/app/types.ts +7 -1
- package/src/data/config/chart-settings.ts +11 -2
- package/src/data/config/store/index.test.ts +83 -9
- package/src/data/config/store/migrations.ts +16 -0
- package/src/data/config/store/normalize.ts +59 -1
- package/src/data/fred-series.ts +8 -2
- package/src/i18n/es.ts +126 -0
- package/src/i18n/ja.ts +126 -0
- package/src/i18n/ko.ts +126 -0
- package/src/i18n/zh-cn.ts +126 -0
- package/src/i18n/zh-tw.ts +126 -0
- package/src/market-data/coordinator/chart.ts +3 -2
- package/src/market-data/hooks.tsx +3 -2
- package/src/market-data/market/status.test.ts +12 -0
- package/src/market-data/market/status.ts +34 -17
- package/src/news/aggregator.test.ts +39 -0
- package/src/news/aggregator.ts +78 -22
- package/src/news/hooks.ts +4 -0
- package/src/notifications/app-notifier.test.ts +28 -6
- package/src/notifications/app-notifier.ts +24 -5
- package/src/plugins/broker-sync/broker-sync.test.ts +130 -0
- package/src/plugins/broker-sync/native-loader.ts +10 -0
- package/src/plugins/broker-sync/normalize.ts +271 -0
- package/src/plugins/broker-sync/public.ts +122 -0
- package/src/plugins/broker-sync/robinhood-native.ts +367 -0
- package/src/plugins/broker-sync/robinhood.ts +114 -0
- package/src/plugins/broker-sync/simplefin-native.ts +201 -0
- package/src/plugins/broker-sync/simplefin.ts +70 -0
- package/src/plugins/builtin/account-management/footer.ts +8 -19
- package/src/plugins/builtin/account-management/pane.tsx +13 -8
- package/src/plugins/builtin/ai/pi/host.ts +6 -5
- package/src/plugins/builtin/ai/providers.ts +1 -1
- package/src/plugins/builtin/ai/screener/footer.ts +0 -7
- package/src/plugins/builtin/ai/screener/pane.test.tsx +2 -1
- package/src/plugins/builtin/ai/screener/pane.tsx +3 -1
- package/src/plugins/builtin/ai/screener/results-view.tsx +8 -0
- package/src/plugins/builtin/ai/screener/runner.ts +7 -3
- package/src/plugins/builtin/ai/workspace/pane.tsx +13 -2
- package/src/plugins/builtin/alerts/alert-engine.ts +13 -0
- package/src/plugins/builtin/alerts/constants.ts +2 -1
- package/src/plugins/builtin/alerts/index.tsx +67 -36
- package/src/plugins/builtin/alerts/pane.tsx +17 -65
- package/src/plugins/builtin/analytics/index.tsx +24 -11
- package/src/plugins/builtin/analytics/pane-model.ts +48 -14
- package/src/plugins/builtin/analytics/portfolio-selection.ts +19 -0
- package/src/plugins/builtin/analytics/view.tsx +5 -3
- package/src/plugins/builtin/broker-manager/detail.tsx +7 -2
- package/src/plugins/builtin/broker-manager/footer.ts +4 -9
- package/src/plugins/builtin/broker-manager/index.tsx +1 -6
- package/src/plugins/builtin/buildout/detail/ui.tsx +15 -4
- package/src/plugins/builtin/buildout/pane/header.tsx +1 -0
- package/src/plugins/builtin/changelog/index.tsx +60 -45
- package/src/plugins/builtin/chart-composer/catalog-inventory.test.ts +97 -0
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +366 -0
- package/src/plugins/builtin/chart-composer/chart-spec.ts +21 -1
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +307 -0
- package/src/plugins/builtin/chart-composer/editor/controller.ts +1 -1
- package/src/plugins/builtin/chart-composer/index.tsx +45 -5
- package/src/plugins/builtin/chart-composer/pane.tsx +7 -88
- package/src/plugins/builtin/chart-composer/presets.test.ts +48 -0
- package/src/plugins/builtin/chart-composer/presets.ts +69 -3
- package/src/plugins/builtin/chart-composer/quick-add.tsx +8 -5
- package/src/plugins/builtin/chart-composer/semantic.ts +18 -14
- package/src/plugins/builtin/chart-composer/series-catalog.test.ts +39 -0
- package/src/plugins/builtin/chart-composer/series-catalog.ts +104 -3
- package/src/plugins/builtin/chart-composer/shortcuts.test.ts +10 -10
- package/src/plugins/builtin/chart-composer/shortcuts.ts +4 -12
- package/src/plugins/builtin/chart-composer/use-series-catalog.ts +230 -23
- package/src/plugins/builtin/chat/chat.test.tsx +22 -0
- package/src/plugins/builtin/chat/content/composer.tsx +6 -4
- package/src/plugins/builtin/chat/content/index.tsx +7 -0
- package/src/plugins/builtin/chat/content/snapshot.ts +9 -2
- package/src/plugins/builtin/chat/content/transcript.tsx +10 -0
- package/src/plugins/builtin/chat/controller/channel-actions.ts +11 -1
- package/src/plugins/builtin/chat/controller/channels.ts +13 -3
- package/src/plugins/builtin/chat/controller/index.ts +61 -7
- package/src/plugins/builtin/chat/controller/lifecycle.ts +3 -0
- package/src/plugins/builtin/chat/controller/message-loading.ts +5 -1
- package/src/plugins/builtin/chat/controller/messages.ts +3 -1
- package/src/plugins/builtin/chat/controller/notifications.ts +32 -11
- package/src/plugins/builtin/chat/controller/state.ts +7 -0
- package/src/plugins/builtin/chat/controller/view.ts +1 -0
- package/src/plugins/builtin/chat/controller.test.ts +117 -28
- package/src/plugins/builtin/cloud/auth-commands.ts +18 -0
- package/src/plugins/builtin/cloud/device-signin-dialog.tsx +243 -0
- package/src/plugins/builtin/cloud/device-signin.test.ts +217 -0
- package/src/plugins/builtin/cloud/device-signin.ts +240 -0
- package/src/plugins/builtin/cloud/plugin.tsx +7 -1
- package/src/plugins/builtin/cloud-tweets/table.tsx +57 -10
- package/src/plugins/builtin/composite-plugins.ts +39 -5
- package/src/plugins/builtin/congress-trades/detail.tsx +2 -4
- package/src/plugins/builtin/congress-trades/footer.ts +7 -16
- package/src/plugins/builtin/congress-trades/pane.tsx +12 -20
- package/src/plugins/builtin/connections/index.ts +53 -0
- package/src/plugins/builtin/connections/pane.test.tsx +79 -0
- package/src/plugins/builtin/connections/pane.tsx +258 -0
- package/src/plugins/builtin/correlation/index.test.tsx +2 -1
- package/src/plugins/builtin/correlation/index.tsx +58 -19
- package/src/plugins/builtin/correlation/matrix/model.ts +18 -7
- package/src/plugins/builtin/correlation/relationship/pane.tsx +43 -19
- package/src/plugins/builtin/correlation/settings.ts +1 -1
- package/src/plugins/builtin/credit-conditions/client.test.ts +80 -0
- package/src/plugins/builtin/credit-conditions/client.ts +105 -0
- package/src/plugins/builtin/credit-conditions/index.test.tsx +111 -0
- package/src/plugins/builtin/credit-conditions/index.tsx +227 -0
- package/src/plugins/builtin/credit-conditions/model.test.ts +43 -0
- package/src/plugins/builtin/credit-conditions/model.ts +64 -0
- package/src/plugins/builtin/debug/index.tsx +11 -6
- package/src/plugins/builtin/dividend-yield/client.test.ts +58 -0
- package/src/plugins/builtin/dividend-yield/client.ts +252 -0
- package/src/plugins/builtin/dividend-yield/index.tsx +61 -0
- package/src/plugins/builtin/dividend-yield/model.ts +83 -0
- package/src/plugins/builtin/dividend-yield/pane.tsx +305 -0
- package/src/plugins/builtin/dividend-yield/types.ts +22 -0
- package/src/plugins/builtin/earnings/data/cache.test.ts +10 -7
- package/src/plugins/builtin/earnings/data/cache.ts +23 -9
- package/src/plugins/builtin/earnings/index.tsx +57 -6
- package/src/plugins/builtin/econ/calendar-model.test.ts +37 -3
- package/src/plugins/builtin/econ/calendar-model.ts +32 -26
- package/src/plugins/builtin/econ/fred-cache.test.ts +8 -1
- package/src/plugins/builtin/econ/fred-series-map.ts +18 -0
- package/src/plugins/builtin/econ/index.test.tsx +105 -0
- package/src/plugins/builtin/econ/index.tsx +95 -52
- package/src/plugins/builtin/fear-greed/cache.test.ts +18 -3
- package/src/plugins/builtin/fear-greed/cache.ts +18 -6
- package/src/plugins/builtin/fear-greed/charts.tsx +9 -2
- package/src/plugins/builtin/fear-greed/format.ts +0 -9
- package/src/plugins/builtin/fear-greed/pane.tsx +21 -21
- package/src/plugins/builtin/futures/contracts.ts +100 -0
- package/src/plugins/builtin/futures/index.tsx +298 -0
- package/src/plugins/builtin/futures/model.test.ts +129 -0
- package/src/plugins/builtin/futures/model.ts +136 -0
- package/src/plugins/builtin/futures/pane.test.tsx +239 -0
- package/src/plugins/builtin/futures/table.test.ts +155 -0
- package/src/plugins/builtin/futures/table.tsx +241 -0
- package/src/plugins/builtin/fx-matrix/index.tsx +160 -134
- package/src/plugins/builtin/fx-matrix/pairs.ts +12 -1
- package/src/plugins/builtin/fx-matrix/pane.test.tsx +109 -0
- package/src/plugins/builtin/help/components.tsx +1 -30
- package/src/plugins/builtin/help/index.tsx +5 -25
- package/src/plugins/builtin/holders/pane.tsx +17 -12
- package/src/plugins/builtin/holders/treemap.tsx +4 -2
- package/src/plugins/builtin/insider/index.tsx +20 -10
- package/src/plugins/builtin/ipo-calendar/cache.ts +101 -0
- package/src/plugins/builtin/ipo-calendar/client.test.ts +31 -0
- package/src/plugins/builtin/ipo-calendar/client.ts +296 -0
- package/src/plugins/builtin/ipo-calendar/index.tsx +65 -0
- package/src/plugins/builtin/ipo-calendar/model.ts +145 -0
- package/src/plugins/builtin/ipo-calendar/pane.tsx +328 -0
- package/src/plugins/builtin/ipo-calendar/types.ts +19 -0
- package/src/plugins/builtin/kelly-sizer/index.test.tsx +3 -3
- package/src/plugins/builtin/kelly-sizer/model.ts +8 -1
- package/src/plugins/builtin/kelly-sizer/pane.tsx +33 -15
- package/src/plugins/builtin/kelly-sizer/view.tsx +12 -5
- package/src/plugins/builtin/market-halts/client.ts +114 -0
- package/src/plugins/builtin/market-halts/index.tsx +29 -0
- package/src/plugins/builtin/market-halts/model.test.ts +187 -0
- package/src/plugins/builtin/market-halts/model.ts +291 -0
- package/src/plugins/builtin/market-halts/pane.tsx +256 -0
- package/src/plugins/builtin/market-heatmap/data.test.ts +1 -0
- package/src/plugins/builtin/market-heatmap/data.ts +12 -3
- package/src/plugins/builtin/market-heatmap/index.tsx +131 -46
- package/src/plugins/builtin/market-movers/index.tsx +145 -63
- package/src/plugins/builtin/market-movers/model.ts +19 -3
- package/src/plugins/builtin/market-movers/screener.test.ts +108 -0
- package/src/plugins/builtin/market-movers/screener.ts +168 -10
- package/src/plugins/builtin/news/index.tsx +78 -99
- package/src/plugins/builtin/news/wire/article-search.test.ts +72 -0
- package/src/plugins/builtin/news/wire/article-search.ts +140 -0
- package/src/plugins/builtin/news/wire/breaking/pane.tsx +18 -8
- package/src/plugins/builtin/news/wire/categories.ts +35 -0
- package/src/plugins/builtin/news/wire/default-feeds.ts +47 -1
- package/src/plugins/builtin/news/wire/feed-config.test.ts +10 -5
- package/src/plugins/builtin/news/wire/index.tsx +41 -4
- package/src/plugins/builtin/news/wire/industry-pane.tsx +38 -19
- package/src/plugins/builtin/news/wire/news/detail-view.tsx +10 -5
- package/src/plugins/builtin/news/wire/news/footer.ts +1 -0
- package/src/plugins/builtin/news/wire/news/preset-pane.tsx +15 -6
- package/src/plugins/builtin/news/wire/news/query-presets.ts +16 -2
- package/src/plugins/builtin/news/wire/news/table.test.tsx +54 -0
- package/src/plugins/builtin/news/wire/news/table.tsx +111 -17
- package/src/plugins/builtin/notes/files.test.ts +18 -0
- package/src/plugins/builtin/notes/files.ts +10 -4
- package/src/plugins/builtin/notes/index.tsx +4 -1
- package/src/plugins/builtin/notes/quick-notes-pane.test.tsx +182 -0
- package/src/plugins/builtin/notes/quick-notes-pane.tsx +74 -31
- package/src/plugins/builtin/notes/ticker-notes-tab.test.tsx +380 -0
- package/src/plugins/builtin/notes/ticker-notes-tab.tsx +97 -40
- package/src/plugins/builtin/options/calc-seed.test.ts +118 -0
- package/src/plugins/builtin/options/calc-seed.ts +52 -0
- package/src/plugins/builtin/options/footer.ts +4 -1
- package/src/plugins/builtin/options/index.tsx +22 -1
- package/src/plugins/builtin/options/live-quotes.ts +8 -0
- package/src/plugins/builtin/options/table.ts +3 -1
- package/src/plugins/builtin/options/view.test.tsx +5 -1
- package/src/plugins/builtin/options/view.tsx +112 -17
- package/src/plugins/builtin/options-calculator/index.tsx +35 -0
- package/src/plugins/builtin/options-calculator/model.test.ts +172 -0
- package/src/plugins/builtin/options-calculator/model.ts +273 -0
- package/src/plugins/builtin/options-calculator/pane.test.tsx +138 -0
- package/src/plugins/builtin/options-calculator/pane.tsx +218 -0
- package/src/plugins/builtin/plugin-module.test.ts +16 -2
- package/src/plugins/builtin/plugin-module.ts +5 -1
- package/src/plugins/builtin/polls/client.ts +57 -0
- package/src/plugins/builtin/polls/hooks.ts +20 -0
- package/src/plugins/builtin/polls/index.tsx +35 -0
- package/src/plugins/builtin/polls/normalize.test.ts +230 -0
- package/src/plugins/builtin/polls/normalize.ts +319 -0
- package/src/plugins/builtin/polls/pane.tsx +722 -0
- package/src/plugins/builtin/polls/types.ts +77 -0
- package/src/plugins/builtin/portfolio-list/header.tsx +15 -4
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +7 -3
- package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +1 -1
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +2 -0
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +2 -1
- package/src/plugins/builtin/research/analyst-pane.tsx +40 -67
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +25 -19
- package/src/plugins/builtin/research/index.test.ts +6 -25
- package/src/plugins/builtin/research/index.tsx +11 -5
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +86 -26
- package/src/plugins/builtin/scanner/denied.tsx +31 -0
- package/src/plugins/builtin/scanner/feed.ts +94 -0
- package/src/plugins/builtin/scanner/flow-model.test.ts +85 -0
- package/src/plugins/builtin/scanner/flow-model.ts +133 -0
- package/src/plugins/builtin/scanner/flow-pane.tsx +197 -0
- package/src/plugins/builtin/scanner/hilo-bars.tsx +121 -0
- package/src/plugins/builtin/scanner/hilo-model.test.ts +44 -0
- package/src/plugins/builtin/scanner/hilo-model.ts +75 -0
- package/src/plugins/builtin/scanner/hilo-pane.tsx +165 -0
- package/src/plugins/builtin/scanner/index.ts +109 -0
- package/src/plugins/builtin/scanner/waiting.tsx +11 -0
- package/src/plugins/builtin/sec/index.tsx +11 -7
- package/src/plugins/builtin/sectors/index.tsx +105 -81
- package/src/plugins/builtin/sectors/move-bar.tsx +43 -0
- package/src/plugins/builtin/sectors/sector-data.ts +18 -0
- package/src/plugins/builtin/sectors/sector-model.ts +13 -15
- package/src/plugins/builtin/shared/auto-refresh.ts +51 -0
- package/src/plugins/builtin/shared/cloud-upgrade.ts +29 -5
- package/src/plugins/builtin/shared/pane-footer.ts +16 -3
- package/src/plugins/builtin/shared/screener-live-quotes.test.ts +91 -0
- package/src/plugins/builtin/shared/screener-live-quotes.ts +134 -0
- package/src/plugins/builtin/shared/table-pane.ts +1 -5
- package/src/plugins/builtin/shared/use-quote-board.test.tsx +211 -0
- package/src/plugins/builtin/shared/use-quote-board.ts +195 -0
- package/src/plugins/builtin/short-interest/client.ts +124 -0
- package/src/plugins/builtin/short-interest/index.tsx +62 -0
- package/src/plugins/builtin/short-interest/model.ts +113 -0
- package/src/plugins/builtin/short-interest/pane.tsx +252 -0
- package/src/plugins/builtin/short-interest/types.ts +9 -0
- package/src/plugins/builtin/substack/article-detail.tsx +15 -1
- package/src/plugins/builtin/substack/pane-footer.ts +3 -22
- package/src/plugins/builtin/substack/pane.tsx +1 -2
- package/src/plugins/builtin/thirteenf/api.ts +4 -1
- package/src/plugins/builtin/thirteenf/model.ts +2 -0
- package/src/plugins/builtin/thirteenf/pane.tsx +6 -2
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +10 -4
- package/src/plugins/builtin/ticker-detail/data-panes/provider-search.tsx +67 -11
- package/src/plugins/builtin/ticker-detail/financials/tab.tsx +15 -8
- package/src/plugins/builtin/ticker-detail/index.tsx +5 -21
- package/src/plugins/builtin/ticker-detail/overview/components.tsx +72 -32
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +0 -10
- package/src/plugins/builtin/ticker-detail/pane.tsx +4 -1
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.test.tsx +70 -0
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +34 -26
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +96 -49
- package/src/plugins/builtin/ticker-detail/research-tabs.ts +32 -0
- package/src/plugins/builtin/ticker-research-backend-plugin.ts +2 -9
- package/src/plugins/builtin/ticker-research-plugin.ts +6 -0
- package/src/plugins/builtin/treasury-auctions/cache.test.ts +173 -0
- package/src/plugins/builtin/treasury-auctions/cache.ts +104 -0
- package/src/plugins/builtin/treasury-auctions/client.test.ts +181 -0
- package/src/plugins/builtin/treasury-auctions/client.ts +151 -0
- package/src/plugins/builtin/treasury-auctions/index.tsx +90 -0
- package/src/plugins/builtin/treasury-auctions/model.test.ts +147 -0
- package/src/plugins/builtin/treasury-auctions/model.ts +188 -0
- package/src/plugins/builtin/treasury-auctions/pane.test.tsx +170 -0
- package/src/plugins/builtin/treasury-auctions/pane.tsx +417 -0
- package/src/plugins/builtin/treasury-auctions/types.ts +59 -0
- package/src/plugins/builtin/tv/pane.tsx +67 -7
- package/src/plugins/builtin/tv/youtube-embed.test.ts +84 -0
- package/src/plugins/builtin/tv/youtube-embed.ts +173 -0
- package/src/plugins/builtin/tv/youtube-stream.ts +27 -2
- package/src/plugins/builtin/volatility/client.ts +87 -0
- package/src/plugins/builtin/volatility/index.test.tsx +107 -0
- package/src/plugins/builtin/volatility/index.tsx +193 -0
- package/src/plugins/builtin/volatility/model.test.ts +66 -0
- package/src/plugins/builtin/volatility/model.ts +113 -0
- package/src/plugins/builtin/world-indices/footer.ts +43 -23
- package/src/plugins/builtin/world-indices/index.tsx +44 -93
- package/src/plugins/builtin/world-indices/indices.ts +11 -2
- package/src/plugins/builtin/world-indices/model.ts +17 -24
- package/src/plugins/builtin/world-indices/pane.test.tsx +116 -0
- package/src/plugins/builtin/world-indices/table.tsx +82 -37
- package/src/plugins/builtin/yield-curve/index.tsx +16 -7
- package/src/plugins/builtin/yield-curve/treasury-data.test.ts +25 -0
- package/src/plugins/builtin/yield-curve/treasury-data.ts +16 -0
- package/src/plugins/catalog-backend.ts +8 -0
- package/src/plugins/catalog-ui.ts +8 -0
- package/src/plugins/event-bus.ts +1 -0
- package/src/plugins/ibkr/gateway/account-loaders.ts +1 -1
- package/src/plugins/ibkr/trade/tab/footer.ts +9 -23
- package/src/plugins/ibkr/trade/tab/index.tsx +1 -5
- package/src/plugins/ibkr/trading/pane-view.tsx +149 -87
- package/src/plugins/ibkr/trading/pane.tsx +2 -2
- package/src/plugins/ownership.ts +3 -0
- package/src/plugins/pane-manager/floating.ts +8 -2
- package/src/plugins/pane-manager.test.ts +13 -0
- package/src/plugins/prediction-markets/backend-plugin.ts +2 -0
- package/src/plugins/prediction-markets/capability.test.ts +281 -0
- package/src/plugins/prediction-markets/capability.ts +171 -0
- package/src/plugins/prediction-markets/chart.tsx +18 -26
- package/src/plugins/prediction-markets/columns.ts +3 -2
- package/src/plugins/prediction-markets/controller/catalog.ts +15 -12
- package/src/plugins/prediction-markets/controller/detail.ts +4 -0
- package/src/plugins/prediction-markets/controller/index.ts +0 -15
- package/src/plugins/prediction-markets/detail/book.tsx +3 -23
- package/src/plugins/prediction-markets/detail/overview.tsx +0 -18
- package/src/plugins/prediction-markets/detail/pane.tsx +36 -12
- package/src/plugins/prediction-markets/detail.test.tsx +1 -1
- package/src/plugins/prediction-markets/index.tsx +2 -0
- package/src/plugins/prediction-markets/metrics.ts +28 -18
- package/src/plugins/prediction-markets/navigation.ts +1 -0
- package/src/plugins/prediction-markets/pane.test.tsx +1 -1
- package/src/plugins/prediction-markets/pane.tsx +0 -1
- package/src/plugins/prediction-markets/services/fetch.ts +3 -2
- package/src/plugins/prediction-markets/services/kalshi/adapter.ts +82 -23
- package/src/plugins/prediction-markets/services/kalshi/normalize.ts +3 -1
- package/src/plugins/prediction-markets/services/kalshi/types.ts +14 -0
- package/src/plugins/prediction-markets/services/polymarket/adapter.ts +26 -14
- package/src/plugins/prediction-markets/services/polymarket/detail.ts +67 -18
- package/src/plugins/prediction-markets/test-helpers.tsx +0 -1
- package/src/plugins/prediction-markets/types.ts +3 -9
- package/src/plugins/registry/context.ts +6 -1
- package/src/plugins/registry/index.test.ts +2 -0
- package/src/plugins/registry/index.ts +53 -3
- package/src/plugins/runtime/context.tsx +4 -2
- package/src/plugins/runtime/index.tsx +9 -0
- package/src/remote/controller.test.ts +17 -4
- package/src/renderers/electrobun/bun/application-menu/index.ts +1 -1
- package/src/renderers/electrobun/bun/core-capabilities.ts +2 -2
- package/src/renderers/electrobun/bun/desktop/capability-bridge.test.ts +64 -0
- package/src/renderers/electrobun/bun/desktop/capability-bridge.ts +41 -7
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +5 -2
- package/src/renderers/electrobun/bun/desktop/http-fetch.test.ts +33 -0
- package/src/renderers/electrobun/bun/desktop/http-fetch.ts +53 -6
- package/src/renderers/electrobun/bun/desktop/initialization.test.ts +27 -0
- package/src/renderers/electrobun/bun/desktop/initialization.ts +6 -1
- package/src/renderers/electrobun/bun/index.ts +1 -0
- package/src/renderers/electrobun/shared/protocol.ts +2 -0
- package/src/renderers/electrobun/view/app-services.ts +25 -2
- package/src/renderers/electrobun/view/build-assets.ts +5 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +186 -65
- package/src/renderers/electrobun/view/cli-pane-shot-health.test.ts +25 -0
- package/src/renderers/electrobun/view/cli-pane-shot-health.ts +31 -0
- package/src/renderers/electrobun/view/data-table/index.tsx +10 -11
- package/src/renderers/electrobun/view/data-table/row.tsx +2 -0
- package/src/renderers/electrobun/view/desktop/controls.test.tsx +68 -0
- package/src/renderers/electrobun/view/desktop/controls.tsx +25 -1
- package/src/renderers/electrobun/view/host/box.test.tsx +80 -0
- package/src/renderers/electrobun/view/host/media-surface.tsx +70 -3
- package/src/renderers/electrobun/view/host/tabs.tsx +97 -5
- package/src/renderers/electrobun/view/host/text.tsx +5 -2
- package/src/renderers/electrobun/view/input-host.test.tsx +140 -0
- package/src/renderers/electrobun/view/input-host.tsx +4 -2
- package/src/renderers/electrobun/view/native-stubs/backend-rpc.ts +19 -1
- package/src/renderers/electrobun/view/native-stubs/broker-sync-native-loader.ts +7 -0
- package/src/renderers/electrobun/view/native-stubs/chart/kitty-support.ts +10 -0
- package/src/renderers/electrobun/view/remote/capability-invoker.test.ts +46 -0
- package/src/renderers/electrobun/view/remote/capability-invoker.ts +34 -13
- package/src/renderers/electrobun/view/remote/connection-health-backend.ts +19 -0
- package/src/renderers/electrobun/view/remote/connection-health.test.ts +44 -0
- package/src/renderers/electrobun/view/remote/connection-health.ts +49 -0
- package/src/renderers/electrobun/view/styles.css +5 -0
- package/src/renderers/opentui/dialog-host.tsx +279 -80
- package/src/renderers/opentui/host.tsx +15 -1
- package/src/renderers/opentui/terminal-media.test.ts +102 -0
- package/src/renderers/opentui/terminal-media.ts +142 -0
- package/src/renderers/opentui/test-utils.tsx +9 -6
- package/src/renderers/opentui/toast-host.tsx +136 -7
- package/src/renderers/opentui/ui-host.tsx +19 -3
- package/src/sources/provider-router/connection-health.test.ts +28 -0
- package/src/sources/provider-router/connection-health.ts +47 -0
- package/src/sources/provider-router/history.test.ts +53 -4
- package/src/sources/provider-router/history.ts +119 -14
- package/src/sources/provider-router/index.ts +12 -1
- package/src/sources/yahoo-finance/history.ts +2 -9
- package/src/sources/yahoo-finance/http.ts +1 -1
- package/src/sources/yahoo-finance/symbols.ts +1 -1
- package/src/sources/yahoo-finance/types.ts +19 -0
- package/src/state/app/context/index.test.tsx +101 -0
- package/src/state/app/context/index.tsx +10 -0
- package/src/state/config-save-scheduler.ts +1 -6
- package/src/state/persist-scheduler.test.ts +31 -0
- package/src/state/persist-scheduler.ts +21 -8
- package/src/sync/auth-transition.test.ts +36 -0
- package/src/sync/auth-transition.ts +22 -0
- package/src/sync/core-contributors.test.ts +58 -1
- package/src/sync/core-contributors.ts +39 -2
- package/src/sync/react.ts +9 -0
- package/src/test-support/plugin-runtime.ts +3 -0
- package/src/theme/font-scale.test.ts +14 -0
- package/src/theme/font-scale.ts +69 -0
- package/src/tickers/search/index.test.ts +284 -2
- package/src/tickers/search/index.ts +55 -18
- package/src/tickers/search/ranking.ts +143 -18
- package/src/tickers/search/types.ts +1 -0
- package/src/time-series/alignment.ts +15 -11
- package/src/time-series/field-catalog.ts +10 -0
- package/src/time-series/fundamentals.ts +19 -11
- package/src/time-series/hooks.ts +8 -2
- package/src/time-series/parsed-history-cache.ts +35 -0
- package/src/time-series/resolution.ts +10 -0
- package/src/time-series/resolve.test.ts +332 -3
- package/src/time-series/resolve.ts +225 -25
- package/src/time-series/spec-studies.test.ts +23 -0
- package/src/time-series/spec.ts +21 -2
- package/src/time-series/transforms.test.ts +76 -1
- package/src/time-series/transforms.ts +39 -8
- package/src/time-series/types.ts +9 -2
- package/src/time-series/use-chart-resolution.test.tsx +105 -1
- package/src/time-series/use-chart-resolution.ts +67 -13
- package/src/types/config.ts +30 -27
- package/src/types/media.ts +2 -0
- package/src/types/plugin.ts +8 -1
- package/src/ui/host.tsx +4 -0
- package/src/ui/pointer-drag.ts +12 -0
- package/src/ui/qr.test.ts +79 -0
- package/src/ui/qr.ts +82 -0
- package/src/updater/github-releases.test.ts +3 -3
- package/src/updater/github-releases.ts +1 -1
- package/src/updater.test.ts +117 -16
- package/src/updater.ts +32 -5
- package/src/utils/exchanges.ts +1 -0
- package/src/utils/external-url.test.ts +32 -0
- package/src/utils/external-url.ts +23 -0
- package/src/utils/sort-values.ts +31 -0
- package/src/utils/zoned-date-time.ts +67 -0
- package/src/components/onboarding/wizard-keyboard.ts +0 -306
- package/src/plugins/builtin/chart-composer/date-window-dialog.tsx +0 -120
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { SearchRequestContext, DataProvider } from "../../types/data-provider";
|
|
2
2
|
import type { InstrumentSearchResult } from "../../types/instrument";
|
|
3
3
|
import type { TickerRecord } from "../../types/ticker";
|
|
4
|
+
import { canonicalExchange } from "../../utils/exchanges";
|
|
4
5
|
import { parseOptionSymbol } from "../../utils/options";
|
|
5
6
|
import {
|
|
6
7
|
buildSymbolAliases,
|
|
@@ -36,6 +37,7 @@ const SHARE_CLASS_SUFFIXES = new Set(["A", "B", "C", "D", "K"]);
|
|
|
36
37
|
|
|
37
38
|
interface TickerSearchCandidateOptions {
|
|
38
39
|
includeOptionContracts?: boolean;
|
|
40
|
+
providerRanks?: ReadonlyMap<string, number>;
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
export function normalizeTickerInput(activeTicker: string | null, arg?: string): string | null {
|
|
@@ -53,14 +55,21 @@ export function createLocalTickerSearchCandidates(
|
|
|
53
55
|
if (options.includeOptionContracts === false && isOptionTickerRecord(ticker)) return [];
|
|
54
56
|
const symbol = normalizeTickerSymbol(ticker.metadata.ticker);
|
|
55
57
|
const hint = providerHints.get(symbol);
|
|
58
|
+
const exchangeLabel = ticker.metadata.exchange || hint?.exchange || hint?.primaryExchange;
|
|
59
|
+
const savedExchange = canonicalExchange(ticker.metadata.exchange);
|
|
60
|
+
const hintPrimaryExchange = canonicalExchange(hint?.primaryExchange);
|
|
61
|
+
const primaryExchangeLabel = !savedExchange || !hintPrimaryExchange || savedExchange === hintPrimaryExchange
|
|
62
|
+
? hint?.primaryExchange
|
|
63
|
+
: undefined;
|
|
56
64
|
return [{
|
|
57
65
|
id: `goto:${ticker.metadata.ticker}`,
|
|
58
66
|
label: ticker.metadata.ticker,
|
|
59
67
|
symbol,
|
|
60
68
|
detail: resolveLocalSearchName(ticker, hint),
|
|
61
|
-
right:
|
|
62
|
-
exchangeLabel
|
|
63
|
-
primaryExchangeLabel
|
|
69
|
+
right: exchangeLabel,
|
|
70
|
+
exchangeLabel,
|
|
71
|
+
primaryExchangeLabel,
|
|
72
|
+
providerRank: options.providerRanks?.get(symbol),
|
|
64
73
|
category: "Saved",
|
|
65
74
|
kind: "ticker",
|
|
66
75
|
saved: true,
|
|
@@ -77,7 +86,7 @@ function createProviderTickerSearchCandidates(
|
|
|
77
86
|
localTickers: ReadonlyMap<string, TickerRecord>,
|
|
78
87
|
options: TickerSearchCandidateOptions = {},
|
|
79
88
|
): TickerSearchCandidate[] {
|
|
80
|
-
return searchResults.flatMap((result) => {
|
|
89
|
+
return searchResults.flatMap((result, providerRank) => {
|
|
81
90
|
if (options.includeOptionContracts === false && isOptionSearchResult(result)) return [];
|
|
82
91
|
const symbol = getSearchResultSymbol(result);
|
|
83
92
|
const saved = localTickers.has(symbol);
|
|
@@ -89,6 +98,7 @@ function createProviderTickerSearchCandidates(
|
|
|
89
98
|
right: result.exchange || result.primaryExchange || result.type || undefined,
|
|
90
99
|
exchangeLabel: result.exchange,
|
|
91
100
|
primaryExchangeLabel: result.primaryExchange,
|
|
101
|
+
providerRank,
|
|
92
102
|
category: saved ? "Saved" : "Other Listings",
|
|
93
103
|
kind: "search",
|
|
94
104
|
saved,
|
|
@@ -141,13 +151,16 @@ export function buildTickerSearchCandidates({
|
|
|
141
151
|
totalLimit?: number;
|
|
142
152
|
includeOptionContracts?: boolean;
|
|
143
153
|
}): TickerSearchCandidate[] {
|
|
144
|
-
const candidateOptions = { includeOptionContracts };
|
|
145
154
|
const filteredProviderResults = includeOptionContracts
|
|
146
155
|
? providerResults
|
|
147
156
|
: providerResults.filter((result) => !isOptionSearchResult(result));
|
|
148
|
-
const providerHints =
|
|
157
|
+
const providerHints = buildProviderHints(filteredProviderResults, tickers);
|
|
158
|
+
const candidateOptions = {
|
|
159
|
+
includeOptionContracts,
|
|
160
|
+
providerRanks: providerHints.ranks,
|
|
161
|
+
};
|
|
149
162
|
const localItems = rankTickerSearchItems(
|
|
150
|
-
createLocalTickerSearchCandidates(tickers.values(), providerHints, candidateOptions),
|
|
163
|
+
createLocalTickerSearchCandidates(tickers.values(), providerHints.results, candidateOptions),
|
|
151
164
|
query,
|
|
152
165
|
);
|
|
153
166
|
const providerItems = createProviderTickerSearchCandidates(filteredProviderResults, tickers, candidateOptions);
|
|
@@ -192,16 +205,28 @@ export async function resolveTickerSearch({
|
|
|
192
205
|
};
|
|
193
206
|
}
|
|
194
207
|
|
|
195
|
-
function
|
|
196
|
-
|
|
197
|
-
|
|
208
|
+
function buildProviderHints(
|
|
209
|
+
searchResults: InstrumentSearchResult[],
|
|
210
|
+
localTickers: ReadonlyMap<string, TickerRecord>,
|
|
211
|
+
): {
|
|
212
|
+
results: Map<string, InstrumentSearchResult>;
|
|
213
|
+
ranks: Map<string, number>;
|
|
214
|
+
} {
|
|
215
|
+
const results = new Map<string, InstrumentSearchResult>();
|
|
216
|
+
const ranks = new Map<string, number>();
|
|
217
|
+
for (const [rank, result] of searchResults.entries()) {
|
|
198
218
|
const symbol = getSearchResultSymbol(result);
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
219
|
+
if (!ranks.has(symbol)) ranks.set(symbol, rank);
|
|
220
|
+
const existing = results.get(symbol);
|
|
221
|
+
const preferredExchange = localTickers.get(symbol)?.metadata.exchange;
|
|
222
|
+
if (
|
|
223
|
+
!existing
|
|
224
|
+
|| getProviderHintScore(result, preferredExchange) > getProviderHintScore(existing, preferredExchange)
|
|
225
|
+
) {
|
|
226
|
+
results.set(symbol, result);
|
|
202
227
|
}
|
|
203
228
|
}
|
|
204
|
-
return
|
|
229
|
+
return { results, ranks };
|
|
205
230
|
}
|
|
206
231
|
|
|
207
232
|
async function searchProviderResults(
|
|
@@ -284,14 +309,26 @@ function getProviderHintRichness(result: InstrumentSearchResult): number {
|
|
|
284
309
|
return score;
|
|
285
310
|
}
|
|
286
311
|
|
|
312
|
+
function getProviderHintScore(result: InstrumentSearchResult, preferredExchange?: string): number {
|
|
313
|
+
const canonicalPreferredExchange = canonicalExchange(preferredExchange);
|
|
314
|
+
const matchesPreferredExchange = canonicalPreferredExchange
|
|
315
|
+
&& [
|
|
316
|
+
result.exchange,
|
|
317
|
+
result.primaryExchange,
|
|
318
|
+
result.brokerContract?.exchange,
|
|
319
|
+
result.brokerContract?.primaryExchange,
|
|
320
|
+
].some((exchange) => canonicalExchange(exchange) === canonicalPreferredExchange);
|
|
321
|
+
return getProviderHintRichness(result) + (matchesPreferredExchange ? 10_000 : 0);
|
|
322
|
+
}
|
|
323
|
+
|
|
287
324
|
function assignTickerSearchCategories<T extends TickerSearchCandidate>(items: T[]): T[] {
|
|
288
|
-
|
|
289
|
-
item.saved && item.instrumentClass !== "fund" && item.instrumentClass !== "derivative"
|
|
290
|
-
);
|
|
291
|
-
let assignedPrimaryListing = hasSavedListing;
|
|
325
|
+
let assignedPrimaryListing = false;
|
|
292
326
|
|
|
293
327
|
return items.map((item) => {
|
|
294
328
|
if (item.saved || item.kind === "ticker") {
|
|
329
|
+
if (item.instrumentClass !== "fund" && item.instrumentClass !== "derivative") {
|
|
330
|
+
assignedPrimaryListing = true;
|
|
331
|
+
}
|
|
295
332
|
return { ...item, category: "Saved" };
|
|
296
333
|
}
|
|
297
334
|
if (item.instrumentClass === "fund" || item.instrumentClass === "derivative") {
|
|
@@ -6,6 +6,23 @@ import type {
|
|
|
6
6
|
const FUND_TYPES = new Set(["ETF", "ETN", "ETP", "FUND", "MUTUALFUND", "CEF", "CLOSEDEND"]);
|
|
7
7
|
const DERIVATIVE_TYPES = new Set(["OPT", "OPTION", "OPTIONS", "FUT", "FUTURE", "FUTURES", "WARRANT", "WARRANTS", "RIGHT", "RIGHTS"]);
|
|
8
8
|
const EQUITY_TYPES = new Set(["STK", "STOCK", "EQUITY", "COMMONSTOCK", "COMMON STOCK", "ADR", "ORDINARYSHARES", "ORDINARY SHARES"]);
|
|
9
|
+
const COMPANY_NAME_SUFFIXES = new Set([
|
|
10
|
+
"AG",
|
|
11
|
+
"CO",
|
|
12
|
+
"COMPANY",
|
|
13
|
+
"CORP",
|
|
14
|
+
"CORPORATION",
|
|
15
|
+
"INC",
|
|
16
|
+
"INCORPORATED",
|
|
17
|
+
"LTD",
|
|
18
|
+
"LIMITED",
|
|
19
|
+
"NV",
|
|
20
|
+
"PLC",
|
|
21
|
+
"R",
|
|
22
|
+
"REGISTERED",
|
|
23
|
+
"SA",
|
|
24
|
+
"SE",
|
|
25
|
+
]);
|
|
9
26
|
|
|
10
27
|
const EXCHANGE_HINT_ALIASES: Record<string, string[]> = {
|
|
11
28
|
NASDAQ: ["NASDAQ", "NMS"],
|
|
@@ -46,10 +63,13 @@ const ASSET_HINT_MAP: Record<string, TickerSearchInstrumentClass> = {
|
|
|
46
63
|
FUTURES: "derivative",
|
|
47
64
|
};
|
|
48
65
|
|
|
66
|
+
const SAVED_MATCH_BONUS = 900;
|
|
67
|
+
|
|
49
68
|
interface SearchQueryIntent {
|
|
50
69
|
normalizedQuery: string;
|
|
51
70
|
compactQuery: string;
|
|
52
71
|
companyQuery: string;
|
|
72
|
+
companyQueryKey: string;
|
|
53
73
|
exchangeHints: string[];
|
|
54
74
|
assetPreference: TickerSearchInstrumentClass | null;
|
|
55
75
|
}
|
|
@@ -82,6 +102,7 @@ export function rankTickerSearchItems<T extends Pick<TickerSearchRankableItem, "
|
|
|
82
102
|
const normalizedLabel = normalizeSearchText(item.label);
|
|
83
103
|
const normalizedDetail = normalizeSearchText(item.detail);
|
|
84
104
|
const normalizedRight = normalizeSearchText(item.right || "");
|
|
105
|
+
const companyNameKey = getCompanyNameKey(item.detail);
|
|
85
106
|
const textQueries = [intent.normalizedQuery, intent.companyQuery].filter(Boolean);
|
|
86
107
|
const labelScore = maxScoreForQueries(textQueries, normalizedLabel, {
|
|
87
108
|
exact: 24_000,
|
|
@@ -107,16 +128,23 @@ export function rankTickerSearchItems<T extends Pick<TickerSearchRankableItem, "
|
|
|
107
128
|
.reduce((best, alias) => Math.max(best, scoreSearchAlias(intent, alias)), 0);
|
|
108
129
|
const textScore = labelScore + detailScore + aliasScore;
|
|
109
130
|
const saved = isSavedSearchItem(item);
|
|
110
|
-
const
|
|
111
|
-
+ scoreExchangePreference(intent, item)
|
|
112
|
-
|
|
131
|
+
const explicitIntentScore = scoreAssetPreference(intent, item.instrumentClass)
|
|
132
|
+
+ scoreExchangePreference(intent, item);
|
|
133
|
+
const priorityScore = explicitIntentScore + scoreListingPriority(item);
|
|
134
|
+
const companyMatchRank = scoreCompanyNameMatch(intent, companyNameKey);
|
|
113
135
|
return {
|
|
114
136
|
item,
|
|
115
137
|
index,
|
|
138
|
+
companyMatchRank,
|
|
139
|
+
companyNameKey,
|
|
140
|
+
issuerGroupKey: companyMatchRank > 0 && item.instrumentClass === "equity"
|
|
141
|
+
? companyNameKey
|
|
142
|
+
: null,
|
|
143
|
+
explicitIntentScore,
|
|
116
144
|
normalizedSymbol: normalizeSearchText(item.symbol || item.label),
|
|
117
145
|
symbolMatchRank: scoreSymbolMatchRank(intent, item),
|
|
118
146
|
textScore,
|
|
119
|
-
score: textScore + priorityScore + (textScore > 0 && saved ?
|
|
147
|
+
score: textScore + priorityScore + (textScore > 0 && saved ? SAVED_MATCH_BONUS : 0),
|
|
120
148
|
};
|
|
121
149
|
});
|
|
122
150
|
|
|
@@ -126,21 +154,83 @@ export function rankTickerSearchItems<T extends Pick<TickerSearchRankableItem, "
|
|
|
126
154
|
.map(({ normalizedSymbol }) => normalizedSymbol),
|
|
127
155
|
);
|
|
128
156
|
|
|
129
|
-
const filtered = ranked
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
157
|
+
const filtered = ranked.filter(({ item, normalizedSymbol, textScore }) => {
|
|
158
|
+
if (textScore <= 0) return false;
|
|
159
|
+
if (item.kind !== "search") return true;
|
|
160
|
+
return !matchedLocalSymbols.has(normalizedSymbol);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
type RankedEntry = (typeof ranked)[number];
|
|
164
|
+
const compareFallbackEntries = (a: RankedEntry, b: RankedEntry): number => {
|
|
165
|
+
if (b.symbolMatchRank !== a.symbolMatchRank) return b.symbolMatchRank - a.symbolMatchRank;
|
|
166
|
+
if (b.score !== a.score) return b.score - a.score;
|
|
167
|
+
const aSaved = isSavedSearchItem(a.item);
|
|
168
|
+
const bSaved = isSavedSearchItem(b.item);
|
|
169
|
+
if (aSaved !== bSaved) return aSaved ? -1 : 1;
|
|
170
|
+
if (a.item.label.length !== b.item.label.length) return a.item.label.length - b.item.label.length;
|
|
171
|
+
return a.index - b.index;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const hasExplicitHint = intent.exchangeHints.length > 0 || intent.assetPreference != null;
|
|
175
|
+
const bucketGroups = new Map<string, Map<string, RankedEntry[]>>();
|
|
176
|
+
for (const entry of filtered) {
|
|
177
|
+
const exactSymbolRank = entry.symbolMatchRank >= 2 ? entry.symbolMatchRank : 0;
|
|
178
|
+
const bucketKey = [
|
|
179
|
+
exactSymbolRank,
|
|
180
|
+
hasExplicitHint ? entry.explicitIntentScore : 0,
|
|
181
|
+
entry.companyMatchRank,
|
|
182
|
+
].join(":");
|
|
183
|
+
const groupKey = entry.issuerGroupKey
|
|
184
|
+
? `issuer:${entry.issuerGroupKey}`
|
|
185
|
+
: `item:${entry.index}`;
|
|
186
|
+
const groups = bucketGroups.get(bucketKey) ?? new Map<string, RankedEntry[]>();
|
|
187
|
+
const group = groups.get(groupKey) ?? [];
|
|
188
|
+
group.push(entry);
|
|
189
|
+
groups.set(groupKey, group);
|
|
190
|
+
bucketGroups.set(bucketKey, groups);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const groupOrderByIndex = new Map<number, number>();
|
|
194
|
+
for (const groups of bucketGroups.values()) {
|
|
195
|
+
const orderedGroups = [...groups.values()]
|
|
196
|
+
.map((entries) => ({
|
|
197
|
+
entries,
|
|
198
|
+
representative: entries.reduce((best, entry) =>
|
|
199
|
+
compareFallbackEntries(entry, best) < 0 ? entry : best
|
|
200
|
+
),
|
|
201
|
+
}))
|
|
202
|
+
.sort((a, b) => compareFallbackEntries(a.representative, b.representative));
|
|
203
|
+
orderedGroups.forEach(({ entries }, order) => {
|
|
204
|
+
entries.forEach((entry) => groupOrderByIndex.set(entry.index, order));
|
|
143
205
|
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
filtered.sort((a, b) => {
|
|
209
|
+
// Precedence is exact symbol, explicit query hints, whole-word company
|
|
210
|
+
// relevance, issuer relevance, provider order within that issuer, partial
|
|
211
|
+
// symbol, saved relevance, then stable source order.
|
|
212
|
+
const aExactSymbolRank = a.symbolMatchRank >= 2 ? a.symbolMatchRank : 0;
|
|
213
|
+
const bExactSymbolRank = b.symbolMatchRank >= 2 ? b.symbolMatchRank : 0;
|
|
214
|
+
if (bExactSymbolRank !== aExactSymbolRank) return bExactSymbolRank - aExactSymbolRank;
|
|
215
|
+
if (hasExplicitHint && b.explicitIntentScore !== a.explicitIntentScore) {
|
|
216
|
+
return b.explicitIntentScore - a.explicitIntentScore;
|
|
217
|
+
}
|
|
218
|
+
if (b.companyMatchRank !== a.companyMatchRank) {
|
|
219
|
+
return b.companyMatchRank - a.companyMatchRank;
|
|
220
|
+
}
|
|
221
|
+
const aGroupOrder = groupOrderByIndex.get(a.index) ?? a.index;
|
|
222
|
+
const bGroupOrder = groupOrderByIndex.get(b.index) ?? b.index;
|
|
223
|
+
if (aGroupOrder !== bGroupOrder) return aGroupOrder - bGroupOrder;
|
|
224
|
+
if (
|
|
225
|
+
a.issuerGroupKey
|
|
226
|
+
&& a.issuerGroupKey === b.issuerGroupKey
|
|
227
|
+
) {
|
|
228
|
+
const aProviderRank = a.item.providerRank ?? Number.POSITIVE_INFINITY;
|
|
229
|
+
const bProviderRank = b.item.providerRank ?? Number.POSITIVE_INFINITY;
|
|
230
|
+
if (aProviderRank !== bProviderRank) return aProviderRank - bProviderRank;
|
|
231
|
+
}
|
|
232
|
+
return compareFallbackEntries(a, b);
|
|
233
|
+
});
|
|
144
234
|
|
|
145
235
|
const deduped: T[] = [];
|
|
146
236
|
const seen = new Set<string>();
|
|
@@ -216,6 +306,7 @@ function analyzeSearchQuery(query: string): SearchQueryIntent {
|
|
|
216
306
|
normalizedQuery,
|
|
217
307
|
compactQuery,
|
|
218
308
|
companyQuery,
|
|
309
|
+
companyQueryKey: normalizeCompanyName(companyQuery),
|
|
219
310
|
exchangeHints,
|
|
220
311
|
assetPreference,
|
|
221
312
|
};
|
|
@@ -356,6 +447,40 @@ function scoreListingPriority(item: Pick<TickerSearchRankableItem, "label"> & Pa
|
|
|
356
447
|
return score;
|
|
357
448
|
}
|
|
358
449
|
|
|
450
|
+
function getCompanyNameKey(detail: string): string {
|
|
451
|
+
return normalizeCompanyName(detail.split("|")[0] || "");
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function normalizeCompanyName(name: string): string {
|
|
455
|
+
const tokens = normalizeSearchText(name).split(" ").filter(Boolean);
|
|
456
|
+
while (tokens.length > 1) {
|
|
457
|
+
if (COMPANY_NAME_SUFFIXES.has(tokens.at(-1)!)) {
|
|
458
|
+
tokens.pop();
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const punctuatedSuffix = [...COMPANY_NAME_SUFFIXES].find((suffix) =>
|
|
463
|
+
suffix.length > 1
|
|
464
|
+
&& tokens.length > suffix.length
|
|
465
|
+
&& tokens.slice(-suffix.length).every((token, index) =>
|
|
466
|
+
token.length === 1 && token === suffix[index]
|
|
467
|
+
)
|
|
468
|
+
);
|
|
469
|
+
if (!punctuatedSuffix) break;
|
|
470
|
+
tokens.splice(-punctuatedSuffix.length);
|
|
471
|
+
}
|
|
472
|
+
return tokens.join(" ");
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function scoreCompanyNameMatch(intent: SearchQueryIntent, companyName: string): number {
|
|
476
|
+
const query = intent.companyQueryKey;
|
|
477
|
+
if (!query || !companyName) return 0;
|
|
478
|
+
if (companyName === query) return 3;
|
|
479
|
+
if (companyName.startsWith(`${query} `)) return 2;
|
|
480
|
+
if (companyName.includes(` ${query} `) || companyName.endsWith(` ${query}`)) return 1;
|
|
481
|
+
return 0;
|
|
482
|
+
}
|
|
483
|
+
|
|
359
484
|
function isSavedSearchItem(item: Pick<TickerSearchRankableItem, "kind" | "category"> & Partial<TickerSearchRankableItem>): boolean {
|
|
360
485
|
return item.saved === true || item.kind === "ticker" || item.category === "Saved" || item.category === "Open";
|
|
361
486
|
}
|
|
@@ -80,11 +80,23 @@ export function alignTimeSeries(
|
|
|
80
80
|
const exactMaps = series.map((entry) => (
|
|
81
81
|
new Map(entry.points.map((point) => [effectiveTimeSeriesPointTime(point), point]))
|
|
82
82
|
));
|
|
83
|
+
const carryPoints = series.map((entry) => [...entry.points].sort((left, right) => (
|
|
84
|
+
effectiveTimeSeriesPointTime(left) - effectiveTimeSeriesPointTime(right)
|
|
85
|
+
)));
|
|
83
86
|
const sortedTimes = [...timeline].sort((left, right) => left - right);
|
|
87
|
+
const carryPointers = new Array<number>(series.length).fill(-1);
|
|
84
88
|
const rows: AlignedTimeSeriesRow[] = [];
|
|
85
89
|
for (const time of sortedTimes) {
|
|
86
90
|
const values: Record<string, AlignedSeriesValue | null> = {};
|
|
87
91
|
series.forEach((entry, seriesIndex) => {
|
|
92
|
+
const points = carryPoints[seriesIndex]!;
|
|
93
|
+
let pointer = carryPointers[seriesIndex]!;
|
|
94
|
+
while (
|
|
95
|
+
pointer + 1 < points.length
|
|
96
|
+
&& effectiveTimeSeriesPointTime(points[pointer + 1]!) <= time
|
|
97
|
+
) pointer += 1;
|
|
98
|
+
carryPointers[seriesIndex] = pointer;
|
|
99
|
+
|
|
88
100
|
const exact = exactMaps[seriesIndex]!.get(time);
|
|
89
101
|
if (exact) {
|
|
90
102
|
values[entry.id] = { point: exact, value: scalarPointValue(exact), carried: false };
|
|
@@ -96,20 +108,12 @@ export function alignTimeSeries(
|
|
|
96
108
|
return;
|
|
97
109
|
}
|
|
98
110
|
|
|
99
|
-
|
|
100
|
-
let previousEligibleAt = Number.NEGATIVE_INFINITY;
|
|
101
|
-
for (const point of entry.points) {
|
|
102
|
-
const eligibleAt = effectiveTimeSeriesPointTime(point);
|
|
103
|
-
if (eligibleAt <= time && eligibleAt >= previousEligibleAt) {
|
|
104
|
-
previous = point;
|
|
105
|
-
previousEligibleAt = eligibleAt;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
if (!previous) {
|
|
111
|
+
if (pointer < 0) {
|
|
109
112
|
values[entry.id] = null;
|
|
110
113
|
return;
|
|
111
114
|
}
|
|
112
|
-
const
|
|
115
|
+
const previous = points[pointer]!;
|
|
116
|
+
const age = time - effectiveTimeSeriesPointTime(previous);
|
|
113
117
|
if (options.maxCarryMilliseconds !== undefined && age > options.maxCarryMilliseconds) {
|
|
114
118
|
values[entry.id] = null;
|
|
115
119
|
return;
|
|
@@ -300,6 +300,16 @@ export function isMarketFieldId(id: string): boolean {
|
|
|
300
300
|
return canonicalTimeSeriesFieldId(id).startsWith("market.");
|
|
301
301
|
}
|
|
302
302
|
|
|
303
|
+
export function isPriceOnlyMarketFieldId(id: string): boolean {
|
|
304
|
+
const canonical = canonicalTimeSeriesFieldId(id);
|
|
305
|
+
return canonical === "market.ohlcv"
|
|
306
|
+
|| canonical === "market.open"
|
|
307
|
+
|| canonical === "market.high"
|
|
308
|
+
|| canonical === "market.low"
|
|
309
|
+
|| canonical === "market.close"
|
|
310
|
+
|| canonical === "market.volume";
|
|
311
|
+
}
|
|
312
|
+
|
|
303
313
|
export function isFundamentalFieldId(id: string): boolean {
|
|
304
314
|
const canonical = canonicalTimeSeriesFieldId(id);
|
|
305
315
|
return canonical.startsWith("fundamental.") || canonical.startsWith("valuation.");
|
|
@@ -240,11 +240,10 @@ function mergeStatementsByPeriod(
|
|
|
240
240
|
const groups: InternalStatement[][] = [];
|
|
241
241
|
const sorted = [...statements].sort((left, right) => left.date.localeCompare(right.date));
|
|
242
242
|
for (const statement of sorted) {
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
else groups.push([statement as InternalStatement]);
|
|
243
|
+
const lastGroup = groups.at(-1);
|
|
244
|
+
if (lastGroup && areNearbyFinancialPeriodEnds(lastGroup[0]!.date, statement.date)) {
|
|
245
|
+
lastGroup.push(statement as InternalStatement);
|
|
246
|
+
} else groups.push([statement as InternalStatement]);
|
|
248
247
|
}
|
|
249
248
|
return groups
|
|
250
249
|
.map(mergeStatementPeriodGroup)
|
|
@@ -601,12 +600,22 @@ function pointForStatement(
|
|
|
601
600
|
};
|
|
602
601
|
}
|
|
603
602
|
|
|
603
|
+
/**
|
|
604
|
+
* `PricePoint.date` is typed as a `Date`, but history that has crossed a JSON
|
|
605
|
+
* boundary (persisted caches, the screenshot payload) arrives as a string. Read
|
|
606
|
+
* it defensively so a serialized round trip cannot crash valuation history.
|
|
607
|
+
*/
|
|
608
|
+
function pointTime(point: PricePoint): number {
|
|
609
|
+
const date = point.date;
|
|
610
|
+
return date instanceof Date ? date.getTime() : Date.parse(date as unknown as string);
|
|
611
|
+
}
|
|
612
|
+
|
|
604
613
|
function priceAtOrBefore(priceHistory: readonly PricePoint[], date: string): number | null {
|
|
605
614
|
const target = Date.parse(date);
|
|
606
615
|
if (!Number.isFinite(target)) return null;
|
|
607
616
|
let closest: { time: number; close: number } | undefined;
|
|
608
617
|
for (const point of priceHistory) {
|
|
609
|
-
const time = point
|
|
618
|
+
const time = pointTime(point);
|
|
610
619
|
if (!Number.isFinite(time) || time > target || !finiteNumber(point.close) || point.close <= 0) continue;
|
|
611
620
|
if (!closest || time > closest.time) closest = { time, close: point.close };
|
|
612
621
|
}
|
|
@@ -767,11 +776,10 @@ function dedupeFundamentalPeriods(points: readonly TimeSeriesPoint[]): TimeSerie
|
|
|
767
776
|
left.observedAt.getTime() - right.observedAt.getTime()
|
|
768
777
|
));
|
|
769
778
|
for (const point of sorted) {
|
|
770
|
-
const
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
else groups.push([point]);
|
|
779
|
+
const lastGroup = groups.at(-1);
|
|
780
|
+
if (lastGroup && areNearbyFinancialPeriodEnds(lastGroup[0]!.observedAt, point.observedAt)) {
|
|
781
|
+
lastGroup.push(point);
|
|
782
|
+
} else groups.push([point]);
|
|
775
783
|
}
|
|
776
784
|
return groups
|
|
777
785
|
.map((group) => group.slice(1).reduce(preferredPeriodPoint, group[0]!))
|
package/src/time-series/hooks.ts
CHANGED
|
@@ -2,7 +2,8 @@ import { useMemo } from "react";
|
|
|
2
2
|
import { apiClient } from "../api-client";
|
|
3
3
|
import { loadCachedFredSeries } from "../data/fred-series";
|
|
4
4
|
import { instrumentFromTicker } from "../market-data/request-types";
|
|
5
|
-
import { useAssetData } from "../plugins/runtime";
|
|
5
|
+
import { useAssetData, useCapabilityInvoker } from "../plugins/runtime";
|
|
6
|
+
import { createChartSeriesResolver } from "../capabilities";
|
|
6
7
|
import { useAppSelector } from "../state/app/context";
|
|
7
8
|
import type { FredSeriesRequest } from "../data/fred-series";
|
|
8
9
|
import type { TickerRecord } from "../types/ticker";
|
|
@@ -56,11 +57,16 @@ export function useResolvedChartSpec(
|
|
|
56
57
|
options: UseChartResolutionOptions = {},
|
|
57
58
|
): UseChartResolutionResult {
|
|
58
59
|
const dataProvider = useAssetData();
|
|
60
|
+
const capabilityInvoker = useCapabilityInvoker();
|
|
59
61
|
const tickers = useAppSelector((state) => state.tickers);
|
|
60
62
|
const hydratedSpec = useMemo(
|
|
61
63
|
() => hydrateChartSpecInstruments(spec, tickers),
|
|
62
64
|
[spec, tickers],
|
|
63
65
|
);
|
|
64
|
-
const sources = useMemo(() => ({
|
|
66
|
+
const sources = useMemo(() => ({
|
|
67
|
+
dataProvider,
|
|
68
|
+
loadFredSeries: loadFred,
|
|
69
|
+
resolveCapabilitySeries: createChartSeriesResolver(capabilityInvoker),
|
|
70
|
+
}), [capabilityInvoker, dataProvider]);
|
|
65
71
|
return useChartResolution(hydratedSpec, sources, options);
|
|
66
72
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { PricePoint } from "../types/financials";
|
|
2
|
+
import type { TimeRange } from "./range";
|
|
3
|
+
import type { ManualChartResolution } from "./resolution";
|
|
4
|
+
|
|
5
|
+
const MAX_PARSED_HISTORY = 32;
|
|
6
|
+
const parsedHistory = new Map<string, PricePoint[]>();
|
|
7
|
+
|
|
8
|
+
export function parsedPriceHistoryKey(
|
|
9
|
+
symbol: string,
|
|
10
|
+
exchange: string,
|
|
11
|
+
range: TimeRange,
|
|
12
|
+
resolution?: ManualChartResolution,
|
|
13
|
+
): string {
|
|
14
|
+
return [
|
|
15
|
+
symbol.trim().toUpperCase(),
|
|
16
|
+
exchange.trim().toUpperCase(),
|
|
17
|
+
range,
|
|
18
|
+
resolution ?? "",
|
|
19
|
+
].join("|");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function rememberParsedPriceHistory(key: string, points: PricePoint[]): void {
|
|
23
|
+
if (points.length === 0) return;
|
|
24
|
+
if (parsedHistory.has(key)) parsedHistory.delete(key);
|
|
25
|
+
parsedHistory.set(key, points);
|
|
26
|
+
while (parsedHistory.size > MAX_PARSED_HISTORY) {
|
|
27
|
+
const oldest = parsedHistory.keys().next().value;
|
|
28
|
+
if (oldest === undefined) break;
|
|
29
|
+
parsedHistory.delete(oldest);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function readParsedPriceHistory(key: string): PricePoint[] | undefined {
|
|
34
|
+
return parsedHistory.get(key);
|
|
35
|
+
}
|
|
@@ -169,6 +169,16 @@ export function normalizeChartResolutionSupport(support: readonly ChartResolutio
|
|
|
169
169
|
);
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
/** Yahoo-shaped support used for first paint when broker/provider support is async. */
|
|
173
|
+
export const DEFAULT_CHART_RESOLUTION_SUPPORT: ChartResolutionSupport[] = normalizeChartResolutionSupport([
|
|
174
|
+
{ resolution: "5m", maxRange: "1W" },
|
|
175
|
+
{ resolution: "15m", maxRange: "1M" },
|
|
176
|
+
{ resolution: "1h", maxRange: "3M" },
|
|
177
|
+
{ resolution: "1d", maxRange: "5Y" },
|
|
178
|
+
{ resolution: "1wk", maxRange: "ALL" },
|
|
179
|
+
{ resolution: "1mo", maxRange: "ALL" },
|
|
180
|
+
]);
|
|
181
|
+
|
|
172
182
|
export function intersectChartResolutionSupport(
|
|
173
183
|
supportSets: Array<readonly ChartResolutionSupport[]>,
|
|
174
184
|
): ChartResolutionSupport[] {
|