gloomberb 0.16.2 → 0.16.4
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/package.json +4 -1
- package/src/api-client/askg.ts +43 -0
- package/src/api-client/auth.ts +15 -0
- package/src/api-client/beneficial-owners.ts +4 -0
- package/src/api-client/chat.ts +19 -0
- package/src/api-client/company-kpis.ts +14 -2
- package/src/api-client/data.ts +34 -16
- package/src/api-client/index.ts +12 -0
- package/src/api-client/normalizers.ts +27 -0
- package/src/api-client/paths.ts +88 -23
- package/src/api-client/request.ts +2 -1
- package/src/api-client/research-activity.ts +31 -0
- package/src/api-client/socket.ts +39 -8
- package/src/api-client/types.ts +57 -1
- package/src/api-client/upgrade-experiment.ts +90 -0
- package/src/app/global-shortcuts.ts +11 -1
- package/src/app/keybindings/actions.ts +10 -0
- package/src/app/pane-runtime/index.tsx +8 -0
- package/src/app/pane-runtime/pane-template-runtime.ts +5 -0
- package/src/app/pane-runtime/plugin-bindings.ts +65 -25
- package/src/app/pane-runtime/ticker-inspector-runtime.ts +12 -0
- package/src/app/pane-runtime/ticker-open-runtime.ts +18 -1
- package/src/app/runtime/desktop-deeplink.ts +5 -0
- package/src/app/star-prompt/model.ts +98 -0
- package/src/app/star-prompt/runtime.ts +41 -0
- package/src/app/star-prompt/status-line.tsx +190 -0
- package/src/app.tsx +13 -7
- package/src/architecture/core-builtin-allowlist.json +70 -0
- package/src/brokers/account-cache.ts +45 -0
- package/src/brokers/signed-in/adapter.ts +33 -2
- package/src/brokers/signed-in/client.ts +10 -0
- package/src/brokers/signed-in/sign-in-dialog.tsx +23 -9
- package/src/brokers/signed-in/sign-in.ts +62 -5
- package/src/capabilities/registry.ts +8 -1
- package/src/capabilities/types.ts +2 -0
- package/src/cli/command-options.ts +74 -0
- package/src/cli/commands/command-utils.ts +29 -0
- package/src/cli/commands/crypto-hints.ts +12 -4
- package/src/cli/commands/market.ts +524 -148
- package/src/cli/commands/options-chain.ts +172 -0
- package/src/cli/commands/options-leaps.ts +422 -0
- package/src/cli/commands/overview.ts +223 -42
- package/src/cli/commands/search.ts +29 -8
- package/src/cli/commands/system.ts +99 -19
- package/src/cli/commands/themes.ts +64 -0
- package/src/cli/commands/ticker.ts +200 -73
- package/src/cli/desktop-pane-shot.ts +100 -16
- package/src/cli/errors.ts +25 -2
- package/src/cli/freshness.ts +7 -4
- package/src/cli/fx-pair.ts +57 -0
- package/src/cli/help.ts +40 -7
- package/src/cli/history-rows.ts +187 -15
- package/src/cli/index-roots.ts +51 -0
- package/src/cli/index.ts +21 -13
- package/src/cli/listing-arg.ts +211 -3
- package/src/cli/not-a-ticker.ts +37 -0
- package/src/cli/options.ts +55 -7
- package/src/cli/pane-functions/capabilities.ts +13 -2
- package/src/cli/pane-functions/catalog.ts +13 -2
- package/src/cli/pane-functions/data.ts +36 -5
- package/src/cli/pane-functions/dom.ts +89 -28
- package/src/cli/pane-functions/freshness.ts +205 -26
- package/src/cli/pane-functions/function-help.ts +71 -24
- package/src/cli/pane-functions/headless.ts +168 -35
- package/src/cli/pane-functions/index.ts +12 -2
- package/src/cli/pane-functions/market-session.ts +133 -0
- package/src/cli/pane-functions/options.ts +15 -4
- package/src/cli/pane-functions/report-notices.ts +63 -0
- package/src/cli/pane-functions/report.ts +12 -1
- package/src/cli/pane-functions/resolver.ts +32 -8
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +109 -23
- package/src/cli/registry.ts +8 -4
- package/src/cli/report-tables.ts +460 -0
- package/src/cli/result.ts +63 -16
- package/src/cli/row-window.ts +76 -0
- package/src/cli/scroll-truncation.ts +34 -0
- package/src/components/chart/composite/composite-chart.tsx +43 -4
- package/src/components/chart/composite/legend.tsx +39 -6
- package/src/components/chart/composite/rasterizer.ts +64 -4
- package/src/components/chart/composite/series-cues.ts +71 -0
- package/src/components/chart/composite/text-renderer.ts +16 -8
- package/src/components/chart/composite/types.ts +3 -0
- package/src/components/command-bar/commands/direct/index.ts +9 -1
- package/src/components/command-bar/commands/plugin/items.ts +3 -1
- package/src/components/command-bar/commands/registry.ts +7 -0
- package/src/components/command-bar/layout-items/focused-pane.ts +38 -0
- package/src/components/command-bar/pane-templates/workflow.ts +5 -0
- package/src/components/command-bar/routes/root/command-items.ts +2 -0
- package/src/components/command-bar/routes/root/plugin-turn-on.ts +92 -0
- package/src/components/command-bar/routes/root/results.ts +40 -10
- package/src/components/command-bar/routes/root/runtime.ts +8 -0
- package/src/components/command-bar/routes/root/search-providers.ts +97 -14
- package/src/components/command-bar/surface/index.tsx +18 -4
- package/src/components/command-bar/theme-picker.tsx +48 -13
- package/src/components/command-bar/workflow/ops.ts +5 -3
- package/src/components/data-table/export.ts +6 -51
- package/src/components/data-table/view.tsx +31 -10
- package/src/components/layout/floating-pane.tsx +6 -2
- package/src/components/layout/market-summary.ts +23 -9
- package/src/components/layout/pane/content.tsx +46 -29
- package/src/components/layout/pane/cycle-order.ts +2 -11
- package/src/components/layout/pane/header.tsx +2 -1
- package/src/components/layout/pane/title.ts +1 -1
- package/src/components/layout/presentation.ts +22 -0
- package/src/components/layout/shell/active-drag.ts +67 -35
- package/src/components/layout/shell/cursor-occlusion.ts +6 -5
- package/src/components/layout/shell/drag/index.ts +16 -7
- package/src/components/layout/shell/drag/live.ts +193 -0
- package/src/components/layout/shell/drag/overlays.tsx +179 -35
- package/src/components/layout/shell/drag/runtime.ts +62 -50
- package/src/components/layout/shell/drag/slide.ts +10 -0
- package/src/components/layout/shell/index.tsx +84 -57
- package/src/components/layout/shell/layout-state.ts +5 -11
- package/src/components/layout/shell/menu.ts +28 -1
- package/src/components/layout/shell/native/pointer-runtime.ts +13 -13
- package/src/components/layout/shell/native/surfaces.ts +30 -14
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +461 -180
- package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
- package/src/components/layout/shell/pane/new-layout.ts +116 -0
- package/src/components/layout/shell/shortcuts.ts +5 -2
- package/src/components/layout/shell/terminal-pointer-runtime.ts +18 -18
- package/src/components/layout/shell/visible-layout.ts +44 -1
- package/src/components/layout/shell/window-mode/overlays.tsx +12 -4
- package/src/components/layout/status-bar.tsx +4 -1
- package/src/components/markdown-text.tsx +9 -5
- package/src/components/metric-treemap/heat-surface.tsx +27 -8
- package/src/components/metric-treemap/heat-tiles.ts +48 -17
- package/src/components/onboarding/onboarding-frame.tsx +33 -10
- package/src/components/onboarding/onboarding-wizard.tsx +49 -40
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +5 -2
- package/src/components/onboarding/pro-step-layout.ts +86 -0
- package/src/components/onboarding/use-onboarding-upgrade.ts +6 -2
- package/src/components/ui/button.tsx +10 -0
- package/src/components/ui/data-table/index.tsx +38 -0
- package/src/components/ui/data-table/types.ts +8 -1
- package/src/components/ui/data-table/visible-range.ts +2 -0
- package/src/components/ui/icon.tsx +11 -2
- package/src/components/ui/index.ts +1 -1
- package/src/core/connection-health.ts +1 -1
- package/src/core/state/app/layout-reducer.ts +89 -3
- package/src/core/state/app/state.ts +8 -5
- package/src/core/state/app/types.ts +13 -2
- package/src/data/config/layout.ts +55 -21
- package/src/data/config/store/fold-panes.ts +149 -0
- package/src/data/config/store/migrations.ts +7 -0
- package/src/data/config/store/node.ts +27 -6
- package/src/data/config/store/normalize.ts +37 -3
- package/src/data/json-persistence.ts +17 -3
- package/src/data/json-storage.ts +2 -0
- package/src/data/memory-resource-store.ts +46 -0
- package/src/i18n/es.ts +14 -1
- package/src/i18n/ja.ts +14 -1
- package/src/i18n/ko.ts +14 -1
- package/src/i18n/zh-cn.ts +14 -1
- package/src/i18n/zh-tw.ts +14 -1
- package/src/layout/desks.ts +1 -2
- package/src/layout/pane-layout-move.ts +264 -0
- package/src/layout/pane-manager/hidden-panes.ts +160 -0
- package/src/layout/pane-manager/index.ts +1 -0
- package/src/market-data/coordinator/entries.ts +7 -1
- package/src/market-data/coordinator/quotes.ts +2 -2
- package/src/market-data/market/freshness.ts +156 -11
- package/src/market-data/market/status.ts +40 -0
- package/src/market-data/options-alternatives.ts +69 -0
- package/src/market-data/quotes/contributions.ts +19 -2
- package/src/market-data/quotes/freshness.ts +5 -0
- package/src/market-data/quotes/metadata.ts +16 -0
- package/src/market-data/quotes/screener-live-quotes.ts +56 -5
- package/src/plugins/builtin/account-management/keyboard.ts +3 -0
- package/src/plugins/builtin/account-management/model.ts +1 -0
- package/src/plugins/builtin/account-management/navigation.ts +1 -1
- package/src/plugins/builtin/account-management/pane.tsx +31 -4
- package/src/plugins/builtin/alerts/quotes.ts +3 -0
- package/src/plugins/builtin/analytics/pane-model.ts +10 -6
- package/src/plugins/builtin/analytics/risk-headless.ts +3 -1
- package/src/plugins/builtin/analytics/risk-model.ts +37 -8
- package/src/plugins/builtin/analytics/risk-pane.tsx +8 -4
- package/src/plugins/builtin/attention/pane.tsx +1 -1
- package/src/plugins/builtin/backtest/pane.tsx +1 -1
- package/src/plugins/builtin/broker-manager/detail.tsx +4 -0
- package/src/plugins/builtin/broker-manager/index.tsx +7 -3
- package/src/plugins/builtin/broker-manager/model.ts +8 -0
- package/src/plugins/builtin/broker-manager/pane-actions.tsx +8 -2
- package/src/plugins/builtin/broker-manager/sign-in-end.ts +82 -0
- package/src/plugins/builtin/broker-manager/table.ts +5 -0
- package/src/plugins/builtin/builtin-plugin-meta.ts +121 -11
- package/src/plugins/builtin/catalysts/detail.tsx +1 -1
- package/src/plugins/builtin/chart-composer/pane.tsx +1 -1
- package/src/plugins/builtin/chat/channels.ts +34 -36
- package/src/plugins/builtin/chat/command-bar.ts +138 -0
- package/src/plugins/builtin/chat/composer-commands.ts +21 -1
- package/src/plugins/builtin/chat/content/composer-runtime.ts +11 -1
- package/src/plugins/builtin/chat/content/footer.tsx +5 -3
- package/src/plugins/builtin/chat/content/index.tsx +21 -1
- package/src/plugins/builtin/chat/content/mentions.ts +2 -1
- package/src/plugins/builtin/chat/content/user-map.ts +3 -1
- package/src/plugins/builtin/chat/controller/index.ts +48 -0
- package/src/plugins/builtin/chat/conversations.ts +256 -0
- package/src/plugins/builtin/chat/discord-command.ts +91 -0
- package/src/plugins/builtin/chat/edit-window.ts +12 -6
- package/src/plugins/builtin/chat/ghost-user.ts +14 -0
- package/src/plugins/builtin/chat/index.tsx +40 -2
- package/src/plugins/builtin/chat/layout.ts +2 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +2 -1
- package/src/plugins/builtin/chat/message/header.tsx +24 -15
- package/src/plugins/builtin/chat/message/profile-popover.tsx +2 -1
- package/src/plugins/builtin/chat/message/render-state.ts +3 -0
- package/src/plugins/builtin/chat/pane-requests.ts +60 -0
- package/src/plugins/builtin/chat/pane-state.ts +32 -2
- package/src/plugins/builtin/chat/pane.tsx +8 -0
- package/src/plugins/builtin/cloud/askg/controller.ts +112 -4
- package/src/plugins/builtin/cloud/askg/conversation-store.ts +21 -0
- package/src/plugins/builtin/cloud/askg/manifest.ts +1 -0
- package/src/plugins/builtin/cloud/askg/model.ts +129 -70
- package/src/plugins/builtin/cloud/askg/pane.tsx +772 -377
- package/src/plugins/builtin/cloud/askg/protocol.ts +40 -2
- package/src/plugins/builtin/cloud/askg/tool-display.ts +437 -0
- package/src/plugins/builtin/cloud/askg/tool-timeline.tsx +403 -0
- package/src/plugins/builtin/cloud/company-picker.tsx +1 -9
- package/src/plugins/builtin/cloud/mcp-connect/command.ts +24 -0
- package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +360 -0
- package/src/plugins/builtin/cloud/mcp-connect/model.ts +135 -0
- package/src/plugins/builtin/cloud/mcp-connect/sections.ts +62 -0
- package/src/plugins/builtin/cloud/plugin.tsx +36 -1
- package/src/plugins/builtin/cloud/starter-symbols.ts +8 -0
- package/src/plugins/builtin/cloud/terminal-relay/acm-tab.tsx +89 -0
- package/src/plugins/builtin/cloud/terminal-relay/client.ts +97 -0
- package/src/plugins/builtin/cloud/terminal-relay/connect-section.tsx +57 -0
- package/src/plugins/builtin/cloud/terminal-relay/engine.ts +666 -0
- package/src/plugins/builtin/cloud/terminal-relay/grants.ts +137 -0
- package/src/plugins/builtin/cloud/terminal-relay/host.tsx +81 -0
- package/src/plugins/builtin/cloud/terminal-relay/indicator.tsx +82 -0
- package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +234 -0
- package/src/plugins/builtin/cloud/terminal-relay/policy.ts +153 -0
- package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +168 -0
- package/src/plugins/builtin/cloud/terminal-relay/redact.ts +73 -0
- package/src/plugins/builtin/cloud/terminal-relay/summary.ts +62 -0
- package/src/plugins/builtin/cloud/upgrade-dialog.tsx +26 -2
- package/src/plugins/builtin/cloud/upgrade-personalization.ts +57 -0
- package/src/plugins/builtin/cloud/upgrade-tickers.ts +124 -0
- package/src/plugins/builtin/comment-letters/client.ts +1 -3
- package/src/plugins/builtin/company-attention/pane.tsx +1 -1
- package/src/plugins/builtin/company-kpis/client.ts +23 -8
- package/src/plugins/builtin/company-kpis/headless.ts +3 -1
- package/src/plugins/builtin/company-kpis/pane.tsx +15 -7
- package/src/plugins/builtin/company-kpis/screenshot-evidence.ts +10 -3
- package/src/plugins/builtin/composite-plugins.ts +107 -64
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +4 -4
- package/src/plugins/builtin/credit-boards/index.tsx +21 -21
- package/src/plugins/builtin/credit-boards/model.ts +0 -1
- package/src/plugins/builtin/credit-boards/pane.tsx +30 -0
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +4 -4
- package/src/plugins/builtin/debt-maturities/client.ts +37 -9
- package/src/plugins/builtin/debt-maturities/headless.ts +3 -1
- package/src/plugins/builtin/debt-maturities/pane.tsx +5 -4
- package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
- package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
- package/src/plugins/builtin/earnings-calls/data.ts +28 -7
- package/src/plugins/builtin/earnings-calls/headless.ts +3 -2
- package/src/plugins/builtin/earnings-calls/pane.tsx +10 -5
- package/src/plugins/builtin/econ/calendar-model.ts +42 -17
- package/src/plugins/builtin/econ/detail-view.tsx +2 -2
- package/src/plugins/builtin/econ/index.tsx +68 -22
- package/src/plugins/builtin/econ-statistics/headless.ts +12 -2
- package/src/plugins/builtin/econ-statistics/pane.tsx +1 -1
- package/src/plugins/builtin/econ-statistics/view.ts +17 -0
- package/src/plugins/builtin/executives/data.ts +17 -6
- package/src/plugins/builtin/executives/pane.tsx +16 -7
- package/src/plugins/builtin/filing-events/pane.tsx +22 -5
- package/src/plugins/builtin/fx-matrix/freshness.ts +65 -0
- package/src/plugins/builtin/fx-matrix/index.tsx +22 -1
- package/src/plugins/builtin/fx-matrix/pairs.ts +1 -1
- package/src/plugins/builtin/fx-matrix/settings.ts +42 -2
- package/src/plugins/builtin/gpu/headless.ts +9 -3
- package/src/plugins/builtin/gpu/model.ts +14 -5
- package/src/plugins/builtin/help/index.tsx +1 -0
- package/src/plugins/builtin/holders/beneficial-client.ts +29 -7
- package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
- package/src/plugins/builtin/holders/client.ts +3 -6
- package/src/plugins/builtin/holders/format.ts +31 -1
- package/src/plugins/builtin/holders/headless.ts +32 -6
- package/src/plugins/builtin/holders/pane.tsx +25 -13
- package/src/plugins/builtin/holders/report-header.ts +46 -5
- package/src/plugins/builtin/insider/index.tsx +4 -4
- package/src/plugins/builtin/iv-history/charts.tsx +21 -7
- package/src/plugins/builtin/iv-history/client.ts +12 -2
- package/src/plugins/builtin/iv-history/format.ts +33 -2
- package/src/plugins/builtin/iv-history/headless.ts +22 -10
- package/src/plugins/builtin/iv-history/index.tsx +3 -3
- package/src/plugins/builtin/iv-history/model.ts +61 -13
- package/src/plugins/builtin/iv-history/pane.tsx +11 -3
- package/src/plugins/builtin/iv-history/screen-pane.tsx +42 -18
- package/src/plugins/builtin/jobs/pane.tsx +1 -1
- package/src/plugins/builtin/kelly-sizer/headless.ts +149 -0
- package/src/plugins/builtin/kelly-sizer/history.ts +80 -0
- package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +121 -45
- package/src/plugins/builtin/kelly-sizer/portfolio.ts +25 -0
- package/src/plugins/builtin/kelly-sizer/sections.tsx +14 -0
- package/src/plugins/builtin/kelly-sizer/types.ts +9 -1
- package/src/plugins/builtin/layout-manager/index.tsx +9 -1
- package/src/plugins/builtin/macro-day/client.ts +24 -0
- package/src/plugins/builtin/macro-day/headless.ts +11 -8
- package/src/plugins/builtin/macro-day/index.tsx +3 -0
- package/src/plugins/builtin/macro-day/model.ts +11 -6
- package/src/plugins/builtin/macro-day/pane.tsx +12 -8
- package/src/plugins/builtin/macro-day/release-table.ts +40 -0
- package/src/plugins/builtin/macro-day/releases.ts +62 -44
- package/src/plugins/builtin/market-heatmap/data.ts +25 -5
- package/src/plugins/builtin/market-heatmap/evidence.ts +90 -0
- package/src/plugins/builtin/market-heatmap/index.tsx +144 -63
- package/src/plugins/builtin/market-heatmap/model.ts +94 -3
- package/src/plugins/builtin/market-heatmap/portfolio.ts +12 -2
- package/src/plugins/builtin/market-movers/headless.ts +31 -4
- package/src/plugins/builtin/market-movers/index.tsx +8 -1
- package/src/plugins/builtin/market-movers/model.ts +71 -17
- package/src/plugins/builtin/market-movers/table.ts +50 -23
- package/src/plugins/builtin/members/pane.tsx +10 -0
- package/src/plugins/builtin/news/headless.ts +9 -2
- package/src/plugins/builtin/news/wire/news/footer.ts +10 -0
- package/src/plugins/builtin/openfda/client.ts +1 -1
- package/src/plugins/builtin/options/carry.ts +95 -0
- package/src/plugins/builtin/options/index.tsx +58 -5
- package/src/plugins/builtin/options/strike-window.ts +183 -0
- package/src/plugins/builtin/options/table.ts +55 -3
- package/src/plugins/builtin/options/types.ts +8 -1
- package/src/plugins/builtin/options/view.tsx +161 -12
- package/src/plugins/builtin/options-positioning/headless.ts +4 -2
- package/src/plugins/builtin/options-scenario/charts.tsx +2 -2
- package/src/plugins/builtin/options-scenario/client.ts +73 -17
- package/src/plugins/builtin/options-scenario/headless.ts +71 -24
- package/src/plugins/builtin/options-scenario/hedge.ts +284 -0
- package/src/plugins/builtin/options-scenario/index.tsx +9 -2
- package/src/plugins/builtin/options-scenario/model.ts +33 -0
- package/src/plugins/builtin/options-scenario/pane.tsx +40 -16
- package/src/plugins/builtin/pe-band/model.ts +2 -2
- package/src/plugins/builtin/pe-band/report-dates.ts +11 -7
- package/src/plugins/builtin/perps/equity-row.tsx +8 -5
- package/src/plugins/builtin/perps/model.ts +16 -5
- package/src/plugins/builtin/perps/pane.tsx +1 -1
- package/src/plugins/builtin/plugin-marketplace/model.ts +64 -21
- package/src/plugins/builtin/plugin-marketplace/packs.ts +118 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +344 -32
- package/src/plugins/builtin/plugin-marketplace/store.ts +7 -1
- package/src/plugins/builtin/plugin-module.ts +87 -4
- package/src/plugins/builtin/portfolio-list/account-metrics.ts +16 -1
- package/src/plugins/builtin/portfolio-list/allocation.ts +3 -0
- package/src/plugins/builtin/portfolio-list/cached-account.ts +18 -9
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +71 -36
- package/src/plugins/builtin/portfolio-list/cli/render.ts +89 -18
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +2 -16
- package/src/plugins/builtin/portfolio-list/headless.ts +40 -7
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +7 -4
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +22 -4
- package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +11 -1
- package/src/plugins/builtin/realized-vol/headless.ts +3 -0
- package/src/plugins/builtin/realized-vol/pane.tsx +1 -1
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +2 -2
- package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +1 -1
- package/src/plugins/builtin/research/relative-valuation-model.ts +7 -3
- package/src/plugins/builtin/revenue-breakdown/client.ts +13 -6
- package/src/plugins/builtin/revenue-breakdown/headless.ts +4 -1
- package/src/plugins/builtin/revenue-breakdown/pane.tsx +7 -4
- package/src/plugins/builtin/reverse-dcf/headless.ts +5 -1
- package/src/plugins/builtin/reverse-dcf/model.ts +2 -1
- package/src/plugins/builtin/reverse-dcf/pane.tsx +1 -1
- package/src/plugins/builtin/risk-factors/data.ts +23 -9
- package/src/plugins/builtin/risk-factors/headless.ts +5 -2
- package/src/plugins/builtin/risk-factors/pane.tsx +6 -5
- package/src/plugins/builtin/seasonality/pane.tsx +1 -1
- package/src/plugins/builtin/sec/index.tsx +5 -5
- package/src/plugins/builtin/sectors/client.ts +10 -2
- package/src/plugins/builtin/sectors/headless.ts +35 -6
- package/src/plugins/builtin/sectors/index.tsx +18 -1
- package/src/plugins/builtin/sectors/sector-model.ts +150 -41
- package/src/plugins/builtin/shared/command-tab.ts +51 -0
- package/src/plugins/builtin/shared/headless-market-data.ts +33 -1
- package/src/plugins/builtin/shared/members-menu.tsx +260 -0
- package/src/plugins/builtin/shared/report-freshness.ts +50 -2
- package/src/plugins/builtin/shared/ticker-request.ts +25 -1
- package/src/plugins/builtin/shared/use-quote-board.ts +25 -5
- package/src/plugins/builtin/shared/volatility/options.ts +1 -46
- package/src/plugins/builtin/short-interest/index.tsx +19 -4
- package/src/plugins/builtin/short-interest/surface.tsx +4 -4
- package/src/plugins/builtin/short-volume/index.tsx +1 -10
- package/src/plugins/builtin/short-volume/pane.tsx +1 -1
- package/src/plugins/builtin/social-mentions/pane.tsx +1 -1
- package/src/plugins/builtin/supply-chain/model.ts +1 -1
- package/src/plugins/builtin/themes/pane.tsx +3 -0
- package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +4 -0
- package/src/plugins/builtin/ticker-detail/financials/model.ts +25 -2
- package/src/plugins/builtin/ticker-detail/headless.ts +63 -25
- package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -4
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +3 -2
- package/src/plugins/builtin/ticker-detail/pane.tsx +4 -5
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +94 -6
- package/src/plugins/builtin/treasury-auctions/cache.ts +5 -2
- package/src/plugins/builtin/treasury-auctions/client.ts +22 -8
- package/src/plugins/builtin/treasury-auctions/headless.ts +40 -4
- package/src/plugins/builtin/treasury-auctions/index.tsx +11 -9
- package/src/plugins/builtin/treasury-auctions/model.ts +197 -30
- package/src/plugins/builtin/treasury-auctions/pane.tsx +35 -11
- package/src/plugins/builtin/treasury-auctions/types.ts +11 -1
- package/src/plugins/builtin/vol-surface/charts.tsx +1 -3
- package/src/plugins/builtin/vol-surface/client.ts +6 -2
- package/src/plugins/builtin/vol-surface/evidence.ts +11 -6
- package/src/plugins/builtin/vol-surface/headless.ts +124 -20
- package/src/plugins/builtin/vol-surface/model.ts +23 -11
- package/src/plugins/builtin/vol-surface/pane.tsx +38 -27
- package/src/plugins/builtin/vol-surface/tables.ts +124 -0
- package/src/plugins/builtin/world-indices/client.ts +22 -4
- package/src/plugins/builtin/world-indices/headless.ts +54 -27
- package/src/plugins/builtin/world-indices/model.ts +4 -2
- package/src/plugins/builtin/world-indices/table.tsx +13 -2
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +2 -0
- package/src/plugins/builtin/world-venue-map/basemap.ts +18 -0
- package/src/plugins/builtin/world-venue-map/country-labels.ts +78 -0
- package/src/plugins/builtin/world-venue-map/geo-series.ts +1 -1
- package/src/plugins/builtin/world-venue-map/geo-svg.tsx +2 -1
- package/src/plugins/builtin/world-venue-map/index.ts +6 -6
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +27 -14
- package/src/plugins/builtin/world-venue-map/layers.ts +68 -10
- package/src/plugins/builtin/world-venue-map/map.tsx +198 -62
- package/src/plugins/builtin/world-venue-map/model.ts +16 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +3 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/labels.chunk.ts +244 -0
- package/src/plugins/builtin/world-venue-map/pane.tsx +16 -10
- package/src/plugins/builtin/yield-curve/index.tsx +1 -1
- package/src/plugins/builtin-editorial.ts +126 -0
- package/src/plugins/catalog-backend.ts +16 -9
- package/src/plugins/catalog-browser.ts +127 -63
- package/src/plugins/catalog-manifest.ts +73 -40
- package/src/plugins/catalog-ui.ts +26 -6
- package/src/plugins/extracted-plugins.ts +7 -1
- package/src/plugins/ownership.ts +150 -7
- package/src/plugins/plugin-functions.ts +54 -0
- package/src/plugins/plugin-off.ts +36 -0
- package/src/plugins/registry/host-actions.ts +16 -0
- package/src/plugins/registry/index.ts +84 -24
- package/src/plugins/registry/plugin-state.ts +25 -1
- package/src/plugins/runtime/context.tsx +29 -0
- package/src/react/input.ts +48 -1
- package/src/remote/app-host.tsx +5 -0
- package/src/remote/controller.ts +3 -53
- package/src/remote/matching.ts +69 -0
- package/src/remote/schema.ts +1 -1
- package/src/remote/semantic-tree.tsx +14 -0
- package/src/remote/types.ts +2 -0
- package/src/renderers/browser/app-services.ts +3 -1
- package/src/renderers/dom/data-table/dom.ts +31 -0
- package/src/renderers/dom/data-table/index.tsx +5 -0
- package/src/renderers/dom/desktop/icons.tsx +14 -0
- package/src/renderers/dom/desktop/query-bar.tsx +59 -32
- package/src/renderers/dom/host/box.tsx +113 -17
- package/src/renderers/dom/host/drag-shield.ts +35 -0
- package/src/renderers/dom/host/live-frame.ts +62 -0
- package/src/renderers/dom/host/mouse.ts +8 -1
- package/src/renderers/dom/host/scroll-box.tsx +6 -5
- package/src/renderers/dom/host/tabs.tsx +3 -2
- package/src/renderers/dom/input-host.tsx +6 -1
- package/src/renderers/dom/styles.css +26 -5
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +7 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +7 -1
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +12 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +15 -1
- package/src/renderers/electrobun/shared/protocol.ts +12 -1
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +4 -1
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +101 -5
- package/src/renderers/electrobun/view/host/native.ts +0 -10
- package/src/renderers/electrobun/view/host/window-move.ts +28 -0
- package/src/renderers/electrobun/view/main.tsx +4 -1
- package/src/renderers/electrobun/view/remote/persistence.ts +15 -2
- package/src/renderers/electrobun/view/ui-host.tsx +2 -5
- package/src/renderers/opentui/input-host.tsx +6 -1
- package/src/renderers/opentui/start.tsx +9 -0
- package/src/renderers/opentui/ui-host.tsx +7 -1
- package/src/shares/portable-layout.ts +16 -6
- package/src/sources/gloomberb-cloud/index.ts +19 -10
- package/src/sources/gloomberb-cloud/normalizers.ts +20 -21
- package/src/sources/listing-symbols.ts +11 -5
- package/src/sources/provider-errors.ts +88 -3
- package/src/sources/provider-router/batches.ts +3 -3
- package/src/sources/provider-router/cached-routes.ts +8 -4
- package/src/sources/provider-router/financial-routes.ts +13 -7
- package/src/sources/provider-router/financials.ts +106 -16
- package/src/sources/provider-router/history.ts +27 -11
- package/src/sources/provider-router/index.ts +1 -1
- package/src/sources/provider-router/primary.ts +24 -6
- package/src/sources/sec-edgar.ts +68 -8
- package/src/state/pane-scroll-registry.tsx +67 -35
- package/src/sync/core-contributors.ts +4 -3
- package/src/test-support/cli-context.ts +2 -1
- package/src/test-support/data-provider.ts +34 -0
- package/src/test-support/margin-account.ts +108 -0
- package/src/test-support/shell-pane-keys.tsx +1 -0
- package/src/theme/series-colors.ts +46 -0
- package/src/theme/themes.ts +149 -0
- package/src/tickers/search/index.ts +22 -2
- package/src/tickers/search/ranking.ts +45 -1
- package/src/tickers/search/types.ts +3 -1
- package/src/time-series/resolution.ts +15 -0
- package/src/time-series/resolve.ts +1 -14
- package/src/types/config.ts +61 -1
- package/src/types/financials.ts +32 -3
- package/src/types/headless.ts +11 -0
- package/src/types/instrument.ts +8 -0
- package/src/types/plugin.ts +49 -3
- package/src/ui/host.tsx +16 -0
- package/src/ui/index.tsx +10 -3
- package/src/ui/scroll-box-axis.ts +26 -0
- package/src/utils/cli-output.ts +14 -1
- package/src/utils/currency-units.ts +8 -3
- package/src/utils/depositary-receipt.ts +54 -10
- package/src/utils/display-number.ts +63 -0
- package/src/utils/exchanges.ts +13 -0
- package/src/utils/format.ts +2 -1
- package/src/utils/fundamentals.ts +17 -1
- package/src/utils/fx-market-hours.ts +34 -0
- package/src/utils/option-expiry.ts +126 -0
- package/src/utils/price-history-integrity.ts +19 -6
- package/src/utils/price-history.ts +39 -6
- package/src/utils/rpc-timeout-error.ts +6 -2
- package/src/utils/sec-eps-basis.ts +159 -30
- package/src/utils/sec.ts +38 -34
- package/src/utils/throttled-fetch.ts +51 -22
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { formatShortDate, parseDisplayDate } from "../../utils/datetime-format";
|
|
2
2
|
import { formatReportedMoney } from "../../utils/reported-money";
|
|
3
|
+
import { fundamentalsCurrency, reportedEnterpriseValue } from "../../utils/fundamentals";
|
|
3
4
|
import { latestFinancialPeriod } from "../../utils/latest-financial-period";
|
|
4
5
|
import { exportedFundamentals, formatPriceEarnings, priceEarningsOnEarnings } from "../../utils/price-earnings";
|
|
5
6
|
import { describeFundamentalMarketCap, selectMarketCapitalization } from "../../utils/market-capitalization";
|
|
@@ -21,8 +22,10 @@ import {
|
|
|
21
22
|
type CliStatEntry,
|
|
22
23
|
} from "../../utils/cli-output";
|
|
23
24
|
import {
|
|
25
|
+
EXTENDED_SESSION_LABELS,
|
|
24
26
|
exchangeShortName,
|
|
25
27
|
getExtendedSessionDisplay,
|
|
28
|
+
getQuoteSessionFields,
|
|
26
29
|
getRegularSessionDisplay,
|
|
27
30
|
marketStateLabel,
|
|
28
31
|
} from "../../market-data/market/status";
|
|
@@ -48,11 +51,15 @@ import {
|
|
|
48
51
|
formatWatchlistNames,
|
|
49
52
|
} from "../helpers";
|
|
50
53
|
import { NotesFiles } from "../../plugins/builtin/notes/files";
|
|
51
|
-
import {
|
|
54
|
+
import { isKnownNonUsListing } from "../../utils/sec";
|
|
52
55
|
import { canonicalExchange, exchangeLabel, isKnownExchangeCode } from "../../utils/exchanges";
|
|
53
56
|
import { failIfNotTraded, ListingArgError, listingIdentity, resolveCliListing, type CliListing } from "../listing-arg";
|
|
54
|
-
import {
|
|
57
|
+
import { isNotATickerMessage } from "../not-a-ticker";
|
|
58
|
+
import { sharesOutstandingInReceipts } from "../../utils/depositary-receipt";
|
|
55
59
|
import { cliFreshnessFooter } from "../result";
|
|
60
|
+
import { providerMissReason } from "../../sources/provider-errors";
|
|
61
|
+
import { exportEntriesTable, reportFooterLines, type CliReportTables } from "../report-tables";
|
|
62
|
+
import type { ReportFreshness } from "../pane-functions/freshness";
|
|
56
63
|
import { fundamentalsFreshness, quotesFreshness } from "../freshness";
|
|
57
64
|
|
|
58
65
|
const NEWS_ITEM_LIMIT = 5;
|
|
@@ -99,10 +106,26 @@ function buildStatementMetrics(statement: FinancialStatement, currency?: string)
|
|
|
99
106
|
["Total Debt", money(statement.totalDebt)],
|
|
100
107
|
["Equity", money(statement.totalEquity)],
|
|
101
108
|
["Diluted EPS", money(statement.eps, true)],
|
|
102
|
-
|
|
109
|
+
// Labelled only when the service says the row counts receipts.
|
|
110
|
+
["Diluted Shares", statement.dilutedShares != null && statement.shareBasis === "depositary_receipt"
|
|
111
|
+
? `${formatCompact(statement.dilutedShares)} (ADR equivalent)`
|
|
112
|
+
: formatCompact(statement.dilutedShares)],
|
|
103
113
|
];
|
|
104
114
|
}
|
|
105
115
|
|
|
116
|
+
/**
|
|
117
|
+
* A receipt's count is its ordinary shares expressed in receipts, as its
|
|
118
|
+
* market cap is; the ordinary count follows when the service gives it.
|
|
119
|
+
*/
|
|
120
|
+
function sharesOutstandingText(fundamentals: TickerFinancials["fundamentals"], inReceipts: boolean): string {
|
|
121
|
+
const shares = fundamentals?.sharesOutstanding;
|
|
122
|
+
if (shares == null || !inReceipts) return formatCompact(shares);
|
|
123
|
+
const ordinary = fundamentals?.shareBasis === "depositary_receipt" ? fundamentals.underlyingOrdinaryShares : undefined;
|
|
124
|
+
return ordinary != null && Number.isFinite(ordinary) && ordinary > 0
|
|
125
|
+
? `${formatCompact(shares)} (ADR equivalent = ${formatCompact(ordinary)} ordinary shares)`
|
|
126
|
+
: `${formatCompact(shares)} (ADR equivalent)`;
|
|
127
|
+
}
|
|
128
|
+
|
|
106
129
|
/** Provider prose is wrapped; `verbatim` keeps the user's own spacing, such as a table in a note. */
|
|
107
130
|
function appendTextSection(lines: string[], title: string, content: string | undefined, verbatim = false) {
|
|
108
131
|
const text = content?.trim();
|
|
@@ -159,26 +182,35 @@ function getFilingDescription(filing: SecFilingItem): string | undefined {
|
|
|
159
182
|
return description;
|
|
160
183
|
}
|
|
161
184
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
185
|
+
/**
|
|
186
|
+
* SEC filings are asked for unless the listing is known to be outside the US:
|
|
187
|
+
* by the saved ticker, the requested venue, the quote, or the listing the
|
|
188
|
+
* source still describes when it has no current quote. A symbol nothing is
|
|
189
|
+
* known about yet is looked up as a US ticker.
|
|
190
|
+
*/
|
|
191
|
+
function shouldFetchSecFilings(
|
|
192
|
+
symbol: string,
|
|
193
|
+
exchange: string,
|
|
194
|
+
tickerFile: TickerRecord | null,
|
|
195
|
+
financials: TickerFinancials,
|
|
196
|
+
): boolean {
|
|
197
|
+
const saved = tickerFile?.metadata;
|
|
198
|
+
const { quote, quoteMetadata } = financials;
|
|
199
|
+
return !isKnownNonUsListing({
|
|
200
|
+
metadata: {
|
|
201
|
+
ticker: saved?.ticker ?? symbol,
|
|
202
|
+
exchange: saved?.exchange || exchange || quote?.listingExchangeName || quote?.exchangeName
|
|
203
|
+
|| quoteMetadata?.listingExchangeName || "",
|
|
204
|
+
currency: saved?.currency || quote?.currency || quoteMetadata?.currency || "",
|
|
205
|
+
name: saved?.name ?? symbol,
|
|
206
|
+
broker_contracts: saved?.broker_contracts,
|
|
207
|
+
portfolios: [],
|
|
208
|
+
watchlists: [],
|
|
209
|
+
positions: [],
|
|
210
|
+
custom: {},
|
|
211
|
+
tags: [],
|
|
212
|
+
},
|
|
213
|
+
});
|
|
182
214
|
}
|
|
183
215
|
|
|
184
216
|
async function appendTickerPositions(lines: string[], tickerFile: TickerRecord | null, quote: TickerFinancials["quote"],
|
|
@@ -241,60 +273,103 @@ function enterpriseValueCurrency(
|
|
|
241
273
|
|| undefined;
|
|
242
274
|
}
|
|
243
275
|
|
|
276
|
+
/** A fundamentals line: the text the report prints, and for CSV the figure behind it in `unit`. */
|
|
277
|
+
interface FundamentalsMetric {
|
|
278
|
+
label: string;
|
|
279
|
+
text: string;
|
|
280
|
+
value?: number | string | null;
|
|
281
|
+
unit?: string;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
type MetricFigure = Omit<FundamentalsMetric, "label">;
|
|
285
|
+
|
|
286
|
+
/** An amount in the currency the source reported it in; `ccy?` when it named none, as the text says. */
|
|
287
|
+
function reportedMoney(value: number | undefined, currency: string | undefined, perShare = false): MetricFigure {
|
|
288
|
+
return { text: formatReportedMoney(value, currency, perShare), value, unit: currency?.trim() || "ccy?" };
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function percentFigure(fraction: number | null | undefined, format: (value: number) => string): MetricFigure {
|
|
292
|
+
return fraction != null ? { text: format(fraction), value: fraction * 100, unit: "%" } : { text: "—" };
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function multipleFigure(value: ReturnType<typeof priceEarningsOnEarnings> | number | undefined): MetricFigure {
|
|
296
|
+
const text = formatPriceEarnings(value, 2);
|
|
297
|
+
return { text, value: typeof value === "number" && Number.isFinite(value) && value > 0 ? value : text === "N/M" ? text : null };
|
|
298
|
+
}
|
|
299
|
+
|
|
244
300
|
function fundamentalsMetrics(
|
|
245
301
|
quote: TickerFinancials["quote"],
|
|
246
302
|
fundamentals: TickerFinancials["fundamentals"],
|
|
247
303
|
profile: TickerFinancials["profile"],
|
|
248
|
-
|
|
304
|
+
marketCap: MetricFigure,
|
|
249
305
|
priceReturns: { return1Y?: number | null; return3Y?: number | null },
|
|
250
|
-
|
|
251
|
-
)
|
|
306
|
+
reportingCurrency: string | undefined,
|
|
307
|
+
enterpriseValue = reportedMoney(reportedEnterpriseValue(fundamentals), enterpriseValueCurrency(quote, fundamentals)),
|
|
308
|
+
): FundamentalsMetric[] {
|
|
309
|
+
const signed = (value: number) => colorBySign(formatPercent(value), value);
|
|
310
|
+
const receipt = fundamentals?.sharesOutstanding != null && sharesOutstandingInReceipts(quote, fundamentals, profile?.description);
|
|
252
311
|
return [
|
|
253
|
-
|
|
254
|
-
|
|
312
|
+
{ label: "Market Cap", ...marketCap },
|
|
313
|
+
{ label: "Enterprise Value", ...enterpriseValue },
|
|
255
314
|
// A multiple over a loss is N/M, even beside a positive one the source served from an older period.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
315
|
+
{ label: "P/E (TTM)", ...multipleFigure(priceEarningsOnEarnings(fundamentals?.trailingPE, fundamentals?.eps)) },
|
|
316
|
+
{ label: "Forward P/E", ...multipleFigure(priceEarningsOnEarnings(fundamentals?.forwardPE, fundamentals?.forwardEps)) },
|
|
317
|
+
{ label: "PEG", ...multipleFigure(fundamentals?.pegRatio) },
|
|
259
318
|
// The flows and EPS are one trailing-twelve-month block, the same twelve months for each line.
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
319
|
+
{ label: "EPS (TTM)", ...reportedMoney(fundamentals?.eps, reportingCurrency, true) },
|
|
320
|
+
{
|
|
321
|
+
label: `Dividend Yield${fundamentals?.dividendYieldBasis ? ` (${fundamentals.dividendYieldBasis})` : ""}`,
|
|
322
|
+
...percentFigure(fundamentals?.dividendYield, formatFractionPercentCell),
|
|
323
|
+
},
|
|
324
|
+
{ label: "Revenue (TTM)", ...reportedMoney(fundamentals?.revenue, reportingCurrency) },
|
|
325
|
+
{ label: "Net Income (TTM)", ...reportedMoney(fundamentals?.netIncome, reportingCurrency) },
|
|
326
|
+
{ label: "Operating Cash Flow (TTM)", ...reportedMoney(fundamentals?.operatingCashFlow, reportingCurrency) },
|
|
327
|
+
{ label: "Free Cash Flow (TTM)", ...reportedMoney(fundamentals?.freeCashFlow, reportingCurrency) },
|
|
266
328
|
// Levels, not changes, so they carry no sign.
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
fundamentals?.sharesOutstanding
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
],
|
|
329
|
+
{ label: "Operating Margin", ...percentFigure(fundamentals?.operatingMargin, formatFractionPercentCell) },
|
|
330
|
+
{ label: "Profit Margin", ...percentFigure(fundamentals?.profitMargin, formatFractionPercentCell) },
|
|
331
|
+
{ label: "Revenue Growth", ...percentFigure(fundamentals?.revenueGrowth, signed) },
|
|
332
|
+
{ label: "Last Quarter Growth", ...percentFigure(fundamentals?.lastQuarterGrowth, signed) },
|
|
333
|
+
{ label: "1Y Return", ...percentFigure(priceReturns.return1Y, signed) },
|
|
334
|
+
{ label: "3Y Return", ...percentFigure(priceReturns.return3Y, signed) },
|
|
335
|
+
{
|
|
336
|
+
label: "Shares Outstanding",
|
|
337
|
+
text: sharesOutstandingText(fundamentals, receipt),
|
|
338
|
+
value: fundamentals?.sharesOutstanding,
|
|
339
|
+
...(receipt ? { unit: "ADR equivalent" } : {}),
|
|
340
|
+
},
|
|
280
341
|
];
|
|
281
342
|
}
|
|
282
343
|
|
|
344
|
+
function metricLines(metrics: readonly FundamentalsMetric[]): Array<[string, string]> {
|
|
345
|
+
return metrics.map((metric) => [metric.label, metric.text]);
|
|
346
|
+
}
|
|
347
|
+
|
|
283
348
|
const VALUATION_METRICS = new Set(["Market Cap", "Enterprise Value", "P/E (TTM)", "Forward P/E", "PEG", "EPS (TTM)"]);
|
|
284
349
|
|
|
350
|
+
type FundamentalsReportData = TickerFinancials & { symbol: string; exchange?: string };
|
|
351
|
+
|
|
352
|
+
/** The lines `fundamentals` or `valuation` reports, the ones with a value. */
|
|
353
|
+
function fundamentalsReportMetrics(financials: FundamentalsReportData, view: "fundamentals" | "valuation"): FundamentalsMetric[] {
|
|
354
|
+
const quote = financials.quote;
|
|
355
|
+
const fundamentals = financials.fundamentals;
|
|
356
|
+
const capitalization = selectMarketCapitalization(quote, fundamentals);
|
|
357
|
+
const marketCap: MetricFigure = capitalization
|
|
358
|
+
? { text: `${formatCompact(capitalization.value)} ${capitalization.currency}`, value: capitalization.value, unit: capitalization.currency }
|
|
359
|
+
: { text: "—" };
|
|
360
|
+
const metrics = fundamentalsMetrics(quote, fundamentals, financials.profile, marketCap, computeTickerPriceReturns(financials), fundamentalsCurrency(financials));
|
|
361
|
+
return (view === "valuation"
|
|
362
|
+
? metrics.filter(({ label }) => VALUATION_METRICS.has(label) || label.startsWith("Dividend Yield"))
|
|
363
|
+
: metrics).filter((metric) => metric.text !== "—");
|
|
364
|
+
}
|
|
365
|
+
|
|
285
366
|
/** Text for `gloomberb fundamentals` and `gloomberb valuation`: the ticker report's fundamentals without the rest. */
|
|
286
367
|
export function renderFundamentalsReport(
|
|
287
|
-
financials:
|
|
368
|
+
financials: FundamentalsReportData,
|
|
288
369
|
view: "fundamentals" | "valuation",
|
|
289
370
|
): string {
|
|
290
371
|
const quote = financials.quote;
|
|
291
|
-
const fundamentals = financials.fundamentals;
|
|
292
372
|
const profile = financials.profile;
|
|
293
|
-
const capitalization = selectMarketCapitalization(quote, fundamentals);
|
|
294
|
-
const marketCapText = capitalization
|
|
295
|
-
? `${formatCompact(capitalization.value)} ${capitalization.currency}`
|
|
296
|
-
: "—";
|
|
297
|
-
const metrics = fundamentalsMetrics(quote, fundamentals, profile, marketCapText, computeTickerPriceReturns(financials));
|
|
298
373
|
const symbol = quote?.symbol ?? financials.symbol;
|
|
299
374
|
const name = quote?.name && quote.name !== symbol ? ` ${cliStyles.bold(quote.name)}` : "";
|
|
300
375
|
const lines = [`${cliStyles.accent(symbol)}${name}`];
|
|
@@ -305,16 +380,49 @@ export function renderFundamentalsReport(
|
|
|
305
380
|
].filter((part): part is string => !!part);
|
|
306
381
|
if (profileParts.length > 0) lines.push(cliStyles.muted(profileParts.join(METADATA_SEPARATOR)));
|
|
307
382
|
|
|
308
|
-
const shown = view === "valuation"
|
|
309
|
-
? metrics.filter(([label]) => VALUATION_METRICS.has(label) || label.startsWith("Dividend Yield"))
|
|
310
|
-
: metrics;
|
|
311
383
|
const before = lines.length;
|
|
312
|
-
appendMetricSection(lines, view === "valuation" ? "Valuation" : "Fundamentals",
|
|
384
|
+
appendMetricSection(lines, view === "valuation" ? "Valuation" : "Fundamentals", metricLines(fundamentalsReportMetrics(financials, view)));
|
|
313
385
|
if (lines.length === before) lines.push("", cliStyles.muted(`No ${view} reported for ${financials.symbol}.`));
|
|
314
386
|
if (view === "fundamentals") appendTextSection(lines, "Description", profile?.description);
|
|
315
387
|
return lines.join("\n");
|
|
316
388
|
}
|
|
317
389
|
|
|
390
|
+
/**
|
|
391
|
+
* `fundamentals` and `valuation` for `--csv` and `--ndjson`: the metrics as
|
|
392
|
+
* `Metric,Value` with each unit in its label, and for `fundamentals` the
|
|
393
|
+
* company profile the text prints around them.
|
|
394
|
+
*/
|
|
395
|
+
export function fundamentalsReportTables(
|
|
396
|
+
financials: FundamentalsReportData,
|
|
397
|
+
view: "fundamentals" | "valuation",
|
|
398
|
+
freshness: ReportFreshness,
|
|
399
|
+
): CliReportTables {
|
|
400
|
+
const metrics = fundamentalsReportMetrics(financials, view);
|
|
401
|
+
const tables = [exportEntriesTable(
|
|
402
|
+
view === "valuation" ? "Valuation" : "Fundamentals",
|
|
403
|
+
metrics.map((metric) => ({ label: metric.label, value: metric.value, formatted: metric.text, unit: metric.unit })),
|
|
404
|
+
)];
|
|
405
|
+
if (view === "fundamentals") {
|
|
406
|
+
const quote = financials.quote;
|
|
407
|
+
const profile = financials.profile;
|
|
408
|
+
tables.push(exportEntriesTable("Profile", [
|
|
409
|
+
{ label: "Symbol", value: quote?.symbol ?? financials.symbol },
|
|
410
|
+
{ label: "Name", value: quote?.name },
|
|
411
|
+
{ label: "Exchange", value: financials.exchange ? exchangeLabel(financials.exchange) : undefined },
|
|
412
|
+
{ label: "Sector", value: profile?.sector },
|
|
413
|
+
{ label: "Industry", value: profile?.industry },
|
|
414
|
+
{ label: "Description", value: profile?.description?.trim() },
|
|
415
|
+
].filter((entry) => typeof entry.value === "string" && entry.value.trim().length > 0)));
|
|
416
|
+
}
|
|
417
|
+
return {
|
|
418
|
+
tables,
|
|
419
|
+
footer: reportFooterLines({
|
|
420
|
+
freshness,
|
|
421
|
+
notes: metrics.length === 0 ? [`No ${view} reported for ${financials.symbol}.`] : [],
|
|
422
|
+
}),
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
|
|
318
426
|
/** "Euronext Paris (EPA)": the venue the report is for, named in full when the app knows it. */
|
|
319
427
|
function listingVenueLabel(
|
|
320
428
|
listingExchange: string | undefined,
|
|
@@ -335,6 +443,7 @@ export async function buildTickerReport({
|
|
|
335
443
|
config,
|
|
336
444
|
toBase,
|
|
337
445
|
notes,
|
|
446
|
+
quoteNote,
|
|
338
447
|
recentNews = [],
|
|
339
448
|
recentSecFilings = [],
|
|
340
449
|
}: {
|
|
@@ -346,6 +455,8 @@ export async function buildTickerReport({
|
|
|
346
455
|
config: AppConfig;
|
|
347
456
|
toBase: (value: number, fromCurrency: string) => Promise<number>;
|
|
348
457
|
notes?: string;
|
|
458
|
+
/** Why there is no quote, when a source said; "Quote unavailable." otherwise. */
|
|
459
|
+
quoteNote?: string;
|
|
349
460
|
recentNews?: NewsArticle[];
|
|
350
461
|
recentSecFilings?: SecFilingItem[];
|
|
351
462
|
}): Promise<string> {
|
|
@@ -360,7 +471,7 @@ export async function buildTickerReport({
|
|
|
360
471
|
const lines: string[] = [];
|
|
361
472
|
|
|
362
473
|
lines.push(`${cliStyles.accent(quote?.symbol ?? symbol)} ${cliStyles.bold(name)}`);
|
|
363
|
-
if (!quote) lines.push(cliStyles.muted(
|
|
474
|
+
if (!quote) lines.push(cliStyles.muted(quoteNote ?? QUOTE_UNAVAILABLE));
|
|
364
475
|
|
|
365
476
|
const summaryParts = [
|
|
366
477
|
listingVenueLabel(listingExchange, quote, financials, tickerFile) || undefined,
|
|
@@ -407,10 +518,10 @@ export async function buildTickerReport({
|
|
|
407
518
|
: `${formatCompact(capitalization.value)} ${capitalization.currency}`
|
|
408
519
|
: "—";
|
|
409
520
|
// Shown in the same currency as the market cap, so the two can be compared.
|
|
410
|
-
const enterpriseValue = fundamentals
|
|
521
|
+
const enterpriseValue = reportedEnterpriseValue(fundamentals);
|
|
411
522
|
const evCurrency = enterpriseValueCurrency(quote, fundamentals);
|
|
412
523
|
// A minor unit such as GBp stays as reported: the converter would read it as the major currency.
|
|
413
|
-
const convertedEnterpriseValue = enterpriseValue != null &&
|
|
524
|
+
const convertedEnterpriseValue = enterpriseValue != null && evCurrency && /^[A-Z]{3}$/.test(evCurrency)
|
|
414
525
|
? await toBase(enterpriseValue, evCurrency) : Number.NaN;
|
|
415
526
|
const enterpriseValueText = Number.isFinite(convertedEnterpriseValue)
|
|
416
527
|
? `${formatCompact(convertedEnterpriseValue)} ${config.baseCurrency}`
|
|
@@ -442,12 +553,12 @@ export async function buildTickerReport({
|
|
|
442
553
|
]);
|
|
443
554
|
|
|
444
555
|
appendMetricSection(lines, "Extended Hours", [
|
|
445
|
-
[
|
|
446
|
-
[
|
|
556
|
+
[EXTENDED_SESSION_LABELS.PRE, extendedRow("PRE")],
|
|
557
|
+
[EXTENDED_SESSION_LABELS.POST, extendedRow("POST")],
|
|
447
558
|
]);
|
|
448
559
|
}
|
|
449
560
|
|
|
450
|
-
appendMetricSection(lines, "Fundamentals", fundamentalsMetrics(quote, fundamentals, profile, marketCapText, priceReturns, enterpriseValueText));
|
|
561
|
+
appendMetricSection(lines, "Fundamentals", metricLines(fundamentalsMetrics(quote, fundamentals, profile, { text: marketCapText }, priceReturns, fundamentalsCurrency(financials), { text: enterpriseValueText })));
|
|
451
562
|
|
|
452
563
|
if (capitalization?.provenance.kind === "fundamentals") {
|
|
453
564
|
lines.push(cliStyles.muted(`Market cap: ${describeFundamentalMarketCap(capitalization.provenance)}.`));
|
|
@@ -532,10 +643,9 @@ function buildTickerStructuredData({
|
|
|
532
643
|
symbol: quote.symbol,
|
|
533
644
|
instrumentType: quote.instrumentType,
|
|
534
645
|
name: quote.name,
|
|
535
|
-
|
|
646
|
+
// Last and Change as the text report reads them, then the extended print from that close.
|
|
647
|
+
...getQuoteSessionFields(quote),
|
|
536
648
|
priceBasis: quote.priceBasis ?? null,
|
|
537
|
-
change: quote.change,
|
|
538
|
-
changePercent: quote.changePercent,
|
|
539
649
|
currency: quote.currency,
|
|
540
650
|
marketCap: quote.marketCap ?? null,
|
|
541
651
|
volume: quote.volume ?? null,
|
|
@@ -587,6 +697,18 @@ function buildTickerStructuredData({
|
|
|
587
697
|
};
|
|
588
698
|
}
|
|
589
699
|
|
|
700
|
+
const QUOTE_UNAVAILABLE = "Quote unavailable.";
|
|
701
|
+
|
|
702
|
+
/** Asks for the quote the report lacks once more, for the reason the data service gave when it had none. */
|
|
703
|
+
async function quoteUnavailableNote(dataProvider: MarketContext["dataProvider"], symbol: string, exchange: string): Promise<string> {
|
|
704
|
+
try {
|
|
705
|
+
await dataProvider.getQuote(symbol, exchange);
|
|
706
|
+
} catch (error) {
|
|
707
|
+
return providerMissReason(error) ?? QUOTE_UNAVAILABLE;
|
|
708
|
+
}
|
|
709
|
+
return QUOTE_UNAVAILABLE;
|
|
710
|
+
}
|
|
711
|
+
|
|
590
712
|
export async function ticker(symbol: string, dependencies: TickerCommandDependencies = {}) {
|
|
591
713
|
const initMarketDataFn = dependencies.initMarketData ?? initMarketData;
|
|
592
714
|
const failCommand = dependencies.fail ?? fail;
|
|
@@ -610,7 +732,10 @@ export async function ticker(symbol: string, dependencies: TickerCommandDependen
|
|
|
610
732
|
} catch (error) {
|
|
611
733
|
// A known exchange the symbol is not listed on: say where it is.
|
|
612
734
|
await failIfNotTraded(listing, { store, dataProvider }, { fail: failCommand });
|
|
613
|
-
|
|
735
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
736
|
+
// A symbol no listing carries is not a failed fetch, and the message already names it.
|
|
737
|
+
if (isNotATickerMessage(reason)) failCommand(reason);
|
|
738
|
+
failCommand(`Failed to fetch data for ${normalized}.`, reason);
|
|
614
739
|
}
|
|
615
740
|
|
|
616
741
|
const hasResearchData = financials && (
|
|
@@ -647,7 +772,7 @@ export async function ticker(symbol: string, dependencies: TickerCommandDependen
|
|
|
647
772
|
}),
|
|
648
773
|
// Outside the US the lookup checks the SEC registrant against the listing's company,
|
|
649
774
|
// and refuses another company's filings.
|
|
650
|
-
shouldFetchSecFilings(tickerFile, resolvedFinancials) && dataProvider.getSecFilings
|
|
775
|
+
shouldFetchSecFilings(requestSymbol, exchange, tickerFile, resolvedFinancials) && dataProvider.getSecFilings
|
|
651
776
|
? dataProvider.getSecFilings(requestSymbol, SEC_FILING_LIMIT, exchange || quote?.exchangeName || "",
|
|
652
777
|
listingName ? { listingName } : undefined)
|
|
653
778
|
: Promise.resolve([]),
|
|
@@ -659,10 +784,11 @@ export async function ticker(symbol: string, dependencies: TickerCommandDependen
|
|
|
659
784
|
|
|
660
785
|
// The quote is the feed in this report; without one, the fundamentals date it.
|
|
661
786
|
const freshness = quote ? quotesFreshness([quote]) : fundamentalsFreshness(resolvedFinancials);
|
|
787
|
+
const quoteNote = quote ? undefined : await quoteUnavailableNote(dataProvider, requestSymbol, exchange);
|
|
662
788
|
if (dependencies.printResult) {
|
|
663
789
|
dependencies.printResult({
|
|
664
790
|
freshness,
|
|
665
|
-
warnings: quote ? undefined : [
|
|
791
|
+
warnings: quote ? undefined : [quoteNote!],
|
|
666
792
|
data: buildTickerStructuredData({
|
|
667
793
|
symbol: normalized,
|
|
668
794
|
listing,
|
|
@@ -685,6 +811,7 @@ export async function ticker(symbol: string, dependencies: TickerCommandDependen
|
|
|
685
811
|
config,
|
|
686
812
|
toBase,
|
|
687
813
|
notes,
|
|
814
|
+
quoteNote,
|
|
688
815
|
recentNews,
|
|
689
816
|
recentSecFilings,
|
|
690
817
|
}));
|