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
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { useCallback, useMemo, useRef, useState } from "react";
|
|
2
|
+
import type { FundChange, FundMember } from "../../../api-client/members";
|
|
3
|
+
import { DataTableStackView, DataTableView, DetailScrollBody, EmptyState, KeyValueRow, PaneFooterScope, PaneStatusBody, Prose, QueryBar, StatGrid,
|
|
4
|
+
isSectionedItemRow, renderSectionedRowHeader, useExternalLinkFooter, usePaneNoticeFooter, usePaneStatusFooter, usePaneTabs, useQueryBarSearch,
|
|
5
|
+
type DataTableCell, type DataTableColumn, type PaneFooterSegment, type SectionedRow } from "../../../components";
|
|
6
|
+
import { usePaneRefreshKey } from "../../../components/data-table/table-pane";
|
|
7
|
+
import { useAsyncResource, useAutoRefresh, usePaneInstance, usePaneTickerIdentity, usePaneTitle, usePluginPaneState, usePluginTickerActions } from "../../../public/react";
|
|
8
|
+
import { priceColor } from "../../../theme/colors";
|
|
9
|
+
import { useThemeColors } from "../../../theme/theme-context";
|
|
10
|
+
import type { PaneProps } from "../../../types/plugin";
|
|
11
|
+
import { Box, type ScrollBoxRenderable } from "../../../ui";
|
|
12
|
+
import { nextHeaderSort, type SortPreference } from "../../../utils/sort-values";
|
|
13
|
+
import { isPlainArrowUp, stopSearchFocusNavigation } from "../../../utils/search-focus-navigation";
|
|
14
|
+
import { cachedChanges, cachedFunds, cachedMembers, loadChanges, loadFunds, loadMembers } from "./client";
|
|
15
|
+
import { canonicalFund, changeColumns, changeLabel, changeReason, coveredFund, decimal, DEFAULT_SORT, isTab, memberColumns, memberRows, membersTitle, notCoveredMessage, percent, TABS, type MembersTab } from "./model";
|
|
16
|
+
|
|
17
|
+
type ViewProps = Pick<PaneProps, "width" | "height" | "focused"> & { fund: string; active: boolean };
|
|
18
|
+
const rowKey = (row: SectionedRow<FundMember>) => row.key;
|
|
19
|
+
|
|
20
|
+
function Holdings({ fund, tab, width, height, focused, active }: ViewProps & { tab: MembersTab }) {
|
|
21
|
+
const colors = useThemeColors();
|
|
22
|
+
const { pinTicker } = usePluginTickerActions();
|
|
23
|
+
const resource = useAsyncResource(useCallback((force: boolean) => loadMembers(fund, force), [fund]), { initialData: useCallback(() => cachedMembers(fund), [fund]) });
|
|
24
|
+
const data = resource.data?.payload;
|
|
25
|
+
const [sort, setSort] = usePluginPaneState<SortPreference<string>>(`sort:${fund}`, DEFAULT_SORT);
|
|
26
|
+
const [selected, setSelected] = usePluginPaneState<string | null>(`member:${fund}`, null);
|
|
27
|
+
const [query, setQuery] = useState("");
|
|
28
|
+
const search = useQueryBarSearch();
|
|
29
|
+
const movers = tab === "movers";
|
|
30
|
+
const rows = useMemo(() => memberRows(data?.members ?? [], tab, query, sort), [data, tab, query, sort]);
|
|
31
|
+
const columns = useMemo(() => memberColumns(width, movers), [width, movers]);
|
|
32
|
+
useAutoRefresh(resource.updatedAt, () => { if (active) void resource.load(); });
|
|
33
|
+
usePaneRefreshKey(() => void resource.reload(), { focused, enabled: active && !search.active });
|
|
34
|
+
const info = useMemo<PaneFooterSegment[]>(() => {
|
|
35
|
+
if (!data) return [];
|
|
36
|
+
const dates = [...new Set(data.members.flatMap((row) => row.changePercent !== null && row.dailyAsOf ? [row.dailyAsOf.slice(0, 10)] : []))].sort();
|
|
37
|
+
const date = dates.length === 1 ? dates[0] : dates.length ? `${dates[0]} to ${dates.at(-1)}` : data.fundDailyAsOf?.slice(0, 10);
|
|
38
|
+
const partial = data.aggregate.fresh1D < data.aggregate.total;
|
|
39
|
+
return [
|
|
40
|
+
{ id: "coverage", parts: [{ text: `${partial && width >= 60 ? "Partial " : ""}1D ${data.aggregate.fresh1D}/${data.aggregate.total} · ${decimal(data.aggregate.coveredWeight * 100, 1)}% wt`, tone: partial ? "warning" : "muted" }] },
|
|
41
|
+
{ id: "quote-date", title: `${date ?? "Quote date unavailable"} · 15m delayed · holdings ${data.asOf}`,
|
|
42
|
+
parts: [{ text: data.quotesUnavailable ? "returns unavailable" : width < 60 && dates.length === 1 ? `${date!.slice(5)} delayed` : `${date ? `${date} · ` : ""}15m delayed`, tone: "muted" }] },
|
|
43
|
+
...(width >= 60 ? [{ id: "holdings-date", parts: [{ text: `holdings ${data.asOf}`, tone: "muted" as const }] }] : []),
|
|
44
|
+
];
|
|
45
|
+
}, [data, width]);
|
|
46
|
+
usePaneStatusFooter({ registrationId: "members:status", loading: !!data && resource.loading,
|
|
47
|
+
stale: !!data && (data.stale || resource.data!.stale || !!resource.error), info });
|
|
48
|
+
usePaneNoticeFooter({ registrationId: "members:notices", focused, notices: [
|
|
49
|
+
...(resource.error || resource.data?.refreshError ? [resource.error ?? resource.data!.refreshError!] : []),
|
|
50
|
+
...(data?.quotesUnavailable ? ["Member returns and current prices are unavailable. Dated holdings remain available."] : []),
|
|
51
|
+
...(data && data.aggregate.fresh1D < data.aggregate.total ? [`Fresh 1D: ${data.aggregate.fresh1D}/${data.aggregate.total} holdings, ${decimal(data.aggregate.coveredWeight * 100, 1)}% of whole-fund weight. Missing returns are excluded.`] : []),
|
|
52
|
+
...(movers && data && data.aggregate.fundReturn === null ? ["Fund 1D is unavailable; the difference cannot be calculated."] : []),
|
|
53
|
+
...(movers && data?.aggregate.withinTolerance === false ? [`The covered contribution sum differs from the fund by ${percent(data.aggregate.residual, " pp")}.`] : []),
|
|
54
|
+
...(data?.excludedDerivatives ? [`${data.excludedDerivatives} derivative positions are excluded from these share holdings.`] : []),
|
|
55
|
+
] });
|
|
56
|
+
const renderCell = useCallback((item: SectionedRow<FundMember>, column: DataTableColumn): DataTableCell => {
|
|
57
|
+
if (!isSectionedItemRow(item)) return { text: "" };
|
|
58
|
+
const row = item.item;
|
|
59
|
+
if (column.id === "symbol") return { text: row.symbol ?? "--", color: colors.textBright };
|
|
60
|
+
if (column.id === "name" || column.id === "sector") return { text: row[column.id] ?? "--", color: colors.text };
|
|
61
|
+
if (column.id === "weight") return { text: row.weight == null ? "--" : decimal(row.weight * 100), value: row.weight == null ? null : row.weight * 100 };
|
|
62
|
+
if (column.id === "shares") return { text: decimal(row.shares, 0), value: row.shares };
|
|
63
|
+
if (column.id === "price") return { text: decimal(row.price), value: row.price };
|
|
64
|
+
const value = row[column.id as "changePercent"];
|
|
65
|
+
return { text: percent(value, column.id === "contribution" ? "" : "%", column.id === "contribution" ? 3 : 2), value, color: value === null ? colors.textMuted : priceColor(value, colors) };
|
|
66
|
+
}, [colors]);
|
|
67
|
+
return <PaneStatusBody subject="fund holdings" loading={!data && resource.loading} error={!data ? resource.error : null}>
|
|
68
|
+
{data && <DataTableView<SectionedRow<FundMember>> items={rows} columns={columns} rootWidth={width} rootHeight={height} focused={focused && !search.active}
|
|
69
|
+
rootBefore={<Box flexDirection="column"><QueryBar width={width} search={{ value: query, onChange: setQuery, placeholder: "ticker, name or sector", focused, ...search.searchProps }} />
|
|
70
|
+
{movers && <StatGrid width={width} items={[
|
|
71
|
+
{ label: "Covered contrib.", value: percent(data.aggregate.sum, " pp"), color: priceColor(data.aggregate.sum ?? 0, colors) },
|
|
72
|
+
{ label: `${fund} 1D`, value: percent(data.aggregate.fundReturn), color: priceColor(data.aggregate.fundReturn ?? 0, colors) },
|
|
73
|
+
{ label: "Difference", value: percent(data.aggregate.residual, " pp"), tone: data.aggregate.withinTolerance === false ? "warning" : "muted" },
|
|
74
|
+
]} />}</Box>}
|
|
75
|
+
selection={{ kind: "id", selectedId: selected, getId: rowKey, onChange: (id) => setSelected(String(id)) }} getItemKey={rowKey}
|
|
76
|
+
isNavigable={isSectionedItemRow} renderSectionHeader={renderSectionedRowHeader}
|
|
77
|
+
sortColumnId={movers ? null : sort.columnId} sortDirection={sort.direction}
|
|
78
|
+
onHeaderClick={movers ? undefined : (id) => setSort((previous) => nextHeaderSort(previous, id, { firstDirection: (key) => ["symbol", "name", "sector"].includes(key) ? "asc" : "desc", resetTo: DEFAULT_SORT }))}
|
|
79
|
+
onSortChange={movers ? undefined : (columnId, direction) => setSort({ columnId, direction })}
|
|
80
|
+
onRootKeyDown={(event, context) => { if (context.selectedIndex <= 0 && isPlainArrowUp(event)) { stopSearchFocusNavigation(event); search.focus(); return true; } return false; }}
|
|
81
|
+
onActivate={(row) => { if (isSectionedItemRow(row) && row.item.symbol) pinTicker(row.item.symbol, { floating: true, instrument: null }); }}
|
|
82
|
+
renderCell={renderCell} selectedTextOverridesCellColor resetScrollKey={`${tab}:${query}`} emptyStateTitle={query ? "No matching holdings." : movers ? "No covered movers." : "No holdings."} />}
|
|
83
|
+
</PaneStatusBody>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function Changes({ fund, width, height, focused, active }: ViewProps) {
|
|
87
|
+
const colors = useThemeColors();
|
|
88
|
+
const resource = useAsyncResource(useCallback((force: boolean) => loadChanges(fund, force), [fund]), { initialData: useCallback(() => cachedChanges(fund), [fund]) });
|
|
89
|
+
const data = resource.data?.payload;
|
|
90
|
+
const [selected, setSelected] = usePluginPaneState<string | null>(`change:${fund}`, null);
|
|
91
|
+
const [opened, setOpened] = usePluginPaneState<string | null>(`opened:${fund}`, null);
|
|
92
|
+
const detail = data?.changes.find((row) => row.id === opened);
|
|
93
|
+
const selectedRow = detail ?? data?.changes.find((row) => row.id === selected) ?? data?.changes[0];
|
|
94
|
+
const scrollRef = useRef<ScrollBoxRenderable | null>(null);
|
|
95
|
+
useAutoRefresh(resource.updatedAt, () => { if (active) void resource.load(); });
|
|
96
|
+
usePaneRefreshKey(() => void resource.reload(), { focused, enabled: active });
|
|
97
|
+
useExternalLinkFooter({ registrationId: "members:source", focused, url: selectedRow?.url });
|
|
98
|
+
usePaneStatusFooter({ registrationId: "members:changes", loading: !!data && resource.loading, stale: !!data && (data.stale || resource.data!.stale || !!resource.error),
|
|
99
|
+
info: data?.asOf ? [{ id: "updated", parts: [{ text: `as of ${data.asOf.slice(0, 10)}`, tone: "muted" }] }] : [] });
|
|
100
|
+
usePaneNoticeFooter({ registrationId: "members:changes-notices", focused, notices: resource.error || resource.data?.refreshError ? [resource.error ?? resource.data!.refreshError!] : [] });
|
|
101
|
+
const renderCell = useCallback((row: FundChange, column: DataTableColumn): DataTableCell => {
|
|
102
|
+
if (column.id === "effectiveDate") return { text: row.effectiveDate ?? "--" };
|
|
103
|
+
if (column.id === "daysToGo") return { text: row.daysToGo === null ? "--" : `${row.daysToGo}${column.label === "In" ? "d" : ""}`, value: row.daysToGo, color: row.daysToGo === null ? colors.textMuted : colors.warning, keepColorWhenSelected: row.daysToGo !== null };
|
|
104
|
+
if (column.id === "added") return { text: row.added ?? "--", color: colors.positive };
|
|
105
|
+
if (column.id === "removed") return { text: row.removed ?? "--", color: colors.negative };
|
|
106
|
+
if (column.id === "estimate") { const value = row.estimates.length === 1 ? row.estimates[0]!.days : null; return { text: percent(value, ""), value }; }
|
|
107
|
+
return { text: changeReason(row), color: colors.text };
|
|
108
|
+
}, [colors]);
|
|
109
|
+
return <PaneStatusBody subject="index changes" loading={!data && resource.loading} error={!data ? resource.error : null}>
|
|
110
|
+
{data && !data.available ? <EmptyState title="Index changes are not covered for this fund." /> : data && <DataTableStackView<FundChange>
|
|
111
|
+
rootWidth={width} rootHeight={height} focused={focused} columns={changeColumns(width)} items={data.changes}
|
|
112
|
+
getItemKey={(row) => row.id} selection={{ kind: "id", selectedId: selected, getId: (row) => row.id, onChange: (id) => setSelected(String(id)) }}
|
|
113
|
+
onActivate={(row) => setOpened(row.id)} sortColumnId={null} sortDirection="desc" renderCell={renderCell} selectedTextOverridesCellColor
|
|
114
|
+
detailOpen={!!detail} onBack={() => setOpened(null)} detailTitle={detail ? changeLabel(detail) : undefined} detailScrollRef={scrollRef}
|
|
115
|
+
detailContent={detail && <DetailScrollBody ref={scrollRef} resetScrollKey={detail.id}>
|
|
116
|
+
<KeyValueRow label="Effective" value={detail.effectiveDate ?? "Not confirmed"} />
|
|
117
|
+
{detail.announcedAt && <KeyValueRow label="Announced" value={detail.announcedAt.slice(0, 10)} />}
|
|
118
|
+
{detail.headline && <Prose text={detail.headline} width={Math.max(8, width - 4)} />}
|
|
119
|
+
{detail.reason !== detail.headline && <Prose text={detail.reason} width={Math.max(8, width - 4)} />}
|
|
120
|
+
{detail.estimates.map((estimate) => <KeyValueRow key={estimate.symbol} label={`${estimate.symbol} est. ADV days`} labelWidth={24} value={percent(estimate.days, "")} />)}
|
|
121
|
+
{!!detail.estimates.length && <KeyValueRow label="Holdings as of" labelWidth={24} value={detail.estimates[0]!.asOf} />}
|
|
122
|
+
{!!detail.estimates.length && <Prose text={data.estimateLabel} width={Math.max(8, width - 4)} />}
|
|
123
|
+
{detail.kind === "history" && data.attribution && <Prose text={data.attribution.text} width={Math.max(8, width - 4)} />}
|
|
124
|
+
</DetailScrollBody>} emptyStateTitle="No stored index changes." />}
|
|
125
|
+
</PaneStatusBody>;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function FundView({ fund, ...props }: Pick<PaneProps, "width" | "height" | "focused"> & { fund: string }) {
|
|
129
|
+
const instance = usePaneInstance();
|
|
130
|
+
const initial = isTab(instance?.settings?.tab) ? instance.settings.tab : "members";
|
|
131
|
+
const [storedTab, setTab] = usePluginPaneState<MembersTab>("tab", initial);
|
|
132
|
+
const tab = isTab(storedTab) ? storedTab : "members";
|
|
133
|
+
const [visited, setVisited] = useState({ holdings: tab !== "changes", changes: tab === "changes" });
|
|
134
|
+
const selectTab = (value: string) => { if (isTab(value)) { setTab(value); setVisited((previous) => ({ holdings: previous.holdings || value !== "changes", changes: previous.changes || value === "changes" })); } };
|
|
135
|
+
const { strip, rows } = usePaneTabs({ tabs: TABS, activeValue: tab, onSelect: selectTab, focused: props.focused, compact: true, variant: "bare" });
|
|
136
|
+
const height = Math.max(1, props.height - rows);
|
|
137
|
+
return <Box width={props.width} height={props.height} flexDirection="column">
|
|
138
|
+
{strip}
|
|
139
|
+
{visited.holdings && <Box visible={tab !== "changes"} flexGrow={1} flexBasis={0} overflow="hidden"><PaneFooterScope active={tab !== "changes"}>
|
|
140
|
+
<Holdings fund={fund} {...props} height={height} tab={tab} active={tab !== "changes"} focused={props.focused && tab !== "changes"} />
|
|
141
|
+
</PaneFooterScope></Box>}
|
|
142
|
+
{visited.changes && <Box visible={tab === "changes"} flexGrow={1} flexBasis={0} overflow="hidden"><PaneFooterScope active={tab === "changes"}>
|
|
143
|
+
<Changes fund={fund} {...props} height={height} active={tab === "changes"} focused={props.focused && tab === "changes"} />
|
|
144
|
+
</PaneFooterScope></Box>}
|
|
145
|
+
</Box>;
|
|
146
|
+
}
|
|
147
|
+
function FundPicker({ width, height, focused, choose }: Pick<PaneProps, "width" | "height" | "focused"> & { choose: (fund: string) => void }) {
|
|
148
|
+
const resource = useAsyncResource(loadFunds, { initialData: cachedFunds });
|
|
149
|
+
const [selected, setSelected] = useState<string | null>(null);
|
|
150
|
+
usePaneRefreshKey(() => void resource.reload(), { focused });
|
|
151
|
+
usePaneStatusFooter({ registrationId: "members:picker", loading: resource.loading && !!resource.data, stale: resource.data?.stale });
|
|
152
|
+
return <PaneStatusBody subject="covered funds" loading={!resource.data && resource.loading} error={!resource.data ? resource.error : null}>
|
|
153
|
+
{resource.data && <DataTableView items={resource.data.payload.funds} emptyStateTitle="No covered funds." rootWidth={width} rootHeight={height} focused={focused}
|
|
154
|
+
columns={[{ id: "ticker", label: "Fund", align: "left", width: 8 }, { id: "name", label: "Index", align: "left", width: 24, flexGrow: 1 }, { id: "asOf", label: "Holdings as of", align: "left", width: 16 }]}
|
|
155
|
+
getItemKey={(row) => row.ticker} selection={{ kind: "id", selectedId: selected, getId: (row) => row.ticker, onChange: (id) => setSelected(String(id)) }}
|
|
156
|
+
onActivate={(row) => choose(row.ticker)} sortColumnId={null} sortDirection="asc" renderCell={(row, col) => ({ text: String(row[col.id as "ticker"] ?? "--") })} />}
|
|
157
|
+
</PaneStatusBody>;
|
|
158
|
+
}
|
|
159
|
+
type FundPaneProps = Pick<PaneProps, "width" | "height" | "focused"> & { fund: string; requested: string };
|
|
160
|
+
/** The covered list is the server's, so a fund it adds opens without an app update. A list that cannot be read leaves the fund's own load to report the failure. */
|
|
161
|
+
function CoveredFund({ fund, requested, ...props }: FundPaneProps) {
|
|
162
|
+
const resource = useAsyncResource(loadFunds, { initialData: cachedFunds });
|
|
163
|
+
const funds = resource.data?.payload.funds;
|
|
164
|
+
if (funds?.length && !coveredFund(funds, fund)) return <PaneStatusBody empty emptyTitle={notCoveredMessage(requested, funds)} />;
|
|
165
|
+
return <FundView key={fund} fund={fund} {...props} />;
|
|
166
|
+
}
|
|
167
|
+
export function MembersPane(props: PaneProps) {
|
|
168
|
+
const { symbol } = usePaneTickerIdentity();
|
|
169
|
+
const [chosen, choose] = usePluginPaneState("fund", "");
|
|
170
|
+
const requested = symbol ?? chosen;
|
|
171
|
+
const fund = canonicalFund(requested);
|
|
172
|
+
usePaneTitle(membersTitle(requested));
|
|
173
|
+
if (!fund) return <FundPicker {...props} choose={choose} />;
|
|
174
|
+
return <CoveredFund fund={fund} requested={requested} {...props} />;
|
|
175
|
+
}
|
|
@@ -140,6 +140,7 @@ const text = (value: unknown) => (typeof value === "string" ? value : "");
|
|
|
140
140
|
|
|
141
141
|
export const distressHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
142
142
|
shape: "rows",
|
|
143
|
+
freshness: { source: "Public filings and insolvency notices", status: "not-a-feed", basis: "filed records" },
|
|
143
144
|
description: "Dated public records about companies in difficulty: US 8-K bankruptcy, obligation and listing filings, SEC going-concern disclosures, Taiwan exchange listing designations, and French and UK company insolvency notices. No scores or predictions.",
|
|
144
145
|
argument: { kind: "none" },
|
|
145
146
|
discovery: {
|
|
@@ -33,6 +33,7 @@ export const mnaModule: PluginModule = {
|
|
|
33
33
|
icon: "M",
|
|
34
34
|
component: MnaPane,
|
|
35
35
|
defaultPosition: "right",
|
|
36
|
+
tickerFollower: true,
|
|
36
37
|
defaultMode: "floating",
|
|
37
38
|
defaultFloatingSize: { width: 120, height: 30 },
|
|
38
39
|
tableExport: true,
|
|
@@ -51,7 +52,7 @@ export const mnaModule: PluginModule = {
|
|
|
51
52
|
createInstance: (_context, options) => {
|
|
52
53
|
const symbol = (options?.symbol ?? options?.arg)?.trim().toUpperCase();
|
|
53
54
|
return symbol
|
|
54
|
-
? { instanceId: `${MNA_PANE_ID}:${symbol}`, title: `M&A ${symbol}`, placement: "floating", settings: { ticker: symbol } }
|
|
55
|
+
? { instanceId: `${MNA_PANE_ID}:${symbol}`, title: `M&A ${symbol}`, binding: { kind: "fixed" as const, symbol }, placement: "floating", settings: { ticker: symbol } }
|
|
55
56
|
: { placement: "floating" };
|
|
56
57
|
},
|
|
57
58
|
},
|
|
@@ -26,6 +26,7 @@ import { usePlanAccess } from "../../../api-client/plan-access";
|
|
|
26
26
|
import { useAsyncResource, useAutoRefresh, usePaneSettingValue, usePluginPaneState, useShortcut } from "../../../public/react";
|
|
27
27
|
import { usePaneInstance } from "../../../state/app/context";
|
|
28
28
|
import { usePaneTickerIdentity } from "../../../state/hooks/pane-ticker";
|
|
29
|
+
import { listingIdentity } from "../shared/ticker-request";
|
|
29
30
|
import { blendHex } from "../../../theme/colors";
|
|
30
31
|
import { useThemeColors } from "../../../theme/theme-context";
|
|
31
32
|
import type { PaneProps, TickerResearchTabProps } from "../../../types/plugin";
|
|
@@ -130,10 +131,12 @@ const MNA_TABS: { label: string; value: MnaTab }[] = [
|
|
|
130
131
|
{ label: "Distress", value: "distress" },
|
|
131
132
|
];
|
|
132
133
|
|
|
133
|
-
/** `MA`, or `MA ACVA
|
|
134
|
+
/** `MA`, or `MA ACVA`. A link supplies the ticker; an older pane still has it in settings. */
|
|
134
135
|
export function MnaPane(props: PaneProps) {
|
|
136
|
+
const { symbol: bound } = usePaneTickerIdentity();
|
|
135
137
|
const [ticker] = usePaneSettingValue("ticker", "");
|
|
136
|
-
const
|
|
138
|
+
const fromSettings = typeof ticker === "string" ? ticker.trim().toUpperCase() : "";
|
|
139
|
+
const symbol = listingIdentity(bound)?.symbol || fromSettings;
|
|
137
140
|
// One company's deals have no market-wide distress tab beside them.
|
|
138
141
|
if (symbol) return <MnaDealsView key={symbol} focused={props.focused} width={props.width} height={props.height} symbol={symbol} />;
|
|
139
142
|
return <MnaBoard focused={props.focused} width={props.width} height={props.height} />;
|
|
@@ -6,6 +6,7 @@ export const moneyMarketsHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
6
6
|
discovery: { aliases: ["BTMM"], dataRequirements: ["Gloom Cloud money-markets endpoint"],
|
|
7
7
|
limitations: ["Published daily and weekly observations", "Treasury bill discount yields", "Net liquidity is a same-date proxy"] },
|
|
8
8
|
shape: "bundle", argument: { kind: "none" },
|
|
9
|
+
freshness: { source: "FRED", status: "not-a-feed", basis: "published daily and weekly data" },
|
|
9
10
|
options: [{ key: "tab", type: "enum", description: "Money-market view.", values: [{ value: "rates" }, { value: "bills" }, { value: "liquidity" }], defaultValue: "rates" }],
|
|
10
11
|
describe: "US money markets",
|
|
11
12
|
async load(args, ctx) {
|
|
@@ -81,6 +81,8 @@ function projectNewsHeadless(
|
|
|
81
81
|
return {
|
|
82
82
|
asOf: now.toISOString(),
|
|
83
83
|
items,
|
|
84
|
+
// Published stories, dated by the newest; the list is a history, so its last story is not stale data.
|
|
85
|
+
freshness: { status: "not-a-feed", basis: "published stories", observedKey: "publishedAt", oldest: null },
|
|
84
86
|
metadata: {
|
|
85
87
|
nextCursor: response.nextCursor,
|
|
86
88
|
sentiment,
|
|
@@ -25,6 +25,7 @@ import { NEWS_INDUSTRY_CODES, NEWS_QUERY_PRESETS, parseNewsIndustryCode } from "
|
|
|
25
25
|
import { createRssNewsCapability } from "./rss/source";
|
|
26
26
|
import { rssCliCommand } from "./rss/cli";
|
|
27
27
|
import { newsFeedHeadless } from "../headless";
|
|
28
|
+
import type { PaneDef } from "../../../../types/plugin";
|
|
28
29
|
|
|
29
30
|
const TopPane = createNewsPresetPane({
|
|
30
31
|
paneKey: "top:curated",
|
|
@@ -61,8 +62,11 @@ export const BreakingPane = createNewsPresetPane({
|
|
|
61
62
|
|
|
62
63
|
let disposeBreakingNewsNotifications: (() => void) | null = null;
|
|
63
64
|
|
|
65
|
+
// A rendered news pane is a list of published stories, dated by its newest.
|
|
66
|
+
const NEWS_REPORT_FRESHNESS: PaneDef["reportFreshness"] = { status: "not-a-feed", basis: "published stories" };
|
|
67
|
+
|
|
64
68
|
const newsWirePanes: PluginModule["panes"] = [
|
|
65
|
-
{ id: "news-top", name: "Top News", icon: "T", component: TopPane, defaultPosition: "right", defaultMode: "floating", defaultFloatingSize: { width: 90, height: 30 } },
|
|
69
|
+
{ id: "news-top", reportFreshness: NEWS_REPORT_FRESHNESS, name: "Top News", icon: "T", component: TopPane, defaultPosition: "right", defaultMode: "floating", defaultFloatingSize: { width: 90, height: 30 } },
|
|
66
70
|
{
|
|
67
71
|
id: "news-feed",
|
|
68
72
|
name: "News Feed",
|
|
@@ -75,6 +79,7 @@ const newsWirePanes: PluginModule["panes"] = [
|
|
|
75
79
|
},
|
|
76
80
|
{
|
|
77
81
|
id: "news-industry",
|
|
82
|
+
reportFreshness: NEWS_REPORT_FRESHNESS,
|
|
78
83
|
name: TOPIC_NEWS_TITLE,
|
|
79
84
|
icon: "S",
|
|
80
85
|
component: IndustryPane,
|
|
@@ -85,6 +90,7 @@ const newsWirePanes: PluginModule["panes"] = [
|
|
|
85
90
|
},
|
|
86
91
|
{
|
|
87
92
|
id: NEWS_STORY_PANE_ID,
|
|
93
|
+
reportFreshness: NEWS_REPORT_FRESHNESS,
|
|
88
94
|
name: "Story",
|
|
89
95
|
icon: "A",
|
|
90
96
|
component: NewsStoryPane,
|
|
@@ -94,6 +100,7 @@ const newsWirePanes: PluginModule["panes"] = [
|
|
|
94
100
|
},
|
|
95
101
|
{
|
|
96
102
|
id: "news-breaking",
|
|
103
|
+
reportFreshness: NEWS_REPORT_FRESHNESS,
|
|
97
104
|
name: "Breaking News",
|
|
98
105
|
icon: "!",
|
|
99
106
|
component: BreakingPane,
|
|
@@ -2,7 +2,8 @@ import { apiClient } from "../../../api-client";
|
|
|
2
2
|
import { withCliServices, withConfigData } from "../../../cli/scoped-context";
|
|
3
3
|
import { CLI_COMMAND_GROUPS } from "../../../cli/help";
|
|
4
4
|
import { dryRunNote } from "../../../cli/helpers";
|
|
5
|
-
import { requireArg } from "../../../cli/commands/command-utils";
|
|
5
|
+
import { requireArg, takeOption } from "../../../cli/commands/command-utils";
|
|
6
|
+
import { EXCHANGE_OPTION, requireListingArg } from "../../../cli/listing-arg";
|
|
6
7
|
import { createPluginPersistence } from "../../plugin-persistence";
|
|
7
8
|
import type { CliCommandDef } from "../../../types/plugin";
|
|
8
9
|
import { cliStyles } from "../../../utils/cli-output";
|
|
@@ -17,9 +18,16 @@ export const notesCliCommand: CliCommandDef = {
|
|
|
17
18
|
help: {
|
|
18
19
|
group: CLI_COMMAND_GROUPS.portfolios,
|
|
19
20
|
usage: ["notes show <symbol>", "notes set <symbol> <text...>", "notes delete <symbol>", "notes quick list", "notes export [dir]"],
|
|
20
|
-
|
|
21
|
+
options: [EXCHANGE_OPTION],
|
|
22
|
+
examples: ["notes show AAPL", "notes set AAPL \"Services margin above 70%\"", "notes show SAN:EPA", "notes export ~/notes"],
|
|
21
23
|
},
|
|
22
|
-
execute: async (
|
|
24
|
+
execute: async (rawArgs, ctx) => {
|
|
25
|
+
const args = [...rawArgs];
|
|
26
|
+
const exchange = takeOption(args, "--exchange");
|
|
27
|
+
// A note belongs to one listing: SAN:EPA, or SAN with --exchange EPA.
|
|
28
|
+
const noteSymbol = async (usage: string) => (
|
|
29
|
+
await requireListingArg(requireArg(args[1], usage, ctx), exchange, ctx)
|
|
30
|
+
).key;
|
|
23
31
|
await withConfigData(ctx, async (config) => {
|
|
24
32
|
const notes = new NotesFiles(config.dataDir);
|
|
25
33
|
const action = args[0] ?? "list";
|
|
@@ -62,14 +70,14 @@ export const notesCliCommand: CliCommandDef = {
|
|
|
62
70
|
return;
|
|
63
71
|
}
|
|
64
72
|
if (action === "show") {
|
|
65
|
-
const symbol =
|
|
73
|
+
const symbol = await noteSymbol("Usage: gloomberb notes show <symbol>");
|
|
66
74
|
ctx.printResult({ data: { symbol, text: await notes.load(symbol) } }, {
|
|
67
75
|
text: (data) => data.text?.trim() ? data.text.trimEnd() : cliStyles.muted(`No note for ${symbol}.`),
|
|
68
76
|
});
|
|
69
77
|
return;
|
|
70
78
|
}
|
|
71
79
|
if (action === "set") {
|
|
72
|
-
const symbol =
|
|
80
|
+
const symbol = await noteSymbol("Usage: gloomberb notes set <symbol> <text...>");
|
|
73
81
|
const text = args.slice(2).join(" ");
|
|
74
82
|
if (!ctx.cliOptions.dryRun) await notes.save(symbol, text);
|
|
75
83
|
ctx.printResult({ data: { changed: !ctx.cliOptions.dryRun, dryRun: ctx.cliOptions.dryRun, symbol, bytes: text.length } }, {
|
|
@@ -78,7 +86,7 @@ export const notesCliCommand: CliCommandDef = {
|
|
|
78
86
|
return;
|
|
79
87
|
}
|
|
80
88
|
if (action === "delete" || action === "rm") {
|
|
81
|
-
const symbol =
|
|
89
|
+
const symbol = await noteSymbol("Usage: gloomberb notes delete <symbol>");
|
|
82
90
|
// Only picks the message; an unreadable note is still deleted.
|
|
83
91
|
const existed = await notes.load(symbol).then((text) => !!text?.trim(), () => true);
|
|
84
92
|
if (!ctx.cliOptions.dryRun) await notes.delete(symbol);
|
|
@@ -3,6 +3,7 @@ import type { PluginModule } from "../plugin-module";
|
|
|
3
3
|
import { createTickerSurfacePaneTemplate } from "../shared/ticker-surface";
|
|
4
4
|
import type { OptionsViewProps } from "./types";
|
|
5
5
|
import { OptionsView } from "./view";
|
|
6
|
+
import { isKnownMutualFund } from "../../../tickers/instrument-kind";
|
|
6
7
|
|
|
7
8
|
/** The registered chain shows IV rank; isolated view renders stay offline. */
|
|
8
9
|
function OptionsPane(props: OptionsViewProps) {
|
|
@@ -95,7 +96,7 @@ export const optionsModule: PluginModule = {
|
|
|
95
96
|
order: 35,
|
|
96
97
|
component: OptionsResearchTab,
|
|
97
98
|
instruments: ["equity", "fund", "index", "future", "option"],
|
|
98
|
-
isVisible: ({ hasOptionsChain }) => hasOptionsChain,
|
|
99
|
+
isVisible: ({ ticker, financials, hasOptionsChain }) => hasOptionsChain && !isKnownMutualFund(ticker, financials),
|
|
99
100
|
});
|
|
100
101
|
},
|
|
101
102
|
};
|
|
@@ -39,6 +39,7 @@ function report(draft: OptionCalcDraft, valuation: OptionValuation | null,
|
|
|
39
39
|
],
|
|
40
40
|
complete: valuation !== null && errors.length === 0,
|
|
41
41
|
errors, unavailableSymbols: surface?.error && draft.symbol ? [draft.symbol] : [],
|
|
42
|
+
...(surface ? { freshness: { source: "Your inputs and Gloom Cloud volatility" } } : {}),
|
|
42
43
|
metadata: { model, inputs: draft, valuation, impliedVolatility: implied, surface, effectiveTreeSteps,
|
|
43
44
|
warnings: surface?.warnings ?? [], method: model === "american" ? "CRR American tree with discrete cash dividends" : "European Black-Scholes",
|
|
44
45
|
greekUnits: { delta: "underlying units per option unit", gamma: "delta per underlying price unit", theta: "currency per calendar day",
|
|
@@ -49,6 +50,7 @@ function report(draft: OptionCalcDraft, valuation: OptionValuation | null,
|
|
|
49
50
|
|
|
50
51
|
export const optionsCalculatorHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
51
52
|
shape: "bundle", argument: { kind: "none" }, describe: "OVME option valuation",
|
|
53
|
+
freshness: { source: "Your inputs", status: "not-a-feed", basis: "calculator" },
|
|
52
54
|
discovery: { limitations: ["Discrete dividends use days from valuation and cash per underlying unit; model values exclude fees and assignment costs."] },
|
|
53
55
|
options: [
|
|
54
56
|
{ key: "model", type: "enum", values: [{ value: "european" }, { value: "american" }], defaultValue: "european", description: "European closed form or American CRR tree" },
|
|
@@ -23,6 +23,7 @@ const gamma = (value: unknown) => formatGamma(typeof value === "number" ? value
|
|
|
23
23
|
/** OPX opens on Strikes, GEX on its own tab; the report carries every section either way. */
|
|
24
24
|
export const optionsPositioningHeadless = (initialTab: PositioningTab): HeadlessPaneDefinition<"bundle"> => ({
|
|
25
25
|
shape: "bundle",
|
|
26
|
+
freshness: { status: "not-a-feed", basis: "daily open interest", cadence: "daily" },
|
|
26
27
|
argument: { kind: "ticker", optional: true, description: "US option underlying, or SPX; SPY when omitted" },
|
|
27
28
|
describe: (args) => `${initialTab === "gex" ? "GEX" : "OPX"} ${args.symbols[0] ?? "SPY"}`,
|
|
28
29
|
discovery: {
|
|
@@ -59,6 +60,8 @@ export const optionsPositioningHeadless = (initialTab: PositioningTab): Headless
|
|
|
59
60
|
];
|
|
60
61
|
const changes = openInterest.previousOiDate != null;
|
|
61
62
|
return {
|
|
63
|
+
// Open interest is published once a day for the prior session; the spot beside it is context.
|
|
64
|
+
freshness: { asOf: openInterest.oiDate },
|
|
62
65
|
sections: [
|
|
63
66
|
{ title: `Expiries · OI as of ${openInterest.oiDate ?? "--"}`, columns: [
|
|
64
67
|
{ key: "date", header: "Expiry" }, { key: "days", header: "Days" },
|
|
@@ -57,7 +57,12 @@ export const optionsScenarioHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
57
57
|
// A seeded strategy starts at the spot its quote mids imply; the last print is reported beside it.
|
|
58
58
|
const lastPrint = midVolatility && !supplied(settings.spot) && market.spot != null && money(market.spot) !== money(position!.spot)
|
|
59
59
|
? market.spot : null;
|
|
60
|
+
const chain = market.chain;
|
|
60
61
|
return {
|
|
62
|
+
freshness: suppliedInputs
|
|
63
|
+
? { source: "Your inputs", status: "not-a-feed", basis: "scenario" }
|
|
64
|
+
: { asOf: market.asOf, ...(chain?.dataSource === "live" || chain?.dataSource === "delayed" ? { status: chain.dataSource } : {}),
|
|
65
|
+
...(chain?.delayMinutes ? { delayMinutes: chain.delayMinutes } : {}) },
|
|
61
66
|
sections: scenario ? [
|
|
62
67
|
{ title: "Position", columns: [
|
|
63
68
|
{ key: "side", header: "Side" }, { key: "strike", header: "Strike" }, { key: "expiry", header: "Expiry" },
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
import { apiClient } from "../../../api-client";
|
|
1
2
|
import { getSharedMarketDataCoordinator, MarketDataCoordinator, resolveEntryValue } from "../../../market-data/coordinator";
|
|
3
|
+
import { fxLegForCurrency } from "../../../market-data/coordinator/fx-legs";
|
|
4
|
+
import { dailyFxCloses, FxHistoryError, type FxCloses } from "../../../market-data/fx-closes";
|
|
2
5
|
import type { InstrumentRef } from "../../../market-data/request-types";
|
|
3
6
|
import type { ManualChartResolution } from "../../../time-series/resolution";
|
|
4
7
|
import type { DataProvider } from "../../../types/data-provider";
|
|
5
8
|
import type { PricePoint, TickerFinancials } from "../../../types/financials";
|
|
6
|
-
import { abortable, abortError } from "../../../utils/async-deadline";
|
|
9
|
+
import { abortable, abortError, settleWithin } from "../../../utils/async-deadline";
|
|
7
10
|
import { errorMessage } from "../../../utils/errors";
|
|
11
|
+
import { isUsListingExchange } from "../../../utils/exchanges";
|
|
12
|
+
import { fetchEarningsHistory } from "../earnings/client";
|
|
13
|
+
import { epsFxCurrencies } from "./model";
|
|
14
|
+
import { reportDatesFrom, type ReportDate } from "./report-dates";
|
|
8
15
|
|
|
9
16
|
export interface PeBandInputs {
|
|
10
17
|
financials: TickerFinancials | null;
|
|
@@ -14,25 +21,81 @@ export interface PeBandInputs {
|
|
|
14
21
|
error: string | null;
|
|
15
22
|
/** Price history failed: the pane can still list EPS, but draws nothing. */
|
|
16
23
|
historyError: string | null;
|
|
24
|
+
/** Report dates for US listings; empty for the rest and when the earnings history is unavailable. */
|
|
25
|
+
reports: ReportDate[];
|
|
26
|
+
/** Daily FX closes for each currency a dollar-priced listing reports its EPS in. */
|
|
27
|
+
fx: Map<string, FxCloses>;
|
|
28
|
+
/** Why a currency's FX closes are missing; its EPS then stays unconverted. */
|
|
29
|
+
fxError: string | null;
|
|
17
30
|
fetchedAt: number;
|
|
18
31
|
}
|
|
19
32
|
|
|
20
33
|
const CANCELLED = "P/E band load was cancelled";
|
|
21
34
|
/** Weekly bars: daily history is only served to 5Y, and the band covers every year of statements on record. */
|
|
22
35
|
const PE_BAND_HISTORY_RESOLUTION: ManualChartResolution = "1wk";
|
|
36
|
+
/** The most reports the server returns for one company: about ten years of quarters. */
|
|
37
|
+
const REPORT_LIMIT = 40;
|
|
38
|
+
/** Report dates only refine the figures' dates, so the pane does not wait longer than this for them. */
|
|
39
|
+
const REPORT_DEADLINE_MS = 8_000;
|
|
40
|
+
|
|
41
|
+
/** Daily FX closes back this far before the oldest statement, so its weeks find a close. */
|
|
42
|
+
const FX_LEAD_DAYS = 14;
|
|
43
|
+
/** About thirty years of daily closes; a longer reply is not a daily FX history. */
|
|
44
|
+
const FX_MAX_ROWS = 8_000;
|
|
45
|
+
|
|
46
|
+
type ReportClient = Pick<typeof apiClient, "getCloudEarningsHistory" | "getCloudHistory">;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Completed daily closes of each currency's dollar pair, from just before the
|
|
50
|
+
* oldest statement in that currency. Never rejects but on cancel: a missing
|
|
51
|
+
* or stale history is said in `error`, and that currency's EPS stays unconverted.
|
|
52
|
+
*/
|
|
53
|
+
async function loadFxCloses(financials: TickerFinancials, client: ReportClient, signal: AbortSignal | undefined, now: Date):
|
|
54
|
+
Promise<{ fx: Map<string, FxCloses>; error: string | null }> {
|
|
55
|
+
const fx = new Map<string, FxCloses>();
|
|
56
|
+
const errors: string[] = [];
|
|
57
|
+
const rows = [...financials.annualStatements, ...financials.quarterlyStatements];
|
|
58
|
+
await Promise.all(epsFxCurrencies(financials).map(async (currency) => {
|
|
59
|
+
const leg = fxLegForCurrency(currency)!;
|
|
60
|
+
const oldest = rows.filter((row) => row.currency?.trim().toUpperCase() === currency && Number.isFinite(Date.parse(row.date)))
|
|
61
|
+
.reduce((min, row) => Math.min(min, Date.parse(row.date)), now.getTime());
|
|
62
|
+
try {
|
|
63
|
+
const response = await client.getCloudHistory(leg.instrument.symbol, leg.instrument.exchange ?? "", {
|
|
64
|
+
interval: "1day", startDate: new Date(oldest - FX_LEAD_DAYS * 86_400_000).toISOString().slice(0, 10),
|
|
65
|
+
endDate: now.toISOString().slice(0, 10), outputsize: FX_MAX_ROWS,
|
|
66
|
+
}, signal ? { signal } : undefined);
|
|
67
|
+
fx.set(currency, dailyFxCloses(response, leg, now, FX_MAX_ROWS));
|
|
68
|
+
} catch (error) {
|
|
69
|
+
if (signal?.aborted) throw abortError(CANCELLED);
|
|
70
|
+
errors.push(`daily ${currency} FX closes are ${error instanceof FxHistoryError && error.problem === "stale" ? "stale" : "unavailable"}`);
|
|
71
|
+
}
|
|
72
|
+
}));
|
|
73
|
+
return { fx, error: errors.length ? errors.join("; ") : null };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Never rejects: a listing without reports, an outage or a refused session leaves the figures as they are. */
|
|
77
|
+
function loadReportDates(symbol: string, client: ReportClient): Promise<ReportDate[]> {
|
|
78
|
+
return settleWithin(fetchEarningsHistory(symbol, client, REPORT_LIMIT), REPORT_DEADLINE_MS)
|
|
79
|
+
.then((payload) => (payload ? reportDatesFrom(payload) : []));
|
|
80
|
+
}
|
|
23
81
|
|
|
24
82
|
/**
|
|
25
83
|
* Statements with the extended SEC history where the listing has one (the
|
|
26
|
-
* snapshot alone carries about six quarters), and every week of closes.
|
|
84
|
+
* snapshot alone carries about six quarters), and every week of closes. US
|
|
85
|
+
* listings also get the company's report dates, which date the figures that
|
|
86
|
+
* have no publication date of their own.
|
|
27
87
|
*/
|
|
28
88
|
export async function loadPeBandInputs(
|
|
29
89
|
request: { instrument: InstrumentRef; signal?: AbortSignal; forceRefresh?: boolean },
|
|
30
90
|
marketData: DataProvider,
|
|
31
91
|
coordinator: MarketDataCoordinator = getSharedMarketDataCoordinator() ?? new MarketDataCoordinator(marketData),
|
|
92
|
+
cloud: ReportClient = apiClient,
|
|
32
93
|
): Promise<PeBandInputs> {
|
|
33
94
|
if (request.signal?.aborted) throw abortError(CANCELLED);
|
|
34
95
|
const now = Date.now();
|
|
35
96
|
const { instrument } = request;
|
|
97
|
+
// Asked alongside the statements when the instrument names a US exchange; otherwise once the quote has said where it lists.
|
|
98
|
+
const early = isUsListingExchange(instrument.exchange) ? loadReportDates(instrument.symbol, cloud) : null;
|
|
36
99
|
const [financials, chart] = await abortable(Promise.allSettled([
|
|
37
100
|
marketData.getTickerFinancials(instrument.symbol, instrument.exchange ?? "", {
|
|
38
101
|
brokerId: instrument.instrument?.brokerId ?? instrument.brokerId,
|
|
@@ -49,9 +112,18 @@ export async function loadPeBandInputs(
|
|
|
49
112
|
const value = financials.status === "fulfilled" ? financials.value : null;
|
|
50
113
|
const entry = chart.status === "fulfilled" ? chart.value : null;
|
|
51
114
|
const history = entry ? resolveEntryValue(entry) ?? [] : [];
|
|
115
|
+
const quote = value?.quote;
|
|
116
|
+
const [reports, fx] = await abortable(Promise.all([
|
|
117
|
+
early ?? (isUsListingExchange(quote?.listingExchangeName ?? quote?.exchangeName ?? quote?.fullExchangeName)
|
|
118
|
+
? loadReportDates(instrument.symbol, cloud) : Promise.resolve([])),
|
|
119
|
+
value ? loadFxCloses(value, cloud, request.signal, new Date(now)) : Promise.resolve({ fx: new Map<string, FxCloses>(), error: null }),
|
|
120
|
+
]), request.signal, CANCELLED);
|
|
52
121
|
return {
|
|
53
122
|
financials: value,
|
|
54
123
|
history,
|
|
124
|
+
reports,
|
|
125
|
+
fx: fx.fx,
|
|
126
|
+
fxError: fx.error,
|
|
55
127
|
stale: !!value?.fundamentals?.stale || !!entry?.error || (entry?.staleAt != null && entry.staleAt <= now),
|
|
56
128
|
error: financials.status === "rejected" ? errorMessage(financials.reason) : null,
|
|
57
129
|
historyError: chart.status === "rejected" ? errorMessage(chart.reason)
|