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
|
@@ -27,7 +27,7 @@ function renderCell(row: ShortVolumeObservation, column: VolumeColumn, _index: n
|
|
|
27
27
|
function VolumeDetail({ row, width, height }: { row: ShortVolumeObservation; width: number; height: number }) {
|
|
28
28
|
const { nativePaneChrome } = useUiCapabilities();
|
|
29
29
|
// The stack title is the date, so the rows start with the figures.
|
|
30
|
-
return <ScrollBox width={width} height={nativePaneChrome ? undefined : height} flexGrow={1} flexBasis={0} minHeight={0} contentOptions={{ paddingX: 1 }}>
|
|
30
|
+
return <ScrollBox scrollY width={width} height={nativePaneChrome ? undefined : height} flexGrow={1} flexBasis={0} minHeight={0} contentOptions={{ paddingX: 1 }}>
|
|
31
31
|
<KeyValueRow labelWidth={DETAIL_LABEL_WIDTH} label="Off-exchange short ratio" value={volumePercent(row.ratioPercent)} />
|
|
32
32
|
<KeyValueRow labelWidth={DETAIL_LABEL_WIDTH} label="Short shares" value={exactQuantity(row.shortVolume)} />
|
|
33
33
|
<KeyValueRow labelWidth={DETAIL_LABEL_WIDTH} label="Exempt shares" value={exactQuantity(row.shortExemptVolume)} detail="included in short shares" />
|
|
@@ -59,7 +59,7 @@ function DayDetail({ symbol, row, recent, width, height }: {
|
|
|
59
59
|
{ id: "ratio", label: "Vs median", value: socialRatio(row.ratio) },
|
|
60
60
|
{ id: "stance", label: "Stance", value: socialStance(row.stance), detail: stanceWord(row.stance) },
|
|
61
61
|
]} />
|
|
62
|
-
<ScrollBox width={width} height={nativePaneChrome ? undefined : Math.max(1, height - 3)} flexGrow={1} flexBasis={0} minHeight={0} contentOptions={{ paddingX: 1 }}>
|
|
62
|
+
<ScrollBox scrollY width={width} height={nativePaneChrome ? undefined : Math.max(1, height - 3)} flexGrow={1} flexBasis={0} minHeight={0} contentOptions={{ paddingX: 1 }}>
|
|
63
63
|
<PaneStatusBody loading={posts.loading && !list.length} error={!list.length ? posts.error : null} subject="top posts"
|
|
64
64
|
empty={!posts.loading && !list.length} emptyTitle="No top posts for this day.">
|
|
65
65
|
<Box flexDirection="column" gap={1} width={lineWidth}>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SupplyChainPayload, SupplyOptions, SupplyRole, SupplyRow } from "../../../api-client/supply-chain";
|
|
2
|
-
import { SERIES_COLORS } from "../../../
|
|
2
|
+
import { SERIES_COLORS } from "../../../theme/series-colors";
|
|
3
3
|
import { revenueAmount } from "../revenue-breakdown/model";
|
|
4
4
|
import { activeRelationship, corroborationLabel, evidenceDate, evidenceLabel, isUnconfirmed, matchesSupplyOptions, trustTier } from "./trust";
|
|
5
5
|
|
|
@@ -8,6 +8,7 @@ import { priceColor } from "../../../theme/colors";
|
|
|
8
8
|
import { useThemeColors } from "../../../theme/theme-context";
|
|
9
9
|
import { Box, Text } from "../../../ui";
|
|
10
10
|
import { nextHeaderSort } from "../../../utils/sort-values";
|
|
11
|
+
import { useMembersMenu } from "../shared/members-menu";
|
|
11
12
|
import { cachedMembers, cachedThemes, loadMembers, loadThemes } from "./client";
|
|
12
13
|
import { aggregateText, coverageWidth, DEFAULT_SORT, matchTheme, memberColumns, memberPrice, percent, sortMembers, sortThemes, themeColumns, type ThemeSort } from "./model";
|
|
13
14
|
|
|
@@ -37,6 +38,8 @@ function Members({ id, width, height, focused }: { id: string; width: number; he
|
|
|
37
38
|
useAutoRefresh(resource.updatedAt, resource.load);
|
|
38
39
|
usePaneRefreshKey(() => void resource.reload(), { focused });
|
|
39
40
|
useSnapshotFooter("themes:members", resource, focused);
|
|
41
|
+
const memberList = useMemo(() => data ? { title: data.theme.name, watchlistName: data.theme.name, members: rows } : null, [data, rows]);
|
|
42
|
+
useMembersMenu("themes:members-menu", memberList);
|
|
40
43
|
const renderCell = useCallback((row: ThemeMember, column: DataTableColumn): DataTableCell => {
|
|
41
44
|
if (column.id === "symbol") return { text: row.symbol, color: colors.textBright };
|
|
42
45
|
if (column.id === "name") return { text: row.name ?? "--", color: colors.text };
|
|
@@ -166,10 +166,14 @@ function aggregateQuarterlyStatements(
|
|
|
166
166
|
}
|
|
167
167
|
const currencies = new Set(statements.map((statement) => statement.currency));
|
|
168
168
|
if (currencies.size > 1) return null;
|
|
169
|
+
// Its counts and EPS are on the quarters' share basis when all four state the same one.
|
|
170
|
+
const shareBases = new Set(statements.map((statement) => statement.shareBasis));
|
|
171
|
+
const shareBasis = shareBases.size === 1 ? [...shareBases][0] : undefined;
|
|
169
172
|
|
|
170
173
|
const aggregate: FinancialTableStatement = {
|
|
171
174
|
date,
|
|
172
175
|
currency: [...currencies][0],
|
|
176
|
+
...(shareBasis ? { shareBasis } : {}),
|
|
173
177
|
aggregation: {
|
|
174
178
|
kind: "trailing-four-quarters",
|
|
175
179
|
periodEnd: statements.at(-1)!.date,
|
|
@@ -107,7 +107,13 @@ const SHARE_COUNT_FIELDS = new Set<keyof FinancialStatement>([
|
|
|
107
107
|
"basicShares", "dilutedShares", "shareIssued", "ordinarySharesNumber", "treasurySharesNumber",
|
|
108
108
|
]);
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
const PER_SHARE_EARNINGS_FIELDS = new Set<keyof FinancialStatement>(["eps", "basicEps"]);
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Currency changes affect monetary comparisons, not counts of reported
|
|
114
|
+
* shares. Counts and EPS compare only on one share basis: receipts against
|
|
115
|
+
* ordinary shares would read as a split.
|
|
116
|
+
*/
|
|
111
117
|
export function canCompareFinancialRow(
|
|
112
118
|
row: FinancialTableRow,
|
|
113
119
|
current: FinancialStatement,
|
|
@@ -116,7 +122,9 @@ export function canCompareFinancialRow(
|
|
|
116
122
|
): boolean {
|
|
117
123
|
if (!previous) return false;
|
|
118
124
|
const key = row.kind === "group" ? row.summaryKey : row.key;
|
|
119
|
-
|
|
125
|
+
const sameShareBasis = current.shareBasis === previous.shareBasis;
|
|
126
|
+
if (key && SHARE_COUNT_FIELDS.has(key)) return sameShareBasis;
|
|
127
|
+
if (key && PER_SHARE_EARNINGS_FIELDS.has(key) && !sameShareBasis) return false;
|
|
120
128
|
const currentCurrency = (current.currency ?? financialCurrency)?.trim();
|
|
121
129
|
const previousCurrency = (previous.currency ?? financialCurrency)?.trim();
|
|
122
130
|
return !!currentCurrency && currentCurrency === previousCurrency;
|
|
@@ -269,6 +277,19 @@ export function financialStatementLimitations(financials: TickerFinancials | nul
|
|
|
269
277
|
return limitations;
|
|
270
278
|
}
|
|
271
279
|
|
|
280
|
+
/** "Ordinary Shares (bn ADRs)": a share-count line whose counts are depositary receipts. */
|
|
281
|
+
export function receiptShareCountLabel(row: Pick<FinancialTableModelRow, "key" | "label" | "unitLabel">): string {
|
|
282
|
+
if (!row.key || !SHARE_COUNT_FIELDS.has(row.key)) return row.unitLabel;
|
|
283
|
+
const unit = row.unitLabel.startsWith(`${row.label} (`) ? row.unitLabel.slice(row.label.length + 2, -1) : "";
|
|
284
|
+
return `${row.label} (${unit ? `${unit} ` : ""}ADRs)`;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** Whether a table row shows share counts or per-share earnings. */
|
|
288
|
+
export function isPerShareFinancialRow(row: Pick<FinancialTableModelRow, "key" | "summaryKey">): boolean {
|
|
289
|
+
const key = row.key ?? row.summaryKey;
|
|
290
|
+
return !!key && (SHARE_COUNT_FIELDS.has(key) || PER_SHARE_EARNINGS_FIELDS.has(key));
|
|
291
|
+
}
|
|
292
|
+
|
|
272
293
|
export function resolveFinancialPeriod(
|
|
273
294
|
requestedPeriod: FinancialPeriod,
|
|
274
295
|
hasAnnualStatements: boolean,
|
|
@@ -495,6 +516,7 @@ interface FinancialTableModelRow {
|
|
|
495
516
|
id: string;
|
|
496
517
|
key?: keyof FinancialStatement;
|
|
497
518
|
summaryKey?: keyof FinancialStatement;
|
|
519
|
+
label: string;
|
|
498
520
|
unitLabel: string;
|
|
499
521
|
depth: number;
|
|
500
522
|
growthDirection: FinancialGrowthDirection;
|
|
@@ -614,6 +636,7 @@ export function buildFinancialTableModel(
|
|
|
614
636
|
id: row.id,
|
|
615
637
|
key: row.kind === "metric" ? row.key : undefined,
|
|
616
638
|
summaryKey: row.kind === "group" ? row.summaryKey : undefined,
|
|
639
|
+
label: row.label,
|
|
617
640
|
unitLabel: row.unitLabel,
|
|
618
641
|
depth: row.depth,
|
|
619
642
|
growthDirection: row.growthDirection,
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { FINANCIAL_VINTAGE_NOTICE } from "../../../utils/financial-statements";
|
|
2
2
|
import { hasValidQuoteObservationTime } from "../../../market-data/quotes/freshness";
|
|
3
|
-
import {
|
|
3
|
+
import { EXTENDED_SESSION_LABELS, getQuoteSessionFields, type ExtendedSession } from "../../../market-data/market/status";
|
|
4
4
|
import type { HeadlessPaneColumn, HeadlessPaneDefinition } from "../../../types/headless";
|
|
5
5
|
import type { TimeRange } from "../../../time-series/range";
|
|
6
6
|
import { formatNumber, formatPercentRaw } from "../../../utils/format";
|
|
7
7
|
import { formatMarketPrice, formatMarketPriceWithCurrency, formatPriceObservation, withCurrencyMinorDigits, type MarketFormatOptions } from "../../../market-data/market/format";
|
|
8
8
|
import { pricePointValues, priceHistoryIntegrityNotice } from "../../../utils/price-history-integrity";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
buildFinancialTableModel, financialStatementCurrency, financialStatementDateNotice, financialStatementLimitations,
|
|
11
|
+
formatFinancialHeader, isPerShareFinancialRow, receiptShareCountLabel,
|
|
12
|
+
} from "./financials/model";
|
|
13
|
+
import { adrRatioText } from "../../../utils/depositary-receipt";
|
|
10
14
|
import { paneSchemas } from "./headless-schema";
|
|
11
15
|
import { loadPeriodEndHistory } from "./financials/period-end-history";
|
|
12
16
|
import {
|
|
@@ -52,8 +56,18 @@ export const financialStatementsHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
|
52
56
|
const statementCurrency = financialStatementCurrency(financials, [
|
|
53
57
|
...financials.annualStatements, ...financials.quarterlyStatements,
|
|
54
58
|
]);
|
|
55
|
-
|
|
59
|
+
// Gloom Cloud states when a period's share counts and EPS are on the receipts.
|
|
60
|
+
const receiptPeriods = table?.statements.filter(({ shareBasis }) => shareBasis === "depositary_receipt").map(({ date }) => date) ?? [];
|
|
61
|
+
const allReceipts = receiptPeriods.length > 0 && receiptPeriods.length === table?.statements.length;
|
|
62
|
+
const shareBases = new Set(table?.statements.map(({ shareBasis }) => shareBasis ?? null));
|
|
63
|
+
const ratio = adrRatioText(financials.fundamentals?.adrRatio ?? financials.quote?.adrRatio);
|
|
64
|
+
const shareBasisNotice = receiptPeriods.length === 0 || !table?.rows.some(isPerShareFinancialRow) ? null
|
|
65
|
+
: allReceipts
|
|
66
|
+
? `Share counts are in ADRs and EPS is per ADR${ratio ? `; ${ratio}` : ""}.`
|
|
67
|
+
: `Share counts are in ADRs and EPS is per ADR for ${receiptPeriods.join(", ")}${ratio ? ` (${ratio})` : ""}; other periods as reported.`;
|
|
68
|
+
const dates = table?.statements.map(({ date, currency, dateSource, providerDate, dateEvidence, availableAt, fieldAvailability, fieldSources, unavailableFields, epsBasis, unavailableEarnings, aggregation, shareBasis }) => ({
|
|
56
69
|
date, currency: currency ?? statementCurrency ?? null,
|
|
70
|
+
shareBasis: shareBasis ?? null,
|
|
57
71
|
availableAt: availableAt ?? null,
|
|
58
72
|
fieldAvailability: fieldAvailability ? { ...fieldAvailability } : null,
|
|
59
73
|
...(fieldSources ? { fieldSources } : {}),
|
|
@@ -68,7 +82,7 @@ export const financialStatementsHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
|
68
82
|
label: formatFinancialHeader(date, [currency ?? statementCurrency, table.unit].filter(Boolean).join(" ") || undefined, dateSource, false, aggregation?.periodEnd).trim(),
|
|
69
83
|
})) ?? [];
|
|
70
84
|
const rows = table?.rows.map((row) => ({
|
|
71
|
-
id: row.id, kind: row.kind, metric: row.unitLabel,
|
|
85
|
+
id: row.id, kind: row.kind, metric: allReceipts ? receiptShareCountLabel(row) : row.unitLabel,
|
|
72
86
|
cells: row.cells.map((cell, index) => ({
|
|
73
87
|
date: dates[index]?.date ?? "", value: cell.value ?? null,
|
|
74
88
|
growth: cell.growth ?? null, formatted: cell.valueText.trim(), growthFormatted: cell.growthText.trim(),
|
|
@@ -92,7 +106,9 @@ export const financialStatementsHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
|
92
106
|
symbol, name: financials.quote?.name ?? symbol, currency: statementCurrency ?? null, unit: table?.unit ?? null, quoteCurrency: financials.quote?.currency ?? null,
|
|
93
107
|
statement: table?.subTab.key ?? options.statement, statementLabel: table?.subTab.name ?? null,
|
|
94
108
|
period: requestedPeriod, growthBasis: requestedPeriod === "quarterly" ? "QoQ" : "YoY", columns: dates,
|
|
95
|
-
|
|
109
|
+
shareBasis: shareBases.size === 1 ? [...shareBases][0] ?? null : null,
|
|
110
|
+
...(receiptPeriods.length > 0 ? { adrRatio: financials.fundamentals?.adrRatio ?? financials.quote?.adrRatio ?? null } : {}),
|
|
111
|
+
notices: rows.length ? [FINANCIAL_VINTAGE_NOTICE, ...(shareBasisNotice ? [shareBasisNotice] : [])] : [],
|
|
96
112
|
limitations: financialStatementLimitations(financials),
|
|
97
113
|
dateProvenance: financialStatementDateNotice(table?.statements ?? []),
|
|
98
114
|
},
|
|
@@ -179,18 +195,34 @@ function quoteAmount(value: unknown, row: Record<string, unknown>, signed = fals
|
|
|
179
195
|
return amount === "—" ? amount : `${signed && value >= 0 ? "+" : ""}${amount}`;
|
|
180
196
|
}
|
|
181
197
|
|
|
198
|
+
function percentCell(value: unknown): string {
|
|
199
|
+
return formatPercentRaw(typeof value === "number" && Number.isFinite(value) ? value : undefined);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const QUOTE_MONITOR_COLUMNS: HeadlessPaneColumn[] = [
|
|
203
|
+
{ key: "symbol", header: "Ticker" },
|
|
204
|
+
{ key: "name", header: "Name" },
|
|
205
|
+
{ key: "price", header: "Last", align: "right", format: (value, row) => quoteAmount(value, row) },
|
|
206
|
+
{ key: "change", header: "Change", align: "right", format: (value, row) => quoteAmount(value, row, true) },
|
|
207
|
+
{ key: "changePercent", header: "Change %", align: "right", format: percentCell },
|
|
208
|
+
];
|
|
209
|
+
|
|
210
|
+
/** The pre-market or after-hours print and its move from the regular close, for the rows that have one. */
|
|
211
|
+
function extendedSessionColumn(session: ExtendedSession): HeadlessPaneColumn {
|
|
212
|
+
return {
|
|
213
|
+
key: "extendedPrice", header: EXTENDED_SESSION_LABELS[session], align: "right",
|
|
214
|
+
format: (value, row) => row.extendedSession === session
|
|
215
|
+
? `${quoteAmount(value, row)} ${percentCell(row.extendedChangePercent)}`
|
|
216
|
+
: "—",
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
182
220
|
export const quoteComparisonHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
183
221
|
...paneSchemas["quote-monitor-pane"],
|
|
184
222
|
shape: "rows",
|
|
185
|
-
description: "Current quotes for one or more tickers: name, last price, change and percent change.",
|
|
223
|
+
description: "Current quotes for one or more tickers: name, the regular session's last price, change and percent change, and any pre-market or after-hours print.",
|
|
186
224
|
describe: ({ symbols }) => `Quote Monitor | ${symbols.join(", ")}`,
|
|
187
|
-
columns:
|
|
188
|
-
{ key: "symbol", header: "Ticker" },
|
|
189
|
-
{ key: "name", header: "Name" },
|
|
190
|
-
{ key: "price", header: "Last", align: "right", format: (value, row) => quoteAmount(value, row) },
|
|
191
|
-
{ key: "change", header: "Change", align: "right", format: (value, row) => quoteAmount(value, row, true) },
|
|
192
|
-
{ key: "changePercent", header: "Change %", align: "right", format: (value) => formatPercentRaw(typeof value === "number" && Number.isFinite(value) ? value : undefined) },
|
|
193
|
-
],
|
|
225
|
+
columns: QUOTE_MONITOR_COLUMNS,
|
|
194
226
|
async load({ symbols }, ctx) {
|
|
195
227
|
const loaded = await loadHeadlessSymbols(symbols, ctx, async (key) => {
|
|
196
228
|
const { symbol, exchange } = await resolveHeadlessInstrument(ctx, key);
|
|
@@ -199,19 +231,25 @@ export const quoteComparisonHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
|
199
231
|
if (!hasValidQuoteObservationTime(quote)) throw new Error(`Quote observation time is unavailable for ${key}`);
|
|
200
232
|
return quote;
|
|
201
233
|
});
|
|
234
|
+
const rows = loaded.entries.map(({ symbol, data: quote }) => {
|
|
235
|
+
// As the pane's cards show them: the regular session, then any extended print from its close.
|
|
236
|
+
const { price, change, changePercent, ...extended } = getQuoteSessionFields(quote);
|
|
237
|
+
return {
|
|
238
|
+
symbol, name: quote.name ?? "", price, currency: quote.currency,
|
|
239
|
+
...(quote.instrumentType ? { instrumentType: quote.instrumentType } : {}),
|
|
240
|
+
...(quote.priceBasis ? { priceBasis: quote.priceBasis } : {}),
|
|
241
|
+
change, changePercent, ...extended,
|
|
242
|
+
marketCap: quote.marketCap ?? null, updatedAt: quote.lastUpdated,
|
|
243
|
+
...quoteFreshnessFields(quote),
|
|
244
|
+
};
|
|
245
|
+
});
|
|
246
|
+
// An extended column only when a row has a print for it, so a closed board stays as narrow as before.
|
|
247
|
+
const extendedColumns = (["PRE", "POST"] as const)
|
|
248
|
+
.filter((session) => rows.some((row) => row.extendedSession === session))
|
|
249
|
+
.map(extendedSessionColumn);
|
|
202
250
|
return {
|
|
203
|
-
rows
|
|
204
|
-
|
|
205
|
-
const display = getActiveQuoteDisplay(quote)!;
|
|
206
|
-
return {
|
|
207
|
-
symbol, name: quote.name ?? "", price: display.price, currency: quote.currency,
|
|
208
|
-
...(quote.instrumentType ? { instrumentType: quote.instrumentType } : {}),
|
|
209
|
-
...(quote.priceBasis ? { priceBasis: quote.priceBasis } : {}),
|
|
210
|
-
change: display.change, changePercent: display.changePercent,
|
|
211
|
-
marketCap: quote.marketCap ?? null, updatedAt: quote.lastUpdated,
|
|
212
|
-
...quoteFreshnessFields(quote),
|
|
213
|
-
};
|
|
214
|
-
}),
|
|
251
|
+
rows,
|
|
252
|
+
...(extendedColumns.length > 0 ? { columns: [...QUOTE_MONITOR_COLUMNS, ...extendedColumns] } : {}),
|
|
215
253
|
unavailableSymbols: loaded.unavailableSymbols, errors: loaded.errors,
|
|
216
254
|
};
|
|
217
255
|
},
|
|
@@ -22,6 +22,7 @@ import type { OverviewFunctionLink, PositionTableRow, StatField } from "./types"
|
|
|
22
22
|
import { getPortfolioPositionMetrics, getPortfolioQuoteDisplay, resolvePortfolioMarketValue, resolvePortfolioPositionPnl, portfolioPnlPercent, signedPositionDirection } from "../../portfolio-list/position-metrics";
|
|
23
23
|
import { liveDividendYield, liveForwardPE, liveMarketCapitalization, liveTrailingPE } from "../../portfolio-list/live-valuation";
|
|
24
24
|
import { formatReportedMoney } from "../../../../utils/reported-money";
|
|
25
|
+
import { fundamentalsCurrency, reportedEnterpriseValue } from "../../../../utils/fundamentals";
|
|
25
26
|
import { formatShortDate } from "../../../../utils/datetime-format";
|
|
26
27
|
import { safeExternalUrl } from "../../../../utils/external-url";
|
|
27
28
|
|
|
@@ -68,6 +69,7 @@ function compactPositionAccount(position: TickerPosition): string {
|
|
|
68
69
|
export function buildOverviewStats({
|
|
69
70
|
quote,
|
|
70
71
|
fundamentals,
|
|
72
|
+
financialCurrency,
|
|
71
73
|
quoteCurrency,
|
|
72
74
|
baseCurrency,
|
|
73
75
|
marketCapExchangeRates = new Map(),
|
|
@@ -77,18 +79,20 @@ export function buildOverviewStats({
|
|
|
77
79
|
}: {
|
|
78
80
|
quote: Quote | undefined;
|
|
79
81
|
fundamentals: TickerFinancials["fundamentals"] | undefined;
|
|
82
|
+
/** The currency the statements report in, for fundamentals that declare none. */
|
|
83
|
+
financialCurrency?: TickerFinancials["financialCurrency"];
|
|
80
84
|
quoteCurrency: string;
|
|
81
85
|
baseCurrency: string;
|
|
82
86
|
toBase: CurrencyConverter;
|
|
83
87
|
marketCapExchangeRates?: ReadonlyMap<string, number>;
|
|
84
88
|
nextEarnings?: NextEarnings;
|
|
85
|
-
/** The
|
|
89
|
+
/** The share count is in depositary receipts, not ordinary shares. */
|
|
86
90
|
depositaryReceipt?: boolean;
|
|
87
91
|
/** The listing's calendar day, YYYY-MM-DD; dates before it are left out. */
|
|
88
92
|
today?: string;
|
|
89
93
|
}): StatField[] {
|
|
90
94
|
const stats: StatField[] = [];
|
|
91
|
-
const money = (value: number, perShare = false) => formatReportedMoney(value, fundamentals
|
|
95
|
+
const money = (value: number, perShare = false) => formatReportedMoney(value, fundamentalsCurrency({ fundamentals, financialCurrency }), perShare);
|
|
92
96
|
|
|
93
97
|
if (quote?.volume != null) {
|
|
94
98
|
// Live figures keep their decimals (12.30M, not 12.3M) so the digits hold still.
|
|
@@ -178,10 +182,11 @@ export function buildOverviewStats({
|
|
|
178
182
|
valueColor: priceColor(fundamentals.revenueGrowth),
|
|
179
183
|
});
|
|
180
184
|
}
|
|
185
|
+
const enterpriseValue = reportedEnterpriseValue(fundamentals);
|
|
181
186
|
if (fundamentals?.unavailableFields?.includes("enterpriseValue")) {
|
|
182
187
|
stats.push({ label: "EV", value: "—" });
|
|
183
|
-
} else if (
|
|
184
|
-
stats.push({ label: "EV", value: formatCompactCurrency(
|
|
188
|
+
} else if (enterpriseValue != null) {
|
|
189
|
+
stats.push({ label: "EV", value: formatCompactCurrency(enterpriseValue, quoteCurrency) });
|
|
185
190
|
}
|
|
186
191
|
if (finite(fundamentals?.beta)) {
|
|
187
192
|
stats.push({ label: "Beta", value: formatNumber(fundamentals.beta, 2), link: RELATIONSHIP_GRAPH });
|
|
@@ -26,7 +26,7 @@ import { Box, ScrollBox, Text, useUiCapabilities } from "../../../ui";
|
|
|
26
26
|
import { publicTickerKey, resolveExchangeTimeZone } from "../../../utils/exchanges";
|
|
27
27
|
import { convertCurrency, displayWidth, formatPercentRaw, truncateToDisplayWidth } from "../../../utils/format";
|
|
28
28
|
import { zonedDateKey } from "../../../utils/zoned-date-time";
|
|
29
|
-
import {
|
|
29
|
+
import { sharesOutstandingInReceipts } from "../../../utils/depositary-receipt";
|
|
30
30
|
import {
|
|
31
31
|
CompactRangeBar,
|
|
32
32
|
FundamentalsGrid,
|
|
@@ -189,12 +189,13 @@ function ResolvedOverviewTab({ width, focused = false, ticker, financials, onOpe
|
|
|
189
189
|
const stats = buildOverviewStats({
|
|
190
190
|
quote,
|
|
191
191
|
fundamentals,
|
|
192
|
+
financialCurrency: financials?.financialCurrency,
|
|
192
193
|
quoteCurrency,
|
|
193
194
|
baseCurrency,
|
|
194
195
|
toBase,
|
|
195
196
|
marketCapExchangeRates: exchangeRates,
|
|
196
197
|
nextEarnings: financials?.nextEarnings,
|
|
197
|
-
depositaryReceipt:
|
|
198
|
+
depositaryReceipt: sharesOutstandingInReceipts(quote, fundamentals, description),
|
|
198
199
|
// Report and ex-dividend dates are the listing's calendar days.
|
|
199
200
|
today: zonedDateKey(Date.now(), chartTimeZone ?? "America/New_York"),
|
|
200
201
|
});
|
|
@@ -256,11 +256,10 @@ export function TickerResearchPane({ focused, width, height }: PaneProps) {
|
|
|
256
256
|
: null;
|
|
257
257
|
usePaneMenuItems("ticker-research:company-research", () => {
|
|
258
258
|
if (!companySymbol || !dialog) return null;
|
|
259
|
-
const choices = COMPANY_RESEARCH.filter((item) =>
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
});
|
|
259
|
+
const choices = COMPANY_RESEARCH.filter((item) => (
|
|
260
|
+
!registry
|
|
261
|
+
|| (registry.paneTemplates?.has(item.id) && !registry.getDisabledPaneTemplateOwner?.(item.id, disabledPlugins))
|
|
262
|
+
));
|
|
264
263
|
if (!choices.length) return null;
|
|
265
264
|
return [{ id: "company-research", label: t("Company Research…"), onSelect: () => {
|
|
266
265
|
void dialog.prompt<string>({
|
|
@@ -8,9 +8,15 @@ import { resolveEntryData } from "../../../../market-data/selectors";
|
|
|
8
8
|
import { useDoubleClickActivation } from "../../../../components/use-double-click-activation";
|
|
9
9
|
import { FigureText } from "../../../../components/ui/figure";
|
|
10
10
|
import { colors, priceColor } from "../../../../theme/colors";
|
|
11
|
-
import { formatPercentRaw } from "../../../../utils/format";
|
|
11
|
+
import { displayWidth, formatPercentRaw } from "../../../../utils/format";
|
|
12
12
|
import { formatMarketPriceWithCurrency, formatSignedMarketPrice, liveQuoteFormatOptions } from "../../../../market-data/market/format";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
getCompletedRegularSessionDisplay,
|
|
15
|
+
getExtendedSessionDisplay,
|
|
16
|
+
getRegularSessionDisplay,
|
|
17
|
+
type ExtendedSessionDisplay,
|
|
18
|
+
} from "../../../../market-data/market/status";
|
|
19
|
+
import { t } from "../../../../i18n";
|
|
14
20
|
import { isQuoteStaleForCurrentSession } from "../../../../market-data/quotes/freshness";
|
|
15
21
|
import { formatQuoteNavAsOf } from "../../../../market-data/quotes/time";
|
|
16
22
|
import { useQuoteFlashDirection } from "../../../../components/quote-flash";
|
|
@@ -28,6 +34,52 @@ function quoteTrend(value: number | null | undefined): PriceSparklineTrend {
|
|
|
28
34
|
return value > 0 ? "positive" : "negative";
|
|
29
35
|
}
|
|
30
36
|
|
|
37
|
+
/** Desktop body text is 12px in the card's monospace face, 0.6 of its size wide. */
|
|
38
|
+
const DESKTOP_DETAIL_CHAR_PX = 12 * 0.6;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The extended print's line, "After-Hours $336.08 -0.17%": the full label
|
|
42
|
+
* where the room allows, else "AH" or "PM" as the heat map marks them, and
|
|
43
|
+
* at the narrowest the mark and the move without the price.
|
|
44
|
+
*/
|
|
45
|
+
function extendedLineParts(
|
|
46
|
+
extended: ExtendedSessionDisplay,
|
|
47
|
+
priceText: string,
|
|
48
|
+
fits: (text: string) => boolean,
|
|
49
|
+
): { label: string; figures: string } | null {
|
|
50
|
+
const pre = extended.session === "PRE";
|
|
51
|
+
const percent = formatPercentRaw(extended.changePercent);
|
|
52
|
+
const candidates = [
|
|
53
|
+
{ label: t(pre ? "Pre-Market" : "After-Hours"), figures: `${priceText} ${percent}` },
|
|
54
|
+
{ label: pre ? "PM" : "AH", figures: `${priceText} ${percent}` },
|
|
55
|
+
{ label: pre ? "PM" : "AH", figures: percent },
|
|
56
|
+
];
|
|
57
|
+
return candidates.find(({ label, figures }) => fits(`${label} ${figures}`)) ?? null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const DESKTOP_DETAIL_TEXT_STYLE = { fontSize: "12px", lineHeight: "14px", whiteSpace: "nowrap" };
|
|
61
|
+
|
|
62
|
+
function ExtendedSessionLine({
|
|
63
|
+
parts,
|
|
64
|
+
color,
|
|
65
|
+
dim,
|
|
66
|
+
desktopStyle,
|
|
67
|
+
}: {
|
|
68
|
+
parts: { label: string; figures: string };
|
|
69
|
+
color: string;
|
|
70
|
+
dim: boolean;
|
|
71
|
+
/** Placement on the desktop card's grid; the terminal gives the line one row. */
|
|
72
|
+
desktopStyle?: Record<string, string | number | undefined>;
|
|
73
|
+
}) {
|
|
74
|
+
const textStyle = desktopStyle ? DESKTOP_DETAIL_TEXT_STYLE : undefined;
|
|
75
|
+
return (
|
|
76
|
+
<Box flexDirection="row" gap={1} height={desktopStyle ? undefined : 1} overflow="hidden" style={desktopStyle}>
|
|
77
|
+
<Text fg={colors.textDim} style={textStyle}>{parts.label}</Text>
|
|
78
|
+
<Text fg={color} attributes={dim ? TextAttributes.DIM : TextAttributes.NONE} style={textStyle}>{parts.figures}</Text>
|
|
79
|
+
</Box>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
31
83
|
/** A mistyped ticker and a broken provider are not the same problem. */
|
|
32
84
|
const UNKNOWN_SYMBOL_REASONS = new Set(["NOT_FOUND", "BAD_MAPPING"]);
|
|
33
85
|
|
|
@@ -83,7 +135,7 @@ export function QuoteMonitorCard({
|
|
|
83
135
|
onSelect?: (symbol: string) => void;
|
|
84
136
|
onOpen: (symbol: string) => void;
|
|
85
137
|
}) {
|
|
86
|
-
const { nativePaneChrome } = useUiCapabilities();
|
|
138
|
+
const { nativePaneChrome, cellWidthPx = 8 } = useUiCapabilities();
|
|
87
139
|
const quote = resolveEntryData(quoteEntry) ?? cachedFinancials?.quote;
|
|
88
140
|
const queriedPriceHistory = resolveEntryData(chartEntry);
|
|
89
141
|
const barHistory = queriedPriceHistory && queriedPriceHistory.length >= 2
|
|
@@ -98,12 +150,17 @@ export function QuoteMonitorCard({
|
|
|
98
150
|
[quote],
|
|
99
151
|
);
|
|
100
152
|
const flashDirection = useQuoteFlashDirection(flashFinancials, valueFlashingEnabled);
|
|
101
|
-
|
|
153
|
+
// The headline is the regular session, which holds at its close; a pre-market or
|
|
154
|
+
// after-hours print is its own line, measured from that close, as on the Overview.
|
|
155
|
+
const display = getRegularSessionDisplay(quote);
|
|
156
|
+
const extended = getExtendedSessionDisplay(quote);
|
|
157
|
+
// Once the close is in, a tick moves only the extended print, so only that line flashes.
|
|
158
|
+
const headlineHolds = getCompletedRegularSessionDisplay(quote) != null;
|
|
102
159
|
const quoteStatus = resolveQuoteStatus(quoteEntry, symbol, quote);
|
|
103
160
|
const quoteFailed = quoteStatus.failed && !!display;
|
|
104
161
|
const navAsOf = formatQuoteNavAsOf(quote);
|
|
105
162
|
const changeColor = quoteFailed ? colors.textDim : priceColor(display?.change ?? 0);
|
|
106
|
-
const flashing = !!flashDirection;
|
|
163
|
+
const flashing = !!flashDirection && !headlineHolds;
|
|
107
164
|
const currency = quote?.currency || ticker?.metadata.currency || "USD";
|
|
108
165
|
const stacked = width < 31;
|
|
109
166
|
const compactQuoteFailure = quoteFailed && stacked && height <= 3;
|
|
@@ -115,6 +172,16 @@ export function QuoteMonitorCard({
|
|
|
115
172
|
const changeValueText = display ? formatSignedMarketPrice(display.change, priceOptions) : "";
|
|
116
173
|
const priceColumnWidth = Math.max(priceText.length, changePercentText.length + changeValueText.length + 1);
|
|
117
174
|
const nameMaxWidth = Math.max(10, width - priceColumnWidth - (nativePaneChrome ? 5 : 3));
|
|
175
|
+
// The terminal sets the line beside the change, under the symbol (or after it in a
|
|
176
|
+
// stacked card); the desktop gives it a row of its own under the name.
|
|
177
|
+
const extendedRoom = nativePaneChrome
|
|
178
|
+
? (width * cellWidthPx - 24) / DESKTOP_DETAIL_CHAR_PX
|
|
179
|
+
: stacked ? width - 3 - displayWidth(symbol) : width - 3 - priceColumnWidth;
|
|
180
|
+
const extendedParts = display && extended
|
|
181
|
+
? extendedLineParts(extended, formatMarketPriceWithCurrency(extended.price, currency, priceOptions), (text) => displayWidth(text) <= extendedRoom)
|
|
182
|
+
: null;
|
|
183
|
+
const extendedColor = quoteFailed ? colors.textDim : priceColor(extended?.change ?? 0);
|
|
184
|
+
const extendedDim = !!flashDirection && headlineHolds;
|
|
118
185
|
const sparklineRange = resolvePriceSparklineRange(priceHistory, chartPeriod);
|
|
119
186
|
// A price in 32nds already has a hyphen (104-16½), so its range reads "to".
|
|
120
187
|
const rangeSeparator = priceOptions.priceBasis === "thirty-seconds" ? " to " : "-";
|
|
@@ -203,7 +270,7 @@ export function QuoteMonitorCard({
|
|
|
203
270
|
minWidth={0}
|
|
204
271
|
style={{
|
|
205
272
|
gridColumn: "1",
|
|
206
|
-
gridRow: "1 / span 2",
|
|
273
|
+
gridRow: extendedParts ? "1" : "1 / span 2",
|
|
207
274
|
minWidth: 0,
|
|
208
275
|
overflow: "hidden",
|
|
209
276
|
}}
|
|
@@ -259,6 +326,25 @@ export function QuoteMonitorCard({
|
|
|
259
326
|
</Box>
|
|
260
327
|
</Box>
|
|
261
328
|
|
|
329
|
+
{extendedParts && (
|
|
330
|
+
<ExtendedSessionLine
|
|
331
|
+
parts={extendedParts}
|
|
332
|
+
color={extendedColor}
|
|
333
|
+
dim={extendedDim}
|
|
334
|
+
desktopStyle={{
|
|
335
|
+
gridColumn: "1 / -1",
|
|
336
|
+
gridRow: "2",
|
|
337
|
+
justifySelf: "start",
|
|
338
|
+
alignSelf: "start",
|
|
339
|
+
maxWidth: "100%",
|
|
340
|
+
marginTop: 2,
|
|
341
|
+
backgroundColor: colors.bg,
|
|
342
|
+
boxShadow: `0 0 0 2px ${colors.bg}`,
|
|
343
|
+
paddingRight: 2,
|
|
344
|
+
}}
|
|
345
|
+
/>
|
|
346
|
+
)}
|
|
347
|
+
|
|
262
348
|
{perpetuals && <Box style={{ gridColumn: "1 / -1", gridRow: "4", alignSelf: "end" }}>{perpetuals}</Box>}
|
|
263
349
|
{rangeLabel && (
|
|
264
350
|
<Text
|
|
@@ -289,6 +375,7 @@ export function QuoteMonitorCard({
|
|
|
289
375
|
{symbol}
|
|
290
376
|
</Text>
|
|
291
377
|
{compactNavAsOf && <Text fg={colors.textDim}>{navAsOf}</Text>}
|
|
378
|
+
{extendedParts && <ExtendedSessionLine parts={extendedParts} color={extendedColor} dim={extendedDim} />}
|
|
292
379
|
</Box>
|
|
293
380
|
<Box flexDirection="column">
|
|
294
381
|
<FigureText fg={changeColor} dim={flashing} style={figureHalo}>
|
|
@@ -311,6 +398,7 @@ export function QuoteMonitorCard({
|
|
|
311
398
|
<Text attributes={TextAttributes.BOLD} fg={symbolFg} bg={symbolBg} style={desktopSymbolStyle}>
|
|
312
399
|
{symbol}
|
|
313
400
|
</Text>
|
|
401
|
+
{extendedParts && <ExtendedSessionLine parts={extendedParts} color={extendedColor} dim={extendedDim} />}
|
|
314
402
|
{nativePaneChrome && ticker?.metadata.name && width >= 36 && (
|
|
315
403
|
<Text
|
|
316
404
|
fg={colors.textDim}
|
|
@@ -6,8 +6,11 @@ import type { TreasuryAuction } from "./types";
|
|
|
6
6
|
|
|
7
7
|
const CACHE_KIND = "treasury-auctions";
|
|
8
8
|
const CACHE_SOURCE = "treasury-fiscal-data";
|
|
9
|
-
/**
|
|
10
|
-
|
|
9
|
+
/**
|
|
10
|
+
* 3: every reported page was validated before this board was cached.
|
|
11
|
+
* 4: boards carry direct takedown and bill discount rates, which a v3 board lacks.
|
|
12
|
+
*/
|
|
13
|
+
const CACHE_SCHEMA_VERSION = 4;
|
|
11
14
|
export const TREASURY_FISCAL_DATA_CONNECTION_ID = "treasury-fiscal-data";
|
|
12
15
|
/**
|
|
13
16
|
* Refresh the auction board hourly; the week-long expiry keeps an offline
|
|
@@ -19,18 +19,27 @@ const FIELDS = [
|
|
|
19
19
|
"bid_to_cover_ratio",
|
|
20
20
|
"comp_accepted",
|
|
21
21
|
"indirect_bidder_accepted",
|
|
22
|
+
"direct_bidder_accepted",
|
|
22
23
|
"primary_dealer_accepted",
|
|
23
24
|
"total_accepted",
|
|
24
25
|
"offering_amt",
|
|
25
26
|
"inflation_index_security",
|
|
26
27
|
"floating_rate",
|
|
27
28
|
"high_discnt_margin",
|
|
29
|
+
"high_discnt_rate",
|
|
30
|
+
"avg_med_discnt_rate",
|
|
28
31
|
].join(",");
|
|
29
32
|
|
|
30
33
|
export const AUCTION_HISTORY_DAYS = 120;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
/**
|
|
35
|
+
* The feed holds roughly 400 auctions a year, so the default 120 days is one
|
|
36
|
+
* page and the longest window (10 years, ~4,000 auctions) is four. One large
|
|
37
|
+
* page costs about the same as a small one, so fewer, larger pages keep a
|
|
38
|
+
* ten-year walk to a few seconds inside the throttle.
|
|
39
|
+
*/
|
|
40
|
+
const AUCTION_PAGE_SIZE = 1000;
|
|
41
|
+
/** Three times the longest window's pages; the bound only exists so bad metadata cannot loop. */
|
|
42
|
+
export const AUCTION_MAX_PAGES = 12;
|
|
34
43
|
|
|
35
44
|
const TREASURY_FETCH = createThrottledFetch({
|
|
36
45
|
requestsPerMinute: 20,
|
|
@@ -49,8 +58,10 @@ export function buildAuctionsUrl(sinceDays: number, now = Date.now(), page = 1):
|
|
|
49
58
|
const params = [
|
|
50
59
|
`fields=${FIELDS}`,
|
|
51
60
|
`filter=auction_date:gte:${isoDateDaysAgo(sinceDays, now)}`,
|
|
52
|
-
|
|
53
|
-
|
|
61
|
+
// The CUSIP breaks ties inside a date, so a page boundary that falls in the
|
|
62
|
+
// middle of a day's auctions cannot repeat or skip one on the next page.
|
|
63
|
+
"sort=-auction_date,-cusip",
|
|
64
|
+
`page%5Bsize%5D=${AUCTION_PAGE_SIZE}`,
|
|
54
65
|
`page%5Bnumber%5D=${page}`,
|
|
55
66
|
];
|
|
56
67
|
return `${BASE_URL}?${params.join("&")}`;
|
|
@@ -95,6 +106,8 @@ export function normalizeAuction(raw: unknown): TreasuryAuction | null {
|
|
|
95
106
|
securityTerm: securityTerm || "—",
|
|
96
107
|
auctionDate,
|
|
97
108
|
highInvestmentRate: toNumber(record.high_investment_rate),
|
|
109
|
+
highDiscountRate: toNumber(record.high_discnt_rate),
|
|
110
|
+
avgMedDiscountRate: toNumber(record.avg_med_discnt_rate),
|
|
98
111
|
highDiscountMargin: toNumber(record.high_discnt_margin),
|
|
99
112
|
highYield: toNumber(record.high_yield),
|
|
100
113
|
avgMedYield: toNumber(record.avg_med_yield),
|
|
@@ -104,6 +117,7 @@ export function normalizeAuction(raw: unknown): TreasuryAuction | null {
|
|
|
104
117
|
bidToCoverRatio: toNumber(record.bid_to_cover_ratio),
|
|
105
118
|
competitiveAccepted: toNumber(record.comp_accepted),
|
|
106
119
|
indirectAccepted: toNumber(record.indirect_bidder_accepted),
|
|
120
|
+
directAccepted: toNumber(record.direct_bidder_accepted),
|
|
107
121
|
primaryDealerAccepted: toNumber(record.primary_dealer_accepted),
|
|
108
122
|
totalAccepted: toNumber(record.total_accepted),
|
|
109
123
|
offeringAmount: toNumber(record.offering_amt),
|
|
@@ -136,15 +150,15 @@ export async function fetchAuctionPages(
|
|
|
136
150
|
const seen = new Set<string>();
|
|
137
151
|
let pages = 1;
|
|
138
152
|
|
|
139
|
-
for (let page = 1; page <= Math.min(pages,
|
|
153
|
+
for (let page = 1; page <= Math.min(pages, AUCTION_MAX_PAGES); page += 1) {
|
|
140
154
|
const body = await loadPage(page);
|
|
141
155
|
const declaredPages = totalPages(body, page);
|
|
142
156
|
if (page === 1) pages = declaredPages;
|
|
143
157
|
else if (declaredPages !== pages) {
|
|
144
158
|
throw new Error(`Treasury auction page count changed on page ${page}`);
|
|
145
159
|
}
|
|
146
|
-
if (pages >
|
|
147
|
-
throw new Error(`Treasury auction history exceeds the ${
|
|
160
|
+
if (pages > AUCTION_MAX_PAGES) {
|
|
161
|
+
throw new Error(`Treasury auction history exceeds the ${AUCTION_MAX_PAGES}-page limit`);
|
|
148
162
|
}
|
|
149
163
|
const data = (body as { data?: unknown } | null)?.data;
|
|
150
164
|
if (!Array.isArray(data)) {
|