gloomberb 0.16.0 → 0.16.2
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 +2 -1
- package/package.json +2 -1
- package/src/api-client/beneficial-owners.ts +92 -0
- package/src/api-client/data.ts +44 -11
- package/src/api-client/errors.ts +12 -0
- package/src/api-client/geo.ts +363 -0
- package/src/api-client/index.ts +5 -0
- package/src/api-client/market-discovery.ts +10 -0
- package/src/api-client/members.ts +26 -0
- package/src/api-client/paths.ts +30 -1
- package/src/api-client/perps.ts +41 -0
- package/src/api-client/request.ts +5 -2
- package/src/api-client/types.ts +9 -1
- package/src/app/global-shortcuts.ts +14 -6
- package/src/app/keybindings/actions.ts +1 -1
- package/src/app/runtime/update.ts +38 -2
- package/src/app.tsx +10 -6
- package/src/brokers/account-cache.ts +24 -0
- package/src/cli/commands/command-utils.ts +8 -0
- package/src/cli/commands/crypto-hints.ts +75 -0
- package/src/cli/commands/market.ts +414 -106
- package/src/cli/commands/overview.ts +77 -32
- package/src/cli/commands/ticker.ts +101 -43
- package/src/cli/desktop-pane-shot.ts +34 -4
- package/src/cli/freshness.ts +61 -0
- package/src/cli/help.ts +1 -0
- package/src/cli/helpers.ts +4 -8
- package/src/cli/index.ts +12 -2
- package/src/cli/listing-arg.ts +321 -0
- package/src/cli/pane-functions/access-gate.ts +42 -0
- package/src/cli/pane-functions/catalog.ts +28 -1
- package/src/cli/pane-functions/data.ts +3 -1
- package/src/cli/pane-functions/dom.ts +20 -2
- package/src/cli/pane-functions/freshness.ts +400 -0
- package/src/cli/pane-functions/function-help.ts +36 -22
- package/src/cli/pane-functions/headless.ts +39 -11
- package/src/cli/pane-functions/index.ts +15 -4
- package/src/cli/pane-functions/options.ts +3 -0
- package/src/cli/pane-functions/report.ts +4 -0
- package/src/cli/pane-functions/resolver.ts +35 -7
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +7 -3
- package/src/cli/result.ts +41 -27
- package/src/cli/ticker-resolution.ts +7 -5
- package/src/components/chart/composite/composite-chart.tsx +88 -2536
- package/src/components/chart/composite/drawing-store.ts +59 -0
- package/src/components/chart/composite/legend.tsx +319 -0
- package/src/components/chart/composite/panel-bitmap.ts +139 -0
- package/src/components/chart/composite/panel-gestures.ts +59 -0
- package/src/components/chart/composite/panel-labels.ts +107 -0
- package/src/components/chart/composite/panel-surface.tsx +876 -0
- package/src/components/chart/composite/tool-catalog.ts +98 -0
- package/src/components/chart/composite/toolbar.tsx +186 -0
- package/src/components/chart/composite/tools.ts +8 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +703 -0
- package/src/components/chart/composite/use-composite-viewport.ts +143 -0
- package/src/components/command-bar/commands/collection.ts +5 -1
- package/src/components/command-bar/list/model.ts +5 -0
- package/src/components/command-bar/list/view.tsx +16 -3
- package/src/components/command-bar/pane-templates/workflow.ts +1 -0
- package/src/components/command-bar/routes/root/command-items.ts +9 -2
- package/src/components/command-bar/routes/root/plugin-install.ts +2 -2
- package/src/components/command-bar/routes/root/provider-search.ts +19 -5
- package/src/components/command-bar/routes/root/runtime.ts +14 -5
- package/src/components/command-bar/routes/ticker-search/actions.ts +5 -0
- package/src/components/command-bar/routes/ticker-search/results.ts +31 -5
- package/src/components/command-bar/routes/ticker-search/route.ts +2 -2
- package/src/components/command-bar/routing/actions.ts +2 -0
- package/src/components/command-bar/selection-runtime.ts +38 -0
- package/src/components/command-bar/surface/index.tsx +7 -2
- package/src/components/command-bar/workflow/ops.ts +1 -1
- package/src/components/command-bar/workflow/tickers.ts +6 -0
- package/src/components/data-table/view.tsx +29 -10
- package/src/components/feedback-dialog.tsx +2 -1
- package/src/components/form-modal/field-row.tsx +2 -2
- package/src/components/index.ts +2 -2
- package/src/components/layout/detached-pane-shell.tsx +6 -3
- package/src/components/layout/floating-pane.tsx +6 -0
- package/src/components/layout/header.tsx +24 -7
- package/src/components/layout/missing-pane.tsx +2 -2
- package/src/components/layout/pane/content.tsx +23 -10
- package/src/components/layout/pane/error-boundary.tsx +103 -0
- package/src/components/layout/pane/footer/registration.tsx +68 -23
- package/src/components/layout/pane/header.tsx +61 -28
- package/src/components/layout/pane/index.tsx +6 -0
- package/src/components/layout/pane/title.ts +31 -7
- package/src/components/layout/shell/drag/index.ts +6 -5
- package/src/components/layout/shell/drag/runtime.ts +3 -0
- package/src/components/layout/shell/index.tsx +6 -0
- package/src/components/layout/shell/menu.ts +2 -1
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +29 -10
- package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -3
- package/src/components/layout/shell/ticker-link-menu.ts +23 -9
- package/src/components/metric-treemap/heat-surface.tsx +745 -0
- package/src/components/metric-treemap/heat-tiles.ts +228 -0
- package/src/components/metric-treemap/index.tsx +2 -0
- package/src/components/metric-treemap/layout.ts +8 -0
- package/src/components/metric-treemap/scene.ts +432 -0
- package/src/components/onboarding/onboarding-keyboard.ts +311 -0
- package/src/components/onboarding/onboarding-wizard.tsx +101 -788
- package/src/components/onboarding/use-onboarding-broker-form.ts +263 -0
- package/src/components/onboarding/use-onboarding-progress.ts +298 -0
- package/src/components/onboarding/use-onboarding-upgrade.ts +83 -0
- package/src/components/pane-settings-dialog/field-dialogs.tsx +1 -0
- package/src/components/ticker/list-table-view.tsx +13 -1
- package/src/components/toggle-list.tsx +38 -12
- package/src/components/ui/country-flag-art.tsx +449 -0
- package/src/components/ui/country-flag.tsx +41 -0
- package/src/components/ui/data-table/types.ts +13 -0
- package/src/components/ui/fields.tsx +8 -0
- package/src/components/ui/icon.tsx +2 -0
- package/src/components/ui/index.ts +4 -0
- package/src/components/ui/multi-select/dialog.tsx +108 -22
- package/src/components/ui/range-track.tsx +53 -0
- package/src/components/ui/status.tsx +8 -2
- package/src/components/ui/tabs.tsx +11 -4
- package/src/components/ui/text-prompt-dialog.tsx +4 -2
- package/src/core/state/app/types.ts +10 -1
- package/src/data/config/store/normalize.ts +17 -1
- package/src/i18n/es.ts +24 -4
- package/src/i18n/ja.ts +24 -4
- package/src/i18n/ko.ts +24 -4
- package/src/i18n/zh-cn.ts +24 -4
- package/src/i18n/zh-tw.ts +24 -4
- package/src/layout/ticker-navigation.ts +28 -2
- package/src/market-data/coordinator/chart.ts +1 -1
- package/src/market-data/coordinator/quotes.ts +23 -4
- package/src/market-data/fx-closes.ts +72 -0
- package/src/market-data/market/freshness.ts +78 -6
- package/src/market-data/market/session-close-note.ts +57 -0
- package/src/market-data/market/status.ts +151 -0
- package/src/market-data/published-apac-sessions.ts +66 -0
- package/src/market-data/quotes/contributions.ts +8 -0
- package/src/market-data/quotes/freshness.ts +36 -0
- package/src/market-data/quotes/resolution.ts +24 -8
- package/src/market-data/quotes/screener-live-quotes.ts +49 -4
- package/src/market-data/quotes/time.ts +16 -0
- package/src/plugins/builtin/account-management/pane.tsx +4 -0
- package/src/plugins/builtin/alerts/cli.ts +10 -5
- package/src/plugins/builtin/alerts/index.tsx +1 -0
- package/src/plugins/builtin/analytics/metrics.ts +8 -3
- package/src/plugins/builtin/analytics/risk-client.ts +330 -79
- package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
- package/src/plugins/builtin/analytics/risk-headless.ts +61 -49
- package/src/plugins/builtin/analytics/risk-math.ts +33 -13
- package/src/plugins/builtin/analytics/risk-model.ts +282 -64
- package/src/plugins/builtin/analytics/risk-pane.tsx +62 -30
- package/src/plugins/builtin/analytics/risk-test-data.ts +206 -0
- package/src/plugins/builtin/attention/headless.ts +6 -4
- package/src/plugins/builtin/attention/index.tsx +1 -1
- package/src/plugins/builtin/attention/pane.tsx +1 -1
- package/src/plugins/builtin/awards/headless.ts +1 -0
- package/src/plugins/builtin/awards/pane.tsx +1 -1
- package/src/plugins/builtin/backtest/headless.ts +1 -0
- package/src/plugins/builtin/bond-calculator/headless.ts +1 -0
- package/src/plugins/builtin/buildout/cells.tsx +15 -12
- package/src/plugins/builtin/buildout/detail/company.tsx +3 -3
- package/src/plugins/builtin/buildout/detail/index.tsx +0 -1
- package/src/plugins/builtin/buildout/detail/intel.tsx +6 -6
- package/src/plugins/builtin/buildout/detail/site.tsx +4 -7
- package/src/plugins/builtin/buildout/detail/ui.tsx +0 -19
- package/src/plugins/builtin/buildout/index.tsx +1 -0
- package/src/plugins/builtin/catalysts/headless.ts +3 -1
- package/src/plugins/builtin/catalysts/index.tsx +2 -2
- package/src/plugins/builtin/catalysts/pane.tsx +3 -1
- package/src/plugins/builtin/cds/headless.ts +2 -0
- package/src/plugins/builtin/cds/index.tsx +1 -0
- package/src/plugins/builtin/central-bank-rates/headless.ts +1 -0
- package/src/plugins/builtin/chart-composer/headless.ts +38 -3
- package/src/plugins/builtin/chart-composer/index.tsx +3 -1
- package/src/plugins/builtin/chart-composer/series-expression.ts +18 -2
- package/src/plugins/builtin/chat/channels.ts +19 -3
- package/src/plugins/builtin/chat/content/composer-runtime.ts +28 -13
- package/src/plugins/builtin/chat/content/footer.tsx +15 -6
- package/src/plugins/builtin/chat/content/index.tsx +120 -21
- package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +261 -113
- package/src/plugins/builtin/chat/content/transcript.tsx +20 -2
- package/src/plugins/builtin/chat/direct-messages.ts +200 -0
- package/src/plugins/builtin/chat/index.tsx +1 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +3 -0
- package/src/plugins/builtin/chat/message/header.tsx +16 -6
- package/src/plugins/builtin/chat/message/inline-tokens.tsx +72 -32
- package/src/plugins/builtin/chat/message/profile-popover.tsx +96 -12
- package/src/plugins/builtin/chat/message/terminal.tsx +3 -0
- package/src/plugins/builtin/chat/message/types.ts +14 -2
- package/src/plugins/builtin/chat/profile-popover.ts +18 -13
- package/src/plugins/builtin/clinical-trials/index.tsx +1 -0
- package/src/plugins/builtin/cloud/askg/executor.ts +2 -1
- package/src/plugins/builtin/cloud/plugin.tsx +1 -0
- package/src/plugins/builtin/cloud/team/module.tsx +1 -0
- package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
- package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
- package/src/plugins/builtin/comment-letters/index.tsx +1 -0
- package/src/plugins/builtin/company-attention/headless.ts +5 -1
- package/src/plugins/builtin/company-attention/pane.tsx +1 -1
- package/src/plugins/builtin/company-kpis/headless.ts +1 -0
- package/src/plugins/builtin/congress-trades/headless.ts +1 -0
- package/src/plugins/builtin/correlation/compute.ts +59 -16
- package/src/plugins/builtin/correlation/geo.ts +34 -0
- package/src/plugins/builtin/correlation/headless-schema.ts +4 -1
- package/src/plugins/builtin/correlation/headless.ts +42 -8
- package/src/plugins/builtin/correlation/history.ts +2 -0
- package/src/plugins/builtin/correlation/index.tsx +68 -14
- package/src/plugins/builtin/correlation/matrix/model.ts +17 -2
- package/src/plugins/builtin/correlation/matrix/selection.ts +5 -3
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
- package/src/plugins/builtin/correlation/relationship/pane.tsx +4 -2
- package/src/plugins/builtin/correlation/relationship/view-model.ts +16 -1
- package/src/plugins/builtin/correlation/settings.ts +1 -1
- package/src/plugins/builtin/cot/headless.ts +6 -3
- package/src/plugins/builtin/cot/index.tsx +3 -3
- package/src/plugins/builtin/cot/model.ts +36 -3
- package/src/plugins/builtin/cpi/headless.ts +4 -0
- package/src/plugins/builtin/credit-boards/headless.ts +2 -0
- package/src/plugins/builtin/credit-conditions/headless.ts +1 -0
- package/src/plugins/builtin/credit-documents/gauge.tsx +5 -8
- package/src/plugins/builtin/credit-documents/headless.ts +2 -0
- package/src/plugins/builtin/crypto-board/headless.ts +3 -0
- package/src/plugins/builtin/custom-view/loader.ts +1 -1
- package/src/plugins/builtin/debt-maturities/headless.ts +4 -0
- package/src/plugins/builtin/debt-maturities/wall-bar.tsx +14 -41
- package/src/plugins/builtin/dividend-yield/client.ts +4 -2
- package/src/plugins/builtin/dividend-yield/headless.ts +1 -0
- package/src/plugins/builtin/doe/headless.ts +7 -0
- package/src/plugins/builtin/doe/range-bar.tsx +7 -37
- package/src/plugins/builtin/earnings/client.ts +2 -2
- package/src/plugins/builtin/earnings/headless.ts +5 -0
- package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
- package/src/plugins/builtin/earnings-calls/index.tsx +1 -0
- package/src/plugins/builtin/earnings-ripple/client.ts +91 -18
- package/src/plugins/builtin/earnings-ripple/headless.ts +28 -8
- package/src/plugins/builtin/earnings-ripple/index.tsx +2 -2
- package/src/plugins/builtin/earnings-ripple/model.ts +97 -7
- package/src/plugins/builtin/earnings-ripple/pane.tsx +148 -23
- package/src/plugins/builtin/econ/index.tsx +1 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +2 -0
- package/src/plugins/builtin/equity-screener/headless.ts +2 -0
- package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
- package/src/plugins/builtin/executives/index.tsx +1 -0
- package/src/plugins/builtin/exposure/headless.ts +3 -1
- package/src/plugins/builtin/fear-greed/headless.ts +2 -0
- package/src/plugins/builtin/filing-events/index.tsx +1 -0
- package/src/plugins/builtin/futures-curve/client.ts +12 -3
- package/src/plugins/builtin/futures-curve/headless.ts +39 -10
- package/src/plugins/builtin/futures-curve/index.tsx +3 -3
- package/src/plugins/builtin/futures-curve/model.ts +188 -4
- package/src/plugins/builtin/futures-curve/pane.tsx +51 -9
- package/src/plugins/builtin/fx-matrix/direction.ts +81 -0
- package/src/plugins/builtin/fx-matrix/index.tsx +71 -33
- package/src/plugins/builtin/fx-matrix/live-legs.ts +17 -0
- package/src/plugins/builtin/fx-matrix/pairs.ts +68 -14
- package/src/plugins/builtin/fx-matrix/settings.ts +62 -0
- package/src/plugins/builtin/gpu/headless.ts +7 -3
- package/src/plugins/builtin/gpu/ladder.tsx +26 -30
- package/src/plugins/builtin/gpu/model.ts +27 -1
- package/src/plugins/builtin/holders/beneficial-client.ts +209 -0
- package/src/plugins/builtin/holders/beneficial-model.ts +279 -0
- package/src/plugins/builtin/holders/beneficial-report.ts +126 -0
- package/src/plugins/builtin/holders/beneficial-view.tsx +241 -0
- package/src/plugins/builtin/holders/headless.ts +139 -5
- package/src/plugins/builtin/holders/index.tsx +10 -3
- package/src/plugins/builtin/holders/pane.tsx +20 -3
- package/src/plugins/builtin/holders/report-header.ts +95 -0
- package/src/plugins/builtin/holders/table-model.ts +20 -5
- package/src/plugins/builtin/holders/thirteenf-match.ts +29 -1
- package/src/plugins/builtin/holders/types.ts +2 -1
- package/src/plugins/builtin/insider/headless.ts +2 -0
- package/src/plugins/builtin/ipo-calendar/headless.ts +1 -0
- package/src/plugins/builtin/iv-history/headless.ts +4 -1
- package/src/plugins/builtin/jobs/headless.ts +1 -0
- package/src/plugins/builtin/jobs/index.tsx +1 -0
- package/src/plugins/builtin/jobs/share-bars.tsx +5 -28
- package/src/plugins/builtin/kelly-sizer/index.tsx +1 -0
- package/src/plugins/builtin/macro-day/headless.ts +2 -0
- package/src/plugins/builtin/market-halts/index.tsx +1 -0
- package/src/plugins/builtin/market-heatmap/data.ts +30 -2
- package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
- package/src/plugins/builtin/market-heatmap/index.tsx +245 -81
- package/src/plugins/builtin/market-heatmap/live.ts +88 -0
- package/src/plugins/builtin/market-heatmap/model.ts +146 -0
- package/src/plugins/builtin/market-heatmap/portfolio.ts +50 -11
- package/src/plugins/builtin/market-movers/client.ts +3 -2
- package/src/plugins/builtin/market-movers/headless.ts +10 -1
- package/src/plugins/builtin/market-movers/screener.ts +18 -5
- package/src/plugins/builtin/market-valuation/headless.ts +2 -0
- package/src/plugins/builtin/members/client.ts +53 -0
- package/src/plugins/builtin/members/headless.ts +35 -0
- package/src/plugins/builtin/members/index.tsx +20 -0
- package/src/plugins/builtin/members/model.ts +68 -0
- package/src/plugins/builtin/members/pane.tsx +175 -0
- package/src/plugins/builtin/mna/distress/headless.ts +1 -0
- package/src/plugins/builtin/mna/headless.ts +1 -0
- package/src/plugins/builtin/mna/index.tsx +2 -1
- package/src/plugins/builtin/mna/pane.tsx +5 -2
- package/src/plugins/builtin/money-markets/headless.ts +1 -0
- package/src/plugins/builtin/news/headless.ts +2 -0
- package/src/plugins/builtin/news/wire/index.tsx +8 -1
- package/src/plugins/builtin/notes/cli.ts +14 -6
- package/src/plugins/builtin/notes/index.tsx +1 -0
- package/src/plugins/builtin/openfda/index.tsx +1 -0
- package/src/plugins/builtin/options/index.tsx +2 -1
- package/src/plugins/builtin/options-calculator/headless.ts +2 -0
- package/src/plugins/builtin/options-positioning/headless.ts +3 -0
- package/src/plugins/builtin/options-scenario/headless.ts +5 -0
- package/src/plugins/builtin/pe-band/client.ts +74 -2
- package/src/plugins/builtin/pe-band/headless.ts +26 -8
- package/src/plugins/builtin/pe-band/model.ts +102 -22
- package/src/plugins/builtin/pe-band/pane.tsx +34 -16
- package/src/plugins/builtin/pe-band/report-dates.ts +78 -0
- package/src/plugins/builtin/perps/client.ts +66 -5
- package/src/plugins/builtin/perps/equity-identity.ts +16 -0
- package/src/plugins/builtin/perps/equity-row.tsx +6 -4
- package/src/plugins/builtin/perps/headless.ts +144 -16
- package/src/plugins/builtin/perps/index.tsx +6 -6
- package/src/plugins/builtin/perps/model.ts +189 -12
- package/src/plugins/builtin/perps/pane.tsx +248 -47
- package/src/plugins/builtin/plugin-marketplace/activation.ts +19 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +2 -2
- package/src/plugins/builtin/plugin-marketplace/store.ts +2 -0
- package/src/plugins/builtin/portfolio-list/allocation.ts +245 -0
- package/src/plugins/builtin/portfolio-list/cached-account.ts +33 -0
- package/src/plugins/builtin/portfolio-list/cell-version.ts +19 -1
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +328 -29
- package/src/plugins/builtin/portfolio-list/cli/render.ts +230 -39
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +67 -2
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +35 -31
- package/src/plugins/builtin/portfolio-list/column-values.ts +124 -47
- package/src/plugins/builtin/portfolio-list/headless.ts +98 -16
- package/src/plugins/builtin/portfolio-list/index.tsx +14 -3
- package/src/plugins/builtin/portfolio-list/live-valuation.ts +7 -5
- package/src/plugins/builtin/portfolio-list/mutations.ts +55 -1
- package/src/plugins/builtin/portfolio-list/pane/data.ts +6 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +47 -13
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +43 -2
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +48 -5
- package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +24 -1
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +26 -7
- package/src/plugins/builtin/power/headless.ts +3 -1
- package/src/plugins/builtin/rate-path/headless.ts +2 -0
- package/src/plugins/builtin/realized-vol/headless.ts +2 -0
- package/src/plugins/builtin/relative-rotation/headless.ts +2 -0
- package/src/plugins/builtin/research/analyst-headless.ts +3 -0
- package/src/plugins/builtin/research/events-headless.ts +2 -0
- package/src/plugins/builtin/research/headless.ts +2 -0
- package/src/plugins/builtin/research/index.tsx +1 -0
- package/src/plugins/builtin/research/relative-valuation-headless.ts +10 -5
- package/src/plugins/builtin/research/relative-valuation-model.ts +11 -3
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +3 -3
- package/src/plugins/builtin/research-search/index.tsx +1 -0
- package/src/plugins/builtin/revenue-breakdown/headless.ts +2 -0
- package/src/plugins/builtin/reverse-dcf/headless.ts +2 -0
- package/src/plugins/builtin/risk-factors/headless.ts +2 -0
- package/src/plugins/builtin/scanner/flow-history.ts +2 -13
- package/src/plugins/builtin/scanner/headless.ts +14 -0
- package/src/plugins/builtin/scanner/hilo-bars.tsx +12 -70
- package/src/plugins/builtin/scanner/hilo-model.ts +0 -18
- package/src/plugins/builtin/seasonality/headless.ts +2 -0
- package/src/plugins/builtin/sec/command-bar-search.ts +14 -4
- package/src/plugins/builtin/sec/filing-content.ts +42 -17
- package/src/plugins/builtin/sec/forms.ts +12 -0
- package/src/plugins/builtin/sec/headless.ts +2 -0
- package/src/plugins/builtin/sectors/client.ts +1 -0
- package/src/plugins/builtin/sectors/headless.ts +9 -1
- package/src/plugins/builtin/sectors/move-bar.tsx +10 -32
- package/src/plugins/builtin/sectors/sector-model.ts +2 -0
- package/src/plugins/builtin/shared/crypto-pair.ts +14 -0
- package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
- package/src/plugins/builtin/shared/report-freshness.ts +57 -0
- package/src/plugins/builtin/shared/research-cells.tsx +4 -9
- package/src/plugins/builtin/short-interest/headless.ts +2 -0
- package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
- package/src/plugins/builtin/short-volume/headless.ts +1 -0
- package/src/plugins/builtin/social-mentions/headless.ts +1 -0
- package/src/plugins/builtin/social-mentions/index.tsx +1 -1
- package/src/plugins/builtin/supply-chain/headless.ts +7 -1
- package/src/plugins/builtin/supply-chain/index.tsx +10 -1
- package/src/plugins/builtin/supply-chain/model.ts +27 -2
- package/src/plugins/builtin/supply-chain/pane.tsx +71 -32
- package/src/plugins/builtin/themes/headless.ts +3 -0
- package/src/plugins/builtin/thirteenf/headless.ts +110 -25
- package/src/plugins/builtin/thirteenf/index.tsx +2 -1
- package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
- package/src/plugins/builtin/ticker-detail/headless.ts +7 -1
- package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
- package/src/plugins/builtin/ticker-detail/overview/components.tsx +5 -60
- package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -2
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +26 -26
- package/src/plugins/builtin/ticker-detail/pane.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/quote-footer.ts +7 -1
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +20 -4
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -2
- package/src/plugins/builtin/time-sales/headless.ts +5 -1
- package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
- package/src/plugins/builtin/vol-surface/index.tsx +1 -1
- package/src/plugins/builtin/volatility/headless.ts +6 -1
- package/src/plugins/builtin/world-indices/headless.ts +2 -0
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +157 -0
- package/src/plugins/builtin/world-venue-map/basemap.ts +214 -0
- package/src/plugins/builtin/world-venue-map/client.ts +45 -0
- package/src/plugins/builtin/world-venue-map/entity-detail.tsx +147 -0
- package/src/plugins/builtin/world-venue-map/entity-table.ts +59 -0
- package/src/plugins/builtin/world-venue-map/evidence.ts +77 -0
- package/src/plugins/builtin/world-venue-map/feed.ts +293 -0
- package/src/plugins/builtin/world-venue-map/geo-draw.tsx +248 -0
- package/src/plugins/builtin/world-venue-map/geo-series.ts +142 -0
- package/src/plugins/builtin/world-venue-map/geo-svg.tsx +447 -0
- package/src/plugins/builtin/world-venue-map/headless.ts +146 -0
- package/src/plugins/builtin/world-venue-map/ids.ts +1 -0
- package/src/plugins/builtin/world-venue-map/index.ts +67 -4
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +552 -0
- package/src/plugins/builtin/world-venue-map/layers.ts +348 -0
- package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +381 -45
- package/src/plugins/builtin/world-venue-map/model.ts +7 -4
- package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +199 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/world-50m.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/pane.tsx +28 -43
- package/src/plugins/builtin/world-venue-map/use-geo.ts +55 -0
- package/src/plugins/builtin/world-venue-map/venue-header.tsx +32 -0
- package/src/plugins/builtin/yield-curve/headless.ts +16 -0
- package/src/plugins/catalog-browser.ts +2 -0
- package/src/plugins/catalog-manifest.ts +1 -0
- package/src/plugins/catalog-ui.ts +3 -1
- package/src/plugins/catalog.ts +1 -1
- package/src/plugins/host-link.ts +33 -1
- package/src/plugins/installer.ts +48 -12
- package/src/plugins/loader.ts +30 -3
- package/src/plugins/manager-node.ts +15 -5
- package/src/plugins/registry/index.ts +1 -1
- package/src/plugins/registry/pane-settings.ts +26 -7
- package/src/public/__snapshots__/public-api.test.ts.snap +2 -0
- package/src/renderers/dom/build-assets.ts +81 -3
- package/src/renderers/dom/data-table/row.tsx +52 -16
- package/src/renderers/dom/desktop/controls.tsx +7 -3
- package/src/renderers/dom/desktop/icons.tsx +1 -0
- package/src/renderers/dom/desktop/list-view.tsx +35 -10
- package/src/renderers/dom/desktop/popover.tsx +73 -14
- package/src/renderers/dom/host/box.tsx +69 -26
- package/src/renderers/dom/host/input.tsx +14 -3
- package/src/renderers/dom/host/tabs.tsx +37 -1
- package/src/renderers/dom/styles.css +41 -7
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +11 -6
- package/src/renderers/electrobun/bun/desktop/backend.ts +1 -0
- package/src/renderers/electrobun/bun/desktop/update.ts +181 -87
- package/src/renderers/electrobun/bun/index.ts +73 -6
- package/src/renderers/electrobun/bun/window/remembered-frame.ts +122 -0
- package/src/renderers/electrobun/shared/protocol.ts +3 -0
- package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +3 -1
- package/src/renderers/electrobun/view/main.tsx +7 -1
- package/src/renderers/electrobun/view/renderer-window-error.ts +18 -0
- package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
- package/src/renderers/electrobun/view/update-host.ts +45 -21
- package/src/renderers/opentui/host.tsx +5 -0
- package/src/sources/gloomberb-cloud/index.ts +25 -4
- package/src/sources/gloomberb-cloud/normalizers.ts +36 -5
- package/src/sources/provider-router/cached-routes.ts +4 -1
- package/src/sources/provider-router/financials.ts +11 -8
- package/src/sources/provider-router/history.ts +15 -10
- package/src/sources/sec-registrant.ts +75 -0
- package/src/state/app/context/index.tsx +24 -8
- package/src/state/hooks/quote-streaming.ts +41 -26
- package/src/sync/core-contributors.ts +4 -0
- package/src/telemetry/benign-window-error.ts +7 -0
- package/src/telemetry/crash-reports-dom.ts +2 -0
- package/src/telemetry/crash-reports.ts +4 -1
- package/src/test-support/cli-context.ts +10 -2
- package/src/test-support/daily-nav.ts +25 -0
- package/src/theme/heat-colors.ts +357 -2
- package/src/tickers/instrument-kind.ts +34 -7
- package/src/tickers/search/asset-classes.ts +24 -9
- package/src/tickers/search/index.ts +44 -11
- package/src/tickers/search/ranking.ts +23 -3
- package/src/time-series/resolve.ts +1 -1
- package/src/time-series/use-chart-resolution.ts +1 -1
- package/src/types/context-menu.ts +6 -0
- package/src/types/data-provider.ts +2 -0
- package/src/types/financials.ts +5 -0
- package/src/types/headless.ts +79 -2
- package/src/types/plugin.ts +38 -6
- package/src/types/ticker.ts +15 -0
- package/src/ui/context-menu.tsx +1 -0
- package/src/ui/host.tsx +16 -0
- package/src/updater/index.ts +38 -13
- package/src/utils/async-deadline.ts +21 -0
- package/src/utils/cli-output.ts +5 -1
- package/src/utils/crypto-pair.ts +41 -0
- package/src/utils/currency-units.ts +14 -0
- package/src/utils/depositary-receipt.ts +26 -0
- package/src/utils/exchanges.ts +72 -0
- package/src/utils/fire-and-forget.ts +24 -0
- package/src/utils/format.ts +13 -0
- package/src/utils/price-earnings.ts +70 -3
- package/src/utils/price-history.ts +58 -13
- package/src/utils/rpc-timeout-error.ts +27 -0
- package/src/utils/sec.ts +13 -1
- package/src/utils/utc-time.ts +79 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AppConfig } from "../../../types/config";
|
|
2
|
-
import type { Portfolio, TickerPosition, TickerRecord, Watchlist } from "../../../types/ticker";
|
|
2
|
+
import type { Portfolio, PortfolioCash, TickerPosition, TickerRecord, Watchlist } from "../../../types/ticker";
|
|
3
3
|
import { resolveCurrencyUnit } from "../../../utils/currency-units";
|
|
4
4
|
import { slugifyName } from "../../../utils/slugify";
|
|
5
5
|
import { parseCollectionRef } from "../cloud/team/collections";
|
|
@@ -149,6 +149,60 @@ export function adoptHeldPortfolioCurrencies(config: AppConfig, tickers: Iterabl
|
|
|
149
149
|
return next;
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
function updatePortfolio(config: AppConfig, portfolioId: string, update: (portfolio: Portfolio) => Portfolio): AppConfig {
|
|
153
|
+
if (!config.portfolios.some((portfolio) => portfolio.id === portfolioId)) throw new Error("Portfolio not found.");
|
|
154
|
+
return {
|
|
155
|
+
...config,
|
|
156
|
+
portfolios: config.portfolios.map((portfolio) => (portfolio.id === portfolioId ? update(portfolio) : portfolio)),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Records the cash held beside a portfolio's positions, replacing any earlier entry. */
|
|
161
|
+
export function setPortfolioCash(config: AppConfig, portfolioId: string, cash: PortfolioCash): AppConfig {
|
|
162
|
+
const currency = cash.currency.trim().toUpperCase();
|
|
163
|
+
if (!Number.isFinite(cash.amount)) throw new Error("Cash amount must be a valid number.");
|
|
164
|
+
if (!/^[A-Z]{3}$/.test(currency)) throw new Error(`"${cash.currency}" is not a currency code such as USD or EUR.`);
|
|
165
|
+
return updatePortfolio(config, portfolioId, (portfolio) => ({ ...portfolio, cash: { amount: cash.amount, currency } }));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function clearPortfolioCash(config: AppConfig, portfolioId: string): { config: AppConfig; changed: boolean } {
|
|
169
|
+
const portfolio = config.portfolios.find((entry) => entry.id === portfolioId);
|
|
170
|
+
if (!portfolio?.cash) return { config, changed: false };
|
|
171
|
+
return {
|
|
172
|
+
config: updatePortfolio(config, portfolioId, ({ cash: _cash, ...rest }) => rest),
|
|
173
|
+
changed: true,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** Sets one target weight, in percent, keyed by ticker symbol (`CASH` for the cash line). */
|
|
178
|
+
export function setPortfolioTargetWeight(config: AppConfig, portfolioId: string, symbol: string, weight: number): AppConfig {
|
|
179
|
+
if (!Number.isFinite(weight) || weight < 0 || weight > 100) throw new Error("Target weight must be between 0% and 100%.");
|
|
180
|
+
if (!symbol.trim()) throw new Error("Ticker symbol is required.");
|
|
181
|
+
return updatePortfolio(config, portfolioId, (portfolio) => ({
|
|
182
|
+
...portfolio,
|
|
183
|
+
targetWeights: { ...portfolio.targetWeights, [symbol]: weight },
|
|
184
|
+
}));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** Removes one symbol's target, or every target when no symbol is given. */
|
|
188
|
+
export function clearPortfolioTargetWeights(
|
|
189
|
+
config: AppConfig,
|
|
190
|
+
portfolioId: string,
|
|
191
|
+
symbol?: string,
|
|
192
|
+
): { config: AppConfig; removed: string[] } {
|
|
193
|
+
const portfolio = config.portfolios.find((entry) => entry.id === portfolioId);
|
|
194
|
+
const current = portfolio?.targetWeights ?? {};
|
|
195
|
+
const removed = symbol == null ? Object.keys(current) : Object.keys(current).filter((key) => key === symbol);
|
|
196
|
+
if (removed.length === 0) return { config, removed };
|
|
197
|
+
const remaining = Object.fromEntries(Object.entries(current).filter(([key]) => !removed.includes(key)));
|
|
198
|
+
return {
|
|
199
|
+
config: updatePortfolio(config, portfolioId, ({ targetWeights: _targets, ...rest }) => (
|
|
200
|
+
Object.keys(remaining).length > 0 ? { ...rest, targetWeights: remaining } : rest
|
|
201
|
+
)),
|
|
202
|
+
removed,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
152
206
|
export function createManualPortfolio(
|
|
153
207
|
config: AppConfig,
|
|
154
208
|
name: string,
|
|
@@ -34,6 +34,9 @@ const QUOTE_SORT_COLUMN_IDS = new Set([
|
|
|
34
34
|
"ext_hours",
|
|
35
35
|
"mkt_value",
|
|
36
36
|
"weight",
|
|
37
|
+
"drift",
|
|
38
|
+
"trade",
|
|
39
|
+
"trade_value",
|
|
37
40
|
"day_pnl",
|
|
38
41
|
"pnl",
|
|
39
42
|
"pnl_pct",
|
|
@@ -153,9 +156,12 @@ export function buildTrackedCurrencies(
|
|
|
153
156
|
financialsMap: Map<string, TickerFinancials>,
|
|
154
157
|
accountState: ResolvedPortfolioAccountState | null,
|
|
155
158
|
baseCurrency: string,
|
|
159
|
+
/** The currency of cash entered by hand. */
|
|
160
|
+
cashCurrency?: string,
|
|
156
161
|
): string[] {
|
|
157
162
|
const currencies = new Set<string>([baseCurrency]);
|
|
158
163
|
if (accountState?.account.currency) currencies.add(accountState.account.currency);
|
|
164
|
+
if (cashCurrency) currencies.add(cashCurrency);
|
|
159
165
|
|
|
160
166
|
for (const ticker of tickers) {
|
|
161
167
|
if (ticker.metadata.currency) {
|
|
@@ -89,6 +89,16 @@ import { useThrottledMemo } from "../use-throttled-memo";
|
|
|
89
89
|
import { useColumnClock } from "../use-column-clock";
|
|
90
90
|
import { liveMarketCapitalization } from "../live-valuation";
|
|
91
91
|
import { hasUnknownOptionMultiplier } from "../position-metrics";
|
|
92
|
+
import {
|
|
93
|
+
allocationTotal,
|
|
94
|
+
buildPortfolioAllocation,
|
|
95
|
+
CASH_SYMBOL,
|
|
96
|
+
hasTargetWeights,
|
|
97
|
+
resolvePortfolioCash,
|
|
98
|
+
} from "../allocation";
|
|
99
|
+
|
|
100
|
+
/** Columns that need the portfolio's total. */
|
|
101
|
+
const ALLOCATION_COLUMN_IDS = new Set(["weight", "drift", "trade", "trade_value"]);
|
|
92
102
|
|
|
93
103
|
// Rows follow every tick. Totals walk the whole collection, so the footer
|
|
94
104
|
// coalesces to about four updates a second and the weight denominator to one.
|
|
@@ -163,9 +173,10 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
|
|
|
163
173
|
|
|
164
174
|
const accountStateInput = useMemo(() => ({ brokerAccounts, config }), [brokerAccounts, config]);
|
|
165
175
|
const { accountState, accountsError } = usePortfolioAccountState(currentPortfolio, accountStateInput);
|
|
176
|
+
const portfolioTargets = currentPortfolio?.targetWeights;
|
|
166
177
|
const columns = useMemo(
|
|
167
|
-
() => resolveVisibleColumns(paneSettings.columnIds, isPortfolioTab),
|
|
168
|
-
[isPortfolioTab, paneSettings.columnIds],
|
|
178
|
+
() => resolveVisibleColumns(paneSettings.columnIds, isPortfolioTab, { targetWeights: hasTargetWeights(currentPortfolio) }),
|
|
179
|
+
[currentPortfolio, isPortfolioTab, paneSettings.columnIds],
|
|
169
180
|
);
|
|
170
181
|
const supplementalData = usePortfolioSupplementalData(tickers, columns, appActive);
|
|
171
182
|
const visibleWarmupRequirements = useMemo(
|
|
@@ -178,19 +189,32 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
|
|
|
178
189
|
() => resolvePortfolioTotalsCurrency(currentPortfolio, config.baseCurrency),
|
|
179
190
|
[config.baseCurrency, currentPortfolio],
|
|
180
191
|
);
|
|
192
|
+
// The broker account's cash when it reports one, else the cash entered by hand.
|
|
193
|
+
const cashLine = useMemo(
|
|
194
|
+
() => isPortfolioTab ? resolvePortfolioCash(currentPortfolio, accountState?.account) : null,
|
|
195
|
+
[accountState, currentPortfolio, isPortfolioTab],
|
|
196
|
+
);
|
|
181
197
|
const trackedCurrencies = useMemo(
|
|
182
|
-
() => buildTrackedCurrencies(tickers, financialsMap, accountState, totalsCurrency),
|
|
183
|
-
[accountState, financialsMap, tickers, totalsCurrency],
|
|
198
|
+
() => buildTrackedCurrencies(tickers, financialsMap, accountState, totalsCurrency, cashLine?.source === "manual" ? cashLine.currency : undefined),
|
|
199
|
+
[accountState, cashLine, financialsMap, tickers, totalsCurrency],
|
|
184
200
|
);
|
|
185
201
|
const exchangeRates = useFxRatesMap(trackedCurrencies);
|
|
186
202
|
const conversionCurrencies = trackedCurrencies.some((currency) => currency !== totalsCurrency) ? trackedCurrencies : [];
|
|
187
203
|
const fxStatus = summarizeFxRates(conversionCurrencies, exchangeRates, (currency) => getSharedMarketDataCoordinator()?.getFxEntry(currency));
|
|
188
204
|
const fxStatusText = fxStatusLabel(fxStatus);
|
|
189
205
|
const activeSort = resolveCollectionSortPreference(activeCollectionId, isPortfolioTab, collectionSorts);
|
|
206
|
+
const accountCurrency = accountState?.account.currency ?? "";
|
|
207
|
+
const convertAccountValue = useCallback(
|
|
208
|
+
(value: number) => convertCurrency(value, accountCurrency, totalsCurrency, exchangeRates),
|
|
209
|
+
[accountCurrency, exchangeRates, totalsCurrency],
|
|
210
|
+
);
|
|
211
|
+
const cashValue = cashLine == null ? null
|
|
212
|
+
: cashLine.source === "broker" ? convertAccountValue(cashLine.amount)
|
|
213
|
+
: convertCurrency(cashLine.amount, cashLine.currency, totalsCurrency, exchangeRates);
|
|
190
214
|
// Only weights divide by the total: skip the walk when nothing shows one.
|
|
191
215
|
const needsWeightTotal = isPortfolioTab
|
|
192
|
-
&& (viewMode === "grid" || columns.some((column) => column.id
|
|
193
|
-
const
|
|
216
|
+
&& (viewMode === "grid" || columns.some((column) => ALLOCATION_COLUMN_IDS.has(column.id)));
|
|
217
|
+
const weightHoldings = useThrottledMemo(
|
|
194
218
|
() => needsWeightTotal ? calculatePortfolioSummaryTotals(
|
|
195
219
|
tickers,
|
|
196
220
|
financialsMap,
|
|
@@ -198,11 +222,13 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
|
|
|
198
222
|
exchangeRates,
|
|
199
223
|
isPortfolioTab,
|
|
200
224
|
activeCollectionId,
|
|
201
|
-
).
|
|
225
|
+
).allocationHoldings : undefined,
|
|
202
226
|
[financialsMap],
|
|
203
227
|
[activeCollectionId, exchangeRates, isPortfolioTab, needsWeightTotal, tickers, totalsCurrency],
|
|
204
228
|
WEIGHT_TOTAL_THROTTLE_MS,
|
|
205
229
|
);
|
|
230
|
+
// Priced holdings plus cash, as `portfolio show` totals them.
|
|
231
|
+
const portfolioTotalMarketValue = weightHoldings ? allocationTotal(weightHoldings, cashValue) ?? undefined : undefined;
|
|
206
232
|
|
|
207
233
|
// The header, footer and notices move with live quotes a few times a second,
|
|
208
234
|
// not on every tick.
|
|
@@ -226,6 +252,7 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
|
|
|
226
252
|
baseCurrency: totalsCurrency,
|
|
227
253
|
exchangeRates,
|
|
228
254
|
portfolioTotalMarketValue,
|
|
255
|
+
portfolioTargets,
|
|
229
256
|
supplementalVersion: supplementalData.version,
|
|
230
257
|
analystResearch: supplementalData.analystResearch,
|
|
231
258
|
corporateActions: supplementalData.corporateActions,
|
|
@@ -234,6 +261,7 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
|
|
|
234
261
|
activeCollectionId,
|
|
235
262
|
exchangeRates,
|
|
236
263
|
isPortfolioTab,
|
|
264
|
+
portfolioTargets,
|
|
237
265
|
portfolioTotalMarketValue,
|
|
238
266
|
supplementalData,
|
|
239
267
|
totalsCurrency,
|
|
@@ -292,11 +320,16 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
|
|
|
292
320
|
: null,
|
|
293
321
|
[accountState],
|
|
294
322
|
);
|
|
295
|
-
|
|
296
|
-
const
|
|
297
|
-
(
|
|
298
|
-
|
|
299
|
-
|
|
323
|
+
// Cash entered by hand gets its own figures; a broker account's cash is already in the header.
|
|
324
|
+
const manualCash = useMemo(() => {
|
|
325
|
+
if (!isPortfolioTab || accountState || (cashLine == null && portfolioTargets?.[CASH_SYMBOL] == null)) return null;
|
|
326
|
+
const allocation = buildPortfolioAllocation({
|
|
327
|
+
holdings: portfolioSummaryTotals.allocationHoldings ?? [],
|
|
328
|
+
cashValue: cashValue ?? (cashLine ? Number.NaN : null),
|
|
329
|
+
targets: portfolioTargets,
|
|
330
|
+
});
|
|
331
|
+
return allocation.cash ? { ...allocation.cash, total: allocation.total } : null;
|
|
332
|
+
}, [accountState, cashLine, cashValue, isPortfolioTab, portfolioSummaryTotals, portfolioTargets]);
|
|
300
333
|
const summarySegments = useMemo(() => buildPortfolioSummarySegments({
|
|
301
334
|
totals: portfolioSummaryTotals,
|
|
302
335
|
accountState: summaryAccountState,
|
|
@@ -304,7 +337,8 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
|
|
|
304
337
|
convertAccountValue,
|
|
305
338
|
currency: totalsCurrency,
|
|
306
339
|
baseCurrency: config.baseCurrency,
|
|
307
|
-
|
|
340
|
+
manualCash,
|
|
341
|
+
}), [config.baseCurrency, convertAccountValue, isPortfolioTab, manualCash, portfolioSummaryTotals, summaryAccountState, totalsCurrency]);
|
|
308
342
|
// The header row sits in the pane's one-cell side padding, like the table.
|
|
309
343
|
const summaryWidth = Math.max(0, width - 2);
|
|
310
344
|
const summaryLayout = useMemo(() => layoutPortfolioSummaryHeader(summarySegments, summaryWidth, {
|
|
@@ -9,10 +9,11 @@ import { useAppInputCapture } from "../../../../state/app/input-capture";
|
|
|
9
9
|
import { t, tf } from "../../../../i18n";
|
|
10
10
|
import { getSharedRegistry } from "../../../registry";
|
|
11
11
|
import { usePluginAppActions } from "../../../runtime";
|
|
12
|
+
import { isDialogOpen } from "../../../../ui/dialog-stack";
|
|
12
13
|
import { colors, priceColor } from "../../../../theme/colors";
|
|
13
14
|
import { formatPercentRaw } from "../../../../utils/format";
|
|
14
15
|
import { formatMarketPrice } from "../../../../market-data/market/format";
|
|
15
|
-
import { upsertTickerFromSearchResult } from "../../../../tickers/search";
|
|
16
|
+
import { listingChoiceQuery, upsertTickerFromSearchResult } from "../../../../tickers/search";
|
|
16
17
|
import type { TickerRecord } from "../../../../types/ticker";
|
|
17
18
|
import { addTickerToPortfolio, addTickerToWatchlist } from "../mutations";
|
|
18
19
|
import { captureAttentionAction } from "../../../../telemetry/attention-counts";
|
|
@@ -20,6 +21,7 @@ import { publicTickerKey } from "../../../../utils/exchanges";
|
|
|
20
21
|
import {
|
|
21
22
|
IDLE_VALIDATION,
|
|
22
23
|
isPlausibleTickerQuery,
|
|
24
|
+
exchangeLabelFromValidation,
|
|
23
25
|
normalizeQuickAddQuery,
|
|
24
26
|
resolveQuickAddValidation,
|
|
25
27
|
tickerNameFromValidation,
|
|
@@ -56,6 +58,10 @@ function QuickAddPreview({
|
|
|
56
58
|
return <Text fg={colors.textMuted}>{t(validation.message)}</Text>;
|
|
57
59
|
}
|
|
58
60
|
|
|
61
|
+
if (validation.status === "choose") {
|
|
62
|
+
return <Text fg={colors.textMuted}>{t("Multiple listings")}</Text>;
|
|
63
|
+
}
|
|
64
|
+
|
|
59
65
|
if (validation.status === "duplicate") {
|
|
60
66
|
return <Text fg={colors.textMuted}>{tf("{symbol} already in {collection}", {
|
|
61
67
|
symbol: validation.symbol,
|
|
@@ -71,6 +77,7 @@ function QuickAddPreview({
|
|
|
71
77
|
: "-";
|
|
72
78
|
const changeValue = quote?.changePercent;
|
|
73
79
|
const name = tickerNameFromValidation(validation);
|
|
80
|
+
const exchange = exchangeLabelFromValidation(validation);
|
|
74
81
|
const showSymbol = normalizeQuickAddQuery(validation.symbol) !== validation.query;
|
|
75
82
|
const symbolPrefix = showSymbol ? `${validation.symbol} ` : "";
|
|
76
83
|
|
|
@@ -81,6 +88,7 @@ function QuickAddPreview({
|
|
|
81
88
|
{formatPercentRaw(changeValue)}
|
|
82
89
|
</Text>
|
|
83
90
|
{name ? <Text fg={colors.textMuted}>{` ${name}`}</Text> : null}
|
|
91
|
+
{exchange ? <Text fg={colors.textDim}>{` ${exchange}`}</Text> : null}
|
|
84
92
|
</Box>
|
|
85
93
|
);
|
|
86
94
|
}
|
|
@@ -129,6 +137,21 @@ export function QuickAddTickerInput({
|
|
|
129
137
|
setValidation(IDLE_VALIDATION);
|
|
130
138
|
}, []);
|
|
131
139
|
|
|
140
|
+
// `NET:` is the command bar's venue dropdown. Choosing a row adds it here.
|
|
141
|
+
const handOffListingChoice = useCallback((query: string) => {
|
|
142
|
+
validationSeqRef.current += 1;
|
|
143
|
+
if (!isDialogOpen()) {
|
|
144
|
+
dispatch({
|
|
145
|
+
type: "SET_COMMAND_BAR",
|
|
146
|
+
open: true,
|
|
147
|
+
query,
|
|
148
|
+
launch: { kind: "add-listing", collectionId, collectionKind },
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
resetInput();
|
|
152
|
+
blurInput();
|
|
153
|
+
}, [blurInput, collectionId, collectionKind, dispatch, resetInput]);
|
|
154
|
+
|
|
132
155
|
useEffect(() => {
|
|
133
156
|
onFocusChange?.(inputFocused && focused);
|
|
134
157
|
}, [focused, inputFocused, onFocusChange]);
|
|
@@ -159,6 +182,15 @@ export function QuickAddTickerInput({
|
|
|
159
182
|
return;
|
|
160
183
|
}
|
|
161
184
|
|
|
185
|
+
if (listingChoiceQuery(query)) {
|
|
186
|
+
setValidation(IDLE_VALIDATION);
|
|
187
|
+
const timeoutId = setTimeout(() => {
|
|
188
|
+
if (validationSeqRef.current !== seq) return;
|
|
189
|
+
handOffListingChoice(query);
|
|
190
|
+
}, QUICK_ADD_DEBOUNCE_MS);
|
|
191
|
+
return () => clearTimeout(timeoutId);
|
|
192
|
+
}
|
|
193
|
+
|
|
162
194
|
if (!isPlausibleTickerQuery(query)) {
|
|
163
195
|
setValidation({ status: "missing", query, message: "Use a ticker symbol" });
|
|
164
196
|
return;
|
|
@@ -174,12 +206,16 @@ export function QuickAddTickerInput({
|
|
|
174
206
|
}, QUICK_ADD_DEBOUNCE_MS);
|
|
175
207
|
|
|
176
208
|
return () => clearTimeout(timeoutId);
|
|
177
|
-
}, [inputValue, validateQuery]);
|
|
209
|
+
}, [handOffListingChoice, inputValue, validateQuery]);
|
|
178
210
|
|
|
179
211
|
const submitInput = useCallback(async (submittedValue?: string) => {
|
|
180
212
|
const recordAttention = captureAttentionAction();
|
|
181
213
|
const query = normalizeQuickAddQuery(submittedValue ?? inputValue);
|
|
182
214
|
if (!query || submitting) return;
|
|
215
|
+
if (listingChoiceQuery(query)) {
|
|
216
|
+
handOffListingChoice(query);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
183
219
|
|
|
184
220
|
setSubmitting(true);
|
|
185
221
|
try {
|
|
@@ -189,6 +225,10 @@ export function QuickAddTickerInput({
|
|
|
189
225
|
)
|
|
190
226
|
? validation
|
|
191
227
|
: await validateQuery(query);
|
|
228
|
+
if (currentValidation.status === "choose") {
|
|
229
|
+
handOffListingChoice(`${query}:`);
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
192
232
|
setValidation(currentValidation);
|
|
193
233
|
|
|
194
234
|
if (currentValidation.status === "duplicate") {
|
|
@@ -275,6 +315,7 @@ export function QuickAddTickerInput({
|
|
|
275
315
|
collectionKind,
|
|
276
316
|
collectionName,
|
|
277
317
|
dispatch,
|
|
318
|
+
handOffListingChoice,
|
|
278
319
|
inputValue,
|
|
279
320
|
notify,
|
|
280
321
|
onAdded,
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { getSharedRegistry } from "../../../registry";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
AmbiguousContractError,
|
|
4
|
+
AmbiguousTickerError,
|
|
5
|
+
resolveTickerSearch,
|
|
6
|
+
type ResolvedTickerSearch,
|
|
7
|
+
} from "../../../../tickers/search";
|
|
3
8
|
import type { Quote } from "../../../../types/financials";
|
|
4
9
|
import type { TickerRecord } from "../../../../types/ticker";
|
|
10
|
+
import { canonicalExchange, parsePublicTickerKey, publicTickerKey } from "../../../../utils/exchanges";
|
|
5
11
|
|
|
6
12
|
const QUICK_ADD_MAX_QUERY_LENGTH = 32;
|
|
7
13
|
const QUICK_ADD_SYMBOL_RE = /^[A-Z0-9][A-Z0-9.\-\s]*$/;
|
|
@@ -21,6 +27,8 @@ export type QuickAddValidation =
|
|
|
21
27
|
| { status: "checking"; query: string }
|
|
22
28
|
| (ResolvedQuickAdd & { status: "ready" })
|
|
23
29
|
| (ResolvedQuickAdd & { status: "duplicate" })
|
|
30
|
+
/** The symbol names several listings and none is the default: the add row asks which. */
|
|
31
|
+
| { status: "choose"; query: string }
|
|
24
32
|
| { status: "missing"; query: string; message: string }
|
|
25
33
|
| { status: "error"; query: string; message: string };
|
|
26
34
|
|
|
@@ -73,6 +81,38 @@ export function tickerNameFromValidation(
|
|
|
73
81
|
return validation.resolved.kind === "provider" ? validation.resolved.result.name : "";
|
|
74
82
|
}
|
|
75
83
|
|
|
84
|
+
export function exchangeLabelFromValidation(
|
|
85
|
+
validation: Extract<QuickAddValidation, { status: "ready" | "duplicate" }>,
|
|
86
|
+
): string {
|
|
87
|
+
if (validation.resolved.kind === "provider") {
|
|
88
|
+
const result = validation.resolved.result;
|
|
89
|
+
return result.exchange === "SMART" ? result.primaryExchange || result.exchange : result.exchange || "";
|
|
90
|
+
}
|
|
91
|
+
return validation.ticker?.metadata.exchange || "";
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The symbol key can already store another listing. Only this listing's own
|
|
96
|
+
* record, and its cached quote, belong to this add.
|
|
97
|
+
*/
|
|
98
|
+
function tickerForResolved(
|
|
99
|
+
resolved: ResolvedTickerSearch,
|
|
100
|
+
tickers: Map<string, TickerRecord>,
|
|
101
|
+
): TickerRecord | null {
|
|
102
|
+
if (resolved.kind === "local") return resolved.ticker;
|
|
103
|
+
const result = resolved.result;
|
|
104
|
+
const exchange = canonicalExchange(result.exchange === "SMART" ? result.primaryExchange : result.exchange);
|
|
105
|
+
const bare = parsePublicTickerKey(resolved.symbol).symbol;
|
|
106
|
+
const qualified = publicTickerKey(bare, exchange || undefined);
|
|
107
|
+
const qualifiedTicker = qualified === bare ? undefined : tickers.get(qualified);
|
|
108
|
+
if (qualifiedTicker) return qualifiedTicker;
|
|
109
|
+
const saved = tickers.get(bare) ?? tickers.get(resolved.symbol) ?? null;
|
|
110
|
+
if (!saved) return null;
|
|
111
|
+
const savedExchange = canonicalExchange(saved.metadata.exchange);
|
|
112
|
+
if (exchange && savedExchange && exchange !== savedExchange) return null;
|
|
113
|
+
return saved;
|
|
114
|
+
}
|
|
115
|
+
|
|
76
116
|
export async function resolveQuickAddValidation({
|
|
77
117
|
query,
|
|
78
118
|
collectionId,
|
|
@@ -108,8 +148,8 @@ export async function resolveQuickAddValidation({
|
|
|
108
148
|
}
|
|
109
149
|
|
|
110
150
|
const symbol = resolved.symbol;
|
|
111
|
-
const ticker = resolved
|
|
112
|
-
const cachedQuote = financials.get(
|
|
151
|
+
const ticker = tickerForResolved(resolved, tickers);
|
|
152
|
+
const cachedQuote = ticker ? financials.get(ticker.metadata.ticker)?.quote ?? null : null;
|
|
113
153
|
let quote = cachedQuote;
|
|
114
154
|
if (!quote) {
|
|
115
155
|
try {
|
|
@@ -126,12 +166,15 @@ export async function resolveQuickAddValidation({
|
|
|
126
166
|
return {
|
|
127
167
|
status: tickerBelongsToCollection(ticker, collectionKind, collectionId) ? "duplicate" : "ready",
|
|
128
168
|
query,
|
|
129
|
-
symbol,
|
|
169
|
+
symbol: ticker?.metadata.ticker ?? symbol,
|
|
130
170
|
resolved,
|
|
131
171
|
ticker,
|
|
132
172
|
quote,
|
|
133
173
|
};
|
|
134
|
-
} catch {
|
|
174
|
+
} catch (error) {
|
|
175
|
+
if (error instanceof AmbiguousTickerError && !(error instanceof AmbiguousContractError)) {
|
|
176
|
+
return { status: "choose", query };
|
|
177
|
+
}
|
|
135
178
|
return { status: "error", query, message: "Ticker lookup failed" };
|
|
136
179
|
}
|
|
137
180
|
}
|
|
@@ -53,6 +53,11 @@ const PORTFOLIO_COLUMN_DEFS: ColumnConfig[] = [
|
|
|
53
53
|
{ id: "cost_basis", label: "COST", width: 10, align: "right", format: "compact" },
|
|
54
54
|
{ id: "mkt_value", label: "MKT VAL", width: 10, align: "right", format: "compact" },
|
|
55
55
|
{ id: "weight", label: "WEIGHT", width: 8, align: "right", format: "percent" },
|
|
56
|
+
// TARGET is the analyst price target; these are the portfolio's own target weights.
|
|
57
|
+
{ id: "target_weight", label: "TGT WT", width: 7, align: "right", format: "percent" },
|
|
58
|
+
{ id: "drift", label: "DRIFT", width: 8, align: "right", format: "percent" },
|
|
59
|
+
{ id: "trade", label: "TRADE", width: 9, align: "right", format: "number" },
|
|
60
|
+
{ id: "trade_value", label: "TRADE VAL", width: 10, align: "right", format: "compact" },
|
|
56
61
|
{ id: "day_pnl", label: "DAY", width: 10, align: "right", format: "compact" },
|
|
57
62
|
{ id: "pnl", label: "P&L", width: 10, align: "right", format: "compact" },
|
|
58
63
|
{ id: "pnl_pct", label: "P&L%", width: 8, align: "right", format: "percent" },
|
|
@@ -69,6 +74,10 @@ const PORTFOLIO_ONLY_COLUMN_IDS = new Set([
|
|
|
69
74
|
"cost_basis",
|
|
70
75
|
"mkt_value",
|
|
71
76
|
"weight",
|
|
77
|
+
"target_weight",
|
|
78
|
+
"drift",
|
|
79
|
+
"trade",
|
|
80
|
+
"trade_value",
|
|
72
81
|
"day_pnl",
|
|
73
82
|
"pnl",
|
|
74
83
|
"pnl_pct",
|
|
@@ -142,8 +151,26 @@ function resolveCollectionOptions(entries: CollectionEntry[]): PaneSettingOption
|
|
|
142
151
|
}));
|
|
143
152
|
}
|
|
144
153
|
|
|
154
|
+
/** Columns that read a portfolio's target weights. */
|
|
155
|
+
const TARGET_COLUMN_IDS = new Set(["target_weight", "drift", "trade", "trade_value"]);
|
|
156
|
+
/** What a portfolio with targets shows when the pane's columns name none of them. */
|
|
157
|
+
const REBALANCE_COLUMN_IDS = ["weight", "target_weight", "drift", "trade"];
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* A portfolio with target weights shows WEIGHT, TGT WT, DRIFT and TRADE beside
|
|
161
|
+
* its market value, unless the pane's columns already pick target columns.
|
|
162
|
+
*/
|
|
163
|
+
function withTargetColumns(columnIds: string[]): string[] {
|
|
164
|
+
if (columnIds.some((id) => TARGET_COLUMN_IDS.has(id))) return columnIds;
|
|
165
|
+
const missing = REBALANCE_COLUMN_IDS.filter((id) => !columnIds.includes(id));
|
|
166
|
+
const anchor = columnIds.includes("weight") ? columnIds.indexOf("weight") : columnIds.indexOf("mkt_value");
|
|
167
|
+
const at = anchor >= 0 ? anchor + 1 : columnIds.length;
|
|
168
|
+
return [...columnIds.slice(0, at), ...missing, ...columnIds.slice(at)];
|
|
169
|
+
}
|
|
170
|
+
|
|
145
171
|
function describeColumnOption(column: ColumnConfig): string {
|
|
146
172
|
if (column.id === PRICE_SPARKLINE_COLUMN_ID) return "One-month price sparkline.";
|
|
173
|
+
if (TARGET_COLUMN_IDS.has(column.id)) return "Shown by default once the portfolio has target weights.";
|
|
147
174
|
return PORTFOLIO_ONLY_COLUMN_IDS.has(column.id)
|
|
148
175
|
? "Visible only when this pane is showing a portfolio."
|
|
149
176
|
: "Visible for watchlists and portfolios.";
|
|
@@ -222,8 +249,12 @@ export function resolvePortfolioPaneCollectionId(
|
|
|
222
249
|
return resolveActiveCollectionId(currentCollectionId, visibleCollections);
|
|
223
250
|
}
|
|
224
251
|
|
|
225
|
-
export function resolveVisibleColumns(
|
|
226
|
-
|
|
252
|
+
export function resolveVisibleColumns(
|
|
253
|
+
columnIds: string[],
|
|
254
|
+
isPortfolioTab: boolean,
|
|
255
|
+
{ targetWeights = false }: { targetWeights?: boolean } = {},
|
|
256
|
+
): ColumnConfig[] {
|
|
257
|
+
const resolved = (isPortfolioTab && targetWeights ? withTargetColumns(columnIds) : columnIds)
|
|
227
258
|
.map((columnId) => PORTFOLIO_COLUMNS_BY_ID.get(columnId))
|
|
228
259
|
.filter((column): column is ColumnConfig => column != null)
|
|
229
260
|
.filter((column) => isPortfolioTab || !PORTFOLIO_ONLY_COLUMN_IDS.has(column.id));
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
type BrokerSnapshotBasis,
|
|
18
18
|
} from "../account-metrics";
|
|
19
19
|
import { formatPortfolioAmount, type PortfolioSummaryTotals } from "./totals";
|
|
20
|
+
import { formatAllocationDrift, formatAllocationWeight, type PortfolioCashLine } from "../allocation";
|
|
20
21
|
import { getMostRecentQuoteUpdate } from "../../../../market-data/quotes/time";
|
|
21
22
|
import { fxStatusLabel, type FxRateStatus } from "../../../../utils/fx-status";
|
|
22
23
|
import { t } from "../../../../i18n";
|
|
@@ -221,6 +222,7 @@ export function buildPortfolioSummarySegments({
|
|
|
221
222
|
convertAccountValue = (value) => value,
|
|
222
223
|
currency = "USD",
|
|
223
224
|
baseCurrency = "USD",
|
|
225
|
+
manualCash = null,
|
|
224
226
|
}: {
|
|
225
227
|
totals: PortfolioSummaryTotals;
|
|
226
228
|
accountState: PortfolioSummaryAccountState | null;
|
|
@@ -231,6 +233,8 @@ export function buildPortfolioSummarySegments({
|
|
|
231
233
|
currency?: string;
|
|
232
234
|
/** The app's base currency: amounts are bare only when both are USD. */
|
|
233
235
|
baseCurrency?: string;
|
|
236
|
+
/** Cash entered by hand, in the totals currency, with the total it is weighed against. */
|
|
237
|
+
manualCash?: (PortfolioCashLine & { total: number | null }) | null;
|
|
234
238
|
}): PortfolioSummarySegment[] {
|
|
235
239
|
const money = (value: number | undefined, signed = false) => formatPortfolioAmount(value, currency, { signed, baseCurrency });
|
|
236
240
|
if (!isPortfolioTab) {
|
|
@@ -241,7 +245,7 @@ export function buildPortfolioSummarySegments({
|
|
|
241
245
|
])]
|
|
242
246
|
: [];
|
|
243
247
|
}
|
|
244
|
-
if (!totals.hasPositions && !accountState) return [];
|
|
248
|
+
if (!totals.hasPositions && !accountState && !manualCash) return [];
|
|
245
249
|
|
|
246
250
|
const candidates: PortfolioSummarySegment[] = [];
|
|
247
251
|
const account = accountState?.account;
|
|
@@ -257,6 +261,14 @@ export function buildPortfolioSummarySegments({
|
|
|
257
261
|
])
|
|
258
262
|
: null;
|
|
259
263
|
|
|
264
|
+
// Holdings plus the cash, as weights divide by it; like Net Liq for a broker account.
|
|
265
|
+
if (manualCash) {
|
|
266
|
+
candidates.push(createSummarySegment("total", [
|
|
267
|
+
{ text: "Total", tone: "label" },
|
|
268
|
+
{ text: money(manualCash.total ?? Number.NaN), tone: "value", bold: true },
|
|
269
|
+
]));
|
|
270
|
+
}
|
|
271
|
+
|
|
260
272
|
if (netLiquidation != null) {
|
|
261
273
|
candidates.push(createSummarySegment("netliq", [
|
|
262
274
|
{ text: "Net Liq", tone: "label" },
|
|
@@ -278,6 +290,17 @@ export function buildPortfolioSummarySegments({
|
|
|
278
290
|
|
|
279
291
|
// A broker account always states its cash, so a missing balance reads as unknown rather than zero.
|
|
280
292
|
if (account) candidates.push(accountValue("cash", "Cash", account.totalCashValue ?? Number.NaN)!);
|
|
293
|
+
if (manualCash) {
|
|
294
|
+
const drift = formatAllocationDrift(manualCash.drift);
|
|
295
|
+
candidates.push(createSummarySegment("cash", [
|
|
296
|
+
{ text: "Cash", tone: "label" },
|
|
297
|
+
{ text: money(manualCash.value), tone: "value", bold: true },
|
|
298
|
+
...(manualCash.weight != null ? [{ text: `(${formatAllocationWeight(manualCash.weight)})`, tone: "muted" as const }] : []),
|
|
299
|
+
...(manualCash.targetWeight != null && manualCash.drift != null
|
|
300
|
+
? [{ text: drift, tone: "muted" as const, color: /[1-9]/.test(drift) ? priceColor(manualCash.drift) : undefined }]
|
|
301
|
+
: []),
|
|
302
|
+
]));
|
|
303
|
+
}
|
|
281
304
|
|
|
282
305
|
candidates.push(createSummarySegment("day", [
|
|
283
306
|
{ text: "Day", tone: "label" },
|
|
@@ -4,7 +4,9 @@ import { convertCurrency, formatCompactAmount } from "../../../../utils/format";
|
|
|
4
4
|
import { getCurrencySymbol } from "../../../../market-data/market/format";
|
|
5
5
|
import { getActiveQuoteDisplay } from "../../../../market-data/market/status";
|
|
6
6
|
import { isQuoteStaleForCurrentSession } from "../../../../market-data/quotes/freshness";
|
|
7
|
+
import { headlineQuoteDisplay } from "../column-values";
|
|
7
8
|
import { isManualPortfolio } from "../mutations";
|
|
9
|
+
import type { AllocationHolding } from "../allocation";
|
|
8
10
|
import {
|
|
9
11
|
getPortfolioPositionMetrics,
|
|
10
12
|
getPortfolioQuoteDisplay,
|
|
@@ -46,6 +48,8 @@ export interface PortfolioSummaryTotals {
|
|
|
46
48
|
livePriced?: boolean;
|
|
47
49
|
/** Lots with a current quote. Broker account snapshots move by these. */
|
|
48
50
|
pricedLots?: PricedPortfolioLot[];
|
|
51
|
+
/** Every ticker of a portfolio valued for weights and targets (see allocation.ts). */
|
|
52
|
+
allocationHoldings?: AllocationHolding[];
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
const CURRENCY_CODE = /^[A-Z]{3}$/;
|
|
@@ -112,6 +116,7 @@ export function calculatePortfolioSummaryTotals(
|
|
|
112
116
|
const unavailableConversions = new Set<string>();
|
|
113
117
|
let livePriced = true;
|
|
114
118
|
const pricedLots: PricedPortfolioLot[] = [];
|
|
119
|
+
const allocationHoldings: AllocationHolding[] = [];
|
|
115
120
|
const now = Date.now();
|
|
116
121
|
const toBase = (value: number, currency: string) => {
|
|
117
122
|
const converted = convertCurrency(value, currency, totalsCurrency, exchangeRates);
|
|
@@ -127,8 +132,10 @@ export function calculatePortfolioSummaryTotals(
|
|
|
127
132
|
const quoteCurrency = quote?.currency || ticker.metadata.currency || "USD";
|
|
128
133
|
|
|
129
134
|
if (!isPortfolio) {
|
|
130
|
-
|
|
131
|
-
|
|
135
|
+
// The CHG% column's value, so Avg Day is the mean of that column.
|
|
136
|
+
const changePercent = headlineQuoteDisplay(activeQuote, quote)?.changePercent;
|
|
137
|
+
if (changePercent != null) {
|
|
138
|
+
watchlistChangeSum += changePercent;
|
|
132
139
|
watchlistCount++;
|
|
133
140
|
}
|
|
134
141
|
continue;
|
|
@@ -139,20 +146,24 @@ export function calculatePortfolioSummaryTotals(
|
|
|
139
146
|
}, quote);
|
|
140
147
|
activeQuote = getPortfolioQuoteDisplay(positionMetrics, quote);
|
|
141
148
|
const { totalPriceUnits, grossPriceUnits, totalCost } = positionMetrics;
|
|
142
|
-
if (positionMetrics.positionCount === 0)
|
|
149
|
+
if (positionMetrics.positionCount === 0) {
|
|
150
|
+
// Not held, so a missing rate is no gap in the totals: it only leaves the trade in units out.
|
|
151
|
+
const unitPrice = activeQuote ? convertCurrency(activeQuote.price, quoteCurrency, totalsCurrency, exchangeRates) : null;
|
|
152
|
+
allocationHoldings.push({ symbol: ticker.metadata.ticker, held: false, marketValue: 0, units: 0, unitPrice });
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const toBaseQuote = (value: number) => toBase(value, quoteCurrency);
|
|
156
|
+
const currentUnitPrice = activeQuote ? toBaseQuote(activeQuote.price) : null;
|
|
143
157
|
hasPositions = true;
|
|
144
158
|
hasShorts ||= positionMetrics.hasShorts;
|
|
145
159
|
totalCostBasis += totalCost;
|
|
146
160
|
if (!positionMetrics.hasCostBasis) unavailableCostSymbols.add(ticker.metadata.ticker);
|
|
147
161
|
|
|
148
|
-
const
|
|
149
|
-
const positionPnl = resolvePortfolioPositionPnl(positionMetrics,
|
|
150
|
-
activeQuote ? toBaseQuote(activeQuote.price) : null);
|
|
162
|
+
const positionPnl = resolvePortfolioPositionPnl(positionMetrics, currentUnitPrice);
|
|
151
163
|
signedUnrealizedPnl += positionPnl.value ?? Number.NaN;
|
|
152
164
|
pnlBases.add(positionPnl.basis);
|
|
153
165
|
if (positionPnl.basis === "broker-snapshot" || positionPnl.basis === "mixed") brokerPnlSymbols.add(ticker.metadata.ticker);
|
|
154
166
|
|
|
155
|
-
const currentUnitPrice = activeQuote ? toBaseQuote(activeQuote.price) : null;
|
|
156
167
|
const freshQuote = currentUnitPrice != null && Number.isFinite(currentUnitPrice)
|
|
157
168
|
&& !!quote && !isQuoteStaleForCurrentSession(quote, now);
|
|
158
169
|
if (!freshQuote || quote.dataSource === "delayed" || quote.dataSource === "snapshot") livePriced = false;
|
|
@@ -172,6 +183,13 @@ export function calculatePortfolioSummaryTotals(
|
|
|
172
183
|
}
|
|
173
184
|
|
|
174
185
|
const marketValue = resolvePortfolioMarketValue(positionMetrics, currentUnitPrice);
|
|
186
|
+
allocationHoldings.push({
|
|
187
|
+
symbol: ticker.metadata.ticker,
|
|
188
|
+
held: true,
|
|
189
|
+
marketValue: marketValue?.net ?? null,
|
|
190
|
+
units: positionMetrics.totalShares,
|
|
191
|
+
unitPrice: currentUnitPrice,
|
|
192
|
+
});
|
|
175
193
|
if (marketValue) {
|
|
176
194
|
totalMktValue += marketValue.gross;
|
|
177
195
|
netMktValue += marketValue.net;
|
|
@@ -216,5 +234,6 @@ export function calculatePortfolioSummaryTotals(
|
|
|
216
234
|
...(unavailableConversions.size > 0 ? { unavailableConversions: [...unavailableConversions].sort() } : {}),
|
|
217
235
|
...(isPortfolio ? { livePriced: hasPositions && livePriced } : {}),
|
|
218
236
|
...(pricedLots.length > 0 ? { pricedLots } : {}),
|
|
237
|
+
...(isPortfolio ? { allocationHoldings } : {}),
|
|
219
238
|
};
|
|
220
239
|
}
|
|
@@ -4,7 +4,9 @@ import { powerQuery } from "./query";
|
|
|
4
4
|
import { POWER_TABS, powerTab } from "./model";
|
|
5
5
|
|
|
6
6
|
export const powerHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
7
|
-
shape: "bundle",
|
|
7
|
+
shape: "bundle",
|
|
8
|
+
freshness: { source: "Grid operator queues and utility filings", status: "not-a-feed", basis: "published records" },
|
|
9
|
+
argument: { kind: "free-text", optional: true, placeholder: "ticker", description: "Optional listed developer or utility ticker, with exchange suffix where needed." },
|
|
8
10
|
options: [
|
|
9
11
|
{ key: "tab", type: "enum", settingKey: "tab", defaultValue: "queue", values: POWER_TABS.map(({ value }) => ({ value })), description: "Queue, history, outcomes, large loads, utility exposure, capacity or coverage." },
|
|
10
12
|
...["country", "region", "fuel", "status", "search", "sourceId", "from", "to"].map((key) => ({ key, type: "string" as const, settingKey: key, description: `Filter by ${key}.` })),
|