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,4 +1,5 @@
|
|
|
1
1
|
import { apiClient } from "../../api-client";
|
|
2
|
+
import { ApiRequestError } from "../../api-client/errors";
|
|
2
3
|
import type { CliCommandDef } from "../../types/plugin";
|
|
3
4
|
import { withCliServices } from "../context";
|
|
4
5
|
import { formatCompact } from "../../utils/format";
|
|
@@ -10,8 +11,18 @@ import {
|
|
|
10
11
|
type ScreenerCategory,
|
|
11
12
|
} from "../../plugins/builtin/market-movers/screener";
|
|
12
13
|
import { formatMoverPrice, moverReferencePrice } from "../../plugins/builtin/market-movers/model";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
14
|
+
import { EXTENDED_SESSION_LABELS, getQuoteSessionFields, type ExtendedSession } from "../../market-data/market/status";
|
|
15
|
+
import {
|
|
16
|
+
COUNTRY_CYCLE,
|
|
17
|
+
FILTER_CYCLE,
|
|
18
|
+
loadCalendar,
|
|
19
|
+
matchesCountry,
|
|
20
|
+
matchesImpact,
|
|
21
|
+
shortCalendarEnd,
|
|
22
|
+
type CountryFilter,
|
|
23
|
+
type ImpactFilter,
|
|
24
|
+
} from "../../plugins/builtin/econ/calendar-model";
|
|
25
|
+
import { isoDate, rejectExtraArgs, requireArg, requireOneArg, takeFlag, takeOption } from "./command-utils";
|
|
15
26
|
import { buildCorrelationSeries } from "../../plugins/builtin/correlation/matrix/model";
|
|
16
27
|
import { alignDailyCloses, correlateDailyCloses } from "../../plugins/builtin/correlation/compute";
|
|
17
28
|
import { mixedSessionCloseNote } from "../../market-data/market/session-close-note";
|
|
@@ -31,39 +42,89 @@ const BASKET_NAMES = new Map<string, string>([
|
|
|
31
42
|
...SECTOR_COLLECTIONS.flatMap((collection) => collection.items.map((item) => [item.etf, item.name] as const)),
|
|
32
43
|
]);
|
|
33
44
|
// Priced like the MOST pane. Index and yield levels (^GSPC, ^TNX) carry no currency sign.
|
|
34
|
-
|
|
35
|
-
|
|
45
|
+
function formatRowPrice(value: unknown, row: Record<string, unknown>): string {
|
|
46
|
+
return typeof value === "number"
|
|
36
47
|
? formatMoverPrice(
|
|
37
48
|
value,
|
|
38
49
|
typeof row.currency === "string" && !String(row.symbol ?? "").startsWith("^") ? row.currency : "",
|
|
39
50
|
moverReferencePrice(row as Parameters<typeof moverReferencePrice>[0]),
|
|
40
|
-
) : ""
|
|
51
|
+
) : "";
|
|
52
|
+
}
|
|
53
|
+
const PRICE_COLUMN = { key: "price", header: "Last", align: "right" as const, format: formatRowPrice };
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* A pre-market or after-hours print and its move from the regular close, as
|
|
57
|
+
* `quote` gives it, in its own column beside Last and Chg%. Text drops a
|
|
58
|
+
* column no row fills, so a table without an extended print stays as before.
|
|
59
|
+
*/
|
|
60
|
+
function extendedColumn(session: ExtendedSession) {
|
|
61
|
+
return {
|
|
62
|
+
key: session === "PRE" ? "preMarket" : "afterHours",
|
|
63
|
+
header: EXTENDED_SESSION_LABELS[session],
|
|
64
|
+
align: "right" as const,
|
|
65
|
+
value: (row: Record<string, unknown>) => row.extendedSession === session ? row.extendedPrice : null,
|
|
66
|
+
format: (value: unknown, row: Record<string, unknown>) => typeof value === "number"
|
|
67
|
+
? [formatRowPrice(value, row), formatChangePercentCell(row.extendedChangePercent)].join(" ").trim()
|
|
68
|
+
: "",
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const EXTENDED_COLUMNS = [extendedColumn("PRE"), extendedColumn("POST")];
|
|
72
|
+
// A narrow terminal drops these before it cuts the names short.
|
|
73
|
+
const MARKET_CAP_CELL = { key: "marketCap", header: "Mkt Cap", align: "right" as const, optional: true, dropPriority: 1 };
|
|
41
74
|
const MOVER_COLUMNS = [
|
|
42
75
|
{ key: "symbol", header: "Symbol" },
|
|
43
76
|
{ key: "name", header: "Name" },
|
|
44
77
|
PRICE_COLUMN,
|
|
45
78
|
{ key: "changePercent", header: "Chg%", align: "right" as const, format: formatChangePercentCell },
|
|
79
|
+
...EXTENDED_COLUMNS,
|
|
46
80
|
{ key: "volume", header: "Volume", align: "right" as const, format: formatCompactCell },
|
|
47
|
-
{
|
|
81
|
+
{ ...MARKET_CAP_CELL, format: formatCompactCell },
|
|
48
82
|
];
|
|
49
83
|
const START_OPTION = { flags: "--start <yyyy-mm-dd>", description: "First observation date (default 2021-01-01)" };
|
|
50
84
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
85
|
+
const MOVER_LISTS: Record<string, ScreenerCategory | "trending"> = {
|
|
86
|
+
gainers: "day_gainers",
|
|
87
|
+
losers: "day_losers",
|
|
88
|
+
active: "most_actives",
|
|
89
|
+
"most-active": "most_actives",
|
|
90
|
+
trending: "trending",
|
|
91
|
+
};
|
|
92
|
+
const MOVERS_USAGE = "movers [gainers|losers|active|trending]";
|
|
93
|
+
|
|
94
|
+
function screenerCategory(args: readonly string[], ctx: Parameters<CliCommandDef["execute"]>[1]): ScreenerCategory | "trending" {
|
|
95
|
+
rejectExtraArgs(args, 1, { usage: MOVERS_USAGE, takes: "one list" }, ctx);
|
|
96
|
+
const list = args[0]?.toLowerCase() ?? "gainers";
|
|
97
|
+
const category = MOVER_LISTS[list];
|
|
98
|
+
if (!category) ctx.fail(`Unknown list "${args[0]}".`, "Use gainers, losers, active or trending.");
|
|
99
|
+
return category;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** A command that takes no arguments fails on one, rather than answering as if it were not there. */
|
|
103
|
+
function rejectArgs(args: readonly string[], usage: string, ctx: Parameters<CliCommandDef["execute"]>[1], advice?: string): void {
|
|
104
|
+
rejectExtraArgs(args, 0, { usage, takes: "no arguments", advice }, ctx);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** A percent to two decimals, as the table prints it. */
|
|
108
|
+
function roundedPercent(value: number | null): number | null {
|
|
109
|
+
return value == null ? null : Number(value.toFixed(2));
|
|
56
110
|
}
|
|
57
111
|
|
|
58
112
|
function quoteRows(results: Awaited<ReturnType<NonNullable<import("../../types/data-provider").AssetDataProvider["getQuotesBatch"]>>>) {
|
|
59
113
|
return results.map((result) => {
|
|
60
114
|
const quote = result.quote;
|
|
115
|
+
// Last and Chg% are the regular session, as `ticker` reads it; a pre-market or
|
|
116
|
+
// after-hours print is its own column, measured from that session's close.
|
|
117
|
+
const session = getQuoteSessionFields(quote);
|
|
61
118
|
return {
|
|
62
119
|
symbol: result.target.symbol,
|
|
63
120
|
name: quote?.name || BASKET_NAMES.get(result.target.symbol) || "",
|
|
64
|
-
price:
|
|
65
|
-
change:
|
|
66
|
-
changePercent:
|
|
121
|
+
price: session.price,
|
|
122
|
+
change: session.change,
|
|
123
|
+
changePercent: roundedPercent(session.changePercent),
|
|
124
|
+
extendedSession: session.extendedSession,
|
|
125
|
+
extendedPrice: session.extendedPrice,
|
|
126
|
+
extendedChange: session.extendedChange,
|
|
127
|
+
extendedChangePercent: roundedPercent(session.extendedChangePercent),
|
|
67
128
|
currency: quote?.currency ?? "",
|
|
68
129
|
providerId: quote?.providerId ?? "",
|
|
69
130
|
marketCap: quote?.marketCap ?? null,
|
|
@@ -72,7 +133,7 @@ function quoteRows(results: Awaited<ReturnType<NonNullable<import("../../types/d
|
|
|
72
133
|
}
|
|
73
134
|
|
|
74
135
|
async function runMoverCommand(args: string[], ctx: Parameters<CliCommandDef["execute"]>[1]) {
|
|
75
|
-
const category = screenerCategory(args
|
|
136
|
+
const category = screenerCategory(args, ctx);
|
|
76
137
|
const limit = ctx.cliOptions.limit ?? 25;
|
|
77
138
|
if (category === "trending") {
|
|
78
139
|
await withCliServices(ctx, async (services) => {
|
|
@@ -112,7 +173,8 @@ async function runQuoteBasket(symbols: string[], ctx: Parameters<CliCommandDef["
|
|
|
112
173
|
{ key: "name", header: "Name" },
|
|
113
174
|
PRICE_COLUMN,
|
|
114
175
|
{ key: "changePercent", header: "Chg%", align: "right", format: formatChangePercentCell },
|
|
115
|
-
|
|
176
|
+
...EXTENDED_COLUMNS,
|
|
177
|
+
{ ...MARKET_CAP_CELL, value: (row) => row.marketCap == null ? "" : formatCompact(Number(row.marketCap)) },
|
|
116
178
|
],
|
|
117
179
|
});
|
|
118
180
|
});
|
|
@@ -126,16 +188,61 @@ function utcDateTimePart(value: unknown, part: "date" | "time"): string {
|
|
|
126
188
|
return part === "date" ? iso.slice(0, 10) : `${iso.slice(11, 16)} UTC`;
|
|
127
189
|
}
|
|
128
190
|
|
|
191
|
+
const ECON_USAGE = "econ [--country <region>] [--impact <level>] [--from <yyyy-mm-dd>]";
|
|
192
|
+
const DAY_MS = 86_400_000;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* What an empty calendar says. A window that starts after the last day listed
|
|
196
|
+
* says where the listing stops, whatever the filters, rather than nothing.
|
|
197
|
+
*/
|
|
198
|
+
function econEmptyMessage(from: string | null, listedThrough: string | null, stopsShort: boolean): string {
|
|
199
|
+
if (!listedThrough) return "No events listed.";
|
|
200
|
+
if (from != null && from > listedThrough) return `No events listed after ${listedThrough}.`;
|
|
201
|
+
const range = from ? ` from ${from}` : "";
|
|
202
|
+
return stopsShort
|
|
203
|
+
? `No matching events${range}; none listed after ${listedThrough}.`
|
|
204
|
+
: `No matching events${range} through ${listedThrough}.`;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** A `yyyy-mm-dd` option, checked here; null when it was not given. */
|
|
208
|
+
function parseDateOption(value: string | undefined, flag: string, ctx: Parameters<CliCommandDef["execute"]>[1]): string | null {
|
|
209
|
+
if (value == null) return null;
|
|
210
|
+
const date = value.trim();
|
|
211
|
+
const time = /^\d{4}-\d{2}-\d{2}$/.test(date) ? Date.parse(`${date}T00:00:00Z`) : Number.NaN;
|
|
212
|
+
if (!Number.isFinite(time) || new Date(time).toISOString().slice(0, 10) !== date) {
|
|
213
|
+
ctx.fail(`${flag} takes a date as yyyy-mm-dd, got "${value}".`);
|
|
214
|
+
}
|
|
215
|
+
return date;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** One of a filter's values, matched without regard to case; anything else fails with the list. */
|
|
219
|
+
function parseFilter<T extends string>(value: string | undefined, values: readonly T[], label: string, ctx: Parameters<CliCommandDef["execute"]>[1]): T {
|
|
220
|
+
if (value == null) return values[0]!;
|
|
221
|
+
const match = values.find((candidate) => candidate.toLowerCase() === value.trim().toLowerCase());
|
|
222
|
+
if (!match) ctx.fail(`Unknown ${label} "${value}".`, `Use ${values.join(", ")}.`);
|
|
223
|
+
return match;
|
|
224
|
+
}
|
|
225
|
+
|
|
129
226
|
async function runEcon(args: string[], ctx: Parameters<CliCommandDef["execute"]>[1]) {
|
|
130
227
|
const rawArgs = [...args];
|
|
131
|
-
const country = (takeOption(rawArgs, "--country")
|
|
132
|
-
const impact = (takeOption(rawArgs, "--impact")
|
|
133
|
-
|
|
134
|
-
|
|
228
|
+
const country: CountryFilter = parseFilter(takeOption(rawArgs, "--country"), COUNTRY_CYCLE, "country", ctx);
|
|
229
|
+
const impact: ImpactFilter = parseFilter(takeOption(rawArgs, "--impact"), FILTER_CYCLE, "impact", ctx);
|
|
230
|
+
const fromOption = parseDateOption(takeOption(rawArgs, "--from"), "--from", ctx);
|
|
231
|
+
rejectArgs(rawArgs, ECON_USAGE, ctx, "Filter with --country and --impact.");
|
|
232
|
+
await withCliServices(ctx, async () => {
|
|
233
|
+
const { data: events, fetchedAt, stale } = await loadCalendar(ctx.cliOptions.refresh);
|
|
234
|
+
const todayStart = Math.floor(Date.now() / DAY_MS) * DAY_MS;
|
|
235
|
+
// The calendar lists from today (UTC). --from moves the first day; --tail
|
|
236
|
+
// alone keeps the newest events of the whole calendar, the past week's too.
|
|
237
|
+
const from = fromOption ?? (ctx.cliOptions.tail != null ? null : new Date(todayStart).toISOString().slice(0, 10));
|
|
238
|
+
const fromTime = from == null ? Number.NEGATIVE_INFINITY : Date.parse(`${from}T00:00:00Z`);
|
|
239
|
+
const lastEvent = events.reduce<Date | null>((last, event) => (!last || event.date > last ? event.date : last), null);
|
|
240
|
+
const listedThrough = lastEvent ? lastEvent.toISOString().slice(0, 10) : null;
|
|
241
|
+
// A calendar that stops short of a week ahead says so under the table.
|
|
242
|
+
const listedAfter = shortCalendarEnd(events, Math.max(todayStart, fromTime)) ? `No events listed after ${listedThrough}` : null;
|
|
135
243
|
const rows = events
|
|
136
|
-
.filter((event) => matchesCountry(event, country) && matchesImpact(event, impact))
|
|
244
|
+
.filter((event) => event.date.getTime() >= fromTime && matchesCountry(event, country) && matchesImpact(event, impact))
|
|
137
245
|
.sort((left, right) => left.date.getTime() - right.date.getTime())
|
|
138
|
-
.slice(0, ctx.cliOptions.limit ?? 50)
|
|
139
246
|
.map((event) => ({
|
|
140
247
|
date: isoDate(event.date),
|
|
141
248
|
time: event.time,
|
|
@@ -148,9 +255,14 @@ async function runEcon(args: string[], ctx: Parameters<CliCommandDef["execute"]>
|
|
|
148
255
|
}));
|
|
149
256
|
ctx.printResult({
|
|
150
257
|
data: rows,
|
|
151
|
-
metadata: { country, impact },
|
|
152
|
-
|
|
258
|
+
metadata: { country, impact, from, listedThrough },
|
|
259
|
+
// The calendar as read, not its rows: those are scheduled, mostly ahead.
|
|
260
|
+
freshness: rowsFreshness([], { status: "not-a-feed", basis: "calendar", asOf: fetchedAt }, { stale }),
|
|
153
261
|
}, {
|
|
262
|
+
dateKey: "date",
|
|
263
|
+
defaultLimit: 50,
|
|
264
|
+
empty: econEmptyMessage(from, listedThrough, listedAfter != null),
|
|
265
|
+
...(listedAfter ? { footnote: listedAfter } : {}),
|
|
154
266
|
columns: [
|
|
155
267
|
// Text shows both halves of the event timestamp in UTC, never the host's zone; exports keep the source values.
|
|
156
268
|
{ key: "date", header: "Date", format: (value) => utcDateTimePart(value, "date") },
|
|
@@ -166,18 +278,70 @@ async function runEcon(args: string[], ctx: Parameters<CliCommandDef["execute"]>
|
|
|
166
278
|
});
|
|
167
279
|
}
|
|
168
280
|
|
|
281
|
+
const FRED_USAGE = "fred <series-id> [--start <yyyy-mm-dd>] [--sort desc|asc]";
|
|
282
|
+
const FRED_LIST_USAGE = "fred --list [filter]";
|
|
283
|
+
|
|
284
|
+
/** `--start`, checked here: Gloom Cloud cannot read anything but yyyy-mm-dd. */
|
|
285
|
+
function parseStartDate(value: string | undefined, ctx: Parameters<CliCommandDef["execute"]>[1]): string {
|
|
286
|
+
return parseDateOption(value, "--start", ctx) ?? "2021-01-01";
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** Gloom Cloud serves a curated set of FRED series and answers 400 for any other id. */
|
|
290
|
+
function isUnsupportedSeries(error: unknown): boolean {
|
|
291
|
+
if (!(error instanceof ApiRequestError) || error.status !== 400) return false;
|
|
292
|
+
const message = typeof error.details?.message === "string" ? error.details.message : error.message;
|
|
293
|
+
return error.details?.code === "unsupported_series" || /^Unsupported FRED series\b/i.test(message);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async function runFredList(filter: string, ctx: Parameters<CliCommandDef["execute"]>[1]) {
|
|
297
|
+
let catalog;
|
|
298
|
+
try {
|
|
299
|
+
catalog = await apiClient.getCloudFredSeriesCatalog();
|
|
300
|
+
} catch (error) {
|
|
301
|
+
if (error instanceof ApiRequestError && error.status === 404) ctx.fail("The list of supported FRED series is not available yet.");
|
|
302
|
+
throw error;
|
|
303
|
+
}
|
|
304
|
+
const terms = filter.toLowerCase().split(/\s+/).filter(Boolean);
|
|
305
|
+
const rows = catalog.series
|
|
306
|
+
.map((series) => ({ id: series.id, title: series.title?.trim() ?? "", group: series.group?.trim() ?? "" }))
|
|
307
|
+
.filter((series) => {
|
|
308
|
+
const text = `${series.id} ${series.title} ${series.group}`.toLowerCase();
|
|
309
|
+
return terms.every((term) => text.includes(term));
|
|
310
|
+
});
|
|
311
|
+
ctx.printResult({ data: rows, metadata: { filter: filter || null, total: catalog.series.length } }, {
|
|
312
|
+
columns: [
|
|
313
|
+
{ key: "id", header: "ID", shrink: false },
|
|
314
|
+
{ key: "title", header: "Title" },
|
|
315
|
+
{ key: "group", header: "Group" },
|
|
316
|
+
],
|
|
317
|
+
empty: filter ? `No supported FRED series match "${filter}". Run gloomberb fred --list to see them all.` : "No FRED series are listed.",
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
|
|
169
321
|
async function runFred(rawArgs: string[], ctx: Parameters<CliCommandDef["execute"]>[1]) {
|
|
170
322
|
const args = [...rawArgs];
|
|
171
|
-
const
|
|
172
|
-
const
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
323
|
+
const list = takeFlag(args, "--list");
|
|
324
|
+
const start = takeOption(args, "--start");
|
|
325
|
+
const sort = takeOption(args, "--sort");
|
|
326
|
+
if (list) {
|
|
327
|
+
if (start != null || sort != null) ctx.fail("--list takes a filter, not --start or --sort.", `Usage: gloomberb ${FRED_LIST_USAGE}`);
|
|
328
|
+
return runFredList(args.join(" ").trim(), ctx);
|
|
329
|
+
}
|
|
330
|
+
const startDate = parseStartDate(start, ctx);
|
|
331
|
+
const sortOrder = (sort ?? "desc").trim().toLowerCase();
|
|
332
|
+
if (sortOrder !== "asc" && sortOrder !== "desc") ctx.fail(`Unknown sort order "${sort}".`, "Use desc (newest first) or asc.");
|
|
333
|
+
const seriesId = requireOneArg(args, FRED_USAGE, "series", ctx).toUpperCase();
|
|
334
|
+
const data = await apiClient.getCloudFredSeries(seriesId, { startDate, sortOrder }).catch((error: unknown) => {
|
|
335
|
+
if (isUnsupportedSeries(error)) ctx.fail(`Unsupported FRED series ${seriesId}. List supported series with: gloomberb fred --list`);
|
|
336
|
+
throw error;
|
|
337
|
+
});
|
|
338
|
+
const rows = data.observations;
|
|
176
339
|
ctx.printResult({
|
|
177
340
|
data: rows,
|
|
178
341
|
metadata: { info: data.info, seriesId, startDate, sortOrder },
|
|
179
342
|
freshness: rowsFreshness(rows, { source: "FRED", status: "not-a-feed", basis: "published statistics", observedKey: "date", oldest: null }),
|
|
180
343
|
}, {
|
|
344
|
+
dateKey: "date",
|
|
181
345
|
textColumns: [
|
|
182
346
|
{ key: "date", header: "Date" },
|
|
183
347
|
{ key: "value", header: data.info?.units ? `Value (${data.info.units})` : "Value", align: "right" },
|
|
@@ -187,8 +351,10 @@ async function runFred(rawArgs: string[], ctx: Parameters<CliCommandDef["execute
|
|
|
187
351
|
|
|
188
352
|
const YIELD_TENORS: Record<string, string> = { DGS3MO: "3M", DGS2: "2Y", DGS10: "10Y", DGS30: "30Y" };
|
|
189
353
|
|
|
190
|
-
async function runYieldCurve(
|
|
191
|
-
const
|
|
354
|
+
async function runYieldCurve(rawArgs: string[], ctx: Parameters<CliCommandDef["execute"]>[1]) {
|
|
355
|
+
const args = [...rawArgs];
|
|
356
|
+
const startDate = parseStartDate(takeOption(args, "--start"), ctx);
|
|
357
|
+
rejectArgs(args, "yield-curve [--start <yyyy-mm-dd>]", ctx);
|
|
192
358
|
const series = Object.keys(YIELD_TENORS);
|
|
193
359
|
const results = await Promise.all(series.map(async (seriesId) => {
|
|
194
360
|
const data = await apiClient.getCloudFredSeries(seriesId, { startDate, sortOrder: "desc" });
|
|
@@ -217,9 +383,10 @@ async function runYieldCurve(args: string[], ctx: Parameters<CliCommandDef["exec
|
|
|
217
383
|
async function runCorrelation(rawArgs: string[], ctx: Parameters<CliCommandDef["execute"]>[1]) {
|
|
218
384
|
const args = [...rawArgs];
|
|
219
385
|
const exchange = takeOption(args, "--exchange");
|
|
220
|
-
const usage = "
|
|
221
|
-
requireArg(args[0], usage
|
|
222
|
-
requireArg(args[1], usage
|
|
386
|
+
const usage = "correlation <symbol-a> <symbol-b>";
|
|
387
|
+
requireArg(args[0], `Usage: gloomberb ${usage}`, ctx);
|
|
388
|
+
requireArg(args[1], `Usage: gloomberb ${usage}`, ctx);
|
|
389
|
+
rejectExtraArgs(args, 2, { usage, takes: "two symbols", advice: "Run it once per pair." }, ctx);
|
|
223
390
|
await withCliServices(ctx, async (services) => {
|
|
224
391
|
// --exchange is for a symbol that names no exchange of its own.
|
|
225
392
|
const [leftListing, rightListing] = await Promise.all([args[0]!, args[1]!].map((raw) => (
|
|
@@ -274,7 +441,7 @@ export const overviewCliCommands: CliCommandDef[] = [
|
|
|
274
441
|
description: "Show gainers, losers, most active, or trending stocks",
|
|
275
442
|
help: {
|
|
276
443
|
group: CLI_COMMAND_GROUPS.markets,
|
|
277
|
-
usage: [
|
|
444
|
+
usage: [MOVERS_USAGE],
|
|
278
445
|
examples: ["movers", "movers losers --limit 10", "movers trending"],
|
|
279
446
|
},
|
|
280
447
|
execute: runMoverCommand,
|
|
@@ -283,39 +450,53 @@ export const overviewCliCommands: CliCommandDef[] = [
|
|
|
283
450
|
name: "indices",
|
|
284
451
|
description: "Show the major US stock indices",
|
|
285
452
|
help: { group: CLI_COMMAND_GROUPS.markets, usage: ["indices"] },
|
|
286
|
-
execute: (
|
|
453
|
+
execute: (args, ctx) => {
|
|
454
|
+
rejectArgs(args, "indices", ctx);
|
|
455
|
+
return runQuoteBasket([...MARKET_SUMMARY_SYMBOLS], ctx, { group: "indices" });
|
|
456
|
+
},
|
|
287
457
|
},
|
|
288
458
|
{
|
|
289
459
|
name: "sectors",
|
|
290
460
|
description: "Show the SPDR sector ETFs",
|
|
291
461
|
help: { group: CLI_COMMAND_GROUPS.markets, usage: ["sectors"] },
|
|
292
|
-
execute: (
|
|
462
|
+
execute: (args, ctx) => {
|
|
463
|
+
rejectArgs(args, "sectors", ctx);
|
|
464
|
+
return runQuoteBasket(getSectorCollection("sectors").items.map((item) => item.etf), ctx, { group: "sectors" });
|
|
465
|
+
},
|
|
293
466
|
},
|
|
294
467
|
{
|
|
295
468
|
name: "econ",
|
|
296
469
|
description: "List upcoming economic calendar events",
|
|
297
470
|
help: {
|
|
298
471
|
group: CLI_COMMAND_GROUPS.markets,
|
|
299
|
-
usage: [
|
|
472
|
+
usage: [ECON_USAGE],
|
|
300
473
|
options: [
|
|
301
474
|
{ flags: "--country <region>", description: "US, G7, EU, or all (default all)" },
|
|
302
475
|
{ flags: "--impact <level>", description: "high, medium, low, or all (default all)" },
|
|
476
|
+
{ flags: "--from <yyyy-mm-dd>", description: "First day listed (default today, UTC); an earlier day reaches past events" },
|
|
303
477
|
],
|
|
304
|
-
examples: ["econ", "econ --country US --impact high"],
|
|
478
|
+
examples: ["econ", "econ --country US --impact high", "econ --tail 20"],
|
|
305
479
|
},
|
|
306
480
|
execute: runEcon,
|
|
307
481
|
},
|
|
308
482
|
{
|
|
309
483
|
name: "fred",
|
|
310
|
-
description: "Fetch a FRED economic series
|
|
484
|
+
description: "Fetch a FRED economic series, or list the ones served",
|
|
311
485
|
help: {
|
|
312
486
|
group: CLI_COMMAND_GROUPS.markets,
|
|
313
|
-
usage: [
|
|
487
|
+
usage: [FRED_USAGE, FRED_LIST_USAGE],
|
|
314
488
|
options: [
|
|
315
489
|
START_OPTION,
|
|
316
490
|
{ flags: "--sort <order>", description: "desc for newest first (default) or asc" },
|
|
491
|
+
{ flags: "--list", description: "List the series Gloom Cloud serves (ID, title, group); words after it filter the list" },
|
|
317
492
|
],
|
|
318
|
-
|
|
493
|
+
sections: [{
|
|
494
|
+
title: "Series",
|
|
495
|
+
lines: [
|
|
496
|
+
"Gloom Cloud serves a curated set of FRED series and needs no sign-in for them. gloomberb fred --list prints them; any other ID fails with that pointer.",
|
|
497
|
+
],
|
|
498
|
+
}],
|
|
499
|
+
examples: ["fred CPIAUCSL", "fred DGS10 --tail 5", "fred UNRATE --start 2020-01-01 --csv", "fred --list", "fred --list fx"],
|
|
319
500
|
},
|
|
320
501
|
execute: runFred,
|
|
321
502
|
},
|
|
@@ -13,6 +13,7 @@ import { initMarketData, withMarketData } from "../context";
|
|
|
13
13
|
import { fail } from "../errors";
|
|
14
14
|
import type { MarketContext } from "../types";
|
|
15
15
|
import type { CliCommandContext } from "../../types/plugin";
|
|
16
|
+
import { indexRootFor, indexRootTryLine } from "../index-roots";
|
|
16
17
|
|
|
17
18
|
interface SearchCommandDependencies {
|
|
18
19
|
initMarketData?: () => Promise<MarketContext>;
|
|
@@ -52,6 +53,11 @@ export async function searchCandidatesForCli({
|
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
/** "Saved", or the broker a row came from; never the data service's internal id. */
|
|
57
|
+
function searchSourceLabel(candidate: TickerSearchCandidate): string {
|
|
58
|
+
return candidate.kind === "ticker" ? "Saved" : candidate.result?.brokerLabel || "";
|
|
59
|
+
}
|
|
60
|
+
|
|
55
61
|
function resolveSearchName(candidate: TickerSearchCandidate): string {
|
|
56
62
|
return candidate.detail.split(" | ")[0] || candidate.detail || "—";
|
|
57
63
|
}
|
|
@@ -70,14 +76,22 @@ function searchCandidateRows(candidates: TickerSearchCandidate[]) {
|
|
|
70
76
|
|| candidate.result?.brokerContract?.secType
|
|
71
77
|
|| candidate.ticker?.metadata.assetCategory
|
|
72
78
|
|| "",
|
|
73
|
-
source: candidate
|
|
74
|
-
? "Saved"
|
|
75
|
-
: candidate.result?.brokerLabel || candidate.result?.providerId || "Provider",
|
|
79
|
+
source: searchSourceLabel(candidate),
|
|
76
80
|
providerId: candidate.result?.providerId ?? "",
|
|
77
81
|
saved: candidate.kind === "ticker",
|
|
78
82
|
}));
|
|
79
83
|
}
|
|
80
84
|
|
|
85
|
+
/**
|
|
86
|
+
* "^VIX Cboe Volatility Index (try: gloomberb quote ^VIX)" for a bare index root, whose
|
|
87
|
+
* search finds funds named after the index but not the index, unless it does list it.
|
|
88
|
+
*/
|
|
89
|
+
function indexRootNote(query: string, candidates: TickerSearchCandidate[]): string | null {
|
|
90
|
+
const root = indexRootFor(query);
|
|
91
|
+
if (!root || candidates.some((candidate) => candidate.label.toUpperCase() === root.symbol)) return null;
|
|
92
|
+
return indexRootTryLine(root);
|
|
93
|
+
}
|
|
94
|
+
|
|
81
95
|
export function buildSearchReport({
|
|
82
96
|
query,
|
|
83
97
|
candidates,
|
|
@@ -86,6 +100,8 @@ export function buildSearchReport({
|
|
|
86
100
|
candidates: TickerSearchCandidate[];
|
|
87
101
|
}): string {
|
|
88
102
|
const lines = [renderSection(`Search: ${query}`)];
|
|
103
|
+
const indexNote = indexRootNote(query, candidates);
|
|
104
|
+
if (indexNote) lines.push("", indexNote);
|
|
89
105
|
|
|
90
106
|
if (candidates.length === 0) {
|
|
91
107
|
lines.push(cliStyles.muted("No matches found."));
|
|
@@ -93,6 +109,8 @@ export function buildSearchReport({
|
|
|
93
109
|
}
|
|
94
110
|
|
|
95
111
|
const categories = Array.from(new Set(candidates.map((candidate) => candidate.category)));
|
|
112
|
+
// Where a row came from, only when one is saved or from a broker.
|
|
113
|
+
const showSource = candidates.some((candidate) => searchSourceLabel(candidate));
|
|
96
114
|
for (const category of categories) {
|
|
97
115
|
const categoryRows = candidates.filter((candidate) => candidate.category === category);
|
|
98
116
|
lines.push("");
|
|
@@ -103,7 +121,7 @@ export function buildSearchReport({
|
|
|
103
121
|
{ header: "Name" },
|
|
104
122
|
{ header: "Exchange" },
|
|
105
123
|
{ header: "Type" },
|
|
106
|
-
{ header: "Source" },
|
|
124
|
+
...(showSource ? [{ header: "Source" }] : []),
|
|
107
125
|
],
|
|
108
126
|
categoryRows.map((candidate) => [
|
|
109
127
|
candidate.label,
|
|
@@ -117,9 +135,7 @@ export function buildSearchReport({
|
|
|
117
135
|
|| candidate.result?.brokerContract?.secType
|
|
118
136
|
|| candidate.ticker?.metadata.assetCategory
|
|
119
137
|
|| "—",
|
|
120
|
-
candidate
|
|
121
|
-
? "Saved"
|
|
122
|
-
: candidate.result?.brokerLabel || candidate.result?.providerId || "Provider",
|
|
138
|
+
...(showSource ? [searchSourceLabel(candidate) || "—"] : []),
|
|
123
139
|
]),
|
|
124
140
|
));
|
|
125
141
|
}
|
|
@@ -144,7 +160,12 @@ export async function search(query: string, dependencies: SearchCommandDependenc
|
|
|
144
160
|
});
|
|
145
161
|
|
|
146
162
|
if (dependencies.printResult) {
|
|
147
|
-
|
|
163
|
+
const indexNote = indexRootNote(trimmedQuery, candidates);
|
|
164
|
+
dependencies.printResult({
|
|
165
|
+
data: searchCandidateRows(candidates),
|
|
166
|
+
metadata: { query: trimmedQuery },
|
|
167
|
+
warnings: indexNote ? [indexNote] : undefined,
|
|
168
|
+
}, {
|
|
148
169
|
columns: [
|
|
149
170
|
{ key: "category", header: "Category" },
|
|
150
171
|
{ key: "symbol", header: "Symbol" },
|