gloomberb 0.18.3 → 0.18.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/README.zh-CN.md +11 -11
- package/bin/{gloomberb → gloom} +3 -1
- package/package.json +6 -2
- package/src/account/checkout-handoff.tsx +225 -0
- package/src/account/device-signin-dialog.tsx +2 -2
- package/src/account/device-signin.ts +2 -2
- package/src/account/upgrade-dialog.tsx +1 -1
- package/src/api-client/askg.ts +2 -2
- package/src/api-client/auth.ts +2 -2
- package/src/api-client/central-bank-rates.ts +6 -0
- package/src/api-client/collections.ts +5 -1
- package/src/api-client/cot.ts +2 -0
- package/src/api-client/crypto-etf-flows.ts +37 -0
- package/src/api-client/crypto-markets.ts +60 -0
- package/src/api-client/data.ts +84 -5
- package/src/api-client/doe.ts +15 -0
- package/src/api-client/equity-screener.ts +28 -0
- package/src/api-client/exchange-announcements.ts +38 -0
- package/src/api-client/fund-facts.ts +39 -0
- package/src/api-client/futures-curve.ts +9 -1
- package/src/api-client/hiring.ts +301 -0
- package/src/api-client/index.ts +22 -5
- package/src/api-client/market-discovery.ts +14 -0
- package/src/api-client/members.ts +6 -0
- package/src/api-client/mna.ts +6 -0
- package/src/api-client/paths.ts +18 -1
- package/src/api-client/request.ts +21 -4
- package/src/api-client/short-side-publications.ts +37 -0
- package/src/api-client/socket.ts +64 -4
- package/src/api-client/swap-curve.ts +35 -0
- package/src/api-client/themes.ts +7 -1
- package/src/api-client/types.ts +90 -2
- package/src/app/pane-runtime/plugin-bindings.ts +9 -2
- package/src/app/runtime/desktop-deeplink.ts +5 -5
- package/src/app/runtime/plugin-bindings.ts +2 -2
- package/src/app/runtime/startup.ts +13 -0
- package/src/app/star-prompt/status-line.tsx +2 -2
- package/src/architecture/core-builtin-allowlist.json +5 -2
- package/src/architecture/ui-literals-allowlist.json +3 -3
- package/src/architecture/ui-tokens-allowlist.json +1 -1
- package/src/brokers/broker-portfolio-sync.ts +37 -0
- package/src/brokers/directory.ts +11 -0
- package/src/brokers/logos.ts +3 -1
- package/src/brokers/signed-in/adapter.ts +304 -26
- package/src/brokers/signed-in/client.ts +14 -2
- package/src/brokers/signed-in/connect.ts +10 -2
- package/src/brokers/sync-broker-instance.ts +9 -1
- package/src/capabilities/chart-series.ts +22 -6
- package/src/cli/bank-section.ts +1 -1
- package/src/cli/base-converter.ts +23 -14
- package/src/cli/central-bank-events.ts +1 -1
- package/src/cli/command-options.ts +59 -4
- package/src/cli/commands/api.ts +9 -6
- package/src/cli/commands/broker.ts +2 -2
- package/src/cli/commands/command-utils.ts +2 -2
- package/src/cli/commands/crypto-hints.ts +7 -20
- package/src/cli/commands/fred-series.ts +4 -2
- package/src/cli/commands/keybindings.ts +2 -2
- package/src/cli/commands/market.ts +1117 -264
- package/src/cli/commands/news-hints.ts +2 -2
- package/src/cli/commands/news-search.ts +59 -6
- package/src/cli/commands/options-leaps.ts +41 -26
- package/src/cli/commands/overview.ts +121 -48
- package/src/cli/commands/plugins.ts +9 -9
- package/src/cli/commands/remote.ts +13 -10
- package/src/cli/commands/search.ts +64 -44
- package/src/cli/commands/system.ts +27 -19
- package/src/cli/commands/themes.ts +1 -1
- package/src/cli/commands/ticker.ts +192 -47
- package/src/cli/context.ts +3 -2
- package/src/cli/desktop-pane-shot-view.ts +2 -2
- package/src/cli/desktop-pane-shot.ts +1 -1
- package/src/cli/earnings-calendar.ts +4 -4
- package/src/cli/entry.ts +18 -1
- package/src/cli/errors.ts +20 -2
- package/src/cli/exit-codes.ts +1 -1
- package/src/cli/export-source.ts +10 -4
- package/src/cli/freshness.ts +2 -8
- package/src/cli/fx-forward.ts +130 -0
- package/src/cli/fx-pair.ts +10 -9
- package/src/cli/glossary.ts +64 -20
- package/src/cli/help.ts +19 -13
- package/src/cli/history-export.ts +126 -0
- package/src/cli/history-rows.ts +196 -43
- package/src/cli/index-roots.ts +5 -45
- package/src/cli/index.ts +24 -18
- package/src/cli/known-gaps.ts +118 -25
- package/src/cli/listing-arg.ts +300 -41
- package/src/cli/name-entries.ts +30 -18
- package/src/cli/native-smoke.ts +2 -0
- package/src/cli/not-a-ticker.ts +19 -9
- package/src/cli/opentui-libc.ts +5 -0
- package/src/cli/options.ts +12 -0
- package/src/cli/pane-functions/capabilities.ts +75 -20
- package/src/cli/pane-functions/catalog.ts +24 -23
- package/src/cli/pane-functions/discovery.ts +1 -1
- package/src/cli/pane-functions/dom.ts +10 -7
- package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
- package/src/cli/pane-functions/freshness.ts +174 -23
- package/src/cli/pane-functions/function-help.ts +66 -27
- package/src/cli/pane-functions/headless.ts +24 -11
- package/src/cli/pane-functions/index.ts +18 -16
- package/src/cli/pane-functions/options.ts +22 -2
- package/src/cli/pane-functions/report-notices.ts +12 -4
- package/src/cli/pane-functions/report.ts +5 -5
- package/src/cli/pane-functions/resolver.ts +47 -10
- package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
- package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
- package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
- package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
- package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
- package/src/cli/pane-functions/screenshot-payload.ts +453 -0
- package/src/cli/pane-functions/screenshot-render.ts +316 -0
- package/src/cli/pane-functions/screenshot-types.ts +162 -0
- package/src/cli/pane-functions/shot-options.ts +8 -3
- package/src/cli/peso-dollar-rates.ts +79 -0
- package/src/cli/quote-answer.ts +38 -3
- package/src/cli/report-tables.ts +61 -16
- package/src/cli/restore-plugins.ts +29 -14
- package/src/cli/result.ts +111 -22
- package/src/cli/series-search.ts +5 -5
- package/src/cli/statement-filings.ts +19 -0
- package/src/cli/suffixed-listing-rows.ts +49 -0
- package/src/cli/symbol-args.ts +50 -15
- package/src/cli/symbol-cells.ts +120 -0
- package/src/cli/symbol-list.ts +198 -68
- package/src/cli/symbol-rows.ts +131 -25
- package/src/cli/ticker-resolution.ts +108 -11
- package/src/cli/treasury-yields.ts +5 -5
- package/src/cli/types.ts +2 -0
- package/src/cli/uncovered-instrument.ts +3 -3
- package/src/cli/unknown-command.ts +6 -6
- package/src/components/chart/composite/chart-layout.ts +131 -0
- package/src/components/chart/composite/composite-chart.tsx +373 -16
- package/src/components/chart/composite/interactions.ts +7 -2
- package/src/components/chart/composite/legend.tsx +75 -3
- package/src/components/chart/composite/levels.ts +5 -0
- package/src/components/chart/composite/panel-gestures.ts +41 -0
- package/src/components/chart/composite/panel-labels.ts +2 -1
- package/src/components/chart/composite/panel-surface.tsx +305 -11
- package/src/components/chart/composite/price-axis-labels.tsx +27 -3
- package/src/components/chart/composite/rasterizer.ts +44 -19
- package/src/components/chart/composite/scene.ts +16 -4
- package/src/components/chart/composite/text-renderer.ts +48 -21
- package/src/components/chart/composite/toolbar.tsx +52 -5
- package/src/components/chart/composite/types.ts +13 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
- package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
- package/src/components/chart/composite/use-composite-viewport.ts +12 -3
- package/src/components/chart/composite/value-scale.ts +149 -0
- package/src/components/chart/composite/volume-profile-paint.ts +6 -3
- package/src/components/chart/core/pointer.ts +2 -0
- package/src/components/chart-table/index.ts +2 -0
- package/src/components/chart-table/read.tsx +74 -0
- package/src/components/command-bar/commands/collection-list.ts +41 -19
- package/src/components/command-bar/commands/collection.ts +9 -3
- package/src/components/command-bar/commands/direct/index.ts +1 -1
- package/src/components/command-bar/commands/direct/runtime.ts +3 -2
- package/src/components/command-bar/pane-templates/items.ts +59 -6
- package/src/components/command-bar/pane-templates/workflow.ts +10 -1
- package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
- package/src/components/command-bar/routes/root/provider-search.ts +42 -11
- package/src/components/command-bar/routes/root/results.ts +18 -4
- package/src/components/command-bar/routes/root/runtime.ts +15 -3
- package/src/components/command-bar/routes/root/search-providers.ts +25 -2
- package/src/components/command-bar/routes/root/selection.ts +6 -1
- package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
- package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
- package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
- package/src/components/command-bar/selection-runtime.ts +50 -10
- package/src/components/command-bar/surface/index.tsx +24 -2
- package/src/components/command-bar/view-model.ts +7 -0
- package/src/components/command-bar/workflow/broker.ts +2 -2
- package/src/components/command-bar/workflow/collection-actions.ts +46 -7
- package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
- package/src/components/command-bar/workflow/fields.ts +8 -2
- package/src/components/command-bar/workflow/ops.ts +18 -4
- package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
- package/src/components/command-bar/workflow/submit.ts +3 -2
- package/src/components/command-bar/workflow/tickers.ts +5 -1
- package/src/components/company-logo.tsx +39 -0
- package/src/components/data-table/sections.ts +4 -2
- package/src/components/form-modal/confirm.tsx +2 -1
- package/src/components/form-modal/request.ts +5 -0
- package/src/components/form-modal/routes.ts +4 -1
- package/src/components/index.ts +12 -6
- package/src/components/layout/header.tsx +7 -6
- package/src/components/layout/market-summary.ts +9 -6
- package/src/components/layout/pane/capture-status.ts +1 -1
- package/src/components/layout/pane/footer/model.ts +11 -5
- package/src/components/layout/shell/chrome.ts +19 -6
- package/src/components/layout/shell/index.tsx +2 -1
- package/src/components/layout/shell/pane/layers.tsx +19 -1
- package/src/components/layout/status-bar.tsx +2 -2
- package/src/components/market-board/index.tsx +11 -3
- package/src/components/onboarding/onboarding-wizard.tsx +1 -0
- package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
- package/src/components/onboarding/wizard-broker-sync.ts +4 -1
- package/src/components/pane-settings-dialog/desktop.tsx +20 -7
- package/src/components/pane-settings-dialog/tui.tsx +17 -9
- package/src/components/pane-settings-dialog/value.ts +8 -1
- package/src/components/pane-settings-dialog.tsx +44 -13
- package/src/components/sign-in-code-panel.tsx +27 -19
- package/src/components/ui/column-grid.tsx +48 -4
- package/src/components/ui/country-flag-art.tsx +180 -0
- package/src/components/ui/country-flag.tsx +118 -12
- package/src/components/ui/data-table/opentui/index.tsx +61 -2
- package/src/components/ui/data-table/opentui/model.ts +109 -2
- package/src/components/ui/data-table/types.ts +1 -1
- package/src/components/ui/display.tsx +5 -1
- package/src/components/ui/index.ts +3 -1
- package/src/components/ui/logo-mark.tsx +11 -2
- package/src/components/ui/query-bar.tsx +1 -1
- package/src/components/ui/row-notes.ts +79 -0
- package/src/core/state/app/layout.ts +4 -4
- package/src/data/cached-query.ts +8 -1
- package/src/data/config/chart-settings.ts +3 -3
- package/src/data/config/home.ts +10 -2
- package/src/data/config/layout.ts +4 -1
- package/src/data/config/store/node.ts +4 -0
- package/src/data/config/store/normalize.ts +13 -3
- package/src/data/config/store/portfolio-as-of-column.ts +2 -2
- package/src/data/json-storage.ts +2 -0
- package/src/data/saved-copies.ts +84 -0
- package/src/docs/snapshot.json +65 -32
- package/src/i18n/es.ts +29 -12
- package/src/i18n/ja.ts +29 -12
- package/src/i18n/ko.ts +29 -12
- package/src/i18n/zh-cn.ts +29 -12
- package/src/i18n/zh-tw.ts +29 -12
- package/src/layout/desks.ts +1 -1
- package/src/layout/launch-layout.ts +1 -1
- package/src/layout/pane-manager/floating-actions.ts +5 -3
- package/src/layout/pane-manager/floating.ts +43 -1
- package/src/layout/pane-manager/index.ts +2 -0
- package/src/layout/selected-ticker.ts +74 -0
- package/src/market-data/depositary-pair.ts +251 -0
- package/src/market-data/futures-board.ts +1 -1
- package/src/market-data/futures-contract.ts +124 -40
- package/src/market-data/fx-closes.ts +17 -2
- package/src/market-data/hooks.tsx +19 -11
- package/src/market-data/market/change-basis.ts +49 -7
- package/src/market-data/market/freshness.ts +34 -5
- package/src/market-data/market/period-return.ts +163 -0
- package/src/market-data/market/trading-sessions.ts +13 -0
- package/src/market-data/market/year-to-date.ts +8 -13
- package/src/market-data/performance.ts +20 -14
- package/src/market-data/perpetual-premium.ts +32 -0
- package/src/market-data/published-apac-sessions.ts +2 -1
- package/src/market-data/published-futures-sessions.ts +69 -0
- package/src/market-data/quotes/contributions.ts +5 -1
- package/src/market-data/quotes/freshness.ts +42 -0
- package/src/market-data/quotes/intraday-bar.ts +37 -0
- package/src/market-data/quotes/regular-session-valuation.ts +13 -8
- package/src/market-data/quotes/resolution.ts +4 -2
- package/src/market-data/tax-equivalent.ts +1 -1
- package/src/market-data/ticker-price-returns.ts +3 -1
- package/src/news/aggregator.ts +5 -1
- package/src/news/news-model.ts +4 -0
- package/src/news/types.ts +11 -0
- package/src/notifications/app-notifier.ts +1 -1
- package/src/plugins/auto-update.ts +2 -2
- package/src/plugins/builtin/account-management/index.tsx +1 -0
- package/src/plugins/builtin/account-management/pane.tsx +9 -8
- package/src/plugins/builtin/alerts/alert-engine.ts +29 -19
- package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
- package/src/plugins/builtin/alerts/cli.ts +485 -76
- package/src/plugins/builtin/alerts/command.ts +5 -10
- package/src/plugins/builtin/alerts/event-rows.ts +9 -5
- package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
- package/src/plugins/builtin/alerts/events.ts +107 -5
- package/src/plugins/builtin/alerts/fired-log.ts +78 -0
- package/src/plugins/builtin/alerts/format.ts +2 -1
- package/src/plugins/builtin/alerts/headless.ts +100 -39
- package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
- package/src/plugins/builtin/alerts/history-rows.ts +89 -0
- package/src/plugins/builtin/alerts/index.tsx +45 -18
- package/src/plugins/builtin/alerts/iv-level.ts +365 -0
- package/src/plugins/builtin/alerts/levels.ts +3 -3
- package/src/plugins/builtin/alerts/pane.tsx +97 -29
- package/src/plugins/builtin/alerts/price.ts +35 -0
- package/src/plugins/builtin/alerts/quotes.ts +24 -0
- package/src/plugins/builtin/alerts/research-builder.ts +84 -11
- package/src/plugins/builtin/alerts/research-rules.ts +76 -3
- package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
- package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
- package/src/plugins/builtin/alerts/scheduled.ts +188 -29
- package/src/plugins/builtin/alerts/storage.ts +13 -10
- package/src/plugins/builtin/alerts/targets.ts +12 -3
- package/src/plugins/builtin/analytics/index.tsx +8 -2
- package/src/plugins/builtin/analytics/metrics.ts +1 -1
- package/src/plugins/builtin/analytics/risk-book.ts +215 -0
- package/src/plugins/builtin/analytics/risk-client.ts +13 -6
- package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
- package/src/plugins/builtin/analytics/risk-math.ts +6 -3
- package/src/plugins/builtin/analytics/risk-model.ts +297 -104
- package/src/plugins/builtin/analytics/risk-options.ts +17 -2
- package/src/plugins/builtin/analytics/risk-pane.tsx +97 -36
- package/src/plugins/builtin/attention/pane.tsx +6 -2
- package/src/plugins/builtin/awards/headless.ts +7 -3
- package/src/plugins/builtin/awards/model.ts +18 -0
- package/src/plugins/builtin/awards/pane.tsx +6 -3
- package/src/plugins/builtin/backtest/headless.ts +3 -3
- package/src/plugins/builtin/backtest/rules.ts +41 -5
- package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
- package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
- package/src/plugins/builtin/broker-manager/footer.ts +27 -11
- package/src/plugins/builtin/broker-manager/index.tsx +21 -12
- package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
- package/src/plugins/builtin/broker-manager/model.ts +12 -2
- package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
- package/src/plugins/builtin/broker-manager/table.ts +28 -12
- package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
- package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
- package/src/plugins/builtin/broker-trading/controller.ts +45 -13
- package/src/plugins/builtin/broker-trading/dock.tsx +22 -4
- package/src/plugins/builtin/broker-trading/headless.ts +2 -1
- package/src/plugins/builtin/broker-trading/index.tsx +7 -1
- package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
- package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
- package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
- package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
- package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
- package/src/plugins/builtin/broker-trading/pane.tsx +110 -23
- package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
- package/src/plugins/builtin/broker-trading/ticket.tsx +112 -31
- package/src/plugins/builtin/buildout/cells.tsx +4 -0
- package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
- package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
- package/src/plugins/builtin/buildout/pane/index.tsx +25 -12
- package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
- package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
- package/src/plugins/builtin/catalysts/detail.tsx +3 -2
- package/src/plugins/builtin/catalysts/index.tsx +1 -1
- package/src/plugins/builtin/catalysts/model.ts +49 -4
- package/src/plugins/builtin/catalysts/pane.tsx +6 -8
- package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
- package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
- package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
- package/src/plugins/builtin/changelog/index.tsx +1 -0
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
- package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
- package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
- package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
- package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
- package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
- package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
- package/src/plugins/builtin/chart-composer/headless.ts +253 -35
- package/src/plugins/builtin/chart-composer/index.tsx +12 -2
- package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
- package/src/plugins/builtin/chart-composer/pane.tsx +127 -28
- package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
- package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
- package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
- package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
- package/src/plugins/builtin/chart-composer/settings.ts +31 -19
- package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
- package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
- package/src/plugins/builtin/chat/attachments/model.ts +3 -1
- package/src/plugins/builtin/chat/content/index.tsx +1 -1
- package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
- package/src/plugins/builtin/chat/people.ts +1 -1
- package/src/plugins/builtin/clinical-trials/client.ts +5 -2
- package/src/plugins/builtin/clinical-trials/model.ts +13 -4
- package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
- package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
- package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
- package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
- package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
- package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
- package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
- package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
- package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
- package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
- package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
- package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
- package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
- package/src/plugins/builtin/commodity-balances/pane.tsx +11 -4
- package/src/plugins/builtin/company-attention/app-rank.tsx +7 -5
- package/src/plugins/builtin/company-attention/building-model.ts +222 -0
- package/src/plugins/builtin/company-attention/building.tsx +172 -0
- package/src/plugins/builtin/company-attention/client.ts +117 -1
- package/src/plugins/builtin/company-attention/evidence.ts +16 -3
- package/src/plugins/builtin/company-attention/headless.ts +101 -5
- package/src/plugins/builtin/company-attention/index.tsx +6 -3
- package/src/plugins/builtin/company-attention/model.ts +33 -7
- package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
- package/src/plugins/builtin/company-attention/moves.tsx +159 -0
- package/src/plugins/builtin/company-attention/pane.tsx +79 -23
- package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
- package/src/plugins/builtin/company-attention/signals.tsx +160 -0
- package/src/plugins/builtin/company-kpis/headless.ts +3 -2
- package/src/plugins/builtin/company-kpis/model.ts +2 -2
- package/src/plugins/builtin/company-kpis/pane.tsx +1 -1
- package/src/plugins/builtin/composite-plugins.ts +2 -1
- package/src/plugins/builtin/congress-trades/headless.ts +1 -1
- package/src/plugins/builtin/connections/index.ts +1 -0
- package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
- package/src/plugins/builtin/correlation/headless.ts +5 -3
- package/src/plugins/builtin/cot/headless.ts +28 -6
- package/src/plugins/builtin/cot/model.ts +12 -0
- package/src/plugins/builtin/cot/pane.tsx +3 -2
- package/src/plugins/builtin/cpi/headless.ts +5 -1
- package/src/plugins/builtin/cpi/pane.tsx +11 -9
- package/src/plugins/builtin/credit-boards/model.ts +2 -0
- package/src/plugins/builtin/credit-documents/headless.ts +1 -1
- package/src/plugins/builtin/crypto-board/client.ts +86 -0
- package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
- package/src/plugins/builtin/crypto-board/defi.ts +239 -0
- package/src/plugins/builtin/crypto-board/headless.ts +117 -6
- package/src/plugins/builtin/crypto-board/index.tsx +8 -3
- package/src/plugins/builtin/crypto-board/model.ts +40 -8
- package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
- package/src/plugins/builtin/crypto-board/series.ts +19 -1
- package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
- package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
- package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
- package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
- package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
- package/src/plugins/builtin/debug/index.tsx +1 -0
- package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
- package/src/plugins/builtin/docs/index.tsx +1 -1
- package/src/plugins/builtin/docs/pane.tsx +2 -2
- package/src/plugins/builtin/docs/targets.ts +1 -1
- package/src/plugins/builtin/doe/client.ts +5 -1
- package/src/plugins/builtin/doe/headless.ts +12 -6
- package/src/plugins/builtin/doe/model.ts +43 -6
- package/src/plugins/builtin/doe/pane.tsx +18 -11
- package/src/plugins/builtin/earnings/board-model.ts +13 -6
- package/src/plugins/builtin/earnings/board-table.ts +4 -1
- package/src/plugins/builtin/earnings/board.tsx +253 -50
- package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
- package/src/plugins/builtin/earnings/calendar.tsx +338 -0
- package/src/plugins/builtin/earnings/client.ts +4 -3
- package/src/plugins/builtin/earnings/headless.ts +53 -15
- package/src/plugins/builtin/earnings/history-model.ts +53 -36
- package/src/plugins/builtin/earnings/index.tsx +15 -22
- package/src/plugins/builtin/earnings/model.ts +17 -12
- package/src/plugins/builtin/earnings/scope.ts +89 -0
- package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
- package/src/plugins/builtin/earnings-calls/data.ts +146 -2
- package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
- package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
- package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
- package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
- package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
- package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
- package/src/plugins/builtin/econ/calendar-model.ts +132 -20
- package/src/plugins/builtin/econ/detail-view.tsx +48 -10
- package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
- package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
- package/src/plugins/builtin/econ/index.tsx +112 -25
- package/src/plugins/builtin/econ/print-watch.ts +2 -1
- package/src/plugins/builtin/econ/types.ts +32 -1
- package/src/plugins/builtin/econ-statistics/client.ts +16 -3
- package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
- package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
- package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
- package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
- package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
- package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
- package/src/plugins/builtin/econ-statistics/view.ts +16 -1
- package/src/plugins/builtin/equity-screener/client.ts +21 -3
- package/src/plugins/builtin/equity-screener/headless.ts +68 -6
- package/src/plugins/builtin/equity-screener/live.ts +1 -1
- package/src/plugins/builtin/equity-screener/model.ts +6 -0
- package/src/plugins/builtin/equity-screener/pane.tsx +45 -10
- package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
- package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
- package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
- package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
- package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
- package/src/plugins/builtin/exposure/headless.ts +51 -6
- package/src/plugins/builtin/exposure/index.tsx +28 -2
- package/src/plugins/builtin/exposure/model.ts +7 -0
- package/src/plugins/builtin/exposure/pane.tsx +6 -1
- package/src/plugins/builtin/fear-greed/index.tsx +1 -1
- package/src/plugins/builtin/filing-events/index.tsx +1 -1
- package/src/plugins/builtin/futures/model.ts +10 -9
- package/src/plugins/builtin/futures/returns.ts +8 -36
- package/src/plugins/builtin/futures/table.tsx +1 -1
- package/src/plugins/builtin/futures-curve/client.ts +40 -9
- package/src/plugins/builtin/futures-curve/headless.ts +39 -17
- package/src/plugins/builtin/futures-curve/model.ts +258 -69
- package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
- package/src/plugins/builtin/fx-matrix/client.ts +15 -8
- package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
- package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
- package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
- package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
- package/src/plugins/builtin/gpu/headless.ts +9 -4
- package/src/plugins/builtin/help/index.tsx +13 -3
- package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
- package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
- package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
- package/src/plugins/builtin/holders/client.ts +13 -1
- package/src/plugins/builtin/holders/format.ts +28 -17
- package/src/plugins/builtin/holders/headless.ts +46 -7
- package/src/plugins/builtin/holders/index-holders.ts +264 -0
- package/src/plugins/builtin/holders/pane.tsx +79 -15
- package/src/plugins/builtin/holders/report-rows.ts +35 -7
- package/src/plugins/builtin/holders/table-model.ts +2 -1
- package/src/plugins/builtin/holders/treemap.tsx +2 -2
- package/src/plugins/builtin/insider/headless.ts +1 -1
- package/src/plugins/builtin/insider/signals-client.ts +1 -1
- package/src/plugins/builtin/insider/signals.tsx +1 -1
- package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
- package/src/plugins/builtin/iv-history/client.ts +20 -0
- package/src/plugins/builtin/iv-history/headless.ts +4 -4
- package/src/plugins/builtin/iv-history/index.tsx +1 -1
- package/src/plugins/builtin/iv-history/model.ts +13 -4
- package/src/plugins/builtin/iv-history/series.ts +3 -1
- package/src/plugins/builtin/jobs/lock-note.ts +1 -1
- package/src/plugins/builtin/jobs/model.ts +4 -15
- package/src/plugins/builtin/jobs/pane.tsx +7 -5
- package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
- package/src/plugins/builtin/jodi/pane.tsx +10 -4
- package/src/plugins/builtin/layout-manager/index.tsx +1 -0
- package/src/plugins/builtin/macro-day/headless.ts +20 -7
- package/src/plugins/builtin/macro-day/index.tsx +3 -2
- package/src/plugins/builtin/macro-day/model.ts +29 -8
- package/src/plugins/builtin/macro-day/pane.tsx +46 -10
- package/src/plugins/builtin/macro-day/releases.ts +55 -13
- package/src/plugins/builtin/market-heatmap/data.ts +9 -2
- package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
- package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
- package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
- package/src/plugins/builtin/market-heatmap/model.ts +10 -7
- package/src/plugins/builtin/market-movers/client.ts +33 -19
- package/src/plugins/builtin/market-movers/headless.ts +8 -2
- package/src/plugins/builtin/market-movers/index.tsx +16 -10
- package/src/plugins/builtin/market-movers/screener.ts +29 -8
- package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
- package/src/plugins/builtin/market-movers/session-table.ts +4 -2
- package/src/plugins/builtin/market-movers/table.ts +4 -1
- package/src/plugins/builtin/market-valuation/headless.ts +2 -0
- package/src/plugins/builtin/market-valuation/view.ts +5 -0
- package/src/plugins/builtin/members/headless.ts +6 -5
- package/src/plugins/builtin/members/pane.tsx +11 -4
- package/src/plugins/builtin/mna/client.ts +1 -0
- package/src/plugins/builtin/mna/detail.tsx +20 -32
- package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
- package/src/plugins/builtin/mna/distress/model.ts +3 -2
- package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
- package/src/plugins/builtin/mna/headless.ts +6 -13
- package/src/plugins/builtin/mna/model.ts +93 -15
- package/src/plugins/builtin/mna/pane.tsx +5 -4
- package/src/plugins/builtin/news/headless.ts +12 -6
- package/src/plugins/builtin/news/index.tsx +10 -1
- package/src/plugins/builtin/news/wire/index.tsx +3 -2
- package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
- package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
- package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
- package/src/plugins/builtin/notes/cli.ts +49 -14
- package/src/plugins/builtin/openfda/pane.tsx +1 -1
- package/src/plugins/builtin/options/carry.ts +2 -2
- package/src/plugins/builtin/options/index.tsx +1 -1
- package/src/plugins/builtin/options/view.tsx +10 -10
- package/src/plugins/builtin/options-calculator/headless.ts +46 -7
- package/src/plugins/builtin/options-scenario/client.ts +123 -28
- package/src/plugins/builtin/options-scenario/collar.ts +8 -6
- package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
- package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
- package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
- package/src/plugins/builtin/options-scenario/csp.ts +101 -21
- package/src/plugins/builtin/options-scenario/headless.ts +36 -15
- package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
- package/src/plugins/builtin/options-scenario/index.tsx +28 -3
- package/src/plugins/builtin/options-scenario/model.ts +13 -0
- package/src/plugins/builtin/options-scenario/pane.tsx +9 -5
- package/src/plugins/builtin/perps/equity-row.tsx +11 -3
- package/src/plugins/builtin/perps/freshness.ts +8 -5
- package/src/plugins/builtin/perps/headless.ts +3 -1
- package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
- package/src/plugins/builtin/perps/live-rows.ts +161 -0
- package/src/plugins/builtin/perps/markets-section.tsx +154 -0
- package/src/plugins/builtin/perps/pane.tsx +36 -17
- package/src/plugins/builtin/perps/venue-markets.ts +96 -0
- package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +143 -59
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +72 -24
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
- package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
- package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
- package/src/plugins/builtin/portfolio-list/income.ts +13 -2
- package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
- package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
- package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
- package/src/plugins/builtin/power/client.ts +4 -1
- package/src/plugins/builtin/power/evidence.ts +22 -7
- package/src/plugins/builtin/power/gas.tsx +5 -1
- package/src/plugins/builtin/power/pane.tsx +8 -1
- package/src/plugins/builtin/power/prices.tsx +10 -3
- package/src/plugins/builtin/research/analyst-headless.ts +25 -8
- package/src/plugins/builtin/research/analyst-model.ts +68 -3
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
- package/src/plugins/builtin/research/event-model.ts +3 -1
- package/src/plugins/builtin/research/event-sources.ts +12 -4
- package/src/plugins/builtin/research/index.tsx +2 -1
- package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
- package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
- package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
- package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
- package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
- package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
- package/src/plugins/builtin/reverse-dcf/model.ts +6 -2
- package/src/plugins/builtin/risk-factors/index.tsx +2 -2
- package/src/plugins/builtin/scanner/lock-note.ts +1 -1
- package/src/plugins/builtin/sec/forms.ts +13 -0
- package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
- package/src/plugins/builtin/sec/fund-facts.ts +68 -8
- package/src/plugins/builtin/sec/headless.ts +85 -8
- package/src/plugins/builtin/sec/index.tsx +58 -12
- package/src/plugins/builtin/sectors/client.ts +2 -1
- package/src/plugins/builtin/sectors/sector-model.ts +11 -15
- package/src/plugins/builtin/series-inventory.ts +2 -0
- package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
- package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
- package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
- package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
- package/src/plugins/builtin/shared/earnings-report.ts +3 -3
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
- package/src/plugins/builtin/shared/job-posting.ts +129 -0
- package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
- package/src/plugins/builtin/shared/report-freshness.ts +3 -0
- package/src/plugins/builtin/shared/research-trading.tsx +21 -0
- package/src/plugins/builtin/shared/series-cache.ts +2 -0
- package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
- package/src/plugins/builtin/short-interest/client.ts +2 -0
- package/src/plugins/builtin/short-interest/headless.ts +41 -12
- package/src/plugins/builtin/short-interest/index.tsx +23 -1
- package/src/plugins/builtin/short-interest/model.ts +70 -19
- package/src/plugins/builtin/short-interest/pane.tsx +19 -2
- package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
- package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
- package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
- package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
- package/src/plugins/builtin/short-interest/schedule.ts +35 -2
- package/src/plugins/builtin/short-interest/surface.tsx +11 -4
- package/src/plugins/builtin/short-interest/types.ts +9 -0
- package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
- package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
- package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
- package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
- package/src/plugins/builtin/supply-chain/model.ts +51 -3
- package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
- package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
- package/src/plugins/builtin/themes/headless.ts +8 -5
- package/src/plugins/builtin/themes/model.ts +14 -4
- package/src/plugins/builtin/themes/pane.tsx +24 -5
- package/src/plugins/builtin/thirteenf/headless.ts +5 -5
- package/src/plugins/builtin/thirteenf/signals.ts +3 -1
- package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
- package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
- package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
- package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
- package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
- package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
- package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
- package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
- package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
- package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
- package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
- package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
- package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
- package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
- package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
- package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
- package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
- package/src/plugins/builtin/vol-surface/client.ts +5 -4
- package/src/plugins/builtin/vol-surface/headless.ts +12 -3
- package/src/plugins/builtin/vol-surface/model.ts +4 -2
- package/src/plugins/builtin/volatility/model.ts +5 -10
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
- package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
- package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
- package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
- package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
- package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
- package/src/plugins/builtin/world-venue-map/index.ts +3 -26
- package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
- package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
- package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
- package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
- package/src/plugins/builtin/yield-curve/client.ts +25 -0
- package/src/plugins/builtin/yield-curve/curves.ts +7 -4
- package/src/plugins/builtin/yield-curve/headless.ts +38 -4
- package/src/plugins/builtin/yield-curve/history.ts +4 -3
- package/src/plugins/builtin/yield-curve/index.tsx +12 -6
- package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
- package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
- package/src/plugins/bundle.ts +1 -1
- package/src/plugins/catalog-browser.ts +2 -1
- package/src/plugins/compat.ts +3 -3
- package/src/plugins/dependencies.ts +75 -14
- package/src/plugins/extracted-plugins.ts +132 -34
- package/src/plugins/host-link.ts +149 -34
- package/src/plugins/installer.ts +35 -10
- package/src/plugins/loader.ts +206 -38
- package/src/plugins/manager-node.ts +2 -2
- package/src/plugins/marketplace/deactivation.ts +22 -0
- package/src/plugins/marketplace/model.ts +2 -2
- package/src/plugins/marketplace/packs.ts +1 -1
- package/src/plugins/ownership.ts +1 -1
- package/src/plugins/peer-retry.ts +155 -0
- package/src/plugins/registry/contributions.ts +3 -1
- package/src/plugins/registry/index.ts +4 -3
- package/src/plugins/registry/plugin-state.ts +3 -0
- package/src/plugins/seed-notice.ts +20 -0
- package/src/plugins/shortcut-argument.ts +39 -0
- package/src/portfolio/allocation.ts +1 -1
- package/src/portfolio/collection-name.ts +31 -0
- package/src/portfolio/column-values.ts +10 -8
- package/src/portfolio/cost-fx.ts +296 -19
- package/src/portfolio/manual-lots.ts +75 -0
- package/src/portfolio/mutations.ts +60 -22
- package/src/portfolio/suffixed-listings.ts +209 -0
- package/src/portfolio/totals-currency.ts +24 -0
- package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
- package/src/public/time-series.ts +11 -8
- package/src/remote/schema.ts +1 -1
- package/src/renderers/browser/config-host.ts +3 -0
- package/src/renderers/browser/main.tsx +23 -3
- package/src/renderers/dom/boot-frame-page.ts +187 -0
- package/src/renderers/dom/boot-frame.ts +237 -0
- package/src/renderers/dom/build-assets.ts +46 -8
- package/src/renderers/dom/dom-ui-host.tsx +4 -29
- package/src/renderers/dom/host/ascii-text.ts +16 -2
- package/src/renderers/dom/host/box.tsx +43 -2
- package/src/renderers/dom/host/chart-surface.tsx +2 -0
- package/src/renderers/dom/host/hls.chunk.ts +3 -0
- package/src/renderers/dom/host/image-surface.tsx +49 -0
- package/src/renderers/dom/host/media-surface.tsx +24 -18
- package/src/renderers/dom/host/mouse.ts +30 -0
- package/src/renderers/dom/host/size-observer.ts +1 -1
- package/src/renderers/dom/host/style.ts +1 -1
- package/src/renderers/dom/styles.css +76 -0
- package/src/renderers/dom/test-utils.tsx +2 -1
- package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +46 -3
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
- package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
- package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
- package/src/renderers/electrobun/bun/index.ts +11 -1
- package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
- package/src/renderers/electrobun/bun/window/create.ts +4 -1
- package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
- package/src/renderers/electrobun/shared/protocol.ts +6 -1
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
- package/src/renderers/electrobun/view/config-host.ts +3 -0
- package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
- package/src/renderers/electrobun/view/main.tsx +30 -4
- package/src/renderers/electrobun/view/news-source.ts +5 -5
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -1
- package/src/renderers/electrobun/view/ui-host.tsx +1 -1
- package/src/renderers/opentui/browser-open.ts +88 -0
- package/src/renderers/opentui/host.tsx +5 -14
- package/src/renderers/opentui/image/loader.ts +3 -2
- package/src/renderers/opentui/native-smoke.ts +10 -1
- package/src/renderers/opentui/pane-image/index.ts +2 -1
- package/src/renderers/opentui/render-lib.ts +253 -0
- package/src/renderers/opentui/render-timing-smoke.ts +1 -1
- package/src/renderers/opentui/start.tsx +1 -1
- package/src/renderers/share/layout-view.tsx +2 -2
- package/src/renderers/share/main.tsx +4 -4
- package/src/renderers/share/view.tsx +1 -1
- package/src/series/resolve.ts +22 -6
- package/src/series/standalone.ts +30 -2
- package/src/series/types.ts +8 -1
- package/src/shares/api.ts +4 -1
- package/src/shares/pane.ts +1 -1
- package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
- package/src/sources/gloomberb-cloud/index.ts +32 -16
- package/src/sources/gloomberb-cloud/news.ts +39 -0
- package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
- package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
- package/src/sources/listing-symbols.ts +37 -0
- package/src/sources/provider-errors.ts +16 -2
- package/src/sources/provider-router/financial-routes.ts +21 -3
- package/src/sources/provider-router/financials.ts +15 -2
- package/src/sources/provider-router/history.ts +30 -8
- package/src/sources/provider-router/primary.ts +1 -1
- package/src/state/app/bootstrap.ts +23 -0
- package/src/state/hooks/inline-tickers.ts +30 -5
- package/src/sync/controller.ts +1 -1
- package/src/sync/core-contributors.ts +46 -14
- package/src/team/collections-sync.ts +2 -1
- package/src/team/collections.ts +178 -17
- package/src/telemetry/crash-reports.ts +17 -4
- package/src/test-support/builtin-panes.ts +1 -1
- package/src/theme/colors.ts +3 -30
- package/src/theme/ui-tokens.ts +37 -1
- package/src/tickers/company-name-listing.ts +210 -33
- package/src/tickers/index-roots.ts +47 -0
- package/src/tickers/instrument-label.ts +5 -1
- package/src/tickers/metadata.ts +10 -0
- package/src/tickers/perpetual-listing.ts +5 -2
- package/src/tickers/search/home-listing.ts +75 -0
- package/src/tickers/search/index.ts +76 -27
- package/src/tickers/search/ranking.ts +54 -4
- package/src/tickers/search/upsert.ts +29 -0
- package/src/tickers/terminal-codes.ts +416 -40
- package/src/time-series/bar-aggregation.ts +243 -0
- package/src/time-series/base-series.ts +307 -0
- package/src/time-series/chart-bounds.ts +349 -0
- package/src/time-series/chart-seed.ts +142 -0
- package/src/time-series/economic.ts +5 -0
- package/src/time-series/fundamentals.ts +18 -3
- package/src/time-series/history-acquisition.ts +499 -0
- package/src/time-series/leverage.ts +100 -0
- package/src/time-series/market-resolution.ts +4 -2
- package/src/time-series/market.ts +2 -1
- package/src/time-series/price-comparison.ts +175 -30
- package/src/time-series/range.ts +9 -1
- package/src/time-series/resolution.ts +174 -16
- package/src/time-series/resolve-context.ts +157 -0
- package/src/time-series/resolve.ts +126 -1577
- package/src/time-series/series-name.ts +38 -0
- package/src/time-series/series-presentation.ts +208 -0
- package/src/time-series/spec.ts +11 -6
- package/src/time-series/studies.ts +109 -12
- package/src/time-series/tail-reconcile.ts +121 -0
- package/src/time-series/types.ts +29 -2
- package/src/time-series/use-chart-resolution.ts +4 -5
- package/src/types/broker.ts +10 -0
- package/src/types/config.ts +14 -0
- package/src/types/data-provider.ts +14 -0
- package/src/types/exchange-rate.ts +6 -0
- package/src/types/financials.ts +104 -7
- package/src/types/headless.ts +76 -6
- package/src/types/instrument.ts +3 -0
- package/src/types/plugin.ts +65 -8
- package/src/types/price-history.ts +2 -0
- package/src/types/ticker.ts +13 -0
- package/src/types/trading.ts +59 -1
- package/src/ui/ascii-font.ts +13 -1
- package/src/ui/host.tsx +6 -1
- package/src/updater/command-names.ts +175 -0
- package/src/updater/index.ts +10 -5
- package/src/utils/calendar-date.ts +32 -15
- package/src/utils/cash-runway.ts +241 -0
- package/src/utils/central-banks.ts +42 -0
- package/src/utils/cli-output.ts +259 -80
- package/src/utils/contract-month.ts +16 -0
- package/src/utils/crypto-pair.ts +61 -3
- package/src/utils/currency-units.ts +29 -0
- package/src/utils/datetime-format.ts +10 -0
- package/src/utils/debug-log.ts +1 -1
- package/src/utils/decimal-comma.ts +39 -6
- package/src/utils/exchange-announcements.ts +71 -0
- package/src/utils/exchange-rate-snapshot.ts +10 -0
- package/src/utils/financial-statements.ts +83 -4
- package/src/utils/format.ts +34 -16
- package/src/utils/fundamentals.ts +150 -34
- package/src/utils/fx-market-hours.ts +10 -1
- package/src/utils/latest-financial-period.ts +8 -0
- package/src/utils/linux-libc.ts +54 -0
- package/src/utils/market-capitalization.ts +111 -15
- package/src/utils/max-drawdown.ts +64 -0
- package/src/utils/network-failure.ts +83 -0
- package/src/utils/option-expiry.ts +139 -7
- package/src/utils/price-earnings.ts +11 -5
- package/src/utils/price-history.ts +18 -8
- package/src/utils/price-window.ts +131 -0
- package/src/utils/release-date.ts +47 -0
- package/src/utils/sec.ts +3 -0
- package/src/utils/throttled-fetch.ts +11 -4
- package/src/utils/trailing-eps.ts +67 -0
- package/src/utils/typed-text.ts +21 -0
- package/src/utils/utc-time.ts +24 -1
- package/src/version.ts +6 -0
- package/src/cli/pane-functions/screenshot.ts +0 -2122
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { formatCurrency } from "../../../utils/format";
|
|
2
2
|
import { comparablePriceEarnings, notMeaningfulMultiples } from "../../../utils/price-earnings";
|
|
3
|
-
import {
|
|
4
|
-
import { enterpriseValueReconciliationNote, enterpriseValueWithdrawn, reportedEnterpriseValue } from "../../../utils/fundamentals";
|
|
3
|
+
import { marketCapBasisNote, viewMarketCapitalization } from "../../../utils/market-capitalization";
|
|
4
|
+
import { enterpriseValueNotMeaningful, enterpriseValueReconciliationNote, enterpriseValueWithdrawn, reportedEnterpriseValue } from "../../../utils/fundamentals";
|
|
5
5
|
import { getExtendedSessionDisplay, getQuoteSessionFields } from "../../../market-data/market/status";
|
|
6
|
-
import { atRegularSessionPrice, movePriceDerivedFigures } from "../../../market-data/quotes/regular-session-valuation";
|
|
6
|
+
import { atRegularSessionPrice, movePriceDerivedFigures, regularSessionValuationPrice } from "../../../market-data/quotes/regular-session-valuation";
|
|
7
|
+
import { latestFinancialPeriod, latestReportedPeriod } from "../../../utils/latest-financial-period";
|
|
7
8
|
import type { Quote, TickerFinancials } from "../../../types/financials";
|
|
8
9
|
|
|
9
10
|
export function formatRelativePrice(price: number | null | undefined, currency: string | null | undefined): string {
|
|
@@ -12,6 +13,41 @@ export function formatRelativePrice(price: number | null | undefined, currency:
|
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export const RELATIVE_VALUATION_STALE_QUOTE_NOTICE = "Quote stale: quote-based values unavailable";
|
|
16
|
+
|
|
17
|
+
/** The RV figures a row can lack, each with the short reason it draws in its place. */
|
|
18
|
+
export type RelativeValuationGapKey = "price" | "changePercent" | "marketCap" | "trailingPE" | "forwardPE"
|
|
19
|
+
| "evSales" | "fcfYield" | "revenueGrowth" | "operatingMargin";
|
|
20
|
+
|
|
21
|
+
const NOT_REPORTED = "not reported";
|
|
22
|
+
const QUOTE_STALE = "quote stale";
|
|
23
|
+
|
|
24
|
+
const finiteNumber = (value: number | null | undefined): value is number => value != null && Number.isFinite(value);
|
|
25
|
+
|
|
26
|
+
/** Why EV/S is missing, in the order the figure needs its parts. */
|
|
27
|
+
function evSalesGap(
|
|
28
|
+
fundamentals: TickerFinancials["fundamentals"],
|
|
29
|
+
quoteCurrency: string | undefined,
|
|
30
|
+
withdrawn: boolean,
|
|
31
|
+
enterpriseValueGap: boolean,
|
|
32
|
+
): string {
|
|
33
|
+
if (withdrawn || enterpriseValueGap) return "EV unavailable";
|
|
34
|
+
if (!fundamentals) return NOT_REPORTED;
|
|
35
|
+
if (!finiteNumber(fundamentals.enterpriseToRevenue) && !finiteNumber(fundamentals.enterpriseValue)) return "no EV";
|
|
36
|
+
if (!finiteNumber(fundamentals.enterpriseToRevenue) && !(finiteNumber(fundamentals.revenue) && fundamentals.revenue > 0)) return "no revenue";
|
|
37
|
+
// EV/S is read only where the TTM block names its currency and it is the price's.
|
|
38
|
+
if (!fundamentals.financialCurrency) return "revenue ccy unstated";
|
|
39
|
+
if (quoteCurrency && fundamentals.financialCurrency !== quoteCurrency) return `revenue in ${fundamentals.financialCurrency}`;
|
|
40
|
+
return NOT_REPORTED;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Why the FCF yield is missing: no trailing free cash flow, no cap, or the two in different currencies. */
|
|
44
|
+
function fcfYieldGap(fundamentals: TickerFinancials["fundamentals"], capCurrency: string | null): string {
|
|
45
|
+
if (!finiteNumber(fundamentals?.freeCashFlow)) return "no TTM FCF";
|
|
46
|
+
if (!capCurrency) return "no market cap";
|
|
47
|
+
if (!fundamentals?.financialCurrency) return "FCF ccy unstated";
|
|
48
|
+
if (fundamentals.financialCurrency !== capCurrency) return `FCF in ${fundamentals.financialCurrency}`;
|
|
49
|
+
return NOT_REPORTED;
|
|
50
|
+
}
|
|
15
51
|
export const RELATIVE_VALUATION_STALE_FUNDAMENTALS_NOTICE = "Fundamentals stale: retained values may be out of date";
|
|
16
52
|
|
|
17
53
|
/**
|
|
@@ -30,7 +66,9 @@ export function relativeValuationValues(snapshot: TickerFinancials | null) {
|
|
|
30
66
|
const session = getQuoteSessionFields(quoteStale ? null : quote);
|
|
31
67
|
// An overnight price that is the session's bid and ask midpoint, nothing having traded in it.
|
|
32
68
|
const extendedMark = !quoteStale && getExtendedSessionDisplay(quote)?.mark === true;
|
|
33
|
-
|
|
69
|
+
// The cap `valuation` shows: the share count times the price where the provider's sits more than 2% from it.
|
|
70
|
+
const capitalization = viewMarketCapitalization(quoteStale ? undefined : quote, fundamentals,
|
|
71
|
+
quoteStale ? null : regularSessionValuationPrice(quote));
|
|
34
72
|
const enterpriseValue = reportedEnterpriseValue(fundamentals);
|
|
35
73
|
// A zero or non-finite enterprise value is the source's gap, and the ratio it serves beside it comes from the same observation.
|
|
36
74
|
const enterpriseValueGap = fundamentals?.enterpriseValue != null && enterpriseValue == null;
|
|
@@ -42,10 +80,37 @@ export function relativeValuationValues(snapshot: TickerFinancials | null) {
|
|
|
42
80
|
};
|
|
43
81
|
// A multiple over a loss reads N/M even when the source served a positive one beside it.
|
|
44
82
|
const { trailingPE: trailingNotMeaningful, forwardPE: forwardNotMeaningful } = notMeaningfulMultiples(fundamentals);
|
|
45
|
-
|
|
83
|
+
// An EV at or below zero makes EV/S N/M, whatever the source divided it by, as `valuation` reads the EV.
|
|
84
|
+
const evSalesNotMeaningful = enterpriseValueNotMeaningful(fundamentals);
|
|
85
|
+
const notMeaningful: Partial<Record<"trailingPE" | "forwardPE" | "evSales", string>> = {
|
|
46
86
|
...(trailingNotMeaningful ? { trailingPE: trailingNotMeaningful } : {}),
|
|
47
87
|
...(forwardNotMeaningful ? { forwardPE: forwardNotMeaningful } : {}),
|
|
88
|
+
...(evSalesNotMeaningful ? { evSales: evSalesNotMeaningful } : {}),
|
|
48
89
|
};
|
|
90
|
+
const evSalesWithdrawn = enterpriseValueWithdrawn(fundamentals);
|
|
91
|
+
const evSales = !compatibleCurrency || enterpriseValueGap || evSalesNotMeaningful ? null
|
|
92
|
+
: fundamentals?.enterpriseToRevenue != null && Number.isFinite(fundamentals.enterpriseToRevenue)
|
|
93
|
+
? fundamentals.enterpriseToRevenue
|
|
94
|
+
: enterpriseValue != null && fundamentals?.revenue != null && fundamentals.revenue > 0
|
|
95
|
+
? enterpriseValue / fundamentals.revenue : null;
|
|
96
|
+
const fcfYield = capitalization && fundamentals?.financialCurrency === capitalization.currency
|
|
97
|
+
&& fundamentals.freeCashFlow != null && Number.isFinite(fundamentals.freeCashFlow) && capitalization.value > 0
|
|
98
|
+
? fundamentals.freeCashFlow / capitalization.value : null;
|
|
99
|
+
const revenueGrowth = fundamentals?.revenueGrowth ?? fundamentals?.lastQuarterGrowth ?? null;
|
|
100
|
+
const operatingMargin = fundamentals?.operatingMargin ?? null;
|
|
101
|
+
const trailingPE = trailingNotMeaningful ? null : comparablePriceEarnings(reportedMultiples.trailingPE);
|
|
102
|
+
const forwardPE = forwardNotMeaningful ? null : comparablePriceEarnings(reportedMultiples.forwardPE);
|
|
103
|
+
// Every figure a row lacks says why, so an export's blank cell is never silent: N/M multiples say so themselves.
|
|
104
|
+
const gaps: Partial<Record<RelativeValuationGapKey, string>> = {};
|
|
105
|
+
if (session.price == null) gaps.price = quoteStale ? QUOTE_STALE : NOT_REPORTED;
|
|
106
|
+
if (session.changePercent == null) gaps.changePercent = quoteStale ? QUOTE_STALE : NOT_REPORTED;
|
|
107
|
+
if (capitalization == null) gaps.marketCap = quoteStale && !fundamentals?.marketCap ? QUOTE_STALE : NOT_REPORTED;
|
|
108
|
+
if (trailingPE == null && !trailingNotMeaningful && reportedMultiples.trailingPE == null) gaps.trailingPE = NOT_REPORTED;
|
|
109
|
+
if (forwardPE == null && !forwardNotMeaningful && reportedMultiples.forwardPE == null) gaps.forwardPE = NOT_REPORTED;
|
|
110
|
+
if (evSales == null && !evSalesNotMeaningful) gaps.evSales = evSalesGap(fundamentals, quote?.currency, evSalesWithdrawn, enterpriseValueGap);
|
|
111
|
+
if (fcfYield == null) gaps.fcfYield = fcfYieldGap(fundamentals, capitalization?.currency ?? null);
|
|
112
|
+
if (revenueGrowth == null) gaps.revenueGrowth = NOT_REPORTED;
|
|
113
|
+
if (operatingMargin == null) gaps.operatingMargin = NOT_REPORTED;
|
|
49
114
|
return {
|
|
50
115
|
...session,
|
|
51
116
|
extendedMark,
|
|
@@ -61,29 +126,33 @@ export function relativeValuationValues(snapshot: TickerFinancials | null) {
|
|
|
61
126
|
source: fundamentals.source ?? null, retrievedAt: fundamentals.fetchedAt ?? null,
|
|
62
127
|
stale: fundamentals.stale ?? null,
|
|
63
128
|
} : null,
|
|
129
|
+
/** The newest statement period the trailing figures run through, as `valuation` names it. */
|
|
130
|
+
fundamentalsThrough: fundamentals && snapshot ? latestReportedPeriod(snapshot) : null,
|
|
131
|
+
/** The end of the latest quarter, the one revenueGrowth compares with a year earlier. */
|
|
132
|
+
revenueGrowthQuarter: revenueGrowth != null ? latestFinancialPeriod(snapshot?.quarterlyStatements, (row) => row.date)?.date ?? null : null,
|
|
64
133
|
currency: quote?.currency ?? null,
|
|
65
134
|
marketCap: capitalization?.value ?? null,
|
|
66
135
|
marketCapCurrency: capitalization?.currency ?? null,
|
|
67
136
|
marketCapProvenance: capitalization?.provenance ?? null,
|
|
68
|
-
|
|
69
|
-
|
|
137
|
+
/** valuation's note when the cap is the share count times the price: the provider's figure it replaced. */
|
|
138
|
+
marketCapNote: marketCapBasisNote(capitalization) ?? null,
|
|
139
|
+
trailingPE,
|
|
140
|
+
forwardPE,
|
|
70
141
|
reportedMultiples,
|
|
71
|
-
/** Why a multiple is N/M: its earnings base is zero or a loss. */
|
|
142
|
+
/** Why a multiple is N/M: its earnings base is zero or a loss, or for EV/S the enterprise value is at or below zero. */
|
|
72
143
|
notMeaningful,
|
|
73
144
|
// Vendor ADR ratios can mix unverified valuation and reporting units too.
|
|
74
|
-
evSales
|
|
75
|
-
: fundamentals?.enterpriseToRevenue != null && Number.isFinite(fundamentals.enterpriseToRevenue)
|
|
76
|
-
? fundamentals.enterpriseToRevenue
|
|
77
|
-
: enterpriseValue != null && fundamentals?.revenue != null && fundamentals.revenue > 0
|
|
78
|
-
? enterpriseValue / fundamentals.revenue : null,
|
|
145
|
+
evSales,
|
|
79
146
|
/** Why EV/S is missing when the provider's EV was withdrawn, as `valuation` says it; null otherwise. */
|
|
80
|
-
evSalesUnavailable:
|
|
147
|
+
evSalesUnavailable: evSalesWithdrawn
|
|
81
148
|
? enterpriseValueReconciliationNote(fundamentals) ?? "EV unavailable." : null,
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
revenueGrowth
|
|
86
|
-
operatingMargin
|
|
149
|
+
/** Why EV/S is N/M, as `valuation` says it: "EV N/M: cash and short-term investments exceed ..."; null otherwise. */
|
|
150
|
+
evSalesNote: evSalesNotMeaningful ? enterpriseValueReconciliationNote(fundamentals) ?? null : null,
|
|
151
|
+
fcfYield,
|
|
152
|
+
revenueGrowth,
|
|
153
|
+
operatingMargin,
|
|
154
|
+
/** Why each missing figure is missing, in a few words the row draws in its place. */
|
|
155
|
+
gaps,
|
|
87
156
|
};
|
|
88
157
|
}
|
|
89
158
|
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type DataTableCell,
|
|
9
9
|
type DataTableColumn,
|
|
10
10
|
type DataTableKeyEvent,
|
|
11
|
+
type PaneFooterSegment,
|
|
11
12
|
} from "../../../components";
|
|
12
13
|
import type { PaneProps } from "../../../types/plugin";
|
|
13
14
|
import { useAppSelector, usePaneInstance } from "../../../state/app/context";
|
|
@@ -29,7 +30,11 @@ import { handleRefreshKey, useClampSelectedIndex } from "../../../components/dat
|
|
|
29
30
|
import { useAsyncResource } from "../../../react/async-resource";
|
|
30
31
|
import { useBoundTicker as useSymbolBinding } from "../shared/ticker-request";
|
|
31
32
|
import { useFxRatesMap } from "../../../market-data/hooks";
|
|
33
|
+
import { useRemoteUiNode } from "../../../remote/semantic-tree";
|
|
34
|
+
import { quoteFreshnessFields } from "../shared/report-freshness";
|
|
32
35
|
import { RELATIVE_VALUATION_STALE_FUNDAMENTALS_NOTICE, formatRelativePrice, relativeValuationValues, withLiveQuote } from "./relative-valuation-model";
|
|
36
|
+
import { conversionNote, conversionPairText, convertMarketCaps, usdRateFromEntry } from "./relative-valuation-currency";
|
|
37
|
+
import { fundamentalsBasisParts, fundamentalsThroughText } from "./relative-valuation-basis";
|
|
33
38
|
|
|
34
39
|
type ExtendedColumnId = "preMarket" | "afterHours" | "overnight";
|
|
35
40
|
type RelativeColumnId = "symbol" | "price" | "changePercent" | ExtendedColumnId | "marketCap" | "trailingPE" | "forwardPE" | "evSales" | "fcfYield" | "revenueGrowth" | "operatingMargin";
|
|
@@ -49,6 +54,34 @@ function relativeSymbolsFromPane(symbol: string | null, paneSettings: Record<str
|
|
|
49
54
|
|
|
50
55
|
const EXTENDED_COLUMN_IDS: Record<ExtendedSession, ExtendedColumnId> = { PRE: "preMarket", POST: "afterHours", OVERNIGHT: "overnight" };
|
|
51
56
|
|
|
57
|
+
/** The latest quarter's revenue against the same quarter a year earlier; the footer names the quarter. */
|
|
58
|
+
const REVENUE_GROWTH_LABEL = "Q REV%";
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The footer's word on the figures, longest first: the rates MCAP was
|
|
62
|
+
* converted at with their times, the statement period the trailing figures
|
|
63
|
+
* run through and the quarter Q REV% compares, as `fn RV` ends; shorter forms
|
|
64
|
+
* keep the rates without their times, then the period alone after them, then
|
|
65
|
+
* the rates alone.
|
|
66
|
+
*/
|
|
67
|
+
function basisFooterSegment(conversions: Parameters<typeof conversionNote>[1], baseCurrency: string, basis: readonly string[], through: string | null): PaneFooterSegment | null {
|
|
68
|
+
const column = `MCAP ${baseCurrency}`;
|
|
69
|
+
const rates = conversions.length > 0 ? `${column} at ${conversions.map(conversionPairText).join(", ")}` : null;
|
|
70
|
+
const forms = [
|
|
71
|
+
[conversionNote(baseCurrency, conversions, column), ...basis],
|
|
72
|
+
[rates, ...basis],
|
|
73
|
+
[rates, through],
|
|
74
|
+
[rates ?? through],
|
|
75
|
+
].map((form) => form.filter((part): part is string => !!part).join(" · "));
|
|
76
|
+
if (!forms[0]) return null;
|
|
77
|
+
const variants = [...new Set(forms.slice(1))].filter((form) => form && form !== forms[0]);
|
|
78
|
+
return {
|
|
79
|
+
id: "basis",
|
|
80
|
+
parts: [{ text: forms[0], tone: "muted" }],
|
|
81
|
+
...(variants.length > 0 ? { variants: variants.map((text) => [{ text, tone: "muted" as const }]) } : {}),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
52
85
|
/** The extended sessions some peer has a print for, in the order their columns go. */
|
|
53
86
|
function extendedSessionsOf(rows: readonly RelativeRow[]): ExtendedSession[] {
|
|
54
87
|
return (["PRE", "POST", "OVERNIGHT"] as const).filter((session) => rows.some((row) => row.extendedSession === session));
|
|
@@ -83,7 +116,7 @@ function buildRelativeColumns(baseCurrency: string, extendedSessions: readonly E
|
|
|
83
116
|
{ id: "evSales", label: "EV/S", width: metricWidth, align: "right" },
|
|
84
117
|
{ id: "fcfYield", label: "FCF%", width: metricWidth, align: "right" },
|
|
85
118
|
// Latest quarter against the year before, and a trailing-twelve-month margin.
|
|
86
|
-
{ id: "revenueGrowth", label:
|
|
119
|
+
{ id: "revenueGrowth", label: REVENUE_GROWTH_LABEL, width: metricWidth, align: "right" },
|
|
87
120
|
{ id: "operatingMargin", label: "TTM OP%", width: metricWidth, align: "right" },
|
|
88
121
|
];
|
|
89
122
|
}
|
|
@@ -171,14 +204,16 @@ export function RelativeValuationPane({ focused, width, height }: PaneProps) {
|
|
|
171
204
|
weight: 60,
|
|
172
205
|
})), [symbols]);
|
|
173
206
|
const { entries: liveQuotes } = useLiveQuoteEntries(quoteTargets);
|
|
174
|
-
|
|
207
|
+
// Each peer's snapshot with its live quote laid over it.
|
|
208
|
+
const snapshots = useMemo(() => (peers ?? []).map((peer) => {
|
|
175
209
|
const entry = liveQuotes.get(peerQuoteKey(peer.symbol));
|
|
176
|
-
return {
|
|
177
|
-
symbol: peer.symbol,
|
|
178
|
-
...relativeValuationValues(withLiveQuote(peer.financials, entry ? resolveEntryValue(entry) : null)),
|
|
179
|
-
error: peer.error,
|
|
180
|
-
};
|
|
210
|
+
return { peer, financials: withLiveQuote(peer.financials, entry ? resolveEntryValue(entry) : null) };
|
|
181
211
|
}), [liveQuotes, peers]);
|
|
212
|
+
const rows = useMemo<RelativeRow[]>(() => snapshots.map(({ peer, financials }) => ({
|
|
213
|
+
symbol: peer.symbol,
|
|
214
|
+
...relativeValuationValues(financials),
|
|
215
|
+
error: peer.error,
|
|
216
|
+
})), [snapshots]);
|
|
182
217
|
const fxRates = useFxRatesMap([baseCurrency, ...rows.map((row) => row.marketCapCurrency)]);
|
|
183
218
|
// A pre-market or after-hours print gets its own column when a peer has one.
|
|
184
219
|
const extendedSessionsKey = extendedSessionsOf(rows).join(",");
|
|
@@ -191,6 +226,36 @@ export function RelativeValuationPane({ focused, width, height }: PaneProps) {
|
|
|
191
226
|
...row, marketCap: convertMarketCapitalization(row.marketCap, row.marketCapCurrency, baseCurrency, fxRates),
|
|
192
227
|
})), [rows, baseCurrency, fxRates]);
|
|
193
228
|
const missingFx = rows.some((row, index) => row.marketCap != null && comparableRows[index]?.marketCap == null);
|
|
229
|
+
// The rates the converted caps were read at, each with when it was observed, as `fn RV --currency` names them.
|
|
230
|
+
const conversions = useMemo(() => {
|
|
231
|
+
const coordinator = getSharedMarketDataCoordinator();
|
|
232
|
+
const legs = new Map([...fxRates].flatMap(([currency, rate]) => (
|
|
233
|
+
currency === "USD" ? [] : [[currency, usdRateFromEntry(rate, coordinator?.getFxEntry(currency))] as const]
|
|
234
|
+
)));
|
|
235
|
+
const converted = rows.filter((row, index) => row.marketCapCurrency !== baseCurrency && comparableRows[index]?.marketCap != null);
|
|
236
|
+
return convertMarketCaps(converted, baseCurrency, legs).conversions;
|
|
237
|
+
}, [baseCurrency, comparableRows, fxRates, rows]);
|
|
238
|
+
const basis = useMemo(() => fundamentalsBasisParts(rows, REVENUE_GROWTH_LABEL), [rows]);
|
|
239
|
+
const through = useMemo(() => fundamentalsThroughText(rows), [rows]);
|
|
240
|
+
const basisSegment = useMemo(() => basisFooterSegment(conversions, baseCurrency, basis, through), [baseCurrency, basis, conversions, through]);
|
|
241
|
+
const footerInfo = useMemo(() => (basisSegment ? [basisSegment] : []), [basisSegment]);
|
|
242
|
+
// A capture of the pane ends as `fn RV` does: each venue's session, the feed's delay, then the footer's word on
|
|
243
|
+
// the figures. The pane draws the session part nowhere; its footer keeps the rest.
|
|
244
|
+
useRemoteUiNode(rows.length > 0 ? {
|
|
245
|
+
role: "report-freshness",
|
|
246
|
+
label: "Peer freshness",
|
|
247
|
+
getMetadata: () => ({
|
|
248
|
+
datesEachVenue: true,
|
|
249
|
+
...(basisSegment ? {
|
|
250
|
+
note: basisSegment.parts[0]!.text,
|
|
251
|
+
noteVariants: (basisSegment.variants ?? []).map((variant) => variant[0]!.text),
|
|
252
|
+
} : {}),
|
|
253
|
+
observations: snapshots.map(({ financials }, index) => ({
|
|
254
|
+
...quoteFreshnessFields(financials?.quote),
|
|
255
|
+
quoteAsOf: rows[index]?.quoteAsOf ?? null,
|
|
256
|
+
})),
|
|
257
|
+
}),
|
|
258
|
+
} : null);
|
|
194
259
|
// Sorting by a live column would reshuffle rows under the cursor on every
|
|
195
260
|
// tick; the order is taken from values sampled every few seconds instead,
|
|
196
261
|
// and at once when the sort or the peer set changes.
|
|
@@ -216,6 +281,7 @@ export function RelativeValuationPane({ focused, width, height }: PaneProps) {
|
|
|
216
281
|
...rows.filter((row) => row.fundamentalsProvenance?.stale)
|
|
217
282
|
.map((row) => `${row.symbol}: ${RELATIVE_VALUATION_STALE_FUNDAMENTALS_NOTICE}.`),
|
|
218
283
|
...rows.flatMap((row) => row.evSalesUnavailable ? [`${row.symbol}: ${row.evSalesUnavailable}`] : []),
|
|
284
|
+
...rows.flatMap((row) => row.evSalesNote ? [`${row.symbol}: ${row.evSalesNote}`] : []),
|
|
219
285
|
],
|
|
220
286
|
focused,
|
|
221
287
|
});
|
|
@@ -243,7 +309,8 @@ export function RelativeValuationPane({ focused, width, height }: PaneProps) {
|
|
|
243
309
|
case "forwardPE":
|
|
244
310
|
return { text: formatPriceEarnings(row.notMeaningful.forwardPE ? NOT_MEANINGFUL : row.reportedMultiples.forwardPE), color: colors.text };
|
|
245
311
|
case "evSales":
|
|
246
|
-
// A withdrawn EV says so; the footer says why.
|
|
312
|
+
// A withdrawn EV says so, one at or below zero reads N/M as a P/E over a loss does; the footer says why.
|
|
313
|
+
if (row.evSales == null && row.notMeaningful.evSales) return { text: formatPriceEarnings(NOT_MEANINGFUL), color: colors.text };
|
|
247
314
|
return row.evSales == null && row.evSalesUnavailable
|
|
248
315
|
? { text: "EV n/a", color: colors.textDim }
|
|
249
316
|
: { text: formatNumber(row.evSales ?? undefined, 1), color: colors.text };
|
|
@@ -266,7 +333,7 @@ export function RelativeValuationPane({ focused, width, height }: PaneProps) {
|
|
|
266
333
|
}));
|
|
267
334
|
}, []);
|
|
268
335
|
|
|
269
|
-
usePaneStatusFooter({ registrationId: "relative-valuation", loading, error: status });
|
|
336
|
+
usePaneStatusFooter({ registrationId: "relative-valuation", loading, error: status, info: footerInfo });
|
|
270
337
|
|
|
271
338
|
return (
|
|
272
339
|
<DataTableView<RelativeRow, RelativeColumn>
|
|
@@ -277,7 +277,7 @@ export async function pickPeers(symbol: string, financials: TickerFinancials | n
|
|
|
277
277
|
description: financials?.profile?.description ?? null,
|
|
278
278
|
marketCapUsd: null,
|
|
279
279
|
};
|
|
280
|
-
const listYourOwn = `List them yourself:
|
|
280
|
+
const listYourOwn = `List them yourself: gloom fn RV ${symbol} <tickers>.`;
|
|
281
281
|
const group = peerGroupOf(subject);
|
|
282
282
|
if (!group) throw new Error(`${symbol}'s profile names no industry, so --peers cannot pick its peers. ${listYourOwn}`);
|
|
283
283
|
let candidates: PeerCandidates | null = null;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { unavailableText } from "../../../components/ui/status";
|
|
2
2
|
import { atRegularSessionPrice } from "../../../market-data/quotes/regular-session-valuation";
|
|
3
3
|
import type { Fundamentals, TickerFinancials } from "../../../types/financials";
|
|
4
|
-
import { enterpriseValueCheck, enterpriseValueLabel,
|
|
5
|
-
reportedEnterpriseValue } from "../../../utils/fundamentals";
|
|
4
|
+
import { enterpriseValueCheck, enterpriseValueLabel, enterpriseValueNotMeaningful, enterpriseValueReconciliationNote,
|
|
5
|
+
enterpriseValueWithdrawn, reportedEnterpriseValue } from "../../../utils/fundamentals";
|
|
6
6
|
|
|
7
7
|
/** Years of explicit growth before the terminal value. */
|
|
8
8
|
export const FORECAST_YEARS = 10;
|
|
@@ -151,6 +151,10 @@ export function projectReverseDcf(
|
|
|
151
151
|
if (currency && valueCurrency && currency !== valueCurrency) {
|
|
152
152
|
return { ...empty, error: `Cash flows are in ${currency} and the market value in ${valueCurrency}.` };
|
|
153
153
|
}
|
|
154
|
+
// An EV at or below zero is N/M here as in `valuation` and RV, with the same reason: no growth rate prices it.
|
|
155
|
+
if (enterpriseValueNotMeaningful(fundamentals)) {
|
|
156
|
+
return { ...empty, enterpriseValue: null, error: enterpriseValueReconciliationNote(fundamentals)! };
|
|
157
|
+
}
|
|
154
158
|
// A withdrawn EV is unavailable here as in `valuation`, which says why.
|
|
155
159
|
if (enterpriseValueWithdrawn(fundamentals)) {
|
|
156
160
|
return { ...empty, error: enterpriseValueReconciliationNote(fundamentals) ?? unavailableText("Enterprise value") };
|
|
@@ -29,10 +29,10 @@ function riskFactorsLockNote(lock: PaneLock): Promise<string> {
|
|
|
29
29
|
does: "it groups a 10-K's risk factors by theme and shows what was added, dropped or reworded since the year before",
|
|
30
30
|
shows: "it",
|
|
31
31
|
free: [{
|
|
32
|
-
text: (ticker, company) => `
|
|
32
|
+
text: (ticker, company) => `gloom filings ${ticker} --form 10-K lists ${company}'s annual reports, each with its filing date and a link to the filing, whose Item 1A holds the risk factors as written.`,
|
|
33
33
|
answers: (symbol, context) => filesForm(symbol, "10-K", context),
|
|
34
34
|
}, {
|
|
35
|
-
text: (ticker, company) => `
|
|
35
|
+
text: (ticker, company) => `gloom filings ${ticker} --form 20-F lists ${company}'s annual reports, each with its filing date and a link to the filing, whose Item 3.D holds the risk factors as written.`,
|
|
36
36
|
answers: (symbol, context) => filesForm(symbol, "20-F", context),
|
|
37
37
|
}],
|
|
38
38
|
});
|
|
@@ -13,6 +13,6 @@ export function flowLockNote(lock: PaneLock): Promise<string> {
|
|
|
13
13
|
argument: "none",
|
|
14
14
|
does: "it streams real-time sweeps, blocks and large premium prints across US options exchanges",
|
|
15
15
|
shows: "it",
|
|
16
|
-
free: [{ text: (ticker, company) => `
|
|
16
|
+
free: [{ text: (ticker, company) => `gloom options ${ticker} lists ${company}'s option chain, each contract with its volume and open interest.` }],
|
|
17
17
|
});
|
|
18
18
|
}
|
|
@@ -49,6 +49,19 @@ export function filterFilingsByForms(filings: readonly SecFilingItem[], forms: r
|
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* A fund's own filings out of its trust's (ProShares Trust files for 166
|
|
54
|
+
* funds): the ones the service marks as filed for the fund's series. A list
|
|
55
|
+
* the service could not mark, a fund whose registrant runs no other series,
|
|
56
|
+
* or a list in which nothing is marked as the fund's own (a series list that
|
|
57
|
+
* came back empty) stays whole.
|
|
58
|
+
*/
|
|
59
|
+
export function fundSeriesFilings(filings: readonly SecFilingItem[]): readonly SecFilingItem[] {
|
|
60
|
+
return filings.some((filing) => filing.fundSeries === true)
|
|
61
|
+
? filings.filter((filing) => filing.fundSeries === true)
|
|
62
|
+
: filings;
|
|
63
|
+
}
|
|
64
|
+
|
|
52
65
|
/** A form as typed or filed, without punctuation or the `SC`/`SCHEDULE` prefix of ownership schedules. */
|
|
53
66
|
function compactFilingForm(form: string): string {
|
|
54
67
|
return form.toUpperCase().replace(/[^A-Z0-9]/g, "").replace(/^(?:SCHEDULE|SC)(?=\d)/, "");
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { listingSuffixExchange } from "../../../sources/listing-symbols";
|
|
2
|
+
import type { TickerFinancials } from "../../../types/financials";
|
|
3
|
+
import { parsePublicTickerKey } from "../../../utils/exchanges";
|
|
4
|
+
import { safeExternalUrl } from "../../../utils/external-url";
|
|
5
|
+
import { listingAbroadVenue } from "../../../utils/sec";
|
|
6
|
+
|
|
7
|
+
/** A fund listed abroad as its profile names it: its name, its page at its issuer, and where its description is from. */
|
|
8
|
+
export interface FundAbroadProfile {
|
|
9
|
+
name?: string;
|
|
10
|
+
page?: string;
|
|
11
|
+
descriptionSource?: { publisher: string; url: string };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** The venue abroad a listing names, by its key (3042:HKEX) or its symbol's suffix (3042.HK, VUSA.L); null for a US listing. */
|
|
15
|
+
export function venueAbroad(key: string): string | null {
|
|
16
|
+
const keyed = listingAbroadVenue(key);
|
|
17
|
+
if (keyed) return keyed;
|
|
18
|
+
const { symbol, exchange } = parsePublicTickerKey(key);
|
|
19
|
+
const suffixed = exchange ? undefined : listingSuffixExchange(symbol);
|
|
20
|
+
return suffixed ? listingAbroadVenue(`${symbol}:${suffixed}`) : null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** What ETF says of a fund listed abroad, from its quote and profile; only links that are safe to open. */
|
|
24
|
+
export function fundAbroadProfile(financials: Pick<TickerFinancials, "quote" | "profile"> | null | undefined): FundAbroadProfile {
|
|
25
|
+
const page = financials?.profile?.website ? safeExternalUrl(financials.profile.website) : null;
|
|
26
|
+
const source = financials?.profile?.descriptionSource;
|
|
27
|
+
return {
|
|
28
|
+
...(financials?.quote?.name ? { name: financials.quote.name } : {}),
|
|
29
|
+
...(page ? { page } : {}),
|
|
30
|
+
...(source?.publisher && safeExternalUrl(source.url) ? { descriptionSource: source } : {}),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { apiClient } from "../../../api-client";
|
|
2
|
-
import type { FundFactsPayload } from "../../../api-client/fund-facts";
|
|
2
|
+
import type { FundFactsPayload, FundLeverage, FundMetalHoldings } from "../../../api-client/fund-facts";
|
|
3
3
|
import type { StatItem } from "../../../components/ui/stat-grid";
|
|
4
|
+
import { leverageFactorLabel } from "../../../time-series/leverage";
|
|
4
5
|
import { t, tf } from "../../../i18n";
|
|
5
6
|
import { createPluginCache } from "../../../data/plugin-cache";
|
|
6
7
|
import type { HeadlessPaneEntry } from "../../../types/plugin";
|
|
@@ -17,11 +18,22 @@ export const fundFactsCache = createPluginCache<FundFactsPayload>({
|
|
|
17
18
|
type Client = Pick<typeof apiClient, "getFundFacts">;
|
|
18
19
|
|
|
19
20
|
const fact = (value: unknown) => value === null || (typeof value === "object" && value !== null && "value" in value && "source" in value);
|
|
21
|
+
const finite = (value: unknown): value is number => typeof value === "number" && Number.isFinite(value);
|
|
22
|
+
|
|
23
|
+
function isMetalHoldingsShape(value: FundFactsPayload["metalHoldings"]): boolean {
|
|
24
|
+
return value == null || ((value.metal === "gold" || value.metal === "silver") && typeof value.asOf === "string" && finite(value.ounces)
|
|
25
|
+
&& (value.tonnes === null || finite(value.tonnes)) && typeof value.source?.publisher === "string"
|
|
26
|
+
&& (value.change === null || (typeof value.change?.since === "string" && finite(value.change.ounces))));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Absent from servers before it; otherwise a dated factor with its reset period. */
|
|
30
|
+
const leverageShape = (value: FundFactsPayload["leverage"]) => value === undefined || value === null
|
|
31
|
+
|| (fact(value) && typeof value.value === "number" && Number.isFinite(value.value) && (value.reset === "daily" || value.reset === "monthly"));
|
|
20
32
|
|
|
21
33
|
function validateFundFacts(data: FundFactsPayload): FundFactsPayload {
|
|
22
34
|
if (!data || typeof data.ticker !== "string" || typeof data.covered !== "boolean"
|
|
23
35
|
|| ![data.expenseRatio, data.nav, data.premiumDiscount, data.netAssets, data.sponsor, data.inception, data.index].every(fact)
|
|
24
|
-
|| !isBondFactsShape(data.bond)) {
|
|
36
|
+
|| !isBondFactsShape(data.bond) || !leverageShape(data.leverage) || !isMetalHoldingsShape(data.metalHoldings)) {
|
|
25
37
|
throw new Error("Unreadable fund facts response");
|
|
26
38
|
}
|
|
27
39
|
return data;
|
|
@@ -41,13 +53,14 @@ export function fundFactsErrorLine(error: unknown): string {
|
|
|
41
53
|
return message === FUND_FACTS_UNAVAILABLE ? t(FUND_FACTS_UNAVAILABLE) : tf("Fund facts unavailable: {message}", { message });
|
|
42
54
|
}
|
|
43
55
|
|
|
44
|
-
export async function fetchFundFacts(ticker: string, client: Client = apiClient): Promise<FundFactsPayload> {
|
|
45
|
-
try { return validateFundFacts(await client.getFundFacts(ticker)); } catch (error) { throw unavailableOnServer(error, FUND_FACTS_UNAVAILABLE); }
|
|
56
|
+
export async function fetchFundFacts(ticker: string, client: Client = apiClient, signal?: AbortSignal): Promise<FundFactsPayload> {
|
|
57
|
+
try { return validateFundFacts(await (signal ? client.getFundFacts(ticker, { signal }) : client.getFundFacts(ticker))); } catch (error) { throw unavailableOnServer(error, FUND_FACTS_UNAVAILABLE); }
|
|
46
58
|
}
|
|
47
59
|
const cacheKey = (ticker: string) => ticker.trim().toUpperCase();
|
|
48
60
|
export const cachedFundFacts = (ticker: string) => cachedCloudResource(fundFactsCache, cacheKey(ticker), validateFundFacts);
|
|
49
|
-
|
|
50
|
-
|
|
61
|
+
/** Through the cache the ETF pane keeps; `client` is a report's own, `signal` ends a read it no longer waits for. */
|
|
62
|
+
export const loadFundFacts = (ticker: string, force = false, { client = apiClient, signal }: { client?: Client; signal?: AbortSignal } = {}) =>
|
|
63
|
+
loadCloudResource(fundFactsCache, cacheKey(ticker), () => fetchFundFacts(ticker, client, signal), { force, validate: validateFundFacts, signal });
|
|
51
64
|
|
|
52
65
|
/** A fee as the prospectus states it: two decimals at least, four when it has them (0.0945%). */
|
|
53
66
|
function formatFeePercent(value: number): string {
|
|
@@ -67,6 +80,13 @@ function formatNetAssets(value: number): string {
|
|
|
67
80
|
return `$${formatCompact(value)}`;
|
|
68
81
|
}
|
|
69
82
|
|
|
83
|
+
/** Ounces and tonnes as the sponsor publishes them, to its own decimals (34,085,936.5; 1,060.18). */
|
|
84
|
+
const metalFigure = (value: number, signed = false) =>
|
|
85
|
+
`${signed && value > 0 ? "+" : ""}${value.toLocaleString("en-US", { maximumFractionDigits: 3 })}`;
|
|
86
|
+
|
|
87
|
+
/** "Gold in trust", "Silver in trust". */
|
|
88
|
+
const metalLabel = (holdings: FundMetalHoldings) => holdings.metal === "gold" ? "Gold in trust" : "Silver in trust";
|
|
89
|
+
|
|
70
90
|
/**
|
|
71
91
|
* The fee as the server says it is: a sponsor fee (IBIT, GLD), or an expense
|
|
72
92
|
* ratio, net or gross of waivers, which its detail says. A pool's total
|
|
@@ -98,6 +118,17 @@ function wholeFund(facts: FundFactsPayload): boolean {
|
|
|
98
118
|
*/
|
|
99
119
|
const BENCHMARK_LABEL = "Benchmark";
|
|
100
120
|
|
|
121
|
+
/**
|
|
122
|
+
* A leveraged or inverse fund's objective, as the ETF pane and report label
|
|
123
|
+
* it: the times and direction of its benchmark's return it seeks.
|
|
124
|
+
*/
|
|
125
|
+
const OBJECTIVE_LABEL = "Objective";
|
|
126
|
+
|
|
127
|
+
/** The objective in a few words: `3× daily, long`, `-3× daily, inverse`, `1.75× monthly, long`. */
|
|
128
|
+
function leverageObjectiveText(leverage: Pick<FundLeverage, "value" | "reset">): string {
|
|
129
|
+
return `${leverageFactorLabel(leverage.value)} ${leverage.reset}, ${leverage.value < 0 ? "inverse" : "long"}`;
|
|
130
|
+
}
|
|
131
|
+
|
|
101
132
|
/**
|
|
102
133
|
* How each dated figure reads beside the NAV, the date the sheet is about.
|
|
103
134
|
* Every figure says its own date. One that is older than it looks is marked:
|
|
@@ -169,8 +200,24 @@ export function fundFactItems(facts: FundFactsPayload): StatItem[] {
|
|
|
169
200
|
for (const figure of facts.bond ? bondFigures(facts.bond) : []) {
|
|
170
201
|
items.push(cell(figure.key, figure.label, figure.text, { detail: figure.date, marked: facts.stale }));
|
|
171
202
|
}
|
|
203
|
+
// A metal trust's metal in trust, in tonnes as the market quotes it and ounces as the trust counts it, then its day's change.
|
|
204
|
+
const metal = facts.metalHoldings;
|
|
205
|
+
if (metal) {
|
|
206
|
+
const ounces = `${formatCompact(metal.ounces)} oz`;
|
|
207
|
+
items.push(cell("metal", metalLabel(metal), metal.tonnes == null ? ounces : `${metalFigure(metal.tonnes)} t`,
|
|
208
|
+
{ detail: metal.tonnes == null ? metal.asOf : `${ounces} · ${metal.asOf}`, marked: metal.stale }));
|
|
209
|
+
if (metal.change) {
|
|
210
|
+
const change = `${metalFigure(Math.round(metal.change.ounces), true)} oz`;
|
|
211
|
+
items.push(cell("metal-change", "Day change", metal.change.tonnes == null ? change : `${metalFigure(metal.change.tonnes, true)} t`,
|
|
212
|
+
{ detail: metal.change.tonnes == null ? tf("since {date}", { date: metal.change.since }) : `${change} · ${tf("since {date}", { date: metal.change.since })}`, marked: metal.stale }));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
172
215
|
if (facts.sponsor) items.push({ id: "sponsor", label: "Sponsor", value: facts.sponsor.value });
|
|
173
216
|
if (facts.inception) items.push({ id: "inception", label: "Inception", value: facts.inception.value });
|
|
217
|
+
// A leveraged or inverse fund's objective, dated by the sponsor page it was read from, beside its benchmark.
|
|
218
|
+
if (facts.leverage) {
|
|
219
|
+
items.push(cell("objective", OBJECTIVE_LABEL, leverageObjectiveText(facts.leverage), { detail: facts.leverage.asOf ?? undefined, marked: false }));
|
|
220
|
+
}
|
|
174
221
|
if (facts.index) items.push({ id: "index", label: BENCHMARK_LABEL, value: facts.index.value, wide: true });
|
|
175
222
|
return items;
|
|
176
223
|
}
|
|
@@ -251,6 +298,15 @@ export function fundFactEntries(facts: FundFactsPayload): HeadlessPaneEntry[] {
|
|
|
251
298
|
? `${facts.netAssets.asOf} month-end${facts.netAssets.document ? ` ${facts.netAssets.document}` : ""}` : facts.netAssets.asOf;
|
|
252
299
|
add("netAssets", "Net assets", facts.netAssets.value, provenance(formatNetAssets(facts.netAssets.value), date, scope, facts.netAssets.source), "USD");
|
|
253
300
|
}
|
|
301
|
+
const metal = facts.metalHoldings;
|
|
302
|
+
if (metal) {
|
|
303
|
+
// The trust's own figures, as its sponsor's daily holdings file states them; JSON has the tonnes in `fundFacts`.
|
|
304
|
+
add("metalOunces", metalLabel(metal), metal.ounces, provenance(`${metalFigure(metal.ounces)} troy oz`,
|
|
305
|
+
metal.tonnes == null ? null : `${metalFigure(metal.tonnes)} tonnes`, metal.stale ? `${metal.asOf} stale` : metal.asOf, metal.source.publisher), "troy oz");
|
|
306
|
+
add("metalChangeOunces", "Day change", metal.change?.ounces ?? null, metal.change
|
|
307
|
+
? provenance(`${metalFigure(metal.change.ounces, true)} troy oz`, metal.change.tonnes == null ? null : `${metalFigure(metal.change.tonnes, true)} tonnes`, `since ${metal.change.since}`)
|
|
308
|
+
: `-- · ${metal.asOf} is the first day stored`, "troy oz");
|
|
309
|
+
}
|
|
254
310
|
if (facts.bond) {
|
|
255
311
|
add("bondClass", "Bond fund", facts.bond.kind, bondClassText(facts.bond));
|
|
256
312
|
const keys = { secYield: "secYieldPercent", yieldToWorst: "yieldToWorstPercent", duration: "durationYears" } as const;
|
|
@@ -261,6 +317,10 @@ export function fundFactEntries(facts: FundFactsPayload): HeadlessPaneEntry[] {
|
|
|
261
317
|
}
|
|
262
318
|
if (facts.sponsor) add("sponsor", "Sponsor", facts.sponsor.value, facts.sponsor.value);
|
|
263
319
|
if (facts.inception) add("inception", "Inception", facts.inception.value, facts.inception.value);
|
|
320
|
+
if (facts.leverage) {
|
|
321
|
+
add("leverageFactor", OBJECTIVE_LABEL, facts.leverage.value,
|
|
322
|
+
provenance(leverageObjectiveText(facts.leverage), facts.leverage.asOf, facts.leverage.source), "x");
|
|
323
|
+
}
|
|
264
324
|
if (facts.index) add("index", BENCHMARK_LABEL, facts.index.value, provenance(facts.index.value, facts.index.source));
|
|
265
325
|
const url = facts.nav?.url ?? facts.expenseRatio?.url ?? facts.netAssets?.url;
|
|
266
326
|
if (url) add("url", "Sponsor page", url, url);
|
|
@@ -278,8 +338,8 @@ export function listNames(names: readonly string[]): string {
|
|
|
278
338
|
* the consolidated close cites Gloom Cloud on its own line, not here.
|
|
279
339
|
*/
|
|
280
340
|
export function fundFactPublishers(facts: FundFactsPayload): string[] {
|
|
281
|
-
return [...new Set([facts.nav, facts.expenseRatio, facts.netAssets, facts.index, facts.bond?.secYield, facts.bond?.yieldToWorst, facts.bond?.duration]
|
|
282
|
-
.flatMap((value) => value ? [value.source] : []))];
|
|
341
|
+
return [...new Set([...[facts.nav, facts.expenseRatio, facts.netAssets, facts.leverage, facts.index, facts.bond?.secYield, facts.bond?.yieldToWorst, facts.bond?.duration]
|
|
342
|
+
.flatMap((value) => value ? [value.source] : []), ...facts.metalHoldings ? [facts.metalHoldings.source.publisher] : []])];
|
|
283
343
|
}
|
|
284
344
|
|
|
285
345
|
/** The newest NAV is stale: one line saying since when, as the report's note says it. */
|