gloomberb 0.16.3 → 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/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/commands/crypto-hints.ts +12 -4
- package/src/cli/commands/market.ts +359 -99
- package/src/cli/commands/options-chain.ts +172 -0
- package/src/cli/commands/options-leaps.ts +422 -0
- package/src/cli/commands/overview.ts +164 -26
- 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 +62 -30
- package/src/cli/desktop-pane-shot.ts +97 -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 +14 -1
- package/src/cli/index-roots.ts +51 -0
- package/src/cli/index.ts +9 -6
- package/src/cli/listing-arg.ts +211 -3
- package/src/cli/not-a-ticker.ts +37 -0
- package/src/cli/options.ts +50 -6
- package/src/cli/pane-functions/capabilities.ts +8 -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 +21 -13
- package/src/cli/pane-functions/freshness.ts +205 -26
- package/src/cli/pane-functions/function-help.ts +67 -22
- package/src/cli/pane-functions/headless.ts +5 -4
- package/src/cli/pane-functions/index.ts +3 -0
- 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 +4 -0
- package/src/cli/pane-functions/resolver.ts +4 -6
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +105 -23
- package/src/cli/registry.ts +2 -1
- package/src/cli/result.ts +50 -13
- 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/view.tsx +28 -9
- 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 +1 -1
- package/src/components/layout/shell/drag/index.ts +4 -0
- package/src/components/layout/shell/drag/live.ts +76 -5
- package/src/components/layout/shell/drag/runtime.ts +8 -8
- package/src/components/layout/shell/index.tsx +47 -6
- package/src/components/layout/shell/layout-state.ts +5 -11
- package/src/components/layout/shell/menu.ts +28 -1
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +51 -10
- 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/visible-layout.ts +44 -1
- 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/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 +118 -18
- 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/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/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/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/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-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/headless.ts +6 -1
- package/src/plugins/builtin/holders/pane.tsx +3 -0
- 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 +109 -39
- 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/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/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/cli/portfolio-command.ts +71 -36
- package/src/plugins/builtin/portfolio-list/cli/render.ts +87 -18
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +2 -16
- package/src/plugins/builtin/portfolio-list/headless.ts +38 -7
- 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/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/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 +4 -4
- 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/supply-chain/model.ts +1 -1
- package/src/plugins/builtin/ticker-detail/headless.ts +43 -21
- 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/geo-series.ts +1 -1
- package/src/plugins/builtin/world-venue-map/index.ts +1 -1
- 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/dom/desktop/icons.tsx +14 -0
- package/src/renderers/dom/desktop/query-bar.tsx +59 -32
- package/src/renderers/dom/host/box.tsx +1 -1
- package/src/renderers/dom/host/drag-shield.ts +17 -6
- package/src/renderers/dom/host/live-frame.ts +10 -2
- package/src/renderers/dom/input-host.tsx +6 -1
- package/src/renderers/dom/styles.css +13 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +5 -1
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +12 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -1
- package/src/renderers/electrobun/shared/protocol.ts +2 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +101 -5
- package/src/renderers/electrobun/view/main.tsx +4 -1
- package/src/renderers/opentui/input-host.tsx +6 -1
- package/src/renderers/opentui/start.tsx +9 -0
- package/src/shares/portable-layout.ts +16 -6
- package/src/sources/gloomberb-cloud/index.ts +19 -10
- package/src/sources/gloomberb-cloud/normalizers.ts +4 -1
- package/src/sources/listing-symbols.ts +11 -5
- package/src/sources/provider-errors.ts +88 -3
- package/src/sources/provider-router/cached-routes.ts +8 -4
- package/src/sources/provider-router/financial-routes.ts +11 -5
- package/src/sources/provider-router/financials.ts +42 -15
- 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 +23 -5
- package/src/sources/sec-edgar.ts +68 -8
- 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/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/resolve.ts +1 -14
- package/src/types/config.ts +61 -1
- 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 +8 -4
- package/src/ui/index.tsx +2 -0
- package/src/utils/cli-output.ts +14 -1
- package/src/utils/exchanges.ts +13 -0
- package/src/utils/format.ts +2 -1
- package/src/utils/fx-market-hours.ts +34 -0
- package/src/utils/option-expiry.ts +126 -0
- package/src/utils/price-history.ts +39 -6
- package/src/utils/rpc-timeout-error.ts +6 -2
- package/src/utils/sec-eps-basis.ts +159 -30
- package/src/utils/sec.ts +38 -34
- package/src/utils/throttled-fetch.ts +51 -22
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { resolveCurrencyUnit } from "../../../utils/currency-units";
|
|
2
2
|
import { overlayScreenerQuoteEntries } from "../../../market-data/quotes/screener-live-quotes";
|
|
3
|
+
import {
|
|
4
|
+
getExtendedSessionDisplay,
|
|
5
|
+
getRegularSessionDisplay,
|
|
6
|
+
type ExtendedSession,
|
|
7
|
+
type ExtendedSessionDisplay,
|
|
8
|
+
} from "../../../market-data/market/status";
|
|
9
|
+
import { buildQuoteKey, resolveEntryData } from "../../../market-data/selectors";
|
|
10
|
+
import { isFiniteNumber } from "../../../utils/guards";
|
|
3
11
|
import type { Quote } from "../../../types/financials";
|
|
4
12
|
import type { CloudSessionMoversCategory } from "../../../api-client/market-movers";
|
|
5
13
|
import type { QueryEntry } from "../../../market-data/result-types";
|
|
@@ -37,12 +45,20 @@ type MarketMoverColumnId =
|
|
|
37
45
|
| "name"
|
|
38
46
|
| "price"
|
|
39
47
|
| "changePercent"
|
|
48
|
+
| "preMarket"
|
|
49
|
+
| "afterHours"
|
|
40
50
|
| "volume"
|
|
41
51
|
| "volumeRatio"
|
|
42
52
|
| "range"
|
|
43
53
|
| "marketCap";
|
|
44
54
|
export type MarketMoverColumn = DataTableColumn & { id: MarketMoverColumnId };
|
|
45
|
-
|
|
55
|
+
/**
|
|
56
|
+
* A list row. Price and change are the regular session's, as `ticker` reads
|
|
57
|
+
* them; a row whose quote has a pre-market or after-hours print carries it in
|
|
58
|
+
* `extended`, measured from that session's close.
|
|
59
|
+
*/
|
|
60
|
+
export type MoverQuote = ScreenerQuote & { extended?: ExtendedSessionDisplay | null };
|
|
61
|
+
export type MarketMoverRow = MoverQuote & { rank: number };
|
|
46
62
|
|
|
47
63
|
export interface MarketMoverSortPreference {
|
|
48
64
|
columnId: MarketMoverColumnId | null;
|
|
@@ -96,6 +112,9 @@ function getSortValue(
|
|
|
96
112
|
return row.price;
|
|
97
113
|
case "changePercent":
|
|
98
114
|
return row.changePercent;
|
|
115
|
+
case "preMarket":
|
|
116
|
+
case "afterHours":
|
|
117
|
+
return moverExtendedMove(row, columnId === "preMarket" ? "PRE" : "POST");
|
|
99
118
|
case "volume":
|
|
100
119
|
return row.volume;
|
|
101
120
|
case "volumeRatio":
|
|
@@ -123,7 +142,17 @@ export function sortRows(
|
|
|
123
142
|
/** A row is rebuilt only when its quote or rank moved, so unchanged rows skip the render. */
|
|
124
143
|
const moverRows = new WeakMap<ScreenerQuote, MarketMoverRow>();
|
|
125
144
|
|
|
126
|
-
|
|
145
|
+
/** The extended print's move from the close, when the row has one for `session`. */
|
|
146
|
+
export function moverExtendedMove(row: MoverQuote, session: ExtendedSession): number | null {
|
|
147
|
+
return row.extended?.session === session && isFiniteNumber(row.extended.changePercent) ? row.extended.changePercent : null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** The extended sessions some row has a print for, in the order their columns go. */
|
|
151
|
+
export function moverExtendedSessions(rows: readonly MoverQuote[]): ExtendedSession[] {
|
|
152
|
+
return (["PRE", "POST"] as const).filter((session) => rows.some((row) => row.extended?.session === session));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function createRows(quotes: readonly MoverQuote[]): MarketMoverRow[] {
|
|
127
156
|
return quotes.map((quote, index) => {
|
|
128
157
|
const cached = moverRows.get(quote);
|
|
129
158
|
if (cached?.rank === index + 1) return cached;
|
|
@@ -137,26 +166,36 @@ export function createRows(quotes: ScreenerQuote[]): MarketMoverRow[] {
|
|
|
137
166
|
});
|
|
138
167
|
}
|
|
139
168
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
): MarketSummaryQuote {
|
|
169
|
+
/** An index in the summary strip, at its regular session's level and move. */
|
|
170
|
+
export function summaryQuoteFromQuote(symbol: string, quote: Quote): MarketSummaryQuote {
|
|
171
|
+
const headline = getRegularSessionDisplay(quote)!;
|
|
144
172
|
return {
|
|
145
173
|
symbol,
|
|
146
174
|
name: quote.name ?? symbol,
|
|
147
|
-
price:
|
|
148
|
-
change:
|
|
149
|
-
changePercent:
|
|
175
|
+
price: headline.price,
|
|
176
|
+
change: headline.change ?? Number.NaN,
|
|
177
|
+
changePercent: headline.changePercent ?? Number.NaN,
|
|
150
178
|
};
|
|
151
179
|
}
|
|
152
180
|
|
|
153
|
-
|
|
181
|
+
/** The extended print beside a quote's regular session, or null; a non-finite price is none. */
|
|
182
|
+
function moverExtended(quote: Quote): ExtendedSessionDisplay | null {
|
|
183
|
+
const extended = getExtendedSessionDisplay(quote);
|
|
184
|
+
return extended && isFiniteNumber(extended.price) ? extended : null;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* A trending row from its quote: Last and Chg% are the regular session, as
|
|
189
|
+
* `ticker` reads it, and a pre-market or after-hours print rides beside them.
|
|
190
|
+
*/
|
|
191
|
+
export function screenerQuoteFromQuote(symbol: string, quote: Quote): MoverQuote {
|
|
192
|
+
const headline = getRegularSessionDisplay(quote)!;
|
|
154
193
|
return {
|
|
155
194
|
symbol,
|
|
156
195
|
name: quote.name ?? symbol,
|
|
157
|
-
price: screenerNumber(
|
|
158
|
-
change: screenerNumber(
|
|
159
|
-
changePercent: screenerNumber(
|
|
196
|
+
price: screenerNumber(headline.price),
|
|
197
|
+
change: screenerNumber(headline.change),
|
|
198
|
+
changePercent: screenerNumber(headline.changePercent),
|
|
160
199
|
volume: screenerVolume(quote.volume),
|
|
161
200
|
avgVolume: null,
|
|
162
201
|
volumeRatio: null,
|
|
@@ -169,6 +208,7 @@ export function screenerQuoteFromQuote(symbol: string, quote: { name?: string; p
|
|
|
169
208
|
exchange: quote.listingExchangeName ?? quote.exchangeName ?? "",
|
|
170
209
|
lastUpdated: quote.lastUpdated,
|
|
171
210
|
previousClose: screenerNumber(quote.previousClose) ?? undefined,
|
|
211
|
+
extended: moverExtended(quote),
|
|
172
212
|
};
|
|
173
213
|
}
|
|
174
214
|
|
|
@@ -198,21 +238,35 @@ export function formatMoverPrice(price: number | null, currency: string, referen
|
|
|
198
238
|
}
|
|
199
239
|
|
|
200
240
|
/** Keyed by the overlaid row, which the shared overlay keeps while its quote holds. */
|
|
201
|
-
const convertedOverlays = new WeakMap<ScreenerQuote,
|
|
241
|
+
const convertedOverlays = new WeakMap<ScreenerQuote, MoverQuote>();
|
|
202
242
|
|
|
203
|
-
/**
|
|
243
|
+
/**
|
|
244
|
+
* Live quotes on the list's rows, which keep the list's order. Price and
|
|
245
|
+
* change are the regular session's, as `ticker` reads them, so after the
|
|
246
|
+
* close they hold at it and a pre-market or after-hours print is the row's
|
|
247
|
+
* `extended`. Range endpoints and the previous close belong to the original
|
|
248
|
+
* screener price denomination.
|
|
249
|
+
*/
|
|
204
250
|
export function overlayMarketMoverQuotes(
|
|
205
|
-
rows: readonly
|
|
251
|
+
rows: readonly MoverQuote[],
|
|
206
252
|
entries: ReadonlyMap<string, QueryEntry<Quote>>,
|
|
207
|
-
):
|
|
253
|
+
): MoverQuote[] {
|
|
208
254
|
return overlayScreenerQuoteEntries(rows, entries).map((row, index) => {
|
|
209
255
|
const original = rows[index]!;
|
|
210
256
|
if (row === original) return row;
|
|
211
257
|
const cached = convertedOverlays.get(row);
|
|
212
258
|
if (cached) return cached;
|
|
213
259
|
const convert = (value: number | undefined) => convertScreenerPriceUnit(value, original.currency, row.currency);
|
|
260
|
+
const quote = resolveEntryData(entries.get(buildQuoteKey({ symbol: row.symbol, exchange: row.exchange })));
|
|
261
|
+
const headline = quote ? getRegularSessionDisplay(quote) : null;
|
|
214
262
|
const converted = {
|
|
215
263
|
...row,
|
|
264
|
+
...(quote && headline ? {
|
|
265
|
+
price: headline.price,
|
|
266
|
+
change: isFiniteNumber(headline.change) ? headline.change : null,
|
|
267
|
+
changePercent: isFiniteNumber(headline.changePercent) ? headline.changePercent : null,
|
|
268
|
+
extended: moverExtended(quote),
|
|
269
|
+
} : {}),
|
|
216
270
|
fiftyTwoWeekLow: convert(original.fiftyTwoWeekLow),
|
|
217
271
|
fiftyTwoWeekHigh: convert(original.fiftyTwoWeekHigh),
|
|
218
272
|
dayLow: convert(original.dayLow),
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { DataTableCell } from "../../../components";
|
|
2
|
+
import { getTableWidth } from "../../../components/ui/table-layout";
|
|
2
3
|
import { TextAttributes } from "../../../ui";
|
|
3
4
|
import { colors, priceColor } from "../../../theme/colors";
|
|
4
5
|
import { formatCompact, formatPercentRaw } from "../../../utils/format";
|
|
6
|
+
import { marketStateLabel, type ExtendedSession } from "../../../market-data/market/status";
|
|
5
7
|
import type { MarketMoverColumn, MarketMoverRow } from "./model";
|
|
6
|
-
import { fiftyTwoWeekPositionPercent, formatMoverPrice, moverReferencePrice } from "./model";
|
|
8
|
+
import { fiftyTwoWeekPositionPercent, formatMoverPrice, moverExtendedMove, moverReferencePrice } from "./model";
|
|
7
9
|
|
|
8
10
|
export function formatVolRatio(ratio: number | null): string {
|
|
9
11
|
if (ratio == null || !Number.isFinite(ratio) || ratio < 0) return "—";
|
|
@@ -22,30 +24,45 @@ function fiftyTwoWeekPosition(price: number | null, low: number | undefined, hig
|
|
|
22
24
|
return pct == null ? "—" : `${Math.round(pct)}%`;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const priceWidth = 11;
|
|
29
|
-
const chgWidth = 9;
|
|
30
|
-
const volWidth = 8;
|
|
31
|
-
const volRatioWidth = 6;
|
|
32
|
-
const rangeWidth = 6;
|
|
33
|
-
const mcapWidth = 8;
|
|
34
|
-
const columnCount = 9;
|
|
35
|
-
const fixedWidth = rankWidth + tickerWidth + priceWidth + chgWidth + volWidth + volRatioWidth + rangeWidth + mcapWidth;
|
|
36
|
-
const nameWidth = Math.max(6, width - 2 - columnCount - fixedWidth);
|
|
27
|
+
const EXTENDED_COLUMN_WIDTH = 9;
|
|
28
|
+
/** With an extended column, a narrow pane drops MCAP, then 52W%, before the name gets narrower than this. */
|
|
29
|
+
const EXTENDED_MIN_NAME_WIDTH = 12;
|
|
37
30
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
{ id: "
|
|
46
|
-
{ id: "
|
|
47
|
-
{ id: "marketCap", label: "MCAP", width: mcapWidth, align: "right" },
|
|
31
|
+
/**
|
|
32
|
+
* The list's columns at `width`. A pre-market or after-hours column follows
|
|
33
|
+
* CHG% for each session in `extendedSessions`; to make room for it a narrow
|
|
34
|
+
* pane gives up MCAP, then 52W%, before it cuts the names short.
|
|
35
|
+
*/
|
|
36
|
+
export function buildMarketMoverColumns(width: number, extendedSessions: readonly ExtendedSession[] = []): MarketMoverColumn[] {
|
|
37
|
+
const lead: MarketMoverColumn[] = [
|
|
38
|
+
{ id: "rank", label: "#", width: 3, align: "left" },
|
|
39
|
+
{ id: "symbol", label: "TICKER", width: 8, align: "left" },
|
|
48
40
|
];
|
|
41
|
+
const quote: MarketMoverColumn[] = [
|
|
42
|
+
{ id: "price", label: "LAST", width: 11, align: "right" },
|
|
43
|
+
{ id: "changePercent", label: "CHG%", width: 9, align: "right" },
|
|
44
|
+
...extendedSessions.map((session): MarketMoverColumn => ({
|
|
45
|
+
id: session === "PRE" ? "preMarket" : "afterHours",
|
|
46
|
+
// Named for the session it trades in, as the header labels it.
|
|
47
|
+
label: marketStateLabel(session),
|
|
48
|
+
width: EXTENDED_COLUMN_WIDTH,
|
|
49
|
+
align: "right",
|
|
50
|
+
})),
|
|
51
|
+
];
|
|
52
|
+
const trailing: MarketMoverColumn[] = [
|
|
53
|
+
{ id: "volume", label: "VOL", width: 8, align: "right" },
|
|
54
|
+
{ id: "volumeRatio", label: "V/AVG", width: 6, align: "right" },
|
|
55
|
+
{ id: "range", label: "52W%", width: 6, align: "right" },
|
|
56
|
+
{ id: "marketCap", label: "MCAP", width: 8, align: "right" },
|
|
57
|
+
];
|
|
58
|
+
// Measured the way the table draws them (a header and its sort mark widen a
|
|
59
|
+
// column, gaps between them); the name adds its own width and a gap.
|
|
60
|
+
const nameRoom = () => width - getTableWidth([...lead, ...quote, ...trailing]) - 1;
|
|
61
|
+
for (const id of ["marketCap", "range"] as const) {
|
|
62
|
+
if (extendedSessions.length === 0 || nameRoom() >= EXTENDED_MIN_NAME_WIDTH) break;
|
|
63
|
+
trailing.splice(trailing.findIndex((column) => column.id === id), 1);
|
|
64
|
+
}
|
|
65
|
+
return [...lead, { id: "name", label: "NAME", width: Math.max(6, nameRoom()), align: "left" }, ...quote, ...trailing];
|
|
49
66
|
}
|
|
50
67
|
|
|
51
68
|
export function renderMarketMoverCell(
|
|
@@ -71,6 +88,16 @@ export function renderMarketMoverCell(
|
|
|
71
88
|
value: row.changePercent,
|
|
72
89
|
color: priceColor(row.changePercent ?? 0),
|
|
73
90
|
};
|
|
91
|
+
case "preMarket":
|
|
92
|
+
case "afterHours": {
|
|
93
|
+
// The extended print's move from the close in LAST.
|
|
94
|
+
const move = moverExtendedMove(row, column.id === "preMarket" ? "PRE" : "POST");
|
|
95
|
+
return {
|
|
96
|
+
text: formatPercentRaw(move ?? undefined),
|
|
97
|
+
value: move,
|
|
98
|
+
color: move == null ? colors.textDim : priceColor(move),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
74
101
|
case "volume":
|
|
75
102
|
return { text: formatCompact(row.volume ?? undefined, { fixedDecimals: true }), value: row.volume, color: colors.textDim };
|
|
76
103
|
case "volumeRatio":
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
mapCloudNewsArticle,
|
|
12
12
|
} from "../../../sources/gloomberb-cloud/news";
|
|
13
13
|
import { parsePublicTickerKey } from "../../../utils/exchanges";
|
|
14
|
+
import { cloudNewsFreshness, cloudRealtimeAccess } from "../shared/report-freshness";
|
|
14
15
|
|
|
15
16
|
const NEWS_COLUMNS = [
|
|
16
17
|
{ key: "publishedAt", header: "Published" },
|
|
@@ -27,11 +28,14 @@ export interface NewsHeadlessDependencies {
|
|
|
27
28
|
context: HeadlessPaneContext,
|
|
28
29
|
): Promise<CloudNewsListResponse>;
|
|
29
30
|
now(): Date;
|
|
31
|
+
/** Whether the session has real-time news; without it the stories are held back. */
|
|
32
|
+
realtimeAccess?(): Promise<boolean | null>;
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
const defaultDependencies: NewsHeadlessDependencies = {
|
|
33
36
|
loadNews: (query, context) => context.apiClient.getCloudNews(cloudNewsParams(query)),
|
|
34
37
|
now: () => new Date(),
|
|
38
|
+
realtimeAccess: cloudRealtimeAccess,
|
|
35
39
|
};
|
|
36
40
|
|
|
37
41
|
function newsRow(article: NewsArticle) {
|
|
@@ -67,6 +71,7 @@ function projectNewsHeadless(
|
|
|
67
71
|
response: CloudNewsListResponse,
|
|
68
72
|
args: HeadlessPaneLoadArgs,
|
|
69
73
|
now: Date,
|
|
74
|
+
realtime: boolean | null,
|
|
70
75
|
): HeadlessSnapshotResult {
|
|
71
76
|
const sentiment = selectedSentiment(args);
|
|
72
77
|
const minImportance = Number(args.options.minImportance ?? 0);
|
|
@@ -81,8 +86,8 @@ function projectNewsHeadless(
|
|
|
81
86
|
return {
|
|
82
87
|
asOf: now.toISOString(),
|
|
83
88
|
items,
|
|
84
|
-
//
|
|
85
|
-
freshness:
|
|
89
|
+
// Dated by the newest story, held back for an account without real-time news.
|
|
90
|
+
freshness: cloudNewsFreshness(realtime),
|
|
86
91
|
metadata: {
|
|
87
92
|
nextCursor: response.nextCursor,
|
|
88
93
|
sentiment,
|
|
@@ -179,6 +184,7 @@ export function createNewsFeedHeadless(
|
|
|
179
184
|
await dependencies.loadNews(queryFor(args, "latest"), context),
|
|
180
185
|
args,
|
|
181
186
|
dependencies.now(),
|
|
187
|
+
await dependencies.realtimeAccess?.() ?? null,
|
|
182
188
|
);
|
|
183
189
|
},
|
|
184
190
|
};
|
|
@@ -205,6 +211,7 @@ export function createTickerNewsHeadless(
|
|
|
205
211
|
),
|
|
206
212
|
args,
|
|
207
213
|
dependencies.now(),
|
|
214
|
+
await dependencies.realtimeAccess?.() ?? null,
|
|
208
215
|
);
|
|
209
216
|
},
|
|
210
217
|
};
|
|
@@ -10,6 +10,7 @@ import { CLOUD_NEWS_DELAY_HOURS } from "../../../../../api-client/plan-access";
|
|
|
10
10
|
import { usePaneStatusLinkFooter } from "../../../../../components/layout/pane/status-footer";
|
|
11
11
|
import { usePluginAppActions } from "../../../../runtime";
|
|
12
12
|
import { useOptionalPaneInstanceId } from "../../../../../state/app/context";
|
|
13
|
+
import { useRemoteUiNode } from "../../../../../remote/semantic-tree";
|
|
13
14
|
|
|
14
15
|
interface NewsFooterArticle {
|
|
15
16
|
title?: string | null;
|
|
@@ -60,6 +61,15 @@ export function useNewsArticleFooter({
|
|
|
60
61
|
shortcutScope: `${registrationId}:news-upgrade`,
|
|
61
62
|
});
|
|
62
63
|
|
|
64
|
+
// A report or capture of the pane says how far its stories are held back, as the footer does.
|
|
65
|
+
useRemoteUiNode({
|
|
66
|
+
role: "report-freshness",
|
|
67
|
+
label: "News freshness",
|
|
68
|
+
getMetadata: () => (access.hasProAccess
|
|
69
|
+
? { status: "live" }
|
|
70
|
+
: { status: "delayed", delayMinutes: CLOUD_NEWS_DELAY_HOURS * 60 }),
|
|
71
|
+
});
|
|
72
|
+
|
|
63
73
|
const accessInfo = useMemo<PaneFooterSegment[]>(() => {
|
|
64
74
|
if (access.isPayingPro) {
|
|
65
75
|
return [{ id: "news-access", parts: [{ text: t("real-time news"), tone: "positive" }] }];
|
|
@@ -280,7 +280,7 @@ export class OpenFdaClient {
|
|
|
280
280
|
async listPage(dataset: OpenFdaDataset, query: string, offset: number, signal?: AbortSignal): Promise<OpenFdaPage> {
|
|
281
281
|
const response = await openFdaFetch.fetch(buildOpenFdaUrl(dataset, query, offset), {
|
|
282
282
|
headers: authorizationHeaders(),
|
|
283
|
-
signal
|
|
283
|
+
signal,
|
|
284
284
|
});
|
|
285
285
|
// openFDA answers a search with no matches with a 404.
|
|
286
286
|
if (response.status === 404) {
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { OptionContract } from "../../../types/financials";
|
|
2
|
+
import { daysToExpiryFrom, optionMid, type OptionSide } from "../shared/volatility";
|
|
3
|
+
import { optionSpread } from "./market-reference";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* What holding a contract costs in time value, read the same way by the OMON
|
|
7
|
+
* columns and the LEAPS screen (`gloomberb options --leaps`):
|
|
8
|
+
*
|
|
9
|
+
* intrinsic = max(0, spot - strike) for a call, max(0, strike - spot) for a put
|
|
10
|
+
* extrinsic = midpoint - intrinsic, the midpoint of a two-sided quote
|
|
11
|
+
* extrinsic per year = extrinsic / spot / years to expiry
|
|
12
|
+
*
|
|
13
|
+
* Years are calendar days to the 16:00 New York close on the expiry date, over
|
|
14
|
+
* 365, counted from the instant the Greeks are valued at. Under a day from the
|
|
15
|
+
* close there is no yearly figure: a few cents over a few hours annualises to
|
|
16
|
+
* noise. Extrinsic is negative when the midpoint sits below intrinsic value, as
|
|
17
|
+
* a wide deep in-the-money quote can. Without a two-sided quote or a current
|
|
18
|
+
* spot there is no figure, never a zero.
|
|
19
|
+
*/
|
|
20
|
+
export interface OptionCarry {
|
|
21
|
+
/** Time value per share, in the contract's currency. */
|
|
22
|
+
extrinsic: number;
|
|
23
|
+
/** Time value as a fraction of spot per year: 0.042 reads 4.2%. Null under a day from expiry. */
|
|
24
|
+
extrinsicPerYear: number | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Less time than this to expiry and a yearly rate means nothing. */
|
|
28
|
+
const MIN_CARRY_DAYS = 1;
|
|
29
|
+
|
|
30
|
+
function positive(value: number | null | undefined): value is number {
|
|
31
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function optionIntrinsicValue(side: OptionSide, strike: number, spot: number): number {
|
|
35
|
+
return Math.max(0, side === "call" ? spot - strike : strike - spot);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function optionCarry(
|
|
39
|
+
contract: Pick<OptionContract, "bid" | "ask" | "strike" | "expiration">,
|
|
40
|
+
side: OptionSide,
|
|
41
|
+
spot: number | null | undefined,
|
|
42
|
+
valuationTime: number,
|
|
43
|
+
): OptionCarry | null {
|
|
44
|
+
const mid = optionMid(contract);
|
|
45
|
+
if (mid == null || !positive(spot) || !positive(contract.strike)) return null;
|
|
46
|
+
const extrinsic = mid - optionIntrinsicValue(side, contract.strike, spot);
|
|
47
|
+
const days = daysToExpiryFrom(contract.expiration, valuationTime);
|
|
48
|
+
return { extrinsic, extrinsicPerYear: days >= MIN_CARRY_DAYS ? extrinsic / spot / (days / 365) : null };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Bid/ask width as a percent of the midpoint; null without a two-sided quote. */
|
|
52
|
+
export function optionSpreadPercent(contract: Pick<OptionContract, "bid" | "ask">): number | null {
|
|
53
|
+
const spread = optionSpread(contract);
|
|
54
|
+
return spread.kind === "two-sided" ? spread.percentOfMid : null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* What a contract costs against the stock it covers: the midpoint of a
|
|
59
|
+
* two-sided quote over spot, so a protective put's premium reads as a share of
|
|
60
|
+
* the position it protects (a 5.495 put on a 778.57 underlying is 0.706%).
|
|
61
|
+
* Null without a two-sided quote or a current spot, never a zero.
|
|
62
|
+
*/
|
|
63
|
+
export function optionCostOfSpot(
|
|
64
|
+
contract: Pick<OptionContract, "bid" | "ask">,
|
|
65
|
+
spot: number | null | undefined,
|
|
66
|
+
): number | null {
|
|
67
|
+
const mid = optionMid(contract);
|
|
68
|
+
return mid == null || !positive(spot) ? null : mid / spot;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Below this a cost of spot reads as a bound: the digits would outrun the column. */
|
|
72
|
+
const MIN_COST_OF_SPOT_PERCENT = 0.001;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* A fraction as a percent to three significant digits: 0.00706 reads 0.706%,
|
|
76
|
+
* 0.0123 reads 1.23%, 0.123 reads 12.3%. Under a thousandth of a percent it
|
|
77
|
+
* reads <0.001%, so a far out-of-the-money quote stays inside the column.
|
|
78
|
+
*/
|
|
79
|
+
export function formatCostOfSpot(value: number | null | undefined): string {
|
|
80
|
+
if (value == null || !Number.isFinite(value) || value < 0) return "\u2014";
|
|
81
|
+
const percent = value * 100;
|
|
82
|
+
if (percent === 0) return "0%";
|
|
83
|
+
if (percent < MIN_COST_OF_SPOT_PERCENT) return `<${MIN_COST_OF_SPOT_PERCENT}%`;
|
|
84
|
+
// Rounded first, so 9.996 reads 10.0% rather than 10.00%.
|
|
85
|
+
const rounded = Number(percent.toPrecision(3));
|
|
86
|
+
const decimals = Math.max(0, 2 - Math.floor(Math.log10(rounded)));
|
|
87
|
+
return `${rounded.toFixed(decimals)}%`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** A fraction as a percent: one decimal under 100% (0.0421 reads 4.2%), whole percents above. */
|
|
91
|
+
export function formatCarryPercent(value: number | null | undefined): string {
|
|
92
|
+
if (value == null || !Number.isFinite(value)) return "—";
|
|
93
|
+
const percent = value * 100;
|
|
94
|
+
return `${percent.toFixed(Math.abs(percent) < 100 ? 1 : 0)}%`;
|
|
95
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import type { PaneSettingsDef, TickerResearchTabProps } from "../../../types/plugin";
|
|
1
|
+
import type { PaneReportOptionDef, PaneSettingsDef, TickerResearchTabProps } from "../../../types/plugin";
|
|
2
2
|
import type { PluginModule } from "../plugin-module";
|
|
3
3
|
import { createTickerSurfacePaneTemplate } from "../shared/ticker-surface";
|
|
4
4
|
import type { OptionsViewProps } from "./types";
|
|
5
5
|
import { OptionsView } from "./view";
|
|
6
6
|
import { isKnownMutualFund } from "../../../tickers/instrument-kind";
|
|
7
|
+
import { expirationOptionSeconds, expiryIsoDate, OPTION_EXPIRATION_FORMAT, OPTION_EXPIRATION_PLACEHOLDER, readOptionExpiration } from "../../../utils/option-expiry";
|
|
7
8
|
|
|
8
9
|
/** The registered chain shows IV rank; isolated view renders stay offline. */
|
|
9
10
|
function OptionsPane(props: OptionsViewProps) {
|
|
@@ -22,19 +23,40 @@ import {
|
|
|
22
23
|
LIVE_STREAMING_QUICK_SETTING,
|
|
23
24
|
withLiveStreamingSetting,
|
|
24
25
|
} from "../../../state/hooks/live-streaming";
|
|
25
|
-
import { OPTION_FIELD_DEFS, resolveOptionFieldIds } from "./table";
|
|
26
|
+
import { OPTION_FIELD_DEFS, normalizeOptionColumnsOption, resolveOptionFieldIds } from "./table";
|
|
27
|
+
import {
|
|
28
|
+
STRIKE_WINDOW_PRESETS,
|
|
29
|
+
STRIKE_WINDOW_SETTING,
|
|
30
|
+
normalizeStrikeWindowOption,
|
|
31
|
+
resolveStrikeWindow,
|
|
32
|
+
strikeWindowShortLabel,
|
|
33
|
+
strikeWindowValue,
|
|
34
|
+
} from "./strike-window";
|
|
26
35
|
|
|
27
36
|
function optionsSettings(settings: Record<string, unknown>): PaneSettingsDef {
|
|
37
|
+
const strikeWindow = resolveStrikeWindow(settings[STRIKE_WINDOW_SETTING]);
|
|
38
|
+
const strikeWindowText = strikeWindowValue(strikeWindow);
|
|
39
|
+
const strikeWindowOptions = STRIKE_WINDOW_PRESETS.map(({ value, label, description }) => ({ value, label, description }));
|
|
28
40
|
return {
|
|
29
41
|
title: "Options Settings",
|
|
30
42
|
values: {
|
|
31
43
|
optionColumnIds: resolveOptionFieldIds(settings.optionColumnIds),
|
|
44
|
+
[STRIKE_WINDOW_SETTING]: strikeWindowText,
|
|
32
45
|
},
|
|
33
46
|
fields: [
|
|
47
|
+
{
|
|
48
|
+
key: STRIKE_WINDOW_SETTING,
|
|
49
|
+
label: "Strikes",
|
|
50
|
+
description: "Which strikes the chain lists: all of them, a count either side of the money, or those whose call or put delta falls in a band.",
|
|
51
|
+
type: "select",
|
|
52
|
+
// A window typed on the command line that no preset matches stays selectable.
|
|
53
|
+
options: strikeWindowOptions.some((option) => option.value === strikeWindowText) ? strikeWindowOptions
|
|
54
|
+
: [...strikeWindowOptions, { value: strikeWindowText, label: strikeWindowShortLabel(strikeWindow), description: "Set from the command line." }],
|
|
55
|
+
},
|
|
34
56
|
{
|
|
35
57
|
key: "optionColumnIds",
|
|
36
58
|
label: "Columns",
|
|
37
|
-
description: "Choose and order the fields mirrored around the strike.",
|
|
59
|
+
description: "Choose and order the fields mirrored around the strike. Cost % of spot shows on the put side only.",
|
|
38
60
|
type: "ordered-multi-select",
|
|
39
61
|
options: OPTION_FIELD_DEFS.map((field) => ({
|
|
40
62
|
value: field.id,
|
|
@@ -58,6 +80,16 @@ function optionsSettings(settings: Record<string, unknown>): PaneSettingsDef {
|
|
|
58
80
|
};
|
|
59
81
|
}
|
|
60
82
|
|
|
83
|
+
/** `fn OMON AAPL --expiration 2028-01-21`: the expiry the chain opens at, as the pane setting a handoff sets. */
|
|
84
|
+
const EXPIRATION_REPORT_OPTION: PaneReportOptionDef = {
|
|
85
|
+
key: "expiration",
|
|
86
|
+
type: "string",
|
|
87
|
+
placeholder: OPTION_EXPIRATION_PLACEHOLDER,
|
|
88
|
+
description: `The expiry to show, as ${OPTION_EXPIRATION_FORMAT}. Without it, the nearest one.`,
|
|
89
|
+
example: "--expiration 2028-01-21",
|
|
90
|
+
normalize: (value) => expiryIsoDate(expirationOptionSeconds(value)),
|
|
91
|
+
};
|
|
92
|
+
|
|
61
93
|
export const optionsModule: PluginModule = {
|
|
62
94
|
panes: [
|
|
63
95
|
{
|
|
@@ -72,6 +104,25 @@ export const optionsModule: PluginModule = {
|
|
|
72
104
|
quickSettings: [LIVE_STREAMING_QUICK_SETTING],
|
|
73
105
|
settings: (context) => withLiveStreamingSetting(optionsSettings(context.settings), context.settings),
|
|
74
106
|
tableExport: true,
|
|
107
|
+
reportOptions: [EXPIRATION_REPORT_OPTION, {
|
|
108
|
+
key: STRIKE_WINDOW_SETTING,
|
|
109
|
+
aliases: ["delta"],
|
|
110
|
+
type: "string",
|
|
111
|
+
placeholder: "all|count|delta band",
|
|
112
|
+
description: "Strikes to list: all (the default), a count either side of the money such as 10, "
|
|
113
|
+
+ "or a call or put delta band such as 0.70-0.90. --delta 0.70-0.90 reads the same",
|
|
114
|
+
example: "--strikes 0.70-0.90",
|
|
115
|
+
normalize: normalizeStrikeWindowOption,
|
|
116
|
+
}, {
|
|
117
|
+
key: "columns",
|
|
118
|
+
settingKey: "optionColumnIds",
|
|
119
|
+
type: "string",
|
|
120
|
+
placeholder: "fields",
|
|
121
|
+
description: `Fields mirrored around the strike, in order, as the Columns setting picks them: ${OPTION_FIELD_DEFS.map((field) => field.id).join(", ")}. `
|
|
122
|
+
+ "costOfSpot (the put's midpoint as a percent of spot) shows on the put side only",
|
|
123
|
+
example: "--columns bid,ask,spread,delta,openInterest,extrinsicPerYear",
|
|
124
|
+
normalize: normalizeOptionColumnsOption,
|
|
125
|
+
}],
|
|
75
126
|
},
|
|
76
127
|
],
|
|
77
128
|
|
|
@@ -83,8 +134,10 @@ export const optionsModule: PluginModule = {
|
|
|
83
134
|
description: "Options chain for the selected ticker.",
|
|
84
135
|
keywords: ["options", "chain", "calls", "puts", "omon"],
|
|
85
136
|
shortcut: "OMON",
|
|
86
|
-
settings: (_symbol, _context, options) =>
|
|
87
|
-
|
|
137
|
+
settings: (_symbol, _context, options) => {
|
|
138
|
+
const expiration = readOptionExpiration(options?.values?.expiration);
|
|
139
|
+
return expiration == null ? {} : { expiration, expirationTargetKey: null };
|
|
140
|
+
},
|
|
88
141
|
publicShare: true,
|
|
89
142
|
}),
|
|
90
143
|
],
|