gloomberb 0.17.6 → 0.18.0
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 +2 -0
- package/README.zh-CN.md +2 -0
- package/package.json +6 -1
- package/patches/electrobun@1.18.1.patch +74 -0
- package/src/account/auth-model.ts +3 -2
- package/src/account/device-signin-dialog.tsx +38 -13
- package/src/account/device-signin.ts +2 -1
- package/src/account/upgrade-dialog.tsx +6 -2
- package/src/api-client/askg.ts +5 -3
- package/src/api-client/bank-figures.ts +73 -0
- package/src/api-client/credit-boards.ts +21 -1
- package/src/api-client/crypto-markets.ts +88 -1
- package/src/api-client/data.ts +104 -4
- package/src/api-client/debt-maturities.ts +18 -0
- package/src/api-client/equity-screener.ts +3 -0
- package/src/api-client/errors.ts +13 -0
- package/src/api-client/fund-facts.ts +72 -0
- package/src/api-client/futures-curve.ts +26 -3
- package/src/api-client/geo.ts +11 -1
- package/src/api-client/index.ts +25 -2
- package/src/api-client/insider-signals.ts +95 -11
- package/src/api-client/normalizers.ts +1 -0
- package/src/api-client/paths.ts +20 -1
- package/src/api-client/request.ts +11 -3
- package/src/api-client/research-activity.ts +15 -8
- package/src/api-client/socket.ts +6 -3
- package/src/api-client/supply-chain-graph.ts +2 -2
- package/src/api-client/supply-chain.ts +8 -0
- package/src/api-client/tape.ts +12 -0
- package/src/api-client/types.ts +66 -2
- package/src/api-client/upgrade-experiment.ts +4 -3
- package/src/api-client/wall-experiments.ts +5 -3
- package/src/api-client/wall-summary.ts +3 -1
- package/src/api-client/web-experiments.ts +5 -2
- package/src/api-client/yield-curves.ts +17 -0
- package/src/app/command-bar-intro.ts +38 -0
- package/src/app/keybindings/actions.ts +1 -1
- package/src/app/pane-runtime/pane-template-runtime.ts +35 -7
- package/src/app/pane-runtime/plugin-bindings.ts +4 -0
- package/src/app/pane-runtime/ticker-open-runtime.ts +4 -14
- package/src/app/pane-runtime/ticker-open-target.ts +31 -0
- package/src/app/runtime/desktop-deeplink.ts +3 -4
- package/src/app/runtime/plugin-bindings.ts +3 -2
- package/src/app/runtime/startup.ts +3 -4
- package/src/app/runtime/ticker-refresh.ts +13 -12
- package/src/app/runtime/update.ts +3 -2
- package/src/architecture/core-builtin-allowlist.json +0 -3
- package/src/architecture/silent-catch-allowlist.json +3 -0
- package/src/architecture/ui-literals-allowlist.json +186 -0
- package/src/architecture/ui-tokens-allowlist.json +40 -0
- package/src/ask-gloom/pane-context.ts +3 -1
- package/src/brokers/signed-in/catalog.ts +2 -1
- package/src/brokers/signed-in/client.ts +7 -2
- package/src/brokers/signed-in/sign-in-dialog.tsx +120 -26
- package/src/brokers/signed-in/sign-in.ts +22 -20
- package/src/brokers/sync-broker-instance.ts +2 -1
- package/src/capabilities/chart-series.ts +2 -0
- package/src/capabilities/registry.ts +1 -3
- package/src/cli/bank-section.ts +147 -0
- package/src/cli/base-converter.ts +5 -2
- package/src/cli/board-coins.ts +70 -0
- package/src/cli/commands/fred-series.ts +90 -0
- package/src/cli/commands/market.ts +340 -69
- package/src/cli/commands/news-search.ts +35 -2
- package/src/cli/commands/options-chain.ts +7 -5
- package/src/cli/commands/options-leaps.ts +3 -3
- package/src/cli/commands/overview.ts +78 -29
- package/src/cli/commands/plugins.ts +1 -0
- package/src/cli/commands/search.ts +87 -24
- package/src/cli/commands/system.ts +5 -2
- package/src/cli/commands/ticker.ts +337 -60
- package/src/cli/context.ts +2 -1
- package/src/cli/desktop-pane-shot.ts +11 -3
- package/src/cli/earnings-calendar.ts +2 -1
- package/src/cli/errors.ts +10 -0
- package/src/cli/export-source.ts +18 -3
- package/src/cli/glossary.ts +196 -14
- package/src/cli/history-rows.ts +60 -9
- package/src/cli/index-roots.ts +26 -0
- package/src/cli/index.ts +34 -9
- package/src/cli/known-gaps.ts +156 -22
- package/src/cli/listing-arg.ts +156 -12
- package/src/cli/listing-suggestion.ts +4 -2
- package/src/cli/name-entries.ts +76 -0
- package/src/cli/not-a-ticker.ts +15 -6
- package/src/cli/pane-functions/access-gate.ts +22 -0
- package/src/cli/pane-functions/capabilities.ts +62 -4
- package/src/cli/pane-functions/catalog.ts +94 -39
- package/src/cli/pane-functions/data.ts +6 -5
- package/src/cli/pane-functions/discovery.ts +1 -1
- package/src/cli/pane-functions/dom.ts +3 -3
- package/src/cli/pane-functions/freshness.ts +49 -8
- package/src/cli/pane-functions/function-help.ts +13 -10
- package/src/cli/pane-functions/headless.ts +177 -42
- package/src/cli/pane-functions/index.ts +64 -8
- package/src/cli/pane-functions/options.ts +17 -3
- package/src/cli/pane-functions/report-notices.ts +17 -3
- package/src/cli/pane-functions/resolver.ts +48 -13
- package/src/cli/pane-functions/screenshot.ts +124 -23
- package/src/cli/pane-functions/shot-options.ts +68 -0
- package/src/cli/perpetual-contract.ts +3 -1
- package/src/cli/report-tables.ts +10 -2
- package/src/cli/staged-tickers.ts +5 -0
- package/src/cli/statement-filings.ts +261 -0
- package/src/cli/symbol-args.ts +47 -8
- package/src/cli/symbol-list.ts +9 -2
- package/src/cli/symbol-rows.ts +269 -29
- package/src/cli/ticker-resolution.ts +148 -34
- package/src/cli/treasury-yields.ts +86 -0
- package/src/cli/types.ts +3 -0
- package/src/cli/uncovered-instrument.ts +20 -0
- package/src/components/chart/composite/axis-overlays.tsx +16 -9
- package/src/components/chart/composite/composite-chart.tsx +85 -6
- package/src/components/chart/composite/downsample.ts +19 -3
- package/src/components/chart/composite/format.ts +3 -0
- package/src/components/chart/composite/legend.tsx +155 -76
- package/src/components/chart/composite/panel-bitmap.ts +8 -2
- package/src/components/chart/composite/panel-surface.tsx +3 -3
- package/src/components/chart/composite/toolbar.tsx +12 -7
- package/src/components/chart/composite/types.ts +6 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +28 -1
- package/src/components/chart/curve/curve-surface.tsx +1 -1
- package/src/components/chart/static/series.ts +39 -0
- package/src/components/chart/static/trail-chart-surface.tsx +2 -1
- package/src/components/command-bar/commands/collection-list.ts +45 -15
- package/src/components/command-bar/commands/collection.ts +10 -3
- package/src/components/command-bar/commands/registry.ts +2 -2
- package/src/components/command-bar/list/badge.ts +4 -3
- package/src/components/command-bar/list/model.ts +5 -0
- package/src/components/command-bar/list/view.tsx +1 -1
- package/src/components/command-bar/panel/index.tsx +19 -8
- package/src/components/command-bar/panel/native-surface.ts +6 -4
- package/src/components/command-bar/panel/prompt-example.ts +22 -0
- package/src/components/command-bar/routes/root/provider-search.ts +3 -9
- package/src/components/command-bar/routes/root/results.ts +13 -0
- package/src/components/command-bar/routes/root/start-here.ts +90 -0
- package/src/components/command-bar/routes/ticker-search/results.ts +42 -3
- package/src/components/command-bar/routes/ticker-search/route.ts +3 -10
- package/src/components/command-bar/theme-picker.tsx +3 -1
- package/src/components/command-bar/workflow/builtin.ts +5 -1
- package/src/components/command-bar/workflow/collection-actions.ts +21 -12
- package/src/components/command-bar/workflow/ops.ts +21 -1
- package/src/{plugins/builtin/portfolio-list/command-bar.ts → components/command-bar/workflow/portfolio-position.ts} +42 -9
- package/src/components/command-bar/workflow/tickers.ts +6 -4
- package/src/components/feedback-dialog.tsx +1 -1
- package/src/components/form-modal/broker-step.tsx +7 -63
- package/src/components/form-modal/content.tsx +7 -2
- package/src/components/form-modal/field-row.tsx +6 -8
- package/src/components/form-modal/host.tsx +3 -3
- package/src/components/form-modal/model.ts +3 -0
- package/src/components/form-modal/routes.ts +17 -2
- package/src/components/index.ts +6 -6
- package/src/components/input-search-bar.tsx +43 -6
- package/src/components/layout/detached-pane-shell.tsx +0 -1
- package/src/components/layout/floating-pane.tsx +0 -1
- package/src/components/layout/header.tsx +8 -7
- package/src/components/layout/pane/footer/index.tsx +7 -4
- package/src/components/layout/pane/footer/model.ts +28 -2
- package/src/components/layout/pane/header.tsx +9 -19
- package/src/components/layout/pane/index.tsx +0 -1
- package/src/components/layout/pane/instrument-coverage-gate.tsx +57 -0
- package/src/components/layout/pane/pane-tabs.tsx +4 -3
- package/src/components/layout/pane/sizing.ts +9 -0
- package/src/components/layout/pane/ticker-fate-gate.tsx +8 -2
- package/src/components/layout/shell/pane/capture.ts +44 -20
- package/src/components/layout/status-bar.tsx +3 -6
- package/src/components/markdown-text.tsx +17 -2
- package/src/components/market-board/index.tsx +19 -8
- package/src/components/metric-treemap/heat-surface.tsx +2 -7
- package/src/components/onboarding/account-step/qr-panel.tsx +5 -2
- package/src/components/onboarding/onboarding-frame.tsx +24 -21
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +20 -10
- package/src/components/onboarding/wizard-positions.ts +40 -11
- package/src/components/pane-settings-dialog/desktop.tsx +12 -50
- package/src/components/pane-settings-dialog/field-dialogs.tsx +1 -1
- package/src/components/price-performance.tsx +18 -2
- package/src/components/reader/article-reader.tsx +11 -10
- package/src/components/reader/detail-reader.tsx +9 -5
- package/src/components/reader/reader-text.tsx +51 -24
- package/src/components/sign-in-code-panel.tsx +129 -75
- package/src/components/ticker/badge/index.tsx +2 -1
- package/src/components/ui/action-row.tsx +5 -2
- package/src/components/ui/audio-player.tsx +70 -0
- package/src/components/ui/card.tsx +75 -0
- package/src/components/ui/data-table/index.tsx +4 -2
- package/src/components/ui/data-table/types.ts +11 -0
- package/src/components/ui/detail-scroll-body.tsx +1 -1
- package/src/components/ui/dialog-actions.tsx +1 -21
- package/src/components/ui/display.tsx +13 -5
- package/src/components/ui/external-link.tsx +4 -2
- package/src/components/ui/fields.tsx +12 -0
- package/src/components/ui/figure.tsx +5 -3
- package/src/components/ui/frame.tsx +40 -6
- package/src/components/ui/icon.tsx +4 -0
- package/src/components/ui/index.ts +4 -1
- package/src/components/ui/list-view.tsx +8 -0
- package/src/components/ui/prose.tsx +97 -25
- package/src/components/ui/query-bar-keys.tsx +3 -1
- package/src/components/ui/query-bar.tsx +6 -0
- package/src/components/ui/quote.ts +42 -0
- package/src/components/ui/range-track.tsx +15 -2
- package/src/components/ui/reveal-in-scroll-box.ts +21 -3
- package/src/components/ui/select-button.tsx +38 -3
- package/src/components/ui/status.tsx +73 -4
- package/src/components/ui/table-layout.ts +20 -0
- package/src/components/use-pinned-moment.ts +19 -0
- package/src/core/app-runtime.ts +2 -2
- package/src/core/state/app/instrument.ts +18 -1
- package/src/core/state/app/layout.ts +6 -0
- package/src/core/state/app/state.ts +14 -2
- package/src/data/cached-query.ts +1 -1
- package/src/data/config/chart-settings.ts +3 -1
- package/src/data/config/home.ts +4 -1
- package/src/data/config/store/node.ts +9 -4
- package/src/data/config/store/normalize.ts +9 -0
- package/src/data/json-storage.ts +6 -3
- package/src/data/json-ticker-repository.ts +3 -1
- package/src/data/plugin-cache.ts +5 -1
- package/src/data/sqlite/json.ts +3 -1
- package/src/data/ticker-repository.ts +5 -2
- package/src/feedback/diagnostics.ts +2 -6
- package/src/i18n/es.ts +86 -6
- package/src/i18n/index.ts +3 -9
- package/src/i18n/ja.ts +86 -6
- package/src/i18n/ko.ts +86 -6
- package/src/i18n/zh-cn.ts +86 -6
- package/src/i18n/zh-tw.ts +86 -6
- package/src/layout-marketplace/gallery-desktop.tsx +8 -4
- package/src/market-data/bars-per-year.ts +43 -0
- package/src/market-data/bond-funds.ts +85 -0
- package/src/market-data/coordinator/auxiliary.ts +5 -2
- package/src/market-data/coordinator/index.ts +6 -5
- package/src/market-data/futures-contract.ts +102 -5
- package/src/market-data/hooks.tsx +20 -11
- package/src/market-data/market/bar-period.ts +36 -0
- package/src/market-data/market/format.ts +5 -13
- package/src/market-data/market/freshness.ts +1 -3
- package/src/market-data/market/index-level.ts +51 -0
- package/src/market-data/model-dividend-yield.ts +57 -16
- package/src/market-data/quotes/live-valuation.ts +48 -2
- package/src/market-data/realized-volatility.ts +16 -7
- package/src/market-data/tax-equivalent.ts +344 -0
- package/src/news/aggregator.ts +4 -2
- package/src/notifications/notification-log.ts +5 -3
- package/src/plugins/auto-update-node.ts +1 -0
- package/src/plugins/builtin/account-management/footer.ts +1 -1
- 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/pane.tsx +71 -19
- package/src/plugins/builtin/account-management/trial-cancel.ts +40 -0
- package/src/plugins/builtin/alerts/cli.ts +7 -18
- package/src/plugins/builtin/alerts/constants.ts +8 -0
- package/src/plugins/builtin/alerts/event-rows.ts +16 -0
- package/src/plugins/builtin/alerts/events-pane.tsx +2 -14
- package/src/plugins/builtin/alerts/headless.ts +182 -0
- package/src/plugins/builtin/alerts/index.tsx +3 -0
- package/src/plugins/builtin/alerts/pane.tsx +1 -7
- package/src/plugins/builtin/alerts/storage.ts +17 -1
- package/src/plugins/builtin/analytics/index.tsx +6 -1
- package/src/plugins/builtin/analytics/metrics.ts +47 -9
- package/src/plugins/builtin/analytics/risk-headless.ts +14 -2
- package/src/plugins/builtin/analytics/risk-math.ts +83 -0
- package/src/plugins/builtin/analytics/risk-model.ts +97 -4
- package/src/plugins/builtin/analytics/risk-pane.tsx +11 -6
- package/src/plugins/builtin/analytics/sector-model.ts +14 -3
- package/src/plugins/builtin/awards/headless.ts +6 -5
- package/src/plugins/builtin/awards/index.tsx +1 -1
- package/src/plugins/builtin/backtest/client.ts +38 -8
- package/src/plugins/builtin/backtest/engine.ts +25 -13
- package/src/plugins/builtin/backtest/export.ts +27 -0
- package/src/plugins/builtin/backtest/format.ts +19 -3
- package/src/plugins/builtin/backtest/headless.ts +42 -28
- package/src/plugins/builtin/backtest/index.tsx +3 -0
- package/src/plugins/builtin/backtest/pane.tsx +39 -10
- package/src/plugins/builtin/backtest/report.ts +160 -0
- package/src/plugins/builtin/backtest/rules.ts +2 -0
- package/src/plugins/builtin/backtest/window.ts +112 -0
- package/src/plugins/builtin/bond-calculator/headless.ts +3 -2
- package/src/plugins/builtin/broker-manager/add-flow.tsx +4 -4
- package/src/plugins/builtin/catalysts/headless.ts +24 -13
- package/src/plugins/builtin/catalysts/index.tsx +4 -2
- package/src/plugins/builtin/catalysts/model.ts +18 -1
- package/src/plugins/builtin/catalysts/pane.tsx +2 -2
- package/src/plugins/builtin/cds/client.ts +28 -5
- package/src/plugins/builtin/cds/headless.ts +183 -31
- package/src/plugins/builtin/cds/index.tsx +1 -1
- package/src/plugins/builtin/cds/model.ts +229 -53
- package/src/plugins/builtin/cds/pane.tsx +82 -26
- package/src/plugins/builtin/central-bank-rates/headless.ts +1 -1
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +39 -1
- package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +77 -0
- package/src/plugins/builtin/chart-composer/chart-spec.ts +15 -0
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +22 -2
- package/src/plugins/builtin/chart-composer/editor/desktop-view.tsx +2 -2
- package/src/plugins/builtin/chart-composer/headless-schema.ts +10 -2
- package/src/plugins/builtin/chart-composer/headless.ts +99 -21
- package/src/plugins/builtin/chart-composer/index.tsx +70 -13
- package/src/plugins/builtin/chart-composer/pane.tsx +65 -15
- package/src/plugins/builtin/chart-composer/presets.ts +79 -11
- package/src/plugins/builtin/chart-composer/series-catalog.ts +50 -14
- package/src/plugins/builtin/chart-composer/series-expression.ts +9 -7
- package/src/plugins/builtin/chart-composer/series-listings.ts +178 -0
- package/src/plugins/builtin/chart-composer/session-range.ts +87 -0
- package/src/plugins/builtin/chat/attachments/desktop.tsx +4 -1
- package/src/plugins/builtin/chat/content/composer-runtime.ts +49 -14
- package/src/plugins/builtin/chat/content/composer.tsx +22 -1
- package/src/plugins/builtin/chat/content/index.tsx +35 -5
- package/src/plugins/builtin/chat/content/layout-metrics.ts +3 -0
- package/src/plugins/builtin/chat/content/shortcuts.ts +32 -13
- package/src/plugins/builtin/chat/content/snapshot.ts +29 -6
- package/src/plugins/builtin/chat/ghost-user.ts +11 -3
- package/src/plugins/builtin/chat/layout.ts +2 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +13 -5
- package/src/plugins/builtin/chat/message/header.tsx +26 -4
- package/src/plugins/builtin/chat/message/pane-chip.tsx +131 -35
- package/src/plugins/builtin/chat/message/render-state.ts +28 -1
- package/src/plugins/builtin/chat/message/terminal.tsx +9 -3
- package/src/plugins/builtin/chat/pane-links/composer.ts +87 -0
- package/src/plugins/builtin/chat/pane-links/model.ts +1 -1
- package/src/plugins/builtin/chat/share/flow.tsx +9 -73
- package/src/plugins/builtin/cloud/askg/controller.ts +5 -3
- package/src/plugins/builtin/cloud/askg/executor.ts +3 -1
- package/src/plugins/builtin/cloud/askg/lock-note.ts +16 -0
- package/src/plugins/builtin/cloud/askg/pane.tsx +6 -2
- package/src/plugins/builtin/cloud/auth-actions.tsx +4 -2
- package/src/plugins/builtin/cloud/company-picker.tsx +21 -26
- package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +5 -3
- package/src/plugins/builtin/cloud/plugin.tsx +2 -0
- package/src/plugins/builtin/cloud/team/module.tsx +5 -1
- package/src/plugins/builtin/cloud/team/pane.tsx +11 -4
- package/src/plugins/builtin/cloud/team/views.ts +11 -4
- package/src/plugins/builtin/cloud/terminal-relay/engine.ts +9 -4
- package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +3 -2
- package/src/plugins/builtin/cloud/thesis/detail.tsx +2 -1
- package/src/plugins/builtin/cloud/thesis/exposure.ts +3 -0
- package/src/plugins/builtin/cloud/thesis/prompts.tsx +3 -2
- package/src/plugins/builtin/cloud/thesis/ticker-tab.tsx +2 -1
- package/src/plugins/builtin/cloud/trial-offer-status-widget.tsx +2 -1
- package/src/plugins/builtin/cloud/verification-status-widget.tsx +2 -1
- package/src/plugins/builtin/commodities-energy/index.tsx +8 -5
- package/src/plugins/builtin/commodities-energy/view-state.ts +11 -0
- package/src/plugins/builtin/company-attention/headless.ts +15 -7
- package/src/plugins/builtin/company-attention/index.tsx +1 -1
- package/src/plugins/builtin/company-attention/model.ts +49 -4
- package/src/plugins/builtin/company-attention/pane.tsx +11 -9
- package/src/plugins/builtin/company-kpis/headless.ts +4 -3
- package/src/plugins/builtin/company-kpis/index.tsx +2 -2
- package/src/plugins/builtin/company-kpis/pane.tsx +9 -3
- package/src/plugins/builtin/congress-trades/headless.ts +23 -2
- package/src/plugins/builtin/correlation/relationship/pane.tsx +18 -46
- package/src/plugins/builtin/cot/headless.ts +5 -2
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +41 -13
- package/src/plugins/builtin/credit-boards/client.ts +9 -2
- package/src/plugins/builtin/credit-boards/headless.ts +93 -27
- package/src/plugins/builtin/credit-boards/index.tsx +15 -4
- package/src/plugins/builtin/credit-boards/model.ts +105 -6
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +14 -3
- package/src/plugins/builtin/credit-documents/detail.tsx +2 -1
- package/src/plugins/builtin/credit-documents/index.tsx +3 -0
- package/src/plugins/builtin/credit-documents/model.ts +3 -10
- package/src/plugins/builtin/crypto-board/client.ts +152 -2
- package/src/plugins/builtin/crypto-board/headless.ts +138 -19
- package/src/plugins/builtin/crypto-board/index.tsx +5 -3
- package/src/plugins/builtin/crypto-board/model.ts +210 -12
- package/src/plugins/builtin/crypto-board/pane.tsx +148 -9
- package/src/plugins/builtin/crypto-board/series.ts +52 -1
- package/src/plugins/builtin/crypto-board/supply.ts +123 -0
- package/src/plugins/builtin/debt-maturities/client.ts +54 -1
- package/src/plugins/builtin/debt-maturities/headless.ts +27 -3
- package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
- package/src/plugins/builtin/debt-maturities/model.ts +58 -13
- package/src/plugins/builtin/debt-maturities/pane.tsx +47 -7
- package/src/plugins/builtin/dividend-yield/client.ts +42 -36
- package/src/plugins/builtin/dividend-yield/headless.ts +113 -18
- package/src/plugins/builtin/dividend-yield/index.tsx +5 -2
- package/src/plugins/builtin/dividend-yield/pane.tsx +37 -13
- package/src/plugins/builtin/dividend-yield/provider-client.ts +7 -3
- package/src/plugins/builtin/dividend-yield/ranking.ts +187 -0
- package/src/plugins/builtin/dividend-yield/reference-price.ts +28 -5
- package/src/plugins/builtin/dividend-yield/types.ts +6 -1
- package/src/plugins/builtin/dividend-yield/view.ts +1 -1
- package/src/plugins/builtin/docs/blocks.tsx +54 -8
- package/src/plugins/builtin/docs/pane.tsx +8 -13
- package/src/plugins/builtin/earnings/headless.ts +3 -2
- package/src/plugins/builtin/earnings-calls/data.ts +51 -0
- package/src/plugins/builtin/earnings-calls/headless.ts +7 -0
- package/src/plugins/builtin/earnings-calls/index.tsx +1 -0
- package/src/plugins/builtin/earnings-calls/model.ts +97 -0
- package/src/plugins/builtin/earnings-calls/pane.tsx +107 -7
- package/src/plugins/builtin/earnings-calls/transcript-view.tsx +140 -22
- package/src/plugins/builtin/earnings-calls/use-call-playback.ts +194 -0
- package/src/plugins/builtin/econ/calendar-model.ts +22 -0
- package/src/plugins/builtin/econ/calendar-source.ts +35 -0
- package/src/plugins/builtin/econ/index.tsx +40 -8
- package/src/plugins/builtin/econ-statistics/defs.ts +7 -0
- package/src/plugins/builtin/econ-statistics/detail.tsx +8 -1
- package/src/plugins/builtin/econ-statistics/headless.ts +26 -5
- package/src/plugins/builtin/econ-statistics/pane.tsx +4 -2
- package/src/plugins/builtin/econ-statistics/stats.ts +10 -0
- package/src/plugins/builtin/econ-statistics/view.ts +19 -0
- package/src/plugins/builtin/equity-screener/client.ts +1 -1
- package/src/plugins/builtin/equity-screener/model.ts +46 -4
- package/src/plugins/builtin/equity-screener/pane.tsx +3 -0
- package/src/plugins/builtin/estimate-revisions/client.ts +32 -22
- package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
- package/src/plugins/builtin/estimate-revisions/index.tsx +1 -0
- package/src/plugins/builtin/estimate-revisions/pane.tsx +5 -3
- package/src/plugins/builtin/executives/index.tsx +1 -0
- package/src/plugins/builtin/exposure/editor.tsx +3 -3
- package/src/plugins/builtin/fear-greed/index.tsx +9 -0
- package/src/plugins/builtin/filing-events/index.tsx +1 -0
- package/src/plugins/builtin/futures/index.tsx +2 -2
- package/src/plugins/builtin/futures/model.ts +34 -21
- package/src/plugins/builtin/futures/table.tsx +1 -1
- package/src/plugins/builtin/futures/use-board-terms.ts +2 -2
- package/src/plugins/builtin/futures-curve/headless.ts +4 -2
- package/src/plugins/builtin/futures-curve/model.ts +5 -7
- package/src/plugins/builtin/help/index.tsx +55 -8
- package/src/plugins/builtin/help/shortcut-table.tsx +15 -2
- package/src/plugins/builtin/holders/headless.ts +12 -0
- package/src/plugins/builtin/insider/headless.ts +311 -41
- package/src/plugins/builtin/insider/index.tsx +280 -106
- package/src/plugins/builtin/insider/insiders.tsx +224 -0
- package/src/plugins/builtin/insider/signals-cells.tsx +52 -0
- package/src/plugins/builtin/insider/signals-client.ts +135 -11
- package/src/plugins/builtin/insider/signals-model.ts +628 -56
- package/src/plugins/builtin/insider/signals.tsx +283 -83
- package/src/plugins/builtin/ipo-calendar/headless.ts +17 -7
- package/src/plugins/builtin/ipo-calendar/index.tsx +23 -3
- package/src/plugins/builtin/ipo-calendar/model.ts +84 -36
- package/src/plugins/builtin/ipo-calendar/pane.tsx +20 -8
- package/src/plugins/builtin/iv-history/headless.ts +2 -0
- package/src/plugins/builtin/jobs/headless.ts +1 -0
- package/src/plugins/builtin/jobs/index.tsx +1 -0
- package/src/plugins/builtin/jodi/headless.ts +2 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
- package/src/plugins/builtin/kelly-sizer/portfolio.ts +1 -1
- package/src/plugins/builtin/market-heatmap/headless.ts +1 -0
- package/src/plugins/builtin/market-heatmap/portfolio.ts +3 -1
- package/src/plugins/builtin/market-valuation/pane.tsx +1 -1
- package/src/plugins/builtin/market-valuation/zone-scale/desktop.tsx +31 -57
- package/src/plugins/builtin/mna/distress/headless.ts +2 -1
- package/src/plugins/builtin/mna/headless.ts +14 -2
- package/src/plugins/builtin/mna/index.tsx +1 -0
- package/src/plugins/builtin/news/headless.ts +4 -0
- package/src/plugins/builtin/news/wire/news/footer.ts +5 -3
- package/src/plugins/builtin/news/wire/news/table.tsx +57 -11
- package/src/plugins/builtin/notes/cli.ts +8 -4
- package/src/plugins/builtin/notes/files.ts +66 -20
- package/src/plugins/builtin/notes/migration.ts +18 -6
- package/src/plugins/builtin/notes/owner.tsx +3 -2
- package/src/plugins/builtin/notes/quick-notes-pane.tsx +3 -2
- package/src/plugins/builtin/options-scenario/client.ts +7 -4
- package/src/plugins/builtin/options-scenario/headless.ts +5 -3
- package/src/plugins/builtin/pe-band/index.tsx +1 -1
- package/src/plugins/builtin/pe-band/model.ts +1 -15
- package/src/plugins/builtin/perps/headless.ts +30 -13
- package/src/plugins/builtin/perps/model.ts +45 -3
- package/src/plugins/builtin/perps/pane.tsx +7 -7
- package/src/plugins/builtin/portfolio-list/cell-version.ts +10 -4
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +128 -14
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +108 -46
- package/src/plugins/builtin/portfolio-list/cli/render.ts +368 -45
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +8 -2
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +24 -34
- package/src/plugins/builtin/portfolio-list/grid.tsx +3 -1
- package/src/plugins/builtin/portfolio-list/headless.ts +151 -29
- package/src/plugins/builtin/portfolio-list/income.ts +296 -0
- package/src/plugins/builtin/portfolio-list/metrics.ts +2 -2
- package/src/plugins/builtin/portfolio-list/pane/futures-terms.ts +58 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +27 -10
- package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +47 -28
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +3 -2
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +10 -3
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +26 -4
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +31 -3
- package/src/plugins/builtin/portfolio-list/table.tsx +25 -5
- package/src/plugins/builtin/power/prices-headless.ts +2 -1
- package/src/plugins/builtin/realized-vol/chart-model.ts +29 -5
- package/src/plugins/builtin/realized-vol/charts.tsx +14 -8
- package/src/plugins/builtin/realized-vol/evidence.ts +2 -0
- package/src/plugins/builtin/realized-vol/headless.ts +6 -4
- package/src/plugins/builtin/realized-vol/model.ts +5 -1
- package/src/plugins/builtin/realized-vol/pane.tsx +31 -11
- package/src/plugins/builtin/realized-vol/settings.ts +1 -1
- package/src/plugins/builtin/research/analyst-headless.ts +4 -0
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +2 -0
- package/src/plugins/builtin/research/event-model.ts +22 -2
- package/src/plugins/builtin/research/headless-schema.ts +1 -0
- package/src/plugins/builtin/research/headless.ts +3 -0
- package/src/plugins/builtin/research/index.tsx +3 -0
- package/src/plugins/builtin/research/relative-valuation-columns.ts +27 -5
- package/src/plugins/builtin/research/relative-valuation-headless.ts +2 -0
- package/src/plugins/builtin/revenue-breakdown/index.tsx +1 -0
- package/src/plugins/builtin/reverse-dcf/headless.ts +9 -6
- package/src/plugins/builtin/reverse-dcf/index.tsx +2 -2
- package/src/plugins/builtin/reverse-dcf/model.ts +51 -4
- package/src/plugins/builtin/reverse-dcf/pane.tsx +23 -10
- package/src/plugins/builtin/risk-factors/headless.ts +7 -0
- package/src/plugins/builtin/risk-factors/index.tsx +1 -0
- package/src/plugins/builtin/scanner/feed.ts +5 -3
- package/src/plugins/builtin/scanner/headless.ts +9 -57
- package/src/plugins/builtin/scanner/index.ts +1 -2
- package/src/plugins/builtin/sec/forms.ts +2 -6
- package/src/plugins/builtin/sec/fund-facts-view.tsx +53 -0
- package/src/plugins/builtin/sec/fund-facts.ts +328 -0
- package/src/plugins/builtin/sec/headless.ts +140 -44
- package/src/plugins/builtin/sec/index.tsx +95 -30
- package/src/plugins/builtin/sec/model.ts +2 -44
- package/src/plugins/builtin/shared/headless-options.ts +10 -0
- package/src/plugins/builtin/shared/locked-rows.tsx +3 -1
- package/src/plugins/builtin/shared/move-rank.ts +108 -0
- package/src/plugins/builtin/shared/report-freshness.ts +25 -9
- package/src/plugins/builtin/shared/scanner-capture.ts +95 -0
- package/src/plugins/builtin/shared/treasury-cutoffs.ts +15 -0
- package/src/plugins/builtin/shared/use-quote-board.ts +1 -0
- package/src/plugins/builtin/shared/volatility/live-session.ts +34 -0
- package/src/plugins/builtin/shared/volatility-indices.ts +32 -0
- package/src/plugins/builtin/short-interest/headless.ts +3 -0
- package/src/plugins/builtin/short-interest/watch-model.ts +2 -2
- package/src/plugins/builtin/social-mentions/client.ts +8 -1
- package/src/plugins/builtin/social-mentions/pane.tsx +8 -6
- package/src/plugins/builtin/supply-chain/client.ts +12 -3
- package/src/plugins/builtin/supply-chain/disclosure-quote.tsx +9 -5
- package/src/plugins/builtin/supply-chain/evidence.ts +3 -1
- package/src/plugins/builtin/supply-chain/flow-layout.ts +2 -1
- package/src/plugins/builtin/supply-chain/flow.tsx +23 -16
- package/src/plugins/builtin/supply-chain/graph-client.ts +8 -5
- package/src/plugins/builtin/supply-chain/graph-evidence.ts +1 -1
- package/src/plugins/builtin/supply-chain/graph-model.ts +10 -2
- package/src/plugins/builtin/supply-chain/graph-pane.tsx +9 -7
- package/src/plugins/builtin/supply-chain/graph.tsx +8 -6
- package/src/plugins/builtin/supply-chain/headless.ts +69 -27
- package/src/plugins/builtin/supply-chain/index.tsx +1 -1
- package/src/plugins/builtin/supply-chain/model.ts +76 -15
- package/src/plugins/builtin/supply-chain/pane.tsx +29 -15
- package/src/plugins/builtin/supply-chain/row-evidence.tsx +5 -4
- package/src/plugins/builtin/themes/model.ts +2 -5
- package/src/plugins/builtin/thirteenf/api.ts +50 -2
- package/src/plugins/builtin/thirteenf/data.ts +250 -11
- package/src/plugins/builtin/thirteenf/headless.ts +311 -28
- package/src/plugins/builtin/thirteenf/index.tsx +4 -1
- package/src/plugins/builtin/thirteenf/model.ts +244 -19
- package/src/plugins/builtin/thirteenf/overlap-pane.tsx +133 -33
- package/src/plugins/builtin/thirteenf/overlap.ts +1 -1
- package/src/plugins/builtin/thirteenf/pane.tsx +24 -5
- package/src/plugins/builtin/thirteenf/report-notes.ts +78 -0
- package/src/plugins/builtin/thirteenf/types.ts +49 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +22 -8
- package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +17 -1
- package/src/plugins/builtin/ticker-detail/financials/model.ts +2 -42
- package/src/plugins/builtin/ticker-detail/financials/tab.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/headless.ts +23 -10
- package/src/plugins/builtin/ticker-detail/overview/components.tsx +27 -3
- package/src/plugins/builtin/ticker-detail/overview/dividend.ts +60 -0
- package/src/plugins/builtin/ticker-detail/overview/model.ts +46 -9
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +3 -0
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +36 -3
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +18 -19
- package/src/plugins/builtin/time-sales/client.ts +7 -4
- package/src/plugins/builtin/time-sales/headless.ts +71 -22
- package/src/plugins/builtin/time-sales/model.ts +12 -0
- package/src/plugins/builtin/time-sales/pane.tsx +31 -7
- package/src/plugins/builtin/time-sales/window.ts +128 -0
- package/src/plugins/builtin/trace-bonds/client.ts +351 -33
- package/src/plugins/builtin/trace-bonds/headless.ts +60 -22
- package/src/plugins/builtin/trace-bonds/index.tsx +4 -2
- package/src/plugins/builtin/trace-bonds/model.ts +27 -25
- package/src/plugins/builtin/trace-bonds/pane.tsx +63 -45
- package/src/plugins/builtin/treasury-auctions/cache.ts +61 -15
- package/src/plugins/builtin/treasury-auctions/client.ts +45 -10
- package/src/plugins/builtin/treasury-auctions/headless.ts +35 -13
- package/src/plugins/builtin/treasury-auctions/index.tsx +5 -2
- package/src/plugins/builtin/treasury-auctions/model.ts +20 -16
- package/src/plugins/builtin/treasury-auctions/pane.tsx +29 -12
- package/src/plugins/builtin/vol-surface/charts.tsx +2 -1
- package/src/plugins/builtin/vol-surface/headless.ts +3 -2
- package/src/plugins/builtin/vol-surface/pane.tsx +2 -1
- package/src/plugins/builtin/vol-surface/stored.ts +4 -7
- package/src/plugins/builtin/volatility/chart-model.ts +16 -15
- package/src/plugins/builtin/volatility/charts.tsx +5 -5
- package/src/plugins/builtin/volatility/client.ts +73 -2
- package/src/plugins/builtin/volatility/evidence.ts +13 -14
- package/src/plugins/builtin/volatility/headless.ts +13 -7
- package/src/plugins/builtin/volatility/index.tsx +1 -1
- package/src/plugins/builtin/volatility/model.ts +104 -38
- package/src/plugins/builtin/volatility/pane.tsx +42 -24
- package/src/plugins/builtin/volatility/series.ts +22 -13
- package/src/plugins/builtin/world-venue-map/geo-series.ts +9 -0
- package/src/plugins/builtin/world-venue-map/headless.ts +8 -5
- package/src/plugins/builtin/world-venue-map/index.ts +16 -2
- package/src/plugins/builtin/world-venue-map/map.tsx +13 -17
- package/src/plugins/builtin/yield-curve/curves.ts +29 -5
- package/src/plugins/builtin/yield-curve/headless.ts +41 -8
- package/src/plugins/builtin/yield-curve/history.ts +5 -5
- package/src/plugins/builtin/yield-curve/index.tsx +30 -13
- package/src/plugins/compat.ts +3 -1
- package/src/plugins/dependencies.ts +8 -2
- package/src/plugins/host-link.ts +12 -5
- package/src/plugins/installer.ts +16 -7
- package/src/plugins/loader.ts +9 -2
- package/src/plugins/marketplace/activation.ts +10 -4
- package/src/plugins/registry/host-actions.ts +3 -0
- package/src/plugins/registry/index.ts +3 -1
- package/src/{plugins/builtin/portfolio-list → portfolio}/allocation.ts +74 -12
- package/src/{plugins/builtin/portfolio-list → portfolio}/column-values.ts +140 -53
- package/src/portfolio/futures-positions.ts +213 -0
- package/src/portfolio/futures-terms.ts +75 -0
- package/src/portfolio/manual-lots.ts +78 -0
- package/src/portfolio/mutations.ts +54 -10
- package/src/portfolio/position-metrics.ts +44 -10
- package/src/portfolio/valuation-basis.ts +31 -4
- package/src/public/__snapshots__/public-api.test.ts.snap +4 -0
- package/src/public/time-series.ts +2 -1
- package/src/remote/confirm-change.tsx +2 -1
- package/src/remote/server.ts +1 -1
- package/src/remote/watchlist.ts +9 -1
- package/src/renderers/dom/data-table/row.tsx +1 -1
- package/src/renderers/dom/desktop/audio-player.tsx +312 -0
- package/src/renderers/dom/desktop/control-styles.ts +17 -82
- package/src/renderers/dom/desktop/controls.tsx +39 -63
- package/src/renderers/dom/desktop/dialog-actions.tsx +13 -53
- package/src/renderers/dom/desktop/icons.tsx +8 -0
- package/src/renderers/dom/desktop/list-view.tsx +6 -6
- package/src/renderers/dom/desktop/popover.tsx +0 -3
- package/src/renderers/dom/desktop/query-bar.tsx +6 -4
- package/src/renderers/dom/desktop/select-field.tsx +9 -8
- package/src/renderers/dom/desktop/stack-header.ts +3 -0
- package/src/renderers/dom/dom-ui-host.tsx +3 -2
- package/src/renderers/dom/host/chart-surface.tsx +3 -3
- package/src/renderers/dom/host/size-observer.ts +33 -4
- package/src/renderers/dom/host/surface-3d.tsx +3 -2
- package/src/renderers/dom/host/surface-fit.ts +4 -1
- package/src/renderers/dom/host/tabs.tsx +22 -132
- package/src/renderers/dom/styles.css +358 -160
- package/src/renderers/electrobun/bun/core-capabilities.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/backend.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +1 -0
- package/src/renderers/electrobun/bun/desktop/state-broadcaster.ts +43 -1
- package/src/renderers/electrobun/bun/desktop/workspace/requests.ts +5 -1
- package/src/renderers/electrobun/shared/rpc-codec.ts +7 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +21 -17
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +3 -3
- package/src/renderers/electrobun/view/desktop/window/bridge.ts +6 -8
- package/src/renderers/electrobun/view/desktop/window/snapshot.ts +18 -0
- package/src/series/capability.ts +1 -0
- package/src/series/files.ts +9 -3
- package/src/series/registry.ts +40 -14
- package/src/series/resolve.ts +121 -18
- package/src/series/standalone.ts +3 -2
- package/src/series/types.ts +55 -1
- package/src/series/validate.ts +39 -0
- package/src/shares/api.ts +26 -7
- package/src/shares/bug-report-dialog.tsx +2 -2
- package/src/shares/bug-report-flow.tsx +4 -7
- package/src/shares/capture-flow.ts +5 -4
- package/src/shares/capture-preview.tsx +2 -2
- package/src/shares/chat.ts +7 -27
- package/src/shares/flow.tsx +86 -40
- package/src/shares/location.ts +1 -3
- package/src/shares/pane-image.ts +11 -9
- package/src/shares/pane.ts +5 -2
- package/src/shares/payload.ts +1 -1
- package/src/shares/personal-pane.ts +3 -3
- package/src/shares/portable-layout.ts +9 -2
- package/src/shares/ready.ts +42 -0
- package/src/shares/test-harness.ts +62 -0
- package/src/sources/gloomberb-cloud/batched-lookups.ts +73 -0
- package/src/sources/gloomberb-cloud/index.ts +64 -12
- package/src/sources/gloomberb-cloud/normalizers.ts +31 -2
- package/src/sources/gloomberb-cloud/perpetuals.ts +20 -1
- package/src/sources/history-omitted.ts +34 -0
- package/src/sources/history-result.ts +3 -0
- package/src/sources/history-retention.ts +1 -1
- package/src/sources/provider-errors.ts +43 -1
- package/src/sources/provider-router/batches.ts +3 -2
- package/src/sources/provider-router/cache.ts +2 -1
- package/src/sources/provider-router/cached-routes.ts +9 -3
- package/src/sources/provider-router/history.ts +9 -8
- package/src/sources/provider-router/index.ts +18 -3
- package/src/sources/provider-router/primary.ts +5 -4
- package/src/sources/provider-router/quote-route.ts +3 -1
- package/src/sources/provider-router/routing.ts +2 -1
- package/src/sources/provider-router/search.ts +47 -13
- package/src/sources/provider-router/streaming.ts +7 -4
- package/src/sources/sec-edgar.ts +1 -3
- package/src/state/app/context/index.tsx +9 -13
- package/src/state/app/tab-cursor.ts +149 -12
- package/src/state/hooks/quote-streaming.ts +3 -2
- package/src/state/hooks/session-snapshot.ts +3 -2
- package/src/state/persist-scheduler.ts +12 -4
- package/src/sync/controller.ts +22 -1
- package/src/sync/core-contributors.ts +58 -15
- package/src/team/collections-sync.ts +14 -4
- package/src/team/collections.ts +40 -11
- package/src/team/store.ts +5 -4
- package/src/telemetry/attention-counts.ts +8 -2
- package/src/telemetry/crash-reports-dom.ts +3 -0
- package/src/telemetry/crash-reports-node.ts +7 -4
- package/src/telemetry/crash-reports.ts +11 -11
- package/src/telemetry/usage-counts.ts +16 -12
- package/src/theme/colors.ts +2 -0
- package/src/theme/font-scale.ts +2 -0
- package/src/theme/ui-tokens.ts +71 -0
- package/src/tickers/batched-lookups.ts +186 -0
- package/src/tickers/company-name-listing.ts +97 -0
- package/src/tickers/company-name.ts +13 -0
- package/src/tickers/instrument-coverage.ts +112 -0
- package/src/tickers/listing-fate.ts +49 -9
- package/src/tickers/listing-venues.ts +24 -5
- package/src/tickers/open-target.ts +13 -5
- package/src/tickers/search/index.ts +112 -35
- package/src/tickers/search/ranking.ts +49 -1
- package/src/tickers/terminal-codes.ts +79 -0
- package/src/tickers/ticker-changes.ts +74 -3
- package/src/tickers/us-listing.ts +2 -1
- package/src/time-series/chart-data.ts +79 -8
- package/src/time-series/fundamentals.ts +55 -7
- package/src/time-series/ice-credit.ts +17 -2
- package/src/time-series/live-bars.ts +21 -8
- package/src/time-series/live-quotes.ts +2 -3
- package/src/time-series/price-comparison.ts +6 -1
- package/src/time-series/resolve.ts +65 -10
- package/src/time-series/spec.ts +2 -1
- package/src/time-series/studies.ts +3 -3
- package/src/time-series/types.ts +22 -0
- package/src/time-series/use-chart-resolution.ts +2 -1
- package/src/types/config.ts +7 -0
- package/src/types/data-provider.ts +20 -0
- package/src/types/headless.ts +142 -1
- package/src/types/instrument.ts +6 -0
- package/src/types/plugin.ts +32 -9
- package/src/types/price-history.ts +5 -0
- package/src/types/ticker-changes.ts +19 -0
- package/src/types/ticker.ts +10 -2
- package/src/ui/context-menu.tsx +2 -0
- package/src/ui/host.tsx +40 -4
- package/src/ui/measured-cells.ts +13 -7
- package/src/ui/qr.ts +7 -5
- package/src/updater/index.ts +5 -5
- package/src/utils/calendar-date.ts +86 -27
- package/src/utils/currency-units.ts +17 -0
- package/src/utils/debug-log.ts +1 -1
- package/src/utils/dividend-cash.ts +48 -0
- package/src/utils/dom-screenshot-rasters.ts +3 -1
- package/src/utils/dom-screenshot.ts +14 -10
- package/src/utils/exchange-rate-snapshot.ts +9 -4
- package/src/utils/external-url.ts +1 -0
- package/src/utils/fiscal-period.ts +47 -0
- package/src/utils/format.ts +5 -2
- package/src/utils/forward-dividend.ts +160 -11
- package/src/utils/futures-generic.ts +34 -8
- package/src/utils/http-proxy-response.ts +2 -1
- package/src/utils/local-utc-offset.ts +2 -0
- package/src/utils/log-failure.ts +31 -0
- package/src/utils/option-expiry.ts +12 -12
- package/src/utils/price-history-integrity.ts +56 -0
- package/src/utils/price-history.ts +13 -1
- package/src/utils/sec-filings.ts +245 -0
- package/src/utils/selection-clipboard.ts +5 -2
- package/src/utils/throttled-fetch.ts +1 -0
- package/src/{plugins/builtin/dividend-yield/trailing-cash.ts → utils/trailing-dividend.ts} +55 -8
- package/src/utils/url.ts +1 -0
- package/src/utils/utc-time.ts +11 -0
- package/src/plugins/builtin/chat/share/targets.ts +0 -27
- package/src/renderers/dom/host/top-surface.ts +0 -119
- package/src/shares/dialog.tsx +0 -221
- package/src/shares/live.ts +0 -19
|
@@ -4,16 +4,15 @@ import { dryRunNote } from "../../../cli/helpers";
|
|
|
4
4
|
import { requireArg, takeOption } from "../../../cli/commands/command-utils";
|
|
5
5
|
import { EXCHANGE_OPTION, listingReadNotes, requireListingArg, type ListingArg } from "../../../cli/listing-arg";
|
|
6
6
|
import { saveConfig } from "../../../data/config/store";
|
|
7
|
-
import type { AppConfig } from "../../../types/config";
|
|
8
7
|
import type { CliCommandContext, CliCommandDef } from "../../../types/plugin";
|
|
9
8
|
import { getActiveQuoteDisplay } from "../../../market-data/market/status";
|
|
10
9
|
import { settleWithin } from "../../../utils/async-deadline";
|
|
11
10
|
import { cliStyles } from "../../../utils/cli-output";
|
|
12
11
|
import { ambiguousNumberMessage, meantThousandsDot, parsePastedNumber, thousandsDotReadings, type ThousandsDotReadings } from "../../../utils/decimal-comma";
|
|
13
12
|
import { newYorkToday } from "../earnings/board-model";
|
|
14
|
-
import { createAlert,
|
|
15
|
-
import { ALERTS_KEY } from "./constants";
|
|
16
|
-
import { EVENT_ALERTS_KEY, MAX_EVENT_ALERTS, eventAlertTarget,
|
|
13
|
+
import { createAlert, rearmAlert, serializeAlerts } from "./alert-engine";
|
|
14
|
+
import { ALERTS_KEY, ALERTS_PLUGIN_ID } from "./constants";
|
|
15
|
+
import { EVENT_ALERTS_KEY, MAX_EVENT_ALERTS, eventAlertTarget, toggleEventAlert, type EventAlertRule } from "./events";
|
|
17
16
|
import { alertKindLabel } from "./history";
|
|
18
17
|
import { MAX_LEAD_DAYS, type MacroAlertEvent } from "./research-rules";
|
|
19
18
|
import {
|
|
@@ -36,10 +35,9 @@ import {
|
|
|
36
35
|
type ScheduledEventTarget,
|
|
37
36
|
} from "./scheduled";
|
|
38
37
|
import { scheduledEventSources } from "./scheduled-sources";
|
|
38
|
+
import { readAlertStores } from "./storage";
|
|
39
39
|
import type { AlertCondition, AlertRule } from "./types";
|
|
40
40
|
|
|
41
|
-
const ALERTS_PLUGIN_ID = "alerts";
|
|
42
|
-
|
|
43
41
|
const ADD_USAGE = "Usage: gloomberb alerts add <symbol> <above|below|crosses> <price>, alerts add <symbol> earnings [--days <n>], or alerts add <CPI|FOMC> [--days <n>]";
|
|
44
42
|
const DAYS_RULE = `--days takes a whole number of days from 1 to ${MAX_LEAD_DAYS}; without it the alert goes off 1 day before.`;
|
|
45
43
|
|
|
@@ -230,17 +228,6 @@ async function requireEventDate(
|
|
|
230
228
|
return lookup.date;
|
|
231
229
|
}
|
|
232
230
|
|
|
233
|
-
function readAlertStores(config: AppConfig) {
|
|
234
|
-
const pluginState = config.pluginConfig[ALERTS_PLUGIN_ID] ?? {};
|
|
235
|
-
const rawPrice = pluginState[ALERTS_KEY];
|
|
236
|
-
const rawEvents = pluginState[EVENT_ALERTS_KEY];
|
|
237
|
-
return {
|
|
238
|
-
pluginState,
|
|
239
|
-
alerts: deserializeAlerts(typeof rawPrice === "string" ? rawPrice : "[]"),
|
|
240
|
-
events: readEventAlerts(typeof rawEvents === "string" ? rawEvents : "[]"),
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
|
|
244
231
|
export const alertsCliCommand: CliCommandDef = {
|
|
245
232
|
name: "alerts",
|
|
246
233
|
aliases: ["alert"],
|
|
@@ -385,10 +372,12 @@ export const alertsCliCommand: CliCommandDef = {
|
|
|
385
372
|
await save({ events: [...rules, rule] });
|
|
386
373
|
const eventDate = rule.eventDate!;
|
|
387
374
|
const due = scheduledPhase(eventDate, scheduled.leadDays, undefined, today) === "due";
|
|
375
|
+
const delivery = scheduled.target.kind === "macro" ? ", only while it is running" : " while it is running, or on your phone with Cloud sync";
|
|
388
376
|
ctx.printResult({ data: { changed: !ctx.cliOptions.dryRun, dryRun: ctx.cliOptions.dryRun, alert: rule }, ...(read.length > 0 ? { warnings: read } : {}) }, {
|
|
377
|
+
// Delivery, as docs/usage.md states it: CPI and FOMC notify in the running app only; earnings also reach the phone.
|
|
389
378
|
text: (data) => `Added alert ${data.alert.id}: ${name} on ${eventDate}, ${plural(scheduled.leadDays, "day")} before (${due
|
|
390
379
|
? "already reached, so the app alerts at its next check"
|
|
391
|
-
: `the app alerts on ${leadStartDate(eventDate, scheduled.leadDays)}`}).${dryRunNote(data.dryRun)}`,
|
|
380
|
+
: `the app alerts on ${leadStartDate(eventDate, scheduled.leadDays)}`}${delivery}).${dryRunNote(data.dryRun)}`,
|
|
392
381
|
});
|
|
393
382
|
return;
|
|
394
383
|
}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
+
export const ALERTS_PLUGIN_ID = "alerts";
|
|
1
2
|
export const ALERTS_KEY = "alerts";
|
|
3
|
+
|
|
4
|
+
/** The Alerts pane's tabs: what `ALRT --tab` takes, and the pane state `tab` holds. */
|
|
5
|
+
export const ALERT_TABS = [
|
|
6
|
+
{ label: "Prices", value: "prices" },
|
|
7
|
+
{ label: "Events", value: "events" },
|
|
8
|
+
{ label: "History", value: "history" },
|
|
9
|
+
];
|
|
2
10
|
/** Fallback cadence when the pane's Check interval setting is unset. */
|
|
3
11
|
export const POLL_INTERVAL_MS = 30_000;
|
|
4
12
|
export const POLL_SECONDS_KEY = "pollSeconds";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { eventAlertTarget, type EventAlertRule } from "./events";
|
|
2
|
+
import { readScheduledRule, scheduledAlertStatus } from "./scheduled";
|
|
3
|
+
|
|
4
|
+
/** Earnings and macro event rules name the event day they wait for; the rest name what they follow. */
|
|
5
|
+
export function ruleTarget(rule: EventAlertRule): string {
|
|
6
|
+
const target = eventAlertTarget(rule);
|
|
7
|
+
if (!readScheduledRule(rule)) return target;
|
|
8
|
+
return `${target} · ${rule.eventDate ?? "date not known yet"}`;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** The state word the Events tab shows: a scheduled rule is Alerted once it has gone off for its coming event. */
|
|
12
|
+
export function ruleState(rule: EventAlertRule, today: string): "Active" | "Paused" | "Alerted" {
|
|
13
|
+
const scheduled = readScheduledRule(rule);
|
|
14
|
+
const status = scheduled ? scheduledAlertStatus(rule, scheduled.leadDays, today) : rule.status;
|
|
15
|
+
return status === "paused" ? "Paused" : status === "triggered" ? "Alerted" : "Active";
|
|
16
|
+
}
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
toggleEventAlert,
|
|
22
22
|
type EventAlertRule,
|
|
23
23
|
} from "./events";
|
|
24
|
+
import { ruleState, ruleTarget } from "./event-rows";
|
|
24
25
|
import { relativeTime } from "./format";
|
|
25
26
|
import { alertKindLabel, fetchAlertHistory, ruleStateText } from "./history";
|
|
26
27
|
import { isResearchAlertKind } from "./research-rules";
|
|
@@ -28,23 +29,10 @@ import { useAsyncResource } from "../../../public/react";
|
|
|
28
29
|
import { usePlanAccess } from "../../../api-client/plan-access";
|
|
29
30
|
import { useResearchCloudSession } from "../shared/research-cloud-session";
|
|
30
31
|
import { newYorkToday } from "../earnings/board-model";
|
|
31
|
-
import {
|
|
32
|
+
import { rearmScheduledAlert } from "./scheduled";
|
|
32
33
|
import { checkScheduledEventAlertsNow } from "./scheduled-check";
|
|
33
34
|
import { alertTarget, alertViewHints, eventRuleSubject, useOpenAlertTarget } from "./targets";
|
|
34
35
|
|
|
35
|
-
/** Earnings and macro event rules name the event day they wait for; the rest name what they follow. */
|
|
36
|
-
function ruleTarget(rule: EventAlertRule): string {
|
|
37
|
-
const target = eventAlertTarget(rule);
|
|
38
|
-
if (!readScheduledRule(rule)) return target;
|
|
39
|
-
return `${target} · ${rule.eventDate ?? "date not known yet"}`;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function ruleState(rule: EventAlertRule, today: string): "Active" | "Paused" | "Alerted" {
|
|
43
|
-
const scheduled = readScheduledRule(rule);
|
|
44
|
-
const status = scheduled ? scheduledAlertStatus(rule, scheduled.leadDays, today) : rule.status;
|
|
45
|
-
return status === "paused" ? "Paused" : status === "triggered" ? "Alerted" : "Active";
|
|
46
|
-
}
|
|
47
|
-
|
|
48
36
|
const columnsFor = (width: number, lastCheck: boolean): DataTableColumn[] => [
|
|
49
37
|
{ id: "kind", label: "Event", width: 15, align: "left" },
|
|
50
38
|
{ id: "target", label: "Following", width: 28, flexGrow: 1, align: "left" },
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `gloomberb fn ALRT`: the Alerts pane's three tabs as reports. Prices lists
|
|
3
|
+
* the price alerts as the pane's table does, Events the event alerts (earnings,
|
|
4
|
+
* CPI and FOMC with their dates, filings, news, market moves), History the
|
|
5
|
+
* alerts delivered to the account over the last 90 days.
|
|
6
|
+
*/
|
|
7
|
+
import type { HeadlessPaneColumn, HeadlessPaneContext, HeadlessPaneDefinition, HeadlessPaneRow, HeadlessRowsResult } from "../../../types/headless";
|
|
8
|
+
import type { PaneLock } from "../../../types/plugin";
|
|
9
|
+
import { newYorkToday } from "../earnings/board-model";
|
|
10
|
+
import { explainRefusal } from "../shared/cloud-denied";
|
|
11
|
+
import { ALERT_TABS, ALERTS_PLUGIN_ID } from "./constants";
|
|
12
|
+
import { ruleState } from "./event-rows";
|
|
13
|
+
import { eventAlertTarget, type EventAlertRule } from "./events";
|
|
14
|
+
import {
|
|
15
|
+
conditionLabel,
|
|
16
|
+
formatAlertDistance,
|
|
17
|
+
formatAlertTargetPrice,
|
|
18
|
+
formatCurrentPrice,
|
|
19
|
+
formatQuoteChecked,
|
|
20
|
+
relativeTime,
|
|
21
|
+
} from "./format";
|
|
22
|
+
import { alertKindLabel, validateAlertHistory, type AlertHistory, type AlertHistoryItem } from "./history";
|
|
23
|
+
import { readScheduledRule, scheduledEventName } from "./scheduled";
|
|
24
|
+
import { readAlertStores } from "./storage";
|
|
25
|
+
import type { AlertRule } from "./types";
|
|
26
|
+
|
|
27
|
+
type AlertsTab = "prices" | "events" | "history";
|
|
28
|
+
|
|
29
|
+
/** Pages of history one report reads; the pane reads more as it is scrolled. */
|
|
30
|
+
const HISTORY_PAGES = 5;
|
|
31
|
+
|
|
32
|
+
const plural = (count: number, word: string) => `${count} ${word}${count === 1 ? "" : "s"}`;
|
|
33
|
+
const asAlert = (row: HeadlessPaneRow) => row as unknown as AlertRule;
|
|
34
|
+
const text = (value: unknown) => (typeof value === "string" && value ? value : "");
|
|
35
|
+
|
|
36
|
+
/** The text report words each cell as the pane does; CSV and JSON keep the stored numbers and times. */
|
|
37
|
+
const PRICE_COLUMNS: HeadlessPaneColumn[] = [
|
|
38
|
+
{ key: "status", header: "State", format: (value) => (value === "triggered" ? "Triggered" : "Active") },
|
|
39
|
+
{ key: "symbol", header: "Symbol", format: (value, row) => (row.exchange ? `${text(value)}:${text(row.exchange)}` : text(value)) },
|
|
40
|
+
{ key: "lastCheckedPrice", header: "Current", align: "right", textFormat: (_value, row) => formatCurrentPrice(asAlert(row), 14) },
|
|
41
|
+
{ key: "targetPrice", header: "Target", align: "right", textFormat: (_value, row) => formatAlertTargetPrice(asAlert(row), 14) },
|
|
42
|
+
{ key: "awayPercent", header: "Away", align: "right", textFormat: (_value, row) => formatAlertDistance(asAlert(row)) },
|
|
43
|
+
{ key: "condition", header: "Trigger", format: (value) => conditionLabel(value as AlertRule["condition"]) },
|
|
44
|
+
{ key: "lastCheckedAt", header: "Quote", textFormat: (_value, row) => formatQuoteChecked(asAlert(row)) },
|
|
45
|
+
{ key: "triggeredAt", header: "Alerted", textFormat: (value) => (typeof value === "number" ? relativeTime(value) : "-") },
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const EVENT_COLUMNS: HeadlessPaneColumn[] = [
|
|
49
|
+
{ key: "event", header: "Event" },
|
|
50
|
+
{ key: "following", header: "Following" },
|
|
51
|
+
{ key: "eventDate", header: "Event date", textFormat: (value, row) => text(value) || (row.leadDays == null ? "" : "not known yet") },
|
|
52
|
+
{ key: "leadDays", header: "Days before", align: "right" },
|
|
53
|
+
{ key: "state", header: "State" },
|
|
54
|
+
{ key: "since", header: "Since" },
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const HISTORY_COLUMNS: HeadlessPaneColumn[] = [
|
|
58
|
+
{ key: "deliveredAt", header: "Sent (UTC)", format: (value) => text(value).slice(0, 16).replace("T", " ") },
|
|
59
|
+
{ key: "event", header: "Event" },
|
|
60
|
+
{ key: "title", header: "Alert" },
|
|
61
|
+
{ key: "body", header: "Detail" },
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
/** A price alert as the Prices table lists it: the stored fields, without the quote's provider id, and the distance to target. */
|
|
65
|
+
function priceRow(alert: AlertRule): HeadlessPaneRow {
|
|
66
|
+
const { lastQuoteProviderId: _provider, ...stored } = alert;
|
|
67
|
+
const price = alert.lastCheckError ? null : alert.lastCheckedPrice;
|
|
68
|
+
const away = price == null || !Number.isFinite(price) || price === 0 ? null : ((alert.targetPrice - price) / price) * 100;
|
|
69
|
+
return { ...stored, awayPercent: away != null && Number.isFinite(away) ? away : null };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Active alerts first, then the ones that went off, latest first, as the pane orders them. */
|
|
73
|
+
function pricesResult(alerts: readonly AlertRule[], error: string | null, events: number): HeadlessRowsResult {
|
|
74
|
+
const active = alerts.filter((alert) => alert.status === "active");
|
|
75
|
+
const triggered = alerts.filter((alert) => alert.status === "triggered").sort((a, b) => (b.triggeredAt ?? 0) - (a.triggeredAt ?? 0));
|
|
76
|
+
return {
|
|
77
|
+
columns: PRICE_COLUMNS,
|
|
78
|
+
rows: [...active, ...triggered].map(priceRow),
|
|
79
|
+
empty: "No price alerts. Add one with gloomberb alerts add AAPL above 250.",
|
|
80
|
+
...(error ? { errors: [error], complete: false } : {}),
|
|
81
|
+
...(events > 0 ? { notes: [`${plural(events, "event alert")} not listed here: gloomberb fn ALRT --tab events`] } : {}),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** An event alert as the Events table lists it: a scheduled one with its event date and lead time apart. */
|
|
86
|
+
function eventRow(rule: EventAlertRule, today: string): HeadlessPaneRow {
|
|
87
|
+
const scheduled = readScheduledRule(rule);
|
|
88
|
+
return {
|
|
89
|
+
id: rule.id,
|
|
90
|
+
kind: rule.kind,
|
|
91
|
+
event: alertKindLabel(rule.kind),
|
|
92
|
+
following: scheduled ? scheduledEventName(scheduled.target) : eventAlertTarget(rule),
|
|
93
|
+
eventDate: scheduled ? rule.eventDate ?? null : null,
|
|
94
|
+
leadDays: scheduled?.leadDays ?? null,
|
|
95
|
+
state: ruleState(rule, today),
|
|
96
|
+
since: new Date(rule.createdAt).toISOString().slice(0, 10),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function eventsResult(rules: readonly EventAlertRule[], error: string | null): HeadlessRowsResult {
|
|
101
|
+
const today = newYorkToday();
|
|
102
|
+
return {
|
|
103
|
+
columns: EVENT_COLUMNS,
|
|
104
|
+
rows: [...rules].sort((a, b) => b.createdAt - a.createdAt).map((rule) => eventRow(rule, today)),
|
|
105
|
+
empty: "No event alerts. Add one with gloomberb alerts add CRWV earnings --days 3 or gloomberb alerts add CPI --days 1.",
|
|
106
|
+
...(error ? { errors: [error], complete: false } : {}),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function historyRow(item: AlertHistoryItem): HeadlessPaneRow {
|
|
111
|
+
return { id: item.id, deliveredAt: item.deliveredAt, kind: item.kind, event: alertKindLabel(item.kind), title: item.title, body: item.body };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** What a signed-out read of History says: the tab is the account's own list of delivered alerts. */
|
|
115
|
+
export function alertHistoryLockNote({ verifyEmail }: PaneLock): string {
|
|
116
|
+
const account = verifyEmail
|
|
117
|
+
? "verify your email (Ctrl+P, Resend Verification Email)"
|
|
118
|
+
: "log in or sign up free from the command bar (Ctrl+P, Log In or Sign Up)";
|
|
119
|
+
return [
|
|
120
|
+
`ALRT History needs a free Gloom sign-in: it lists the alerts Gloom delivered to your account over the last 90 days. ${verifyEmail ? "Until the email is verified" : "Signed out"} it shows none of them.`,
|
|
121
|
+
`To read it, open the app (gloomberb), ${account}; gloomberb fn ALRT --tab history then reads with that session.`,
|
|
122
|
+
].join("\n");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function historyResult(ctx: HeadlessPaneContext): Promise<HeadlessRowsResult> {
|
|
126
|
+
const items: AlertHistoryItem[] = [];
|
|
127
|
+
let first: AlertHistory | null = null;
|
|
128
|
+
let more = false;
|
|
129
|
+
try {
|
|
130
|
+
for (let offset: number | null = 0, page = 0; offset != null; page += 1) {
|
|
131
|
+
if (page === HISTORY_PAGES) {
|
|
132
|
+
more = true;
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
const history: AlertHistory = validateAlertHistory(await ctx.apiClient.getMobileAlertHistory<unknown>(offset));
|
|
136
|
+
first ??= history;
|
|
137
|
+
if (history.status === "unavailable") break;
|
|
138
|
+
items.push(...history.items);
|
|
139
|
+
offset = history.hasMore ? history.nextOffset : null;
|
|
140
|
+
}
|
|
141
|
+
} catch (error) {
|
|
142
|
+
throw explainRefusal(error, alertHistoryLockNote, { symbol: null, token: "ALRT" });
|
|
143
|
+
}
|
|
144
|
+
const unavailable = first?.status === "unavailable";
|
|
145
|
+
return {
|
|
146
|
+
columns: HISTORY_COLUMNS,
|
|
147
|
+
rows: items.map(historyRow),
|
|
148
|
+
empty: "No alerts delivered in the last 90 days.",
|
|
149
|
+
freshness: { source: "Gloom Cloud", status: "not-a-feed", basis: "delivered alerts", ...(first ? { asOf: first.asOf } : {}) },
|
|
150
|
+
...(unavailable ? { errors: [first?.warning ?? "Alert history is unavailable."], complete: false } : {}),
|
|
151
|
+
...(more ? { notes: [`Showing the latest ${items.length} delivered alerts; the pane loads older ones as you scroll.`] } : {}),
|
|
152
|
+
metadata: { deviceEnabled: first?.deviceEnabled ?? null },
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export const alertsHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
157
|
+
shape: "rows",
|
|
158
|
+
description: "Your alerts: price alerts with current price and distance to target, event alerts (earnings, CPI and FOMC dates, filings, news, market moves) or the alerts delivered to your account.",
|
|
159
|
+
freshness: { source: "Your alerts", status: "not-a-feed", basis: "your alert rules" },
|
|
160
|
+
argument: { kind: "none" },
|
|
161
|
+
options: [{
|
|
162
|
+
key: "tab",
|
|
163
|
+
description: "Alerts tab: prices, events or history (delivered alerts, signed in).",
|
|
164
|
+
type: "enum",
|
|
165
|
+
values: ALERT_TABS.map(({ value }) => ({ value })),
|
|
166
|
+
defaultValue: "prices",
|
|
167
|
+
example: "--tab events",
|
|
168
|
+
pluginState: { pluginId: ALERTS_PLUGIN_ID, key: "tab" },
|
|
169
|
+
}],
|
|
170
|
+
discovery: {
|
|
171
|
+
screenshotReadiness: "live-dom",
|
|
172
|
+
dataRequirements: ["Your saved alerts; the History tab needs a Gloom sign-in"],
|
|
173
|
+
limitations: ["Current price and quote time are what the app saved at its last check, blank until it has checked the alert."],
|
|
174
|
+
},
|
|
175
|
+
describe: (args) => `Alerts | ${String(args.options.tab ?? "prices")}`,
|
|
176
|
+
async load(args, ctx) {
|
|
177
|
+
const tab = (args.options.tab ?? "prices") as AlertsTab;
|
|
178
|
+
if (tab === "history") return historyResult(ctx);
|
|
179
|
+
const { alerts, alertsError, events } = readAlertStores(ctx.config);
|
|
180
|
+
return tab === "events" ? eventsResult(events.rules, events.error) : pricesResult(alerts, alertsError, events.rules.length);
|
|
181
|
+
},
|
|
182
|
+
};
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
parseAlertShortcutValues,
|
|
28
28
|
} from "./command";
|
|
29
29
|
import { POLL_INTERVAL_MS, POLL_SECONDS_KEY } from "./constants";
|
|
30
|
+
import { alertHistoryLockNote, alertsHeadless } from "./headless";
|
|
30
31
|
import { AlertsPane } from "./pane";
|
|
31
32
|
import { alertsCliCommand } from "./cli";
|
|
32
33
|
import {
|
|
@@ -317,6 +318,7 @@ export const alertsPlugin: GloomPlugin = {
|
|
|
317
318
|
ctx.registerPane({
|
|
318
319
|
id: "alerts",
|
|
319
320
|
reportFreshness: { source: "Your alerts", status: "not-a-feed", basis: "your alert rules" },
|
|
321
|
+
reportLockNote: alertHistoryLockNote,
|
|
320
322
|
name: "Alerts",
|
|
321
323
|
icon: "A",
|
|
322
324
|
component: AlertsPane,
|
|
@@ -349,6 +351,7 @@ export const alertsPlugin: GloomPlugin = {
|
|
|
349
351
|
description: "Price, market and filing event alerts",
|
|
350
352
|
keywords: ["alerts", "price", "trigger", "alarm", "watch", "notify"],
|
|
351
353
|
shortcut: { prefix: "ALRT" },
|
|
354
|
+
headless: alertsHeadless,
|
|
352
355
|
});
|
|
353
356
|
},
|
|
354
357
|
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
serializeAlerts,
|
|
29
29
|
} from "./alert-engine";
|
|
30
30
|
import { parseAlertCommandValues } from "./command";
|
|
31
|
-
import { ALERTS_KEY } from "./constants";
|
|
31
|
+
import { ALERT_TABS, ALERTS_KEY } from "./constants";
|
|
32
32
|
import {
|
|
33
33
|
conditionLabel,
|
|
34
34
|
formatAlertDistance,
|
|
@@ -73,12 +73,6 @@ const ALERT_TABLE_CONTENT_WIDTH = ALERT_COLUMNS.reduce(
|
|
|
73
73
|
2,
|
|
74
74
|
);
|
|
75
75
|
|
|
76
|
-
const ALERT_TABS = [
|
|
77
|
-
{ label: "Prices", value: "prices" },
|
|
78
|
-
{ label: "Events", value: "events" },
|
|
79
|
-
{ label: "History", value: "history" },
|
|
80
|
-
];
|
|
81
|
-
|
|
82
76
|
export function AlertsPane(props: PaneProps) {
|
|
83
77
|
const [tab, setTab] = usePluginPaneState<string>("tab", "prices");
|
|
84
78
|
// A missed price alert opened from the Unread list selects its rule on Prices.
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import type { AppConfig } from "../../../types/config";
|
|
1
2
|
import type { GloomPluginContext } from "../../../types/plugin";
|
|
2
3
|
import {
|
|
3
4
|
deserializeAlerts,
|
|
5
|
+
readAlertsStoreError,
|
|
4
6
|
serializeAlerts,
|
|
5
7
|
} from "./alert-engine";
|
|
6
|
-
import { ALERTS_KEY } from "./constants";
|
|
8
|
+
import { ALERTS_KEY, ALERTS_PLUGIN_ID } from "./constants";
|
|
9
|
+
import { EVENT_ALERTS_KEY, readEventAlerts } from "./events";
|
|
7
10
|
import type { AlertRule } from "./types";
|
|
8
11
|
|
|
9
12
|
export function loadAlerts(ctx: GloomPluginContext): AlertRule[] {
|
|
@@ -18,3 +21,16 @@ export function saveAlerts(
|
|
|
18
21
|
): void {
|
|
19
22
|
ctx.configState.set(ALERTS_KEY, serializeAlerts(alerts));
|
|
20
23
|
}
|
|
24
|
+
|
|
25
|
+
/** Both alert stores as the saved config holds them, for the CLI and the reports, which have no plugin context. */
|
|
26
|
+
export function readAlertStores(config: AppConfig) {
|
|
27
|
+
const pluginState = config.pluginConfig[ALERTS_PLUGIN_ID] ?? {};
|
|
28
|
+
const rawPrice = pluginState[ALERTS_KEY];
|
|
29
|
+
const rawEvents = pluginState[EVENT_ALERTS_KEY];
|
|
30
|
+
return {
|
|
31
|
+
pluginState,
|
|
32
|
+
alerts: deserializeAlerts(typeof rawPrice === "string" ? rawPrice : "[]"),
|
|
33
|
+
alertsError: typeof rawPrice === "string" ? readAlertsStoreError(rawPrice) : null,
|
|
34
|
+
events: readEventAlerts(typeof rawEvents === "string" ? rawEvents : "[]"),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -257,6 +257,10 @@ function LegacyPortfolioAnalyticsPane({ focused, width, height }: PaneProps) {
|
|
|
257
257
|
...(sectorAllocation.unvaluedSymbols.length > 0 ? [{
|
|
258
258
|
text: `Weights unavailable: missing prices or FX for ${sectorAllocation.unvaluedSymbols.join(", ")}.`, tone: "warning" as const,
|
|
259
259
|
}] : []),
|
|
260
|
+
// Named once in the pane's notices: its totals and its sectors leave the same futures out.
|
|
261
|
+
...(sectorAllocation.unsizedSymbols.length > 0 ? [{
|
|
262
|
+
text: `No contract size, so not valued: ${sectorAllocation.unsizedSymbols.join(", ")}.`, tone: "warning" as const,
|
|
263
|
+
}] : []),
|
|
260
264
|
];
|
|
261
265
|
const sectorRows = sectorAllocation.rows;
|
|
262
266
|
const sortedSectorRows = useMemo(
|
|
@@ -453,9 +457,10 @@ export const portfolioAnalyticsModule: PluginModule = {
|
|
|
453
457
|
headless: portfolioRiskHeadless,
|
|
454
458
|
tableExport: true,
|
|
455
459
|
// The risk window reads as trailing until it is set.
|
|
456
|
-
settings: (context) => ({ values: { riskSince: context.settings.riskSince ?? "trailing" }, fields: [
|
|
460
|
+
settings: (context) => ({ values: { riskSince: context.settings.riskSince ?? "trailing", riskWeights: context.settings.riskWeights ?? "13f" }, fields: [
|
|
457
461
|
{ key: "analyticsView", label: "View", type: "select", options: [{ value: "overview", label: "Overview" }, { value: "risk", label: "Risk depth" }] },
|
|
458
462
|
{ key: "riskSince", label: "Risk window", type: "select", options: [{ value: "trailing", label: "Trailing 60 sessions" }, { value: "filed", label: "Since 13F filing" }] },
|
|
463
|
+
{ key: "riskWeights", label: "Since-filing weights", type: "select", options: [{ value: "13f", label: "13F weights, bought and held" }, { value: "current", label: "Current weights, held fixed" }] },
|
|
459
464
|
{ key: "riskEvidence", label: "Local evidence JSON", type: "text" },
|
|
460
465
|
{ key: "equityShift", label: "Index shift (%)", type: "text" },
|
|
461
466
|
{ key: "rateShift", label: "10Y shift (bp)", type: "text" },
|
|
@@ -138,23 +138,61 @@ function returnIntervalKey(point: DatedReturn): string {
|
|
|
138
138
|
return `${point.startDateKey}/${point.dateKey}`;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
/** The intervals every series covers, and each series' return on them, in the first series' order. */
|
|
142
|
+
interface AlignedSeries {
|
|
143
|
+
series: DatedReturn[][];
|
|
144
|
+
lengths: number[];
|
|
145
|
+
points: DatedReturn[];
|
|
146
|
+
values: Float64Array[];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Lined-up holdings, kept with their series: weights move with every quote,
|
|
151
|
+
* the series only with their bars, so a portfolio valued again (each Cloud
|
|
152
|
+
* sync values every one, GLO-925) only weighs returns already lined up
|
|
153
|
+
* instead of matching every interval of every holding again. A few lists per
|
|
154
|
+
* first series, since one holding can open more than one portfolio.
|
|
155
|
+
*/
|
|
156
|
+
const alignedByFirstSeries = new WeakMap<DatedReturn[], AlignedSeries[]>();
|
|
157
|
+
|
|
158
|
+
function alignSeries(series: DatedReturn[][]): AlignedSeries {
|
|
159
|
+
const kept = alignedByFirstSeries.get(series[0]!) ?? [];
|
|
160
|
+
const cached = kept.find((entry) => entry.series.length === series.length
|
|
161
|
+
&& entry.series.every((returns, index) => returns === series[index] && entry.lengths[index] === returns.length));
|
|
162
|
+
if (cached) return cached;
|
|
163
|
+
const samples = series.map((returns) => new Map(returns
|
|
164
|
+
.filter(validReturnInterval)
|
|
165
|
+
.map((point) => [returnIntervalKey(point), point])));
|
|
166
|
+
const points: DatedReturn[] = [];
|
|
167
|
+
const columns: number[][] = series.map(() => []);
|
|
168
|
+
for (const [key, first] of samples[0]!) {
|
|
169
|
+
const row: number[] = [];
|
|
170
|
+
for (const sample of samples) {
|
|
171
|
+
const point = sample.get(key);
|
|
172
|
+
if (!point) break;
|
|
173
|
+
row.push(point.value);
|
|
174
|
+
}
|
|
175
|
+
if (row.length < samples.length) continue;
|
|
176
|
+
points.push(first);
|
|
177
|
+
row.forEach((value, index) => columns[index]!.push(value));
|
|
178
|
+
}
|
|
179
|
+
const aligned = { series: [...series], lengths: series.map((returns) => returns.length), points, values: columns.map((column) => Float64Array.from(column)) };
|
|
180
|
+
alignedByFirstSeries.set(series[0]!, [aligned, ...kept].slice(0, 4));
|
|
181
|
+
return aligned;
|
|
182
|
+
}
|
|
183
|
+
|
|
141
184
|
export function computeWeightedPortfolioReturns(series: WeightedReturnSeries[]): DatedReturn[] {
|
|
142
185
|
const holdings = series.filter((entry) => Number.isFinite(entry.weight) && entry.weight > 0);
|
|
143
186
|
const totalWeight = holdings.reduce((sum, entry) => sum + entry.weight, 0);
|
|
144
187
|
if (!holdings.length || !Number.isFinite(totalWeight) || totalWeight <= 0) return [];
|
|
145
|
-
const
|
|
146
|
-
.filter(validReturnInterval)
|
|
147
|
-
.map((point) => [returnIntervalKey(point), point])));
|
|
188
|
+
const { points, values } = alignSeries(holdings.map((entry) => entry.returns));
|
|
148
189
|
const returns: DatedReturn[] = [];
|
|
149
|
-
for (
|
|
190
|
+
for (let row = 0; row < points.length; row++) {
|
|
150
191
|
let value = 0;
|
|
151
|
-
let complete = true;
|
|
152
192
|
for (let index = 0; index < holdings.length; index++) {
|
|
153
|
-
|
|
154
|
-
if (!point) { complete = false; break; }
|
|
155
|
-
value += point.value * (holdings[index]!.weight / totalWeight);
|
|
193
|
+
value += values[index]![row]! * (holdings[index]!.weight / totalWeight);
|
|
156
194
|
}
|
|
157
|
-
if (
|
|
195
|
+
if (Number.isFinite(value)) returns.push({ ...points[row]!, value });
|
|
158
196
|
}
|
|
159
197
|
return returns.sort((left, right) => left.dateKey.localeCompare(right.dateKey));
|
|
160
198
|
}
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
riskPercentile,
|
|
18
18
|
riskValue,
|
|
19
19
|
sinceFallbackNote,
|
|
20
|
+
sinceFiledMethod,
|
|
20
21
|
type PortfolioRiskModel,
|
|
21
22
|
type RiskCoverage,
|
|
22
23
|
type RiskDisplayRow,
|
|
@@ -142,6 +143,7 @@ export const portfolioRiskHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
142
143
|
],
|
|
143
144
|
limitations: [
|
|
144
145
|
`Fixed-current-weight USD equity basket over the holdings that qualify, largest ${RISK_HISTORY_LIMIT} by value; foreign listings convert to USD at daily FX closes; metadata.coverage states the covered share of market value and each holding left out.`,
|
|
146
|
+
"--since filed buys the 13F's own weights at the filing-date close and holds them (--weights current holds today's weights fixed instead).",
|
|
145
147
|
"No account performance inferred.",
|
|
146
148
|
"ETF price-return factor proxies.",
|
|
147
149
|
"Historical percentiles need 20 rolling samples.",
|
|
@@ -163,6 +165,13 @@ export const portfolioRiskHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
163
165
|
values: [{ value: "filed" }],
|
|
164
166
|
description: "Risk rows since the 13F filing date of a portfolio made with portfolio import --13f, instead of the trailing 60 sessions.",
|
|
165
167
|
},
|
|
168
|
+
{
|
|
169
|
+
key: "weights",
|
|
170
|
+
type: "enum",
|
|
171
|
+
settingKey: "riskWeights",
|
|
172
|
+
values: [{ value: "13f" }, { value: "current" }],
|
|
173
|
+
description: "With --since filed: 13f (when left out) buys the 13F's own weights at the filing-date close and holds them; current holds today's weights fixed over the same sessions.",
|
|
174
|
+
},
|
|
166
175
|
{
|
|
167
176
|
key: "evidence",
|
|
168
177
|
type: "string",
|
|
@@ -254,16 +263,19 @@ export const portfolioRiskHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
254
263
|
rates: Number(args.options["rate-shift"] ?? 100),
|
|
255
264
|
volatility: Number(args.options["vol-shift"] ?? 10),
|
|
256
265
|
},
|
|
257
|
-
args.options.since === "filed"
|
|
266
|
+
args.options.since === "filed"
|
|
267
|
+
? { since: "filed", weights: args.options.weights === "current" ? "current" : "13f" }
|
|
268
|
+
: {},
|
|
258
269
|
);
|
|
259
270
|
// Options for views the report does not print are named, not dropped silently; the fallback from --since opens the report.
|
|
260
271
|
const fallback = sinceFallbackNote(local.portfolio);
|
|
261
272
|
const shifted = ["equity-shift", "rate-shift", "vol-shift"].filter((key) => args.options[key] != null);
|
|
262
273
|
const notices = [
|
|
263
|
-
...(model.window.kind === "since-filed" ? [
|
|
274
|
+
...(model.window.kind === "since-filed" ? [sinceFiledMethod(model.window, model.benchmark)] : []),
|
|
264
275
|
...(args.options.since === "filed" && model.window.kind !== "since-filed" ? [fallback] : []),
|
|
265
276
|
...(requestedView && requestedView !== "stress" && shifted.length ? [`${shifted.map((key) => `--${key}`).join(", ")} change${shifted.length === 1 ? "s" : ""} the stress view only, not --view ${requestedView}`] : []),
|
|
266
277
|
...(requestedView && args.options.since != null && requestedView !== "risk" ? [`--since changes the risk view only, not --view ${requestedView}`] : []),
|
|
278
|
+
...(args.options.weights != null && args.options.since !== "filed" ? ["--weights applies with --since filed only"] : []),
|
|
267
279
|
];
|
|
268
280
|
// A basket view is complete only when the basket covers every holding.
|
|
269
281
|
const covered = model.coverage.leftOut.length === 0;
|
|
@@ -340,6 +340,89 @@ export function sinceBasketRisk(
|
|
|
340
340
|
});
|
|
341
341
|
}
|
|
342
342
|
|
|
343
|
+
/** A held basket's daily returns, and why it stops or leaves a holding out when it does. */
|
|
344
|
+
export interface HeldBasket {
|
|
345
|
+
returns: DatedReturn[];
|
|
346
|
+
/**
|
|
347
|
+
* Set when the basket ends before the last session: the holding (its index
|
|
348
|
+
* in the input) whose daily closes end first, and the day they end.
|
|
349
|
+
*/
|
|
350
|
+
cutShort: { holding: number; date: string } | null;
|
|
351
|
+
/** Holdings with no close on or before `since`, which cannot be bought at it and are left out. */
|
|
352
|
+
unpriced: number[];
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Daily returns of a basket bought at the close on or before `since` (a 13F
|
|
357
|
+
* filing date) at `weights` and held: each holding's share drifts with its
|
|
358
|
+
* price, nothing is rebalanced. The basket is valued at every session of
|
|
359
|
+
* `calendar` (the benchmark's, so the two pair; the holdings' own dates when
|
|
360
|
+
* left out). A holding with no close for a session (a halt, a missing bar)
|
|
361
|
+
* holds its value flat, and its multi-day return lands on the session it
|
|
362
|
+
* arrives. The basket ends where the first holding's closes end, and says
|
|
363
|
+
* which.
|
|
364
|
+
*/
|
|
365
|
+
export function buyAndHoldReturns(
|
|
366
|
+
holdings: readonly { weight: number; returns: readonly DatedReturn[] }[],
|
|
367
|
+
since: string,
|
|
368
|
+
calendar?: readonly DatedReturn[],
|
|
369
|
+
): HeldBasket {
|
|
370
|
+
const unpriced: number[] = [];
|
|
371
|
+
// Each holding's price relative to its start close, by date, along its own unbroken run of closes.
|
|
372
|
+
const paths = holdings.flatMap((row, index) => {
|
|
373
|
+
if (!Number.isFinite(row.weight) || row.weight <= 0) return [];
|
|
374
|
+
const points = row.returns
|
|
375
|
+
.filter((point) => valid(point) && point.dateKey > since)
|
|
376
|
+
.toSorted((left, right) => left.dateKey.localeCompare(right.dateKey));
|
|
377
|
+
if (!points.length || points[0]!.startDateKey > since) {
|
|
378
|
+
unpriced.push(index);
|
|
379
|
+
return [];
|
|
380
|
+
}
|
|
381
|
+
const levels: Array<{ date: string; level: number }> = [];
|
|
382
|
+
let level = 1;
|
|
383
|
+
for (const [at, point] of points.entries()) {
|
|
384
|
+
if (at > 0 && point.startDateKey !== points[at - 1]!.dateKey) break;
|
|
385
|
+
level *= 1 + point.value;
|
|
386
|
+
levels.push({ date: point.dateKey, level });
|
|
387
|
+
}
|
|
388
|
+
return [{ index, weight: row.weight, start: points[0]!.startDateKey, levels }];
|
|
389
|
+
});
|
|
390
|
+
if (!paths.length) return { returns: [], cutShort: null, unpriced };
|
|
391
|
+
const sessions = (calendar
|
|
392
|
+
? calendar.filter((point) => valid(point) && point.dateKey > since).map((point) => point.dateKey)
|
|
393
|
+
: [...new Set(paths.flatMap((path) => path.levels.map((point) => point.date)))]
|
|
394
|
+
).toSorted();
|
|
395
|
+
// Known up to the earliest last close: past it a holding's value is unknown, not flat.
|
|
396
|
+
const last = paths.reduce((first, path) => (path.levels.at(-1)!.date < first.levels.at(-1)!.date ? path : first));
|
|
397
|
+
const end = last.levels.at(-1)!.date;
|
|
398
|
+
const total = paths.reduce((sum, path) => sum + path.weight, 0);
|
|
399
|
+
// The close the basket is bought at: the latest start close among the holdings.
|
|
400
|
+
const bought = paths.reduce((latest, path) => (path.start > latest ? path.start : latest), "");
|
|
401
|
+
const cursor = paths.map(() => -1);
|
|
402
|
+
const returns: DatedReturn[] = [];
|
|
403
|
+
let previous = { date: since, value: 1 };
|
|
404
|
+
for (const date of sessions) {
|
|
405
|
+
if (date > end) break;
|
|
406
|
+
let value = 0;
|
|
407
|
+
for (const [at, path] of paths.entries()) {
|
|
408
|
+
let next = cursor[at]!;
|
|
409
|
+
while (next + 1 < path.levels.length && path.levels[next + 1]!.date <= date) next += 1;
|
|
410
|
+
cursor[at] = next;
|
|
411
|
+
value += (path.weight / total) * (next < 0 ? 1 : path.levels[next]!.level);
|
|
412
|
+
}
|
|
413
|
+
const start = returns.length ? previous.date
|
|
414
|
+
: (calendar?.find((point) => point.dateKey === date)?.startDateKey ?? bought);
|
|
415
|
+
returns.push({ startDateKey: start, dateKey: date, value: value / previous.value - 1 });
|
|
416
|
+
previous = { date, value };
|
|
417
|
+
}
|
|
418
|
+
const lastSession = sessions.at(-1);
|
|
419
|
+
return {
|
|
420
|
+
returns,
|
|
421
|
+
cutShort: lastSession && end < lastSession ? { holding: last.index, date: end } : null,
|
|
422
|
+
unpriced,
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
|
|
343
426
|
export function rollingBeta(
|
|
344
427
|
asset: readonly DatedReturn[],
|
|
345
428
|
factor: readonly DatedReturn[],
|