gloomberb 0.16.3 → 0.16.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -91
- package/package.json +7 -1
- package/src/{plugins/builtin/cloud → account}/auth-form.tsx +9 -9
- package/src/{plugins/builtin/cloud → account}/auth-model.ts +4 -4
- package/src/account/billing.ts +57 -0
- package/src/{plugins/builtin/cloud → account}/device-signin-dialog.tsx +18 -12
- package/src/{plugins/builtin/cloud → account}/device-signin.ts +2 -2
- package/src/{plugins/builtin/cloud → account}/email-auth-attempt.ts +2 -2
- package/src/account/session.ts +16 -0
- package/src/{plugins/builtin/cloud → account}/upgrade-dialog.tsx +42 -17
- package/src/account/upgrade-personalization.ts +57 -0
- package/src/account/upgrade-tickers.ts +124 -0
- package/src/{plugins/builtin/cloud → account}/verification-panel.tsx +6 -6
- 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 +58 -18
- package/src/api-client/earnings.ts +6 -0
- package/src/api-client/futures-curve.ts +56 -0
- package/src/api-client/index.ts +16 -1
- package/src/api-client/market-discovery.ts +10 -1
- package/src/api-client/normalizers.ts +27 -0
- package/src/api-client/paths.ts +95 -23
- package/src/api-client/request.ts +2 -1
- package/src/api-client/research-activity.ts +46 -10
- package/src/api-client/socket.ts +39 -8
- package/src/api-client/types.ts +74 -2
- package/src/api-client/upgrade-experiment.ts +90 -0
- package/src/api-client/yield-curves.ts +8 -0
- package/src/app/global-shortcuts.ts +26 -2
- 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 +25 -4
- 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 +61 -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 +34 -14
- package/src/brokers/signed-in/sign-in.ts +62 -5
- package/src/capabilities/chart-series.ts +11 -1
- package/src/capabilities/registry.ts +8 -1
- package/src/capabilities/types.ts +2 -0
- package/src/cli/commands/crypto-hints.ts +19 -4
- package/src/cli/commands/fred-series.ts +61 -0
- package/src/cli/commands/market.ts +744 -181
- package/src/cli/commands/news-hints.ts +62 -0
- package/src/cli/commands/news-search.ts +53 -0
- package/src/cli/commands/options-chain.ts +172 -0
- package/src/cli/commands/options-leaps.ts +425 -0
- package/src/cli/commands/overview.ts +251 -40
- package/src/cli/commands/remote.ts +2 -1
- package/src/cli/commands/search.ts +109 -15
- package/src/cli/commands/system.ts +151 -24
- package/src/cli/commands/themes.ts +64 -0
- package/src/cli/commands/ticker.ts +149 -40
- package/src/cli/context.ts +45 -14
- package/src/cli/desktop-pane-shot.ts +150 -17
- package/src/cli/earnings-calendar.ts +71 -0
- package/src/cli/errors.ts +25 -2
- package/src/cli/freshness.ts +22 -8
- package/src/cli/fx-pair.ts +57 -0
- package/src/cli/glossary.ts +429 -0
- package/src/cli/help.ts +14 -1
- package/src/cli/history-rows.ts +48 -7
- package/src/cli/index-roots.ts +58 -0
- package/src/cli/index.ts +29 -12
- package/src/cli/known-gaps.ts +27 -0
- package/src/cli/listing-arg.ts +595 -26
- package/src/cli/not-a-ticker.ts +44 -0
- package/src/cli/options.ts +50 -6
- package/src/cli/pane-functions/access-gate.ts +5 -0
- package/src/cli/pane-functions/capabilities.ts +11 -4
- package/src/cli/pane-functions/catalog.ts +48 -7
- package/src/cli/pane-functions/data.ts +48 -13
- package/src/cli/pane-functions/discovery.ts +1 -0
- package/src/cli/pane-functions/dom.ts +41 -19
- package/src/cli/pane-functions/freshness.ts +531 -32
- package/src/cli/pane-functions/function-help.ts +77 -25
- package/src/cli/pane-functions/headless.ts +50 -21
- package/src/cli/pane-functions/index.ts +66 -10
- package/src/cli/pane-functions/market-session.ts +147 -0
- package/src/cli/pane-functions/options.ts +77 -25
- package/src/cli/pane-functions/report-notices.ts +81 -0
- package/src/cli/pane-functions/report.ts +19 -8
- package/src/cli/pane-functions/resolver.ts +53 -18
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +199 -30
- package/src/cli/registry.ts +2 -1
- package/src/cli/report-tables.ts +3 -0
- package/src/cli/result.ts +53 -13
- package/src/cli/row-window.ts +76 -0
- package/src/cli/scroll-truncation.ts +34 -0
- package/src/cli/staged-tickers.ts +52 -0
- package/src/cli/symbol-args.ts +9 -0
- package/src/cli/symbol-list.ts +172 -0
- package/src/cli/ticker-resolution.ts +223 -30
- package/src/cli/types.ts +5 -0
- package/src/components/chart/composite/axis-overlays.tsx +6 -2
- package/src/components/chart/composite/composite-chart.tsx +83 -10
- package/src/components/chart/composite/legend.tsx +88 -8
- package/src/components/chart/composite/panel-surface.tsx +44 -17
- package/src/components/chart/composite/price-axis-labels.tsx +3 -1
- 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/panel/index.tsx +11 -3
- package/src/components/command-bar/panel/runtime.ts +3 -0
- package/src/components/command-bar/panel/types.ts +2 -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/provider-search.ts +4 -3
- 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/routes/ticker-search/results.ts +12 -11
- package/src/components/command-bar/routes/ticker-search/route.ts +4 -3
- 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/command-bar/workflow/tickers.ts +23 -4
- package/src/components/data-table/view.tsx +28 -9
- package/src/components/layout/detached-pane-shell.tsx +9 -0
- package/src/components/layout/floating-pane.tsx +9 -2
- package/src/components/layout/header.tsx +20 -5
- package/src/components/layout/market-summary.ts +23 -9
- package/src/components/layout/pane/content.tsx +40 -29
- package/src/components/layout/pane/cycle-order.ts +2 -11
- package/src/components/layout/pane/footer/index.tsx +6 -2
- package/src/components/layout/pane/footer/model.ts +35 -1
- package/src/components/layout/pane/header.tsx +26 -2
- package/src/components/layout/pane/index.tsx +12 -2
- package/src/components/layout/pane/sidebar.tsx +78 -10
- 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 +21 -5
- package/src/components/layout/shell/drag/index.ts +43 -9
- package/src/components/layout/shell/drag/live.ts +87 -6
- package/src/components/layout/shell/drag/runtime.ts +62 -20
- package/src/components/layout/shell/index.tsx +71 -12
- package/src/components/layout/shell/layout-state.ts +5 -11
- package/src/components/layout/shell/menu.ts +33 -1
- package/src/components/layout/shell/native/pointer-runtime.ts +3 -1
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +216 -28
- 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 +24 -0
- 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 +69 -23
- package/src/components/metric-treemap/heat-surface.tsx +37 -9
- package/src/components/metric-treemap/heat-tiles.ts +48 -17
- package/src/components/onboarding/account-step/form-panel.tsx +1 -1
- package/src/components/onboarding/account-step/index.tsx +1 -1
- package/src/components/onboarding/account-step/qr-panel.tsx +1 -1
- package/src/components/onboarding/account-step/signed-in-panel.tsx +1 -1
- package/src/components/onboarding/onboarding-frame.tsx +33 -10
- package/src/components/onboarding/onboarding-keyboard.ts +1 -1
- package/src/components/onboarding/onboarding-wizard.tsx +50 -41
- 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 +8 -4
- package/src/components/onboarding/wizard-account.ts +2 -2
- package/src/components/pane-template-wizard.tsx +9 -1
- package/src/components/price-selector-dialog.tsx +11 -2
- package/src/components/sign-in-gate.tsx +3 -3
- package/src/components/ticker/list-table-view.tsx +24 -1
- package/src/components/ui/action-row.tsx +2 -1
- package/src/components/ui/button.tsx +17 -1
- package/src/components/ui/choice-dialog.tsx +6 -4
- package/src/components/ui/confirm-dialog.tsx +28 -18
- package/src/components/ui/data-table/index.tsx +49 -0
- package/src/components/ui/data-table/opentui/index.tsx +37 -6
- package/src/components/ui/data-table/types.ts +20 -1
- package/src/components/ui/data-table/visible-range.ts +2 -0
- package/src/components/ui/dialog-actions.tsx +64 -0
- package/src/components/ui/display.tsx +17 -3
- package/src/components/ui/frame.tsx +35 -2
- package/src/components/ui/icon.tsx +13 -2
- package/src/components/ui/index.ts +1 -1
- package/src/components/ui/text-prompt-dialog.tsx +11 -9
- 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/cached-query.ts +2 -0
- 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 +44 -5
- package/src/data/ticker-repository.ts +5 -0
- package/src/data/ticker-store.ts +15 -0
- package/src/docs/content.ts +215 -0
- package/src/docs/load.ts +139 -0
- package/src/docs/requests.ts +39 -0
- package/src/docs/snapshot.chunk.ts +8 -0
- package/src/docs/snapshot.json +7416 -0
- package/src/docs/topics.ts +216 -0
- package/src/i18n/es.ts +75 -5
- package/src/i18n/ja.ts +75 -5
- package/src/i18n/ko.ts +75 -5
- package/src/i18n/zh-cn.ts +75 -5
- package/src/i18n/zh-tw.ts +75 -5
- package/src/layout/desks.ts +2 -3
- package/src/layout/pane-layout-move.ts +264 -0
- package/src/layout/pane-manager/dock-tree.ts +18 -0
- package/src/layout/pane-manager/hidden-panes.ts +160 -0
- package/src/layout/pane-manager/index.ts +2 -0
- package/src/market-data/coordinator/chart.ts +10 -4
- package/src/market-data/coordinator/entries.ts +7 -1
- package/src/market-data/coordinator/index.ts +6 -3
- package/src/market-data/coordinator/quotes.ts +2 -2
- package/src/{plugins/builtin/futures/contracts.ts → market-data/futures-board.ts} +81 -28
- package/src/market-data/futures-contract.ts +151 -0
- package/src/market-data/hooks.tsx +10 -2
- package/src/market-data/market/format.ts +39 -21
- package/src/market-data/market/freshness.ts +193 -30
- package/src/market-data/market/status.ts +59 -23
- package/src/market-data/options-alternatives.ts +69 -0
- package/src/market-data/published-apac-sessions.ts +23 -1
- package/src/market-data/quotes/contributions.ts +22 -2
- package/src/market-data/quotes/metadata.ts +8 -9
- package/src/market-data/quotes/resolution.ts +2 -0
- package/src/market-data/quotes/screener-live-quotes.ts +61 -9
- package/src/market-data/result-types.ts +2 -0
- package/src/plugins/builtin/account-management/keyboard.ts +3 -0
- package/src/plugins/builtin/account-management/model.ts +2 -56
- package/src/plugins/builtin/account-management/navigation.ts +1 -1
- package/src/plugins/builtin/account-management/pane.tsx +37 -8
- package/src/plugins/builtin/account-management/password-dialog.tsx +1 -1
- package/src/plugins/builtin/alerts/cli.ts +313 -47
- package/src/plugins/builtin/alerts/events-pane.tsx +45 -7
- package/src/plugins/builtin/alerts/events.ts +23 -2
- package/src/plugins/builtin/alerts/history-pane.tsx +7 -2
- package/src/plugins/builtin/alerts/history.ts +2 -0
- package/src/plugins/builtin/alerts/index.tsx +41 -9
- package/src/plugins/builtin/alerts/pane.tsx +8 -0
- package/src/plugins/builtin/alerts/quotes.ts +3 -0
- package/src/plugins/builtin/alerts/research-builder.ts +8 -3
- package/src/plugins/builtin/alerts/research-rules.ts +18 -2
- package/src/plugins/builtin/alerts/scheduled-check.ts +122 -0
- package/src/plugins/builtin/alerts/scheduled-sources.ts +25 -0
- package/src/plugins/builtin/alerts/scheduled.ts +254 -0
- package/src/plugins/builtin/alerts/targets.ts +92 -0
- package/src/plugins/builtin/analytics/index.tsx +4 -2
- package/src/plugins/builtin/analytics/risk-headless.ts +33 -13
- package/src/plugins/builtin/analytics/risk-math.ts +91 -27
- package/src/plugins/builtin/analytics/risk-model.ts +71 -12
- package/src/plugins/builtin/analytics/risk-pane.tsx +23 -12
- package/src/plugins/builtin/attention/index.tsx +2 -0
- package/src/plugins/builtin/attention/pane.tsx +3 -1
- package/src/plugins/builtin/attention/series.ts +26 -0
- package/src/plugins/builtin/awards/index.tsx +2 -0
- package/src/plugins/builtin/awards/pane.tsx +3 -1
- package/src/plugins/builtin/awards/series.ts +29 -0
- package/src/plugins/builtin/backtest/pane.tsx +1 -1
- package/src/plugins/builtin/bond-calculator/model.ts +2 -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/pane.tsx +3 -1
- package/src/plugins/builtin/cds/client.ts +70 -13
- package/src/plugins/builtin/cds/headless.ts +116 -19
- package/src/plugins/builtin/cds/index.tsx +3 -1
- package/src/plugins/builtin/cds/model.ts +193 -31
- package/src/plugins/builtin/cds/pane.tsx +56 -14
- package/src/plugins/builtin/cds/series.ts +19 -0
- package/src/plugins/builtin/central-bank-rates/index.tsx +2 -0
- package/src/plugins/builtin/central-bank-rates/series.ts +42 -0
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +192 -255
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +84 -46
- package/src/plugins/builtin/chart-composer/editor.tsx +5 -4
- package/src/plugins/builtin/chart-composer/field-series.ts +40 -0
- package/src/plugins/builtin/chart-composer/headless.ts +8 -3
- package/src/plugins/builtin/chart-composer/index.tsx +9 -2
- package/src/plugins/builtin/chart-composer/pane.tsx +1 -1
- package/src/plugins/builtin/chart-composer/series-catalog.ts +58 -50
- package/src/plugins/builtin/chart-composer/series-expression.ts +18 -10
- package/src/plugins/builtin/chart-composer/use-series-catalog.ts +59 -3
- package/src/plugins/builtin/chart-composer/user-series.ts +84 -0
- 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/new-dm-dialog.tsx +10 -2
- package/src/plugins/builtin/chat/content/user-map.ts +3 -1
- package/src/plugins/builtin/chat/controller/index.ts +50 -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 +223 -23
- package/src/plugins/builtin/cloud/askg/conversation-store.ts +21 -0
- package/src/plugins/builtin/cloud/askg/executor.ts +57 -3
- package/src/plugins/builtin/cloud/askg/manifest.ts +33 -7
- package/src/plugins/builtin/cloud/askg/model.ts +156 -78
- package/src/plugins/builtin/cloud/askg/pane.tsx +772 -377
- package/src/plugins/builtin/cloud/askg/protocol.ts +50 -3
- package/src/plugins/builtin/cloud/askg/tool-display.ts +440 -0
- package/src/plugins/builtin/cloud/askg/tool-timeline.tsx +403 -0
- package/src/plugins/builtin/cloud/askg/undo.ts +2 -0
- package/src/plugins/builtin/cloud/auth-actions.tsx +1 -1
- package/src/plugins/builtin/cloud/auth-commands.ts +1 -1
- package/src/plugins/builtin/cloud/auth-dialog.tsx +3 -3
- 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 +363 -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/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 +734 -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 +239 -0
- package/src/plugins/builtin/cloud/terminal-relay/policy.ts +162 -0
- package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +192 -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/thesis/exposure.ts +1 -1
- package/src/plugins/builtin/cloud/thesis/prompts.tsx +2 -1
- package/src/plugins/builtin/comment-letters/client.ts +1 -3
- package/src/plugins/builtin/company-attention/app-rank.tsx +1 -1
- package/src/plugins/builtin/company-attention/headless.ts +19 -5
- package/src/plugins/builtin/company-attention/index.tsx +2 -0
- package/src/plugins/builtin/company-attention/model.ts +26 -7
- package/src/plugins/builtin/company-attention/pane.tsx +12 -9
- package/src/plugins/builtin/company-attention/series.ts +52 -0
- 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 +19 -9
- package/src/plugins/builtin/company-kpis/screenshot-evidence.ts +10 -3
- package/src/plugins/builtin/composite-plugins.ts +116 -67
- package/src/plugins/builtin/cot/index.tsx +3 -1
- package/src/plugins/builtin/cot/model.ts +40 -11
- package/src/plugins/builtin/cot/series.ts +27 -0
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +4 -4
- package/src/plugins/builtin/credit-boards/index.tsx +23 -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/series.ts +66 -0
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +4 -4
- package/src/plugins/builtin/credit-conditions/index.tsx +2 -0
- package/src/plugins/builtin/credit-conditions/series.ts +26 -0
- package/src/plugins/builtin/credit-documents/headless.ts +31 -1
- package/src/plugins/builtin/credit-documents/pane.tsx +3 -1
- package/src/plugins/builtin/crypto-board/headless.ts +2 -3
- package/src/plugins/builtin/crypto-board/index.tsx +2 -0
- package/src/plugins/builtin/crypto-board/model.ts +12 -0
- package/src/plugins/builtin/crypto-board/pane.tsx +19 -12
- package/src/plugins/builtin/crypto-board/series.ts +48 -0
- package/src/plugins/builtin/custom-view/live-quotes.ts +2 -2
- 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/index.tsx +2 -0
- package/src/plugins/builtin/debt-maturities/pane.tsx +5 -4
- package/src/plugins/builtin/debt-maturities/series.ts +45 -0
- package/src/plugins/builtin/dividend-yield/headless.ts +2 -2
- package/src/plugins/builtin/dividend-yield/index.tsx +3 -1
- package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
- package/src/plugins/builtin/dividend-yield/series.ts +20 -0
- package/src/plugins/builtin/docs/blocks.tsx +181 -0
- package/src/plugins/builtin/docs/index.tsx +68 -0
- package/src/plugins/builtin/docs/pane.tsx +426 -0
- package/src/plugins/builtin/docs/targets.ts +72 -0
- package/src/plugins/builtin/docs/use-docs.ts +60 -0
- package/src/plugins/builtin/doe/index.tsx +2 -0
- package/src/plugins/builtin/doe/series.ts +62 -0
- package/src/plugins/builtin/earnings/client.ts +3 -2
- package/src/plugins/builtin/earnings/format.ts +1 -5
- package/src/plugins/builtin/earnings/headless.ts +58 -6
- package/src/plugins/builtin/earnings/history-model.ts +15 -1
- package/src/plugins/builtin/earnings/history-table.ts +13 -2
- package/src/plugins/builtin/earnings/history.tsx +7 -3
- 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/fred-catalog.ts +189 -0
- package/src/plugins/builtin/econ/fred-series-map.ts +0 -46
- package/src/plugins/builtin/econ/index.tsx +70 -22
- package/src/plugins/builtin/econ-statistics/defs.ts +5 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +30 -5
- package/src/plugins/builtin/econ-statistics/pane.tsx +1 -1
- package/src/plugins/builtin/econ-statistics/stats.ts +1 -0
- package/src/plugins/builtin/econ-statistics/view.ts +17 -0
- package/src/plugins/builtin/equity-screener/pane.tsx +4 -11
- package/src/plugins/builtin/executives/data.ts +17 -6
- package/src/plugins/builtin/executives/pane.tsx +16 -7
- package/src/plugins/builtin/exposure/holdings.ts +1 -1
- package/src/plugins/builtin/exposure/pane.tsx +3 -1
- package/src/plugins/builtin/fear-greed/index.tsx +4 -0
- package/src/plugins/builtin/fear-greed/series.ts +52 -0
- package/src/plugins/builtin/filing-events/pane.tsx +22 -5
- package/src/plugins/builtin/futures/index.tsx +43 -3
- package/src/plugins/builtin/futures/model.ts +1 -1
- package/src/plugins/builtin/futures/returns.ts +1 -1
- package/src/plugins/builtin/futures/series.ts +13 -0
- package/src/plugins/builtin/futures/table.tsx +1 -1
- package/src/plugins/builtin/futures/use-front-returns.ts +1 -1
- package/src/plugins/builtin/futures-curve/client.ts +12 -3
- package/src/plugins/builtin/futures-curve/headless.ts +70 -9
- package/src/plugins/builtin/futures-curve/index.tsx +1 -1
- package/src/plugins/builtin/futures-curve/model.ts +66 -11
- package/src/plugins/builtin/futures-curve/pane.tsx +52 -18
- 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/board.tsx +13 -10
- package/src/plugins/builtin/gpu/changes.tsx +4 -4
- package/src/plugins/builtin/gpu/client.ts +19 -1
- package/src/plugins/builtin/gpu/equities.tsx +14 -10
- package/src/plugins/builtin/gpu/headless.ts +64 -27
- package/src/plugins/builtin/gpu/history.tsx +3 -3
- package/src/plugins/builtin/gpu/index.tsx +2 -0
- package/src/plugins/builtin/gpu/model.ts +114 -20
- package/src/plugins/builtin/gpu/pane.tsx +28 -12
- package/src/plugins/builtin/gpu/series.ts +38 -0
- package/src/plugins/builtin/help/function-card.tsx +25 -6
- package/src/plugins/builtin/help/index.tsx +18 -8
- package/src/plugins/builtin/holders/beneficial-client.ts +29 -7
- package/src/plugins/builtin/holders/beneficial-model.ts +90 -3
- package/src/plugins/builtin/holders/beneficial-report.ts +57 -5
- package/src/plugins/builtin/holders/beneficial-view.tsx +62 -14
- package/src/plugins/builtin/holders/client.ts +22 -3
- package/src/plugins/builtin/holders/format.ts +18 -3
- package/src/plugins/builtin/holders/headless.ts +42 -134
- package/src/plugins/builtin/holders/pane.tsx +14 -4
- package/src/plugins/builtin/holders/report-header.ts +40 -5
- package/src/plugins/builtin/holders/report-rows.ts +240 -0
- package/src/plugins/builtin/insider/client.ts +35 -20
- package/src/plugins/builtin/insider/headless.ts +41 -11
- package/src/plugins/builtin/insider/index.tsx +27 -10
- package/src/plugins/builtin/insider/insider-data.ts +10 -0
- package/src/plugins/builtin/insider/issuer.ts +49 -0
- package/src/plugins/builtin/insider/model.ts +3 -0
- package/src/plugins/builtin/iv-history/charts.tsx +21 -7
- package/src/plugins/builtin/iv-history/client.ts +26 -6
- package/src/plugins/builtin/iv-history/format.ts +33 -2
- package/src/plugins/builtin/iv-history/headless.ts +27 -12
- package/src/plugins/builtin/iv-history/index.tsx +5 -3
- package/src/plugins/builtin/iv-history/model.ts +172 -20
- package/src/plugins/builtin/iv-history/pane.tsx +11 -3
- package/src/plugins/builtin/iv-history/screen-pane.tsx +45 -25
- package/src/plugins/builtin/iv-history/series.ts +29 -0
- package/src/plugins/builtin/jobs/headless.ts +28 -3
- package/src/plugins/builtin/jobs/index.tsx +3 -1
- package/src/plugins/builtin/jobs/pane.tsx +1 -1
- package/src/plugins/builtin/jobs/series.ts +19 -0
- 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 +111 -40
- package/src/plugins/builtin/kelly-sizer/portfolio.ts +0 -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 +68 -3
- package/src/plugins/builtin/macro-day/headless.ts +18 -12
- package/src/plugins/builtin/macro-day/index.tsx +3 -0
- package/src/plugins/builtin/macro-day/model.ts +66 -15
- package/src/plugins/builtin/macro-day/pane.tsx +34 -20
- 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 +102 -3
- package/src/plugins/builtin/market-heatmap/portfolio.ts +12 -2
- package/src/plugins/builtin/market-movers/client.ts +7 -5
- package/src/plugins/builtin/market-movers/headless.ts +31 -4
- package/src/plugins/builtin/market-movers/index.tsx +11 -3
- package/src/plugins/builtin/market-movers/model.ts +101 -17
- package/src/plugins/builtin/market-movers/screener.ts +31 -0
- package/src/plugins/builtin/market-movers/table.ts +50 -23
- package/src/plugins/builtin/market-valuation/chart-series.ts +29 -69
- package/src/plugins/builtin/market-valuation/index.tsx +3 -3
- package/src/plugins/builtin/market-valuation/indicators.ts +0 -5
- package/src/plugins/builtin/members/headless.ts +7 -2
- package/src/plugins/builtin/members/model.ts +31 -3
- package/src/plugins/builtin/members/pane.tsx +3 -6
- package/src/plugins/builtin/mna/headless.ts +15 -3
- package/src/plugins/builtin/money-markets/index.tsx +2 -0
- package/src/plugins/builtin/money-markets/series.ts +41 -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/notes/cli.ts +12 -7
- 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 +162 -13
- package/src/plugins/builtin/options-calculator/inputs.ts +2 -1
- package/src/plugins/builtin/options-positioning/client.ts +7 -3
- package/src/plugins/builtin/options-positioning/headless.ts +5 -2
- package/src/plugins/builtin/options-positioning/pane.tsx +2 -2
- package/src/plugins/builtin/options-scenario/charts.tsx +2 -2
- package/src/plugins/builtin/options-scenario/client.ts +75 -18
- package/src/plugins/builtin/options-scenario/headless.ts +72 -24
- package/src/plugins/builtin/options-scenario/hedge.ts +285 -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/client.ts +40 -6
- package/src/plugins/builtin/perps/equity-row.tsx +33 -8
- package/src/plugins/builtin/perps/freshness.ts +66 -0
- package/src/plugins/builtin/perps/headless.ts +45 -30
- package/src/plugins/builtin/perps/index.tsx +18 -1
- package/src/plugins/builtin/perps/model.ts +32 -6
- package/src/plugins/builtin/perps/pane.tsx +76 -20
- package/src/plugins/builtin/perps/series.ts +76 -0
- 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 +357 -39
- package/src/plugins/builtin/plugin-marketplace/store.ts +7 -1
- package/src/plugins/builtin/plugin-module.ts +90 -4
- package/src/plugins/builtin/portfolio-list/account-metrics.ts +1 -1
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +273 -0
- package/src/plugins/builtin/portfolio-list/cli/import-13f.ts +109 -0
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +400 -99
- package/src/plugins/builtin/portfolio-list/cli/render.ts +281 -43
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +26 -16
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +120 -47
- package/src/plugins/builtin/portfolio-list/column-values.ts +1 -1
- package/src/plugins/builtin/portfolio-list/grid.tsx +1 -1
- package/src/plugins/builtin/portfolio-list/headless.ts +70 -9
- package/src/plugins/builtin/portfolio-list/imported-from.ts +8 -0
- package/src/plugins/builtin/portfolio-list/live-valuation.ts +6 -2
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +6 -1
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +17 -1
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +1 -1
- package/src/plugins/builtin/portfolio-list/table.tsx +7 -1
- package/src/plugins/builtin/power/client.ts +16 -0
- package/src/plugins/builtin/power/evidence.ts +6 -2
- package/src/plugins/builtin/power/headless.ts +71 -7
- package/src/plugins/builtin/power/index.tsx +4 -1
- package/src/plugins/builtin/power/model.ts +72 -1
- package/src/plugins/builtin/power/pane.tsx +32 -9
- package/src/plugins/builtin/rate-path/headless.ts +11 -3
- package/src/plugins/builtin/realized-vol/headless.ts +8 -0
- package/src/plugins/builtin/realized-vol/pane.tsx +1 -1
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +7 -4
- package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +1 -1
- package/src/plugins/builtin/research/event-model.ts +68 -24
- package/src/plugins/builtin/research/events-headless.ts +2 -1
- package/src/plugins/builtin/research/headless.ts +2 -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/client.ts +15 -7
- package/src/plugins/builtin/seasonality/headless.ts +36 -12
- package/src/plugins/builtin/seasonality/index.tsx +2 -2
- package/src/plugins/builtin/seasonality/model.ts +119 -0
- package/src/plugins/builtin/seasonality/pane.tsx +108 -37
- 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/series-inventory.ts +91 -0
- package/src/plugins/builtin/shared/cloud-upgrade.ts +1 -1
- package/src/plugins/builtin/shared/command-tab.ts +69 -0
- package/src/plugins/builtin/shared/earnings-report.ts +55 -0
- package/src/plugins/builtin/shared/fred-points.ts +20 -0
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +101 -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/open-description.ts +29 -0
- package/src/plugins/builtin/shared/report-freshness.ts +59 -2
- package/src/plugins/builtin/shared/series-warning.ts +5 -0
- 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/headless.ts +1 -0
- package/src/plugins/builtin/short-interest/index.tsx +21 -4
- package/src/plugins/builtin/short-interest/series.ts +36 -0
- package/src/plugins/builtin/short-interest/surface.tsx +4 -4
- package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
- package/src/plugins/builtin/short-interest/watch-model.ts +9 -5
- package/src/plugins/builtin/short-volume/headless.ts +1 -0
- package/src/plugins/builtin/short-volume/index.tsx +3 -10
- package/src/plugins/builtin/short-volume/series.ts +23 -0
- package/src/plugins/builtin/social-mentions/index.tsx +2 -0
- package/src/plugins/builtin/social-mentions/series.ts +23 -0
- package/src/plugins/builtin/supply-chain/graph-pane.tsx +3 -2
- package/src/plugins/builtin/supply-chain/model.ts +1 -1
- package/src/plugins/builtin/supply-chain/pane.tsx +3 -1
- package/src/plugins/builtin/thirteenf/api.ts +1 -0
- package/src/plugins/builtin/thirteenf/data.ts +6 -4
- package/src/plugins/builtin/thirteenf/headless.ts +217 -36
- package/src/plugins/builtin/thirteenf/model.ts +39 -1
- package/src/plugins/builtin/thirteenf/overlap.ts +75 -0
- package/src/plugins/builtin/thirteenf/pane.tsx +10 -1
- package/src/plugins/builtin/thirteenf/report-notes.ts +103 -1
- package/src/plugins/builtin/thirteenf/types.ts +2 -0
- package/src/plugins/builtin/ticker-detail/headless.ts +43 -21
- package/src/plugins/builtin/ticker-detail/index.tsx +3 -0
- package/src/plugins/builtin/ticker-detail/overview/components.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/overview/futures-contract.ts +31 -0
- package/src/plugins/builtin/ticker-detail/overview/model.ts +3 -3
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +2 -1
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +48 -4
- 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/ticker-detail/quote-monitor/index.tsx +13 -3
- package/src/plugins/builtin/time-sales/headless.ts +1 -0
- 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 +56 -6
- package/src/plugins/builtin/treasury-auctions/index.tsx +12 -9
- package/src/plugins/builtin/treasury-auctions/model.ts +205 -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 +125 -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/volatility/index.tsx +2 -0
- package/src/plugins/builtin/volatility/series.ts +84 -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 +27 -2
- package/src/plugins/builtin/world-venue-map/headless.ts +4 -1
- package/src/plugins/builtin/world-venue-map/index.ts +3 -2
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +8 -4
- package/src/plugins/builtin/world-venue-map/layers.ts +29 -0
- package/src/plugins/builtin/yield-curve/chart.ts +2 -2
- package/src/plugins/builtin/yield-curve/curves.ts +21 -8
- package/src/plugins/builtin/yield-curve/headless.ts +71 -18
- package/src/plugins/builtin/yield-curve/index.tsx +4 -2
- package/src/plugins/builtin/yield-curve/series.ts +86 -0
- package/src/plugins/builtin-editorial.ts +126 -0
- package/src/plugins/catalog-backend.ts +16 -9
- package/src/plugins/catalog-browser.ts +129 -64
- 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 +173 -28
- package/src/plugins/registry/plugin-state.ts +25 -1
- package/src/plugins/runtime/context.tsx +29 -0
- package/src/{plugins/builtin/portfolio-list → portfolio}/position-metrics.ts +6 -6
- package/src/portfolio/position-value.ts +40 -0
- package/src/public/__snapshots__/public-api.test.ts.snap +7 -0
- package/src/public/time-series.ts +17 -0
- package/src/react/auto-refresh.ts +13 -3
- package/src/react/input.ts +48 -1
- package/src/remote/app-host.tsx +25 -4
- package/src/remote/confirm-change.tsx +85 -0
- package/src/remote/controller-utils.ts +8 -1
- package/src/remote/controller.ts +126 -59
- package/src/remote/matching.ts +69 -0
- package/src/remote/pane-screenshot.ts +47 -0
- package/src/remote/schema.ts +63 -1
- package/src/remote/semantic-tree.tsx +14 -0
- package/src/remote/types.ts +32 -0
- package/src/remote/watchlist.ts +306 -0
- package/src/renderers/browser/main.tsx +3 -2
- package/src/renderers/cloudflare/worker.ts +1 -1
- package/src/renderers/dom/data-table/frozen-column.ts +3 -1
- package/src/renderers/dom/data-table/index.tsx +33 -6
- package/src/renderers/dom/data-table/row.tsx +27 -1
- package/src/renderers/dom/desktop/control-styles.ts +63 -1
- package/src/renderers/dom/desktop/controls.tsx +30 -23
- package/src/renderers/dom/desktop/dialog-actions.tsx +170 -0
- package/src/renderers/dom/desktop/icons.tsx +21 -0
- package/src/renderers/dom/desktop/query-bar.tsx +59 -32
- package/src/renderers/dom/dom-ui-host.tsx +3 -0
- package/src/renderers/dom/host/box.tsx +4 -1
- package/src/renderers/dom/host/chart-surface.tsx +6 -2
- package/src/renderers/dom/host/drag-shield.ts +17 -6
- package/src/renderers/dom/host/live-frame.ts +14 -2
- package/src/renderers/dom/host/overflow-fade.ts +14 -1
- package/src/renderers/dom/host/size-observer.ts +26 -0
- package/src/renderers/dom/host/surface-3d.tsx +7 -2
- package/src/renderers/dom/host/text.tsx +1 -1
- package/src/renderers/dom/input-host.tsx +6 -1
- package/src/renderers/dom/styles.css +74 -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 +18 -3
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +109 -5
- package/src/renderers/electrobun/view/cli-pane-shot-health.ts +10 -26
- package/src/renderers/electrobun/view/main.tsx +6 -1
- package/src/renderers/opentui/input-host.tsx +6 -1
- package/src/renderers/opentui/start.tsx +9 -0
- package/src/series/capability.ts +75 -0
- package/src/series/csv.ts +160 -0
- package/src/series/files.ts +107 -0
- package/src/series/registry.ts +198 -0
- package/src/series/resolve.ts +107 -0
- package/src/series/standalone.ts +48 -0
- package/src/series/types.ts +145 -0
- package/src/series/validate.ts +171 -0
- package/src/shares/portable-layout.ts +16 -6
- package/src/sources/gloomberb-cloud/index.ts +26 -17
- package/src/sources/gloomberb-cloud/normalizers.ts +5 -1
- package/src/sources/history-result.ts +1 -0
- package/src/sources/listing-symbols.ts +14 -5
- package/src/sources/provider-errors.ts +88 -3
- package/src/sources/provider-router/batches.ts +4 -1
- package/src/sources/provider-router/cache.ts +4 -2
- package/src/sources/provider-router/cached-routes.ts +9 -5
- package/src/sources/provider-router/financial-routes.ts +12 -5
- package/src/sources/provider-router/financials.ts +55 -15
- package/src/sources/provider-router/history.ts +68 -34
- package/src/sources/provider-router/index.ts +1 -1
- package/src/sources/provider-router/primary.ts +23 -5
- package/src/sources/provider-router/search.ts +1 -0
- package/src/sources/sec-edgar.ts +68 -8
- package/src/sync/core-contributors.ts +5 -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/company-name.ts +75 -0
- package/src/tickers/instrument-kind.ts +25 -0
- package/src/tickers/open-target.ts +3 -2
- package/src/tickers/search/index.ts +67 -9
- package/src/tickers/search/ranking.ts +78 -18
- package/src/tickers/search/types.ts +10 -2
- package/src/tickers/starter-symbols.ts +8 -0
- package/src/tickers/us-listing.ts +34 -0
- package/src/time-series/hooks.ts +9 -0
- package/src/time-series/resolve.ts +96 -30
- package/src/time-series/types.ts +4 -2
- package/src/time-series/use-chart-resolution.ts +32 -0
- package/src/types/config.ts +67 -1
- package/src/types/data-provider.ts +5 -0
- package/src/types/financials.ts +52 -1
- package/src/types/headless.ts +72 -0
- package/src/types/instrument.ts +8 -0
- package/src/types/plugin.ts +68 -3
- package/src/types/price-history.ts +7 -0
- package/src/types/ticker.ts +14 -0
- package/src/ui/host.tsx +26 -4
- package/src/ui/index.tsx +2 -0
- package/src/ui/live-resize.ts +81 -0
- package/src/ui/live-stretch.ts +121 -0
- package/src/ui/measured-cells.ts +58 -0
- package/src/ui/pane-fill.ts +11 -0
- package/src/utils/basis-points.ts +17 -0
- package/src/utils/cli-output.ts +21 -2
- package/src/utils/concurrency.ts +25 -0
- package/src/utils/crypto-pair.ts +20 -0
- package/src/utils/currency-pair.ts +19 -0
- package/src/utils/decimal-comma.ts +19 -0
- package/src/utils/dom-screenshot-css.ts +265 -0
- package/src/utils/dom-screenshot-rasters.ts +276 -0
- package/src/utils/dom-screenshot.ts +437 -52
- package/src/utils/exchange-rate-snapshot.ts +6 -2
- package/src/utils/exchanges.ts +120 -1
- package/src/utils/format.ts +17 -3
- package/src/utils/fundamentals.ts +66 -0
- package/src/utils/futures-generic.ts +6 -12
- package/src/utils/fx-market-hours.ts +44 -0
- package/src/utils/option-expiry.ts +126 -0
- package/src/utils/price-history.ts +130 -40
- package/src/utils/rpc-timeout-error.ts +6 -2
- package/src/utils/sec-eps-basis.ts +178 -36
- package/src/utils/sec.ts +98 -40
- package/src/utils/throttled-fetch.ts +51 -22
- package/src/utils/utc-time.ts +51 -4
|
@@ -1,64 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { ChartSeriesCatalogItem, ChartSeriesCapability } from "../../../capabilities";
|
|
3
|
-
import { colors } from "../../../theme/colors";
|
|
4
|
-
import type { ResolvedSeries, TimeSeriesPoint } from "../../../time-series/types";
|
|
1
|
+
import type { SeriesDefinition, SeriesLoadResult } from "../../../series/types";
|
|
5
2
|
import { buildValuationSeries } from "./align";
|
|
6
3
|
import { defaultValuationSeriesLoader, type ValuationSeriesLoader } from "./client";
|
|
7
4
|
import { indicatorUnavailableReason, indicatorSeries, type IndicatorDef } from "./defs";
|
|
8
|
-
import {
|
|
5
|
+
import { INDICATORS } from "./indicators";
|
|
9
6
|
import type { DatedSeries } from "./series";
|
|
10
7
|
|
|
11
|
-
|
|
8
|
+
/** `CAP:market-valuation:<indicator>`, the expression charts saved before the catalog had these. */
|
|
9
|
+
const MARKET_VALUATION_NAMESPACE = "market-valuation";
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
label: indicator.label,
|
|
17
|
-
description: indicator.description,
|
|
18
|
-
detail: "Market valuation",
|
|
19
|
-
style: "line",
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function matches(indicator: IndicatorDef, query: string): boolean {
|
|
24
|
-
const haystack = `${indicator.id} ${indicator.label} ${indicator.shortLabel} ${indicator.description}`;
|
|
25
|
-
return haystack.toLowerCase().includes(query);
|
|
11
|
+
/** Shiller's series move once a month; the Z.1 and GDP ratios once a quarter. */
|
|
12
|
+
function indicatorFrequency(indicator: IndicatorDef): "monthly" | "quarterly" {
|
|
13
|
+
return indicatorSeries(indicator).some((def) => def.source.kind === "shiller") ? "monthly" : "quarterly";
|
|
26
14
|
}
|
|
27
15
|
|
|
28
16
|
/**
|
|
29
|
-
* A ratio is not a series anyone can fetch, so the pane's own computation is
|
|
30
|
-
* makes it chartable
|
|
31
|
-
*
|
|
17
|
+
* A ratio is not a series anyone can fetch, so the pane's own computation is
|
|
18
|
+
* what makes it chartable: overlaying the Buffett indicator on CPI needs no
|
|
19
|
+
* valuation pane on screen.
|
|
32
20
|
*/
|
|
33
|
-
export function
|
|
21
|
+
export async function loadValuationIndicator(
|
|
22
|
+
indicator: IndicatorDef,
|
|
34
23
|
loader: ValuationSeriesLoader = defaultValuationSeriesLoader,
|
|
35
|
-
):
|
|
36
|
-
return chartSeriesProvider({
|
|
37
|
-
id: MARKET_VALUATION_CAPABILITY_ID,
|
|
38
|
-
name: "Market Valuation",
|
|
39
|
-
provider: {
|
|
40
|
-
catalog: ({ limit }) => INDICATORS.slice(0, limit ?? INDICATORS.length).map(catalogItem),
|
|
41
|
-
search: ({ query, limit }) => {
|
|
42
|
-
const needle = query?.trim().toLowerCase();
|
|
43
|
-
const hits = needle
|
|
44
|
-
? INDICATORS.filter((indicator) => matches(indicator, needle))
|
|
45
|
-
: [...INDICATORS];
|
|
46
|
-
return hits.slice(0, limit ?? hits.length).map(catalogItem);
|
|
47
|
-
},
|
|
48
|
-
resolve: async ({ seriesId }) => resolveValuationSeries(seriesId, loader),
|
|
49
|
-
},
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export async function resolveValuationSeries(
|
|
54
|
-
seriesId: string,
|
|
55
|
-
loader: ValuationSeriesLoader = defaultValuationSeriesLoader,
|
|
56
|
-
): Promise<ResolvedSeries> {
|
|
57
|
-
const indicator = findIndicator(seriesId);
|
|
58
|
-
if (indicator.id !== seriesId.trim().toLowerCase()) {
|
|
59
|
-
throw new Error(`Unknown valuation series ${seriesId}`);
|
|
60
|
-
}
|
|
61
|
-
|
|
24
|
+
): Promise<SeriesLoadResult> {
|
|
62
25
|
const unavailable = indicatorUnavailableReason(indicator);
|
|
63
26
|
if (unavailable) throw new Error(unavailable);
|
|
64
27
|
const legs = new Map<string, DatedSeries>();
|
|
@@ -74,26 +37,23 @@ export async function resolveValuationSeries(
|
|
|
74
37
|
if (built.points.at(-1)?.ratio == null) {
|
|
75
38
|
warnings.push(`${indicator.label}: latest observation unavailable (${built.points.at(-1)!.date})`);
|
|
76
39
|
}
|
|
77
|
-
const points: TimeSeriesPoint[] = built.points.map((point) => {
|
|
78
|
-
const date = new Date(point.date);
|
|
79
|
-
return { date, observedAt: date, value: point.ratio };
|
|
80
|
-
});
|
|
81
|
-
|
|
82
40
|
return {
|
|
83
|
-
|
|
84
|
-
label: indicator.label,
|
|
85
|
-
color: colors.textBright,
|
|
86
|
-
// Source percentages need the same units as ratios scaled into percentages.
|
|
87
|
-
unit: indicator.axisUnit === "%" ? "%" : "x",
|
|
88
|
-
unitGroup: indicator.axisUnit === "%" ? "valuation-percent" : "valuation-ratio",
|
|
89
|
-
nativeFrequency: "daily",
|
|
90
|
-
dataShape: "scalar",
|
|
91
|
-
style: "line",
|
|
92
|
-
transform: "raw",
|
|
93
|
-
axis: "left",
|
|
94
|
-
panelId: "main",
|
|
95
|
-
interpolation: "none",
|
|
41
|
+
points: built.points.map((point) => ({ date: point.date, value: point.ratio })),
|
|
96
42
|
...(warnings.length ? { warning: warnings.join("; ") } : {}),
|
|
97
|
-
points,
|
|
98
43
|
};
|
|
99
44
|
}
|
|
45
|
+
|
|
46
|
+
export function valuationSeriesDefinitions(
|
|
47
|
+
loader: ValuationSeriesLoader = defaultValuationSeriesLoader,
|
|
48
|
+
): SeriesDefinition[] {
|
|
49
|
+
return INDICATORS.map((indicator) => ({
|
|
50
|
+
id: `${MARKET_VALUATION_NAMESPACE}:${indicator.id}`,
|
|
51
|
+
name: indicator.label,
|
|
52
|
+
unit: indicator.axisUnit === "%" ? "%" : "x",
|
|
53
|
+
frequency: indicatorFrequency(indicator),
|
|
54
|
+
group: "Valuation",
|
|
55
|
+
tags: [indicator.shortLabel, "market valuation"],
|
|
56
|
+
description: indicator.description,
|
|
57
|
+
load: () => loadValuationIndicator(indicator, loader),
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { PluginModule } from "../plugin-module";
|
|
2
2
|
import { valuationCache } from "./cache";
|
|
3
|
-
import {
|
|
3
|
+
import { valuationSeriesDefinitions } from "./chart-series";
|
|
4
4
|
import { INDICATORS, resolveIndicatorArg } from "./indicators";
|
|
5
5
|
import { marketValuationHeadless } from "./headless";
|
|
6
6
|
import { MarketValuationPane } from "./pane";
|
|
@@ -35,8 +35,8 @@ const KEYWORDS = [...new Set([
|
|
|
35
35
|
])];
|
|
36
36
|
|
|
37
37
|
export const marketValuationModule: PluginModule = {
|
|
38
|
-
//
|
|
39
|
-
|
|
38
|
+
// Each ratio is a catalog series, so G can overlay them on anything else.
|
|
39
|
+
series: valuationSeriesDefinitions(),
|
|
40
40
|
panes: [{
|
|
41
41
|
id: MARKET_VALUATION_PANE_ID,
|
|
42
42
|
name: "Market Valuation",
|
|
@@ -370,11 +370,6 @@ export const INDICATORS: readonly IndicatorDef[] = [
|
|
|
370
370
|
|
|
371
371
|
export const DEFAULT_INDICATOR_ID = BUFFETT_INDICATOR.id;
|
|
372
372
|
|
|
373
|
-
export function findIndicator(id: string | null | undefined): IndicatorDef {
|
|
374
|
-
const normalized = id?.trim().toLowerCase();
|
|
375
|
-
return INDICATORS.find((entry) => entry.id === normalized) ?? BUFFETT_INDICATOR;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
373
|
/** Resolves shortcut arguments like `VAL cape` or `VAL buffett` onto an indicator. */
|
|
379
374
|
export function resolveIndicatorArg(arg: string | null | undefined): IndicatorDef | null {
|
|
380
375
|
const query = arg?.trim().toLowerCase();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { HeadlessPaneColumn, HeadlessPaneDefinition } from "../../../types/plugin";
|
|
2
2
|
import { fetchChanges, fetchFunds, fetchMembers } from "./client";
|
|
3
|
-
import { canonicalFund, changeReason, decimal, DEFAULT_SORT, memberRows, percent } from "./model";
|
|
3
|
+
import { canonicalFund, changeReason, coverageText, decimal, DEFAULT_SORT, holdingsCaveats, holdingsSourceText, memberRows, percent } from "./model";
|
|
4
4
|
const columns: HeadlessPaneColumn[] = [
|
|
5
5
|
{ key: "symbol", header: "Ticker" }, { key: "name", header: "Name" },
|
|
6
6
|
{ key: "weight", header: "Weight %", align: "right", format: (value) => value == null ? "--" : decimal(Number(value) * 100) },
|
|
@@ -30,6 +30,11 @@ export const membersHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
|
30
30
|
return { freshness: { status: data.stale ? "stale" : "delayed", delayMinutes: 15, ignoreStaleFlags: true }, rows, columns: movers ? [...columns.slice(0, 3), { key: "contribution", header: "Contrib. pp", align: "right", format: (value) => percent(value as number | null, "", 3) }] : columns,
|
|
31
31
|
complete: !data.stale && data.aggregate.fresh1D === data.aggregate.total,
|
|
32
32
|
unavailableSymbols: data.members.flatMap((row) => row.symbol && row.changePercent === null ? [row.symbol] : []),
|
|
33
|
-
metadata: { fund: data.fund, asOf: data.asOf, snapshotAsOf: data.snapshotAsOf, aggregate: data.aggregate, stale: data.stale
|
|
33
|
+
metadata: { fund: data.fund, asOf: data.asOf, snapshotAsOf: data.snapshotAsOf, aggregate: data.aggregate, stale: data.stale, notices: [
|
|
34
|
+
holdingsSourceText(input, data),
|
|
35
|
+
// The pane's coverage figure, and once what the table's dashes mean instead of leaving them bare.
|
|
36
|
+
[coverageText(data.aggregate), data.aggregate.fresh1D < data.aggregate.total ? "1D -- means no fresh delayed quote; those holdings are not counted" : ""].filter(Boolean).join(" | "),
|
|
37
|
+
...holdingsCaveats(data, movers),
|
|
38
|
+
] } };
|
|
34
39
|
},
|
|
35
40
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FundChange, FundMember, MemberFundsPayload } from "../../../api-client/members";
|
|
1
|
+
import type { FundChange, FundMember, FundMembersPayload, MemberFundsPayload } from "../../../api-client/members";
|
|
2
2
|
import type { DataTableColumn } from "../../../components";
|
|
3
3
|
import { buildSectionedRows, type SectionedRow } from "../../../components/data-table/sections";
|
|
4
4
|
import { getTableWidth } from "../../../components/ui/table-layout";
|
|
@@ -7,14 +7,42 @@ export type MembersTab = "members" | "movers" | "changes";
|
|
|
7
7
|
export const TABS = [{ value: "members", label: "Members" }, { value: "movers", label: "Movers" }, { value: "changes", label: "Changes" }];
|
|
8
8
|
export const isTab = (value: unknown): value is MembersTab => TABS.some((tab) => tab.value === value);
|
|
9
9
|
const COVERED = [{ ticker: "IVV", name: "S&P 500" }, { ticker: "IJH", name: "S&P 400" }, { ticker: "IJR", name: "S&P 600" }, { ticker: "IWM", name: "Russell 2000" }, { ticker: "IWB", name: "Russell 1000" }];
|
|
10
|
-
|
|
10
|
+
/** Symbols the app reads as a covered fund before asking the server, which knows its own aliases too. */
|
|
11
|
+
const LOCAL_ALIASES: Record<string, string> = { SPX: "IVV", SPY: "IVV", "^GSPC": "IVV" };
|
|
12
|
+
const requestedSymbol = (input: string) => input.split(":")[0]!.trim().toUpperCase();
|
|
13
|
+
export function canonicalFund(input: string) { const symbol = requestedSymbol(input); return LOCAL_ALIASES[symbol] ?? symbol; }
|
|
11
14
|
/** The covered fund the user asked for, by ticker or by an alias such as SPX, or undefined when it is not covered. */
|
|
12
15
|
export function coveredFund(funds: MemberFundsPayload["funds"], input: string) {
|
|
13
16
|
const symbol = canonicalFund(input);
|
|
14
17
|
return funds.find((fund) => fund.ticker === symbol || fund.aliases.some((alias) => alias.toUpperCase() === symbol));
|
|
15
18
|
}
|
|
19
|
+
/** Every symbol that opens this fund: the server's aliases and the app's own. */
|
|
20
|
+
function fundAliases(fund: MemberFundsPayload["funds"][number]) {
|
|
21
|
+
const local = Object.entries(LOCAL_ALIASES).flatMap(([alias, ticker]) => ticker === fund.ticker ? [alias] : []);
|
|
22
|
+
return [...new Set([...fund.aliases.map((alias) => alias.toUpperCase()), ...local])].filter((alias) => alias !== fund.ticker);
|
|
23
|
+
}
|
|
16
24
|
export function notCoveredMessage(input: string, funds: MemberFundsPayload["funds"]) {
|
|
17
|
-
|
|
25
|
+
const covered = funds.map((fund) => { const aliases = fundAliases(fund); return aliases.length ? `${fund.ticker} (${aliases.join(", ")})` : fund.ticker; });
|
|
26
|
+
return `${requestedSymbol(input)} is not a covered fund. Covered: ${covered.join(", ")}.`;
|
|
27
|
+
}
|
|
28
|
+
/** "Partial 1D 334/504 · 91.5% wt": how many holdings have a fresh 1D return, and their share of the fund. */
|
|
29
|
+
export function coverageText(aggregate: FundMembersPayload["aggregate"], short = false) {
|
|
30
|
+
const partial = aggregate.fresh1D < aggregate.total;
|
|
31
|
+
return `${partial && !short ? "Partial " : ""}1D ${aggregate.fresh1D}/${aggregate.total} · ${decimal(aggregate.coveredWeight * 100, 1)}% wt`;
|
|
32
|
+
}
|
|
33
|
+
/** "S&P 500, IVV holdings as of 2026-10-08 (for SPY)": the holdings file the members come from. */
|
|
34
|
+
export function holdingsSourceText(input: string, data: Pick<FundMembersPayload, "fund" | "asOf">) {
|
|
35
|
+
const requested = requestedSymbol(input);
|
|
36
|
+
return `${data.fund.name}, ${data.fund.ticker} holdings as of ${data.asOf.slice(0, 10)}${requested && requested !== data.fund.ticker ? ` (for ${requested})` : ""}`;
|
|
37
|
+
}
|
|
38
|
+
/** Caveats about a fund's holdings and returns, shared by the pane's notices and the text report. */
|
|
39
|
+
export function holdingsCaveats(data: FundMembersPayload, movers: boolean) {
|
|
40
|
+
return [
|
|
41
|
+
...(data.quotesUnavailable ? ["Member returns and current prices are unavailable. Dated holdings remain available."] : []),
|
|
42
|
+
...(movers && data.aggregate.fundReturn === null ? ["Fund 1D is unavailable; the difference cannot be calculated."] : []),
|
|
43
|
+
...(movers && data.aggregate.withinTolerance === false ? [`The covered contribution sum differs from the fund by ${percent(data.aggregate.residual, " pp")}.`] : []),
|
|
44
|
+
...(data.excludedDerivatives ? [`${data.excludedDerivatives} derivative positions are excluded from these share holdings.`] : []),
|
|
45
|
+
];
|
|
18
46
|
}
|
|
19
47
|
export function membersTitle(input: string) {
|
|
20
48
|
const requested = input.split(":")[0]!.trim().toUpperCase();
|
|
@@ -13,7 +13,7 @@ import { nextHeaderSort, type SortPreference } from "../../../utils/sort-values"
|
|
|
13
13
|
import { isPlainArrowUp, stopSearchFocusNavigation } from "../../../utils/search-focus-navigation";
|
|
14
14
|
import { useMembersMenu, type MemberList } from "../shared/members-menu";
|
|
15
15
|
import { cachedChanges, cachedFunds, cachedMembers, loadChanges, loadFunds, loadMembers } from "./client";
|
|
16
|
-
import { canonicalFund, changeColumns, changeLabel, changeReason, coveredFund, decimal, DEFAULT_SORT, isTab, memberColumns, memberRows, membersTitle, notCoveredMessage, percent, TABS, type MembersTab } from "./model";
|
|
16
|
+
import { canonicalFund, changeColumns, changeLabel, changeReason, coverageText, coveredFund, decimal, DEFAULT_SORT, holdingsCaveats, isTab, memberColumns, memberRows, membersTitle, notCoveredMessage, percent, TABS, type MembersTab } from "./model";
|
|
17
17
|
|
|
18
18
|
type ViewProps = Pick<PaneProps, "width" | "height" | "focused"> & { fund: string; active: boolean };
|
|
19
19
|
const rowKey = (row: SectionedRow<FundMember>) => row.key;
|
|
@@ -47,7 +47,7 @@ function Holdings({ fund, tab, width, height, focused, active }: ViewProps & { t
|
|
|
47
47
|
const date = dates.length === 1 ? dates[0] : dates.length ? `${dates[0]} to ${dates.at(-1)}` : data.fundDailyAsOf?.slice(0, 10);
|
|
48
48
|
const partial = data.aggregate.fresh1D < data.aggregate.total;
|
|
49
49
|
return [
|
|
50
|
-
{ id: "coverage", parts: [{ text:
|
|
50
|
+
{ id: "coverage", parts: [{ text: coverageText(data.aggregate, width < 60), tone: partial ? "warning" : "muted" }] },
|
|
51
51
|
{ id: "quote-date", title: `${date ?? "Quote date unavailable"} · 15m delayed · holdings ${data.asOf}`,
|
|
52
52
|
parts: [{ text: data.quotesUnavailable ? "returns unavailable" : width < 60 && dates.length === 1 ? `${date!.slice(5)} delayed` : `${date ? `${date} · ` : ""}15m delayed`, tone: "muted" }] },
|
|
53
53
|
...(width >= 60 ? [{ id: "holdings-date", parts: [{ text: `holdings ${data.asOf}`, tone: "muted" as const }] }] : []),
|
|
@@ -57,11 +57,8 @@ function Holdings({ fund, tab, width, height, focused, active }: ViewProps & { t
|
|
|
57
57
|
stale: !!data && (data.stale || resource.data!.stale || !!resource.error), info });
|
|
58
58
|
usePaneNoticeFooter({ registrationId: "members:notices", focused, notices: [
|
|
59
59
|
...(resource.error || resource.data?.refreshError ? [resource.error ?? resource.data!.refreshError!] : []),
|
|
60
|
-
...(data?.quotesUnavailable ? ["Member returns and current prices are unavailable. Dated holdings remain available."] : []),
|
|
61
60
|
...(data && data.aggregate.fresh1D < data.aggregate.total ? [`Fresh 1D: ${data.aggregate.fresh1D}/${data.aggregate.total} holdings, ${decimal(data.aggregate.coveredWeight * 100, 1)}% of whole-fund weight. Missing returns are excluded.`] : []),
|
|
62
|
-
...(
|
|
63
|
-
...(movers && data?.aggregate.withinTolerance === false ? [`The covered contribution sum differs from the fund by ${percent(data.aggregate.residual, " pp")}.`] : []),
|
|
64
|
-
...(data?.excludedDerivatives ? [`${data.excludedDerivatives} derivative positions are excluded from these share holdings.`] : []),
|
|
61
|
+
...(data ? holdingsCaveats(data, movers) : []),
|
|
65
62
|
] });
|
|
66
63
|
const renderCell = useCallback((item: SectionedRow<FundMember>, column: DataTableColumn): DataTableCell => {
|
|
67
64
|
if (!isSectionedItemRow(item)) return { text: "" };
|
|
@@ -2,6 +2,8 @@ import type { MnaDealsParams, MnaRegionFilter, MnaStatusFilter, MnaTargetFilter
|
|
|
2
2
|
import type { HeadlessPaneColumn, HeadlessPaneDefinition } from "../../../types/plugin";
|
|
3
3
|
import { fetchMnaDeals } from "./client";
|
|
4
4
|
import { formatDealValue, formatExpectedClose, stageLabel, termsLabel } from "./model";
|
|
5
|
+
import { listingAbroadVenue } from "../../../utils/sec";
|
|
6
|
+
import { shortCompanyName } from "../../../tickers/company-name";
|
|
5
7
|
|
|
6
8
|
const text = (value: unknown) => (typeof value === "string" ? value : "");
|
|
7
9
|
|
|
@@ -44,12 +46,19 @@ export const mnaHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
|
44
46
|
describe: (args) => `M&A${args.symbols[0] ? ` | ${args.symbols[0]}` : ""} | ${text(args.options.status) || "pending"}`,
|
|
45
47
|
async load(args, ctx) {
|
|
46
48
|
const symbol = args.symbols[0];
|
|
49
|
+
// Deals carry US tickers, where SAN is not SAN:EPA's company: a listing abroad is looked up by its company's name.
|
|
50
|
+
const company = symbol && listingAbroadVenue(symbol)
|
|
51
|
+
? await ctx.marketData.getQuote(symbol, "").then((quote) => quote.name?.trim() || null, () => null)
|
|
52
|
+
: null;
|
|
53
|
+
if (symbol && listingAbroadVenue(symbol) && !company) {
|
|
54
|
+
throw new Error(`Deals are filed by US ticker or company name, and ${symbol} has no company name to look them up by.`);
|
|
55
|
+
}
|
|
47
56
|
const params: MnaDealsParams = {
|
|
48
57
|
status: ((args.options.status as MnaStatusFilter | undefined) ?? (symbol ? "all" : "pending")),
|
|
49
58
|
target: symbol ? undefined : (args.options.target as MnaTargetFilter | undefined),
|
|
50
59
|
region: symbol ? undefined : (args.options.region as MnaRegionFilter | undefined),
|
|
51
|
-
symbol,
|
|
52
|
-
query: text(args.options.query) || undefined,
|
|
60
|
+
symbol: company ? undefined : symbol,
|
|
61
|
+
query: text(args.options.query) || (company ? shortCompanyName(company) : undefined),
|
|
53
62
|
limit: Number(args.options.limit ?? 50),
|
|
54
63
|
};
|
|
55
64
|
const payload = await fetchMnaDeals(params, ctx.apiClient);
|
|
@@ -77,7 +86,10 @@ export const mnaHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
|
77
86
|
headline: deal.headline,
|
|
78
87
|
})),
|
|
79
88
|
errors: payload.lockedDeals > 0 ? [`${payload.lockedDeals} deals from the last ${payload.delayDays} days need Gloom Pro`] : [],
|
|
80
|
-
metadata: {
|
|
89
|
+
metadata: {
|
|
90
|
+
asOf: payload.asOf, access: payload.access, delayDays: payload.delayDays, hasMore: payload.hasMore,
|
|
91
|
+
...(company ? { notices: [`Deals are filed by US ticker, so ${symbol}'s are the ones naming ${shortCompanyName(company)}.`] } : {}),
|
|
92
|
+
},
|
|
81
93
|
};
|
|
82
94
|
},
|
|
83
95
|
};
|
|
@@ -2,8 +2,10 @@ import type { PluginModule } from "../plugin-module";
|
|
|
2
2
|
import { moneyMarketsCache } from "./client";
|
|
3
3
|
import { moneyMarketsHeadless } from "./headless";
|
|
4
4
|
import { MoneyMarketsPane } from "./pane";
|
|
5
|
+
import { MONEY_MARKET_SERIES } from "./series";
|
|
5
6
|
|
|
6
7
|
export const moneyMarketsModule: PluginModule = {
|
|
8
|
+
series: MONEY_MARKET_SERIES,
|
|
7
9
|
panes: [{ id: "money-markets", name: "Money Markets", icon: "$", component: MoneyMarketsPane,
|
|
8
10
|
defaultPosition: "right", defaultMode: "floating", defaultFloatingSize: { width: 88, height: 28 },
|
|
9
11
|
tableExport: true, headless: moneyMarketsHeadless,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { MoneyMarketObservation } from "../../../api-client/money-markets";
|
|
2
|
+
import type { SeriesDefinition } from "../../../series/types";
|
|
3
|
+
import { cachedSeriesWarning } from "../shared/series-warning";
|
|
4
|
+
import { loadMoneyMarkets } from "./client";
|
|
5
|
+
|
|
6
|
+
function observations(history: readonly MoneyMarketObservation[]) {
|
|
7
|
+
return history.map((point) => ({ date: point.date, value: point.value }));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The two money-market lines the pane computes: the rates and balances under
|
|
12
|
+
* them are FRED series in the catalog already.
|
|
13
|
+
*/
|
|
14
|
+
export const MONEY_MARKET_SERIES: readonly SeriesDefinition[] = [
|
|
15
|
+
{
|
|
16
|
+
id: "money-markets:net-liquidity",
|
|
17
|
+
name: "Net liquidity (Fed assets less TGA and reverse repo)",
|
|
18
|
+
unit: "billion USD",
|
|
19
|
+
frequency: "weekly",
|
|
20
|
+
group: "Rates",
|
|
21
|
+
tags: ["liquidity", "Fed balance sheet", "TGA", "RRP", "money markets"],
|
|
22
|
+
load: async () => {
|
|
23
|
+
const resource = await loadMoneyMarkets();
|
|
24
|
+
const warning = cachedSeriesWarning(resource);
|
|
25
|
+
return { points: observations(resource.payload.netLiquidity.history), ...(warning ? { warning } : {}) };
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: "money-markets:bill-slope",
|
|
30
|
+
name: "Treasury bill curve slope (1Y less 4W)",
|
|
31
|
+
unit: "bp",
|
|
32
|
+
frequency: "daily",
|
|
33
|
+
group: "Rates",
|
|
34
|
+
tags: ["bills", "curve", "money markets"],
|
|
35
|
+
load: async () => {
|
|
36
|
+
const resource = await loadMoneyMarkets();
|
|
37
|
+
const warning = cachedSeriesWarning(resource);
|
|
38
|
+
return { points: observations(resource.payload.billsCurve.slope.history), ...(warning ? { warning } : {}) };
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
];
|
|
@@ -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" }] }];
|
|
@@ -3,7 +3,7 @@ import { withCliServices, withConfigData } from "../../../cli/scoped-context";
|
|
|
3
3
|
import { CLI_COMMAND_GROUPS } from "../../../cli/help";
|
|
4
4
|
import { dryRunNote } from "../../../cli/helpers";
|
|
5
5
|
import { requireArg, takeOption } from "../../../cli/commands/command-utils";
|
|
6
|
-
import { EXCHANGE_OPTION, requireListingArg } from "../../../cli/listing-arg";
|
|
6
|
+
import { EXCHANGE_OPTION, listingReadNotes, requireListingArg } from "../../../cli/listing-arg";
|
|
7
7
|
import { createPluginPersistence } from "../../plugin-persistence";
|
|
8
8
|
import type { CliCommandDef } from "../../../types/plugin";
|
|
9
9
|
import { cliStyles } from "../../../utils/cli-output";
|
|
@@ -25,9 +25,14 @@ export const notesCliCommand: CliCommandDef = {
|
|
|
25
25
|
const args = [...rawArgs];
|
|
26
26
|
const exchange = takeOption(args, "--exchange");
|
|
27
27
|
// A note belongs to one listing: SAN:EPA, or SAN with --exchange EPA.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
)
|
|
28
|
+
// What a typed listing was read as (7203:TSE as 7203:JPX) is said beside the note.
|
|
29
|
+
let read: { warnings?: string[] } = {};
|
|
30
|
+
const noteSymbol = async (usage: string) => {
|
|
31
|
+
const listing = await requireListingArg(requireArg(args[1], usage, ctx), exchange, ctx);
|
|
32
|
+
const notes = listingReadNotes(listing);
|
|
33
|
+
if (notes.length > 0) read = { warnings: notes };
|
|
34
|
+
return listing.key;
|
|
35
|
+
};
|
|
31
36
|
await withConfigData(ctx, async (config) => {
|
|
32
37
|
const notes = new NotesFiles(config.dataDir);
|
|
33
38
|
const action = args[0] ?? "list";
|
|
@@ -71,7 +76,7 @@ export const notesCliCommand: CliCommandDef = {
|
|
|
71
76
|
}
|
|
72
77
|
if (action === "show") {
|
|
73
78
|
const symbol = await noteSymbol("Usage: gloomberb notes show <symbol>");
|
|
74
|
-
ctx.printResult({ data: { symbol, text: await notes.load(symbol) } }, {
|
|
79
|
+
ctx.printResult({ data: { symbol, text: await notes.load(symbol) }, ...read }, {
|
|
75
80
|
text: (data) => data.text?.trim() ? data.text.trimEnd() : cliStyles.muted(`No note for ${symbol}.`),
|
|
76
81
|
});
|
|
77
82
|
return;
|
|
@@ -80,7 +85,7 @@ export const notesCliCommand: CliCommandDef = {
|
|
|
80
85
|
const symbol = await noteSymbol("Usage: gloomberb notes set <symbol> <text...>");
|
|
81
86
|
const text = args.slice(2).join(" ");
|
|
82
87
|
if (!ctx.cliOptions.dryRun) await notes.save(symbol, text);
|
|
83
|
-
ctx.printResult({ data: { changed: !ctx.cliOptions.dryRun, dryRun: ctx.cliOptions.dryRun, symbol, bytes: text.length } }, {
|
|
88
|
+
ctx.printResult({ data: { changed: !ctx.cliOptions.dryRun, dryRun: ctx.cliOptions.dryRun, symbol, bytes: text.length }, ...read }, {
|
|
84
89
|
text: (data) => `Saved the note for ${symbol}.${dryRunNote(data.dryRun)}`,
|
|
85
90
|
});
|
|
86
91
|
return;
|
|
@@ -90,7 +95,7 @@ export const notesCliCommand: CliCommandDef = {
|
|
|
90
95
|
// Only picks the message; an unreadable note is still deleted.
|
|
91
96
|
const existed = await notes.load(symbol).then((text) => !!text?.trim(), () => true);
|
|
92
97
|
if (!ctx.cliOptions.dryRun) await notes.delete(symbol);
|
|
93
|
-
ctx.printResult({ data: { changed: !ctx.cliOptions.dryRun, dryRun: ctx.cliOptions.dryRun, symbol } }, {
|
|
98
|
+
ctx.printResult({ data: { changed: !ctx.cliOptions.dryRun, dryRun: ctx.cliOptions.dryRun, symbol }, ...read }, {
|
|
94
99
|
text: (data) => existed
|
|
95
100
|
? `Deleted the note for ${symbol}.${dryRunNote(data.dryRun)}`
|
|
96
101
|
: cliStyles.muted(`No note for ${symbol}.`),
|
|
@@ -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
|
+
}
|