gloomberb 0.18.2 → 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/patches/electrobun@1.18.1.patch +106 -5
- 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 +99 -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 +24 -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 +26 -7
- 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/telemetry.ts +17 -0
- package/src/api-client/themes.ts +7 -1
- package/src/api-client/types.ts +90 -2
- package/src/app/global-shortcuts.ts +1 -16
- 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/runtime/update.ts +28 -8
- package/src/app/star-prompt/status-line.tsx +2 -2
- package/src/architecture/core-builtin-allowlist.json +5 -2
- package/src/architecture/pane-tabs-allowlist.json +65 -0
- 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 +1189 -296
- 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 +272 -70
- 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 +20 -14
- 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 +32 -18
- package/src/cli/issuer-membership.ts +103 -0
- package/src/cli/known-gaps.ts +118 -25
- package/src/cli/listing-arg.ts +315 -43
- package/src/cli/name-entries.ts +73 -22
- 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 +77 -20
- package/src/cli/pane-functions/catalog.ts +40 -23
- package/src/cli/pane-functions/discovery.ts +1 -1
- package/src/cli/pane-functions/dom.ts +12 -8
- 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 +48 -16
- package/src/cli/pane-functions/index.ts +82 -21
- 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 +65 -14
- 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 +190 -27
- package/src/cli/restore-plugins.ts +29 -14
- package/src/cli/result.ts +122 -25
- 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 +226 -60
- 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 +387 -21
- package/src/components/chart/composite/drawing-store.ts +26 -6
- package/src/components/chart/composite/interactions.ts +9 -3
- 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 +316 -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 +19 -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/command-items.ts +32 -6
- 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/data-table/view.tsx +23 -3
- 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 +13 -6
- package/src/components/layout/detached-pane-shell.tsx +1 -0
- package/src/components/layout/floating-pane.tsx +1 -0
- package/src/components/layout/header.tsx +234 -60
- 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/pane/header.tsx +10 -3
- package/src/components/layout/pane/index.tsx +1 -0
- package/src/components/layout/pane/pane-tabs.tsx +9 -1
- 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/components/ui/stat-grid.tsx +28 -3
- package/src/components/ui/status.tsx +3 -1
- package/src/core/app-services.ts +4 -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 +51 -12
- package/src/i18n/ja.ts +51 -12
- package/src/i18n/ko.ts +51 -12
- package/src/i18n/zh-cn.ts +51 -12
- package/src/i18n/zh-tw.ts +51 -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 +30 -18
- 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 +108 -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 +77 -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 +107 -43
- package/src/plugins/builtin/attention/pane.tsx +22 -16
- 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 +12 -9
- package/src/plugins/builtin/backtest/export.ts +1 -1
- 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 +24 -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 +115 -26
- package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
- package/src/plugins/builtin/broker-trading/ticket.tsx +122 -36
- 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 +34 -18
- 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/client.ts +2 -2
- 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 +9 -11
- 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 +128 -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 +14 -8
- package/src/plugins/builtin/company-attention/app-rank.tsx +11 -10
- 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 +89 -31
- 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 +5 -4
- 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 +7 -4
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -0
- package/src/plugins/builtin/correlation/settings.ts +1 -0
- 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 +7 -5
- 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/credit-documents/pane.tsx +8 -7
- 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/debt-maturities/pane.tsx +4 -3
- 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 +19 -12
- 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 +77 -5
- package/src/plugins/builtin/equity-screener/live.ts +1 -1
- package/src/plugins/builtin/equity-screener/model.ts +34 -0
- package/src/plugins/builtin/equity-screener/pane.tsx +148 -106
- 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 +16 -10
- 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/board.tsx +4 -1
- package/src/plugins/builtin/gpu/changes.tsx +10 -10
- package/src/plugins/builtin/gpu/equities.tsx +4 -1
- package/src/plugins/builtin/gpu/headless.ts +9 -4
- package/src/plugins/builtin/gpu/history.tsx +4 -2
- package/src/plugins/builtin/gpu/pane.tsx +5 -3
- 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 +15 -2
- package/src/plugins/builtin/holders/format.ts +28 -17
- package/src/plugins/builtin/holders/headless.ts +48 -8
- 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/thirteenf-match.ts +3 -1
- package/src/plugins/builtin/holders/treemap.tsx +2 -2
- package/src/plugins/builtin/insider/base-values.ts +11 -7
- package/src/plugins/builtin/insider/client.ts +3 -0
- package/src/plugins/builtin/insider/headless.ts +20 -7
- package/src/plugins/builtin/insider/index.tsx +17 -8
- package/src/plugins/builtin/insider/issuer.ts +34 -4
- package/src/plugins/builtin/insider/signals-client.ts +3 -3
- package/src/plugins/builtin/insider/signals.tsx +1 -1
- package/src/plugins/builtin/insider/table-model.ts +35 -13
- package/src/plugins/builtin/insider/table.tsx +5 -2
- 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/events.ts +145 -0
- package/src/plugins/builtin/iv-history/format.ts +3 -0
- package/src/plugins/builtin/iv-history/headless.ts +91 -7
- 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 +14 -8
- 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 +36 -21
- 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 +33 -11
- 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 +50 -15
- package/src/plugins/builtin/notes/export.ts +17 -6
- package/src/plugins/builtin/notes/files.ts +16 -5
- package/src/plugins/builtin/openfda/pane.tsx +1 -1
- package/src/plugins/builtin/options/carry.ts +2 -2
- package/src/plugins/builtin/options/enrichment-model.ts +10 -9
- package/src/plugins/builtin/options/index.tsx +1 -1
- package/src/plugins/builtin/options/model-spot.ts +70 -4
- package/src/plugins/builtin/options/view.tsx +51 -23
- package/src/plugins/builtin/options-calculator/headless.ts +46 -7
- package/src/plugins/builtin/options-calculator/pane.tsx +3 -2
- package/src/plugins/builtin/options-positioning/headless.ts +11 -3
- package/src/plugins/builtin/options-positioning/model.ts +24 -0
- package/src/plugins/builtin/options-positioning/pane.tsx +10 -12
- package/src/plugins/builtin/options-scenario/client.ts +142 -29
- 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 +49 -21
- 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 +22 -10
- 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 +145 -60
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +78 -27
- 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 +6 -3
- 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 +44 -32
- 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/client.ts +2 -1
- package/src/plugins/builtin/reverse-dcf/model.ts +10 -5
- package/src/plugins/builtin/risk-factors/index.tsx +2 -2
- package/src/plugins/builtin/scanner/lock-note.ts +1 -1
- package/src/plugins/builtin/seasonality/client.ts +2 -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 +6 -4
- 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-resource.ts +15 -2
- 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 +23 -0
- package/src/plugins/builtin/shared/series-cache.ts +2 -0
- package/src/plugins/builtin/shared/series-list-detail.tsx +3 -1
- package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
- package/src/plugins/builtin/shared/volatility/options.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/social-mentions/client.ts +2 -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 +28 -7
- package/src/plugins/builtin/vol-surface/headless.ts +43 -15
- package/src/plugins/builtin/vol-surface/model.ts +34 -12
- package/src/plugins/builtin/vol-surface/pane.tsx +33 -13
- package/src/plugins/builtin/vol-surface/stored.ts +34 -3
- package/src/plugins/builtin/vol-surface/tables.ts +14 -0
- 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/desktop/controls.tsx +1 -1
- package/src/renderers/dom/desktop/query-bar.tsx +2 -0
- 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/host/tabs.tsx +16 -5
- package/src/renderers/dom/host/top-surface.ts +127 -0
- package/src/renderers/dom/styles.css +115 -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/core-capabilities.ts +9 -1
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +56 -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/desktop/update.ts +210 -30
- 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 +9 -7
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +9 -2
- 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 +8 -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 +39 -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/index.ts +16 -0
- 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 +21 -4
- package/src/telemetry/update-failures-node.ts +59 -0
- package/src/telemetry/update-failures.ts +307 -0
- 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 +215 -36
- package/src/tickers/company-name.ts +43 -0
- package/src/tickers/index-roots.ts +47 -0
- package/src/tickers/instrument-label.ts +5 -1
- package/src/tickers/listing-fate.ts +30 -0
- 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 +20 -0
- package/src/types/exchange-rate.ts +6 -0
- package/src/types/financials.ts +104 -7
- package/src/types/headless.ts +83 -6
- package/src/types/instrument.ts +3 -0
- package/src/types/issuer-listings.ts +28 -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/failure.ts +163 -0
- package/src/updater/index.ts +97 -28
- 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-pair.ts +26 -0
- 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 +71 -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
|
@@ -30,6 +30,8 @@ import {
|
|
|
30
30
|
type PortfolioFuturesTerms,
|
|
31
31
|
} from "../../../../portfolio/futures-positions";
|
|
32
32
|
import { dailyFuturesHistory, loadPortfolioFuturesTerms, type PortfolioFuturesSources } from "../../../../portfolio/futures-terms";
|
|
33
|
+
import { loadPurchaseDateCostFx, withPurchaseDateCostFx, type CostFxHistoryClient, type PurchaseDateCostFx } from "../../../../portfolio/cost-fx";
|
|
34
|
+
import { apiClient } from "../../../../api-client";
|
|
33
35
|
import { formatUtcDayTime, parseReportTime } from "../../../../utils/utc-time";
|
|
34
36
|
import { quoteFreshnessFields } from "../../shared/report-freshness";
|
|
35
37
|
import { resolvePortfolioTotalsCurrency } from "../summary/totals";
|
|
@@ -85,7 +87,7 @@ import { importedFromText } from "../imported-from";
|
|
|
85
87
|
import { findNamedCollection } from "../../../../portfolio/collection-name";
|
|
86
88
|
import { isoDateToday } from "../../../../utils/calendar-date";
|
|
87
89
|
import { lastTradeDate } from "../../../../tickers/listing-fate";
|
|
88
|
-
import { DIVIDEND_READ_DEADLINE_MS, incomeGapNote, loadHoldingDividends, portfolioIncome, projectDrip, type DripYear, type HoldingDividend } from "../income";
|
|
90
|
+
import { DIVIDEND_READ_DEADLINE_MS, incomeGapNote, loadHoldingDividends, portfolioIncome, projectDrip, showsIncomeColumns, type DripYear, type HoldingDividend } from "../income";
|
|
89
91
|
|
|
90
92
|
/** Money prices pad to the currency's minor unit ($337.90, not $337.9), as the ticker view does. */
|
|
91
93
|
function priceFormatOptions(quote: Parameters<typeof quoteFormatOptions>[0] & { currency?: string }, assetCategory?: string) {
|
|
@@ -202,6 +204,8 @@ export interface ShowCollectionOptions {
|
|
|
202
204
|
dividendDeadlineMs?: number;
|
|
203
205
|
/** Where futures' terms and settlements are read; Gloom Cloud's terms and the data provider's daily bars by default. */
|
|
204
206
|
futuresSources?: PortfolioFuturesSources;
|
|
207
|
+
/** Where the FX closes of the lots' purchase dates are read; Gloom Cloud by default. */
|
|
208
|
+
costFxHistory?: CostFxHistoryClient;
|
|
205
209
|
}
|
|
206
210
|
|
|
207
211
|
export async function showCollection(name: string, ctx: CliCommandContext, options: ShowCollectionOptions = {}) {
|
|
@@ -317,8 +321,14 @@ export interface PortfolioValuation {
|
|
|
317
321
|
unknownContractSize: Set<string>;
|
|
318
322
|
/** Futures valued at the close without a confirmed settlement to value them at. */
|
|
319
323
|
unsettled: Set<string>;
|
|
320
|
-
/**
|
|
324
|
+
/**
|
|
325
|
+
* Holdings in another currency whose cost converts at today's rate: no
|
|
326
|
+
* purchase date or cost FX rate was entered (`costFxUndated`), or the
|
|
327
|
+
* date's FX close could not be read (`costFxUnread`).
|
|
328
|
+
*/
|
|
321
329
|
costAtTodaysRate: Set<string>;
|
|
330
|
+
costFxUndated: Set<string>;
|
|
331
|
+
costFxUnread: Set<string>;
|
|
322
332
|
/** Long and short market value of the priced lots, and their net and gross, in the portfolio's currency. */
|
|
323
333
|
exposure: PortfolioExposure;
|
|
324
334
|
}
|
|
@@ -346,10 +356,16 @@ function portfolioExposure(values: Iterable<number | null | undefined>): Portfol
|
|
|
346
356
|
/**
|
|
347
357
|
* What a book says of holdings in another currency whose cost converts at
|
|
348
358
|
* today's rate, which leaves the currency's move since purchase out of their
|
|
349
|
-
* P&L
|
|
359
|
+
* P&L: those with no purchase date or rate, and those whose date's FX close
|
|
360
|
+
* could not be read. `named` lists them as the table names its rows.
|
|
350
361
|
*/
|
|
351
|
-
export function
|
|
352
|
-
|
|
362
|
+
export function costAtTodaysRateNotes(valuation: Pick<PortfolioValuation, "costFxUndated" | "costFxUnread">,
|
|
363
|
+
named: (symbols: Iterable<string>) => string): string[] {
|
|
364
|
+
const undated = valuation.costFxUndated;
|
|
365
|
+
return [
|
|
366
|
+
...undated.size ? [`Cost converted at today's rate for ${named(undated)}; give portfolio position set a --date or --cost-fx to use the rate when bought.`] : [],
|
|
367
|
+
...valuation.costFxUnread.size ? [`Cost converted at today's rate for ${named(valuation.costFxUnread)}: the FX close of the purchase date could not be read.`] : [],
|
|
368
|
+
];
|
|
353
369
|
}
|
|
354
370
|
|
|
355
371
|
/**
|
|
@@ -368,6 +384,7 @@ export async function valuePortfolioPositions({
|
|
|
368
384
|
toBase,
|
|
369
385
|
basis = "latest-print",
|
|
370
386
|
futures,
|
|
387
|
+
purchaseDateFx,
|
|
371
388
|
}: {
|
|
372
389
|
tickers: readonly TickerRecord[];
|
|
373
390
|
quotes: ReadonlyMap<string, CollectionQuote>;
|
|
@@ -378,6 +395,11 @@ export async function valuePortfolioPositions({
|
|
|
378
395
|
basis?: PortfolioValuationBasis;
|
|
379
396
|
/** Each future's contract size and settlement (loadPortfolioFuturesTerms), by symbol. */
|
|
380
397
|
futures?: ReadonlyMap<string, PortfolioFuturesTerms>;
|
|
398
|
+
/**
|
|
399
|
+
* The FX closes of the lots' purchase dates in `currency` (loadPurchaseDateCostFx): a dated lot with no rate of
|
|
400
|
+
* its own into `currency` converts its cost at its date's close, and at today's rate when that could not be read.
|
|
401
|
+
*/
|
|
402
|
+
purchaseDateFx?: PurchaseDateCostFx;
|
|
381
403
|
}): Promise<PortfolioValuation> {
|
|
382
404
|
const id = portfolioId;
|
|
383
405
|
let totalPnl = 0;
|
|
@@ -388,11 +410,13 @@ export async function valuePortfolioPositions({
|
|
|
388
410
|
const unknownContractSize = new Set<string>();
|
|
389
411
|
const unsettled = new Set<string>();
|
|
390
412
|
const costAtTodaysRate = new Set<string>();
|
|
413
|
+
const costFxUndated = new Set<string>();
|
|
414
|
+
const costFxUnread = new Set<string>();
|
|
391
415
|
const values: PortfolioPositionValue[] = [];
|
|
392
416
|
const holdings: AllocationHolding[] = [];
|
|
393
417
|
const known = (value: number | null | undefined): number | null => value != null && Number.isFinite(value) ? value : null;
|
|
394
418
|
|
|
395
|
-
for (const ticker of tickers) {
|
|
419
|
+
for (const ticker of purchaseDateFx ? withPurchaseDateCostFx(tickers, purchaseDateFx, currency, id) : tickers) {
|
|
396
420
|
const quote = quotes.get(ticker.metadata.ticker);
|
|
397
421
|
const futuresTerms = isFuturesTicker(ticker) ? futures?.get(ticker.metadata.ticker) ?? { size: null, settlement: null } : null;
|
|
398
422
|
// A lot entered without its contract size takes the one the terms state; the entries keep the saved record.
|
|
@@ -430,7 +454,7 @@ export async function valuePortfolioPositions({
|
|
|
430
454
|
const atSettlement = valuesAtSettlement(metrics, basis);
|
|
431
455
|
const positionCurrency = metrics.positionCurrency;
|
|
432
456
|
const positionRate = positionCurrency ? await toBase(1, positionCurrency) : Number.NaN;
|
|
433
|
-
// The cost converts at the rate the lot was bought at
|
|
457
|
+
// The cost converts at the rate the lot was bought at, entered or its purchase date's close, else at today's, as its value does.
|
|
434
458
|
const baseMetrics = getPortfolioPositionMetrics({ ...ticker, metadata: { ...ticker.metadata, positions: [position] } }, id, quoteCurrency,
|
|
435
459
|
{ currency, convert: value => value * positionRate }, quote);
|
|
436
460
|
const boughtRate = positionCurrency ? lotCostFxRate(position, positionCurrency, currency) : null;
|
|
@@ -438,7 +462,10 @@ export async function valuePortfolioPositions({
|
|
|
438
462
|
: boughtRate !== null ? baseMetrics.totalCost : await toBase(metrics.totalCost, positionCurrency);
|
|
439
463
|
// Only a lot entered by hand can be given the rate it was bought at; a broker's lot reads as it always has.
|
|
440
464
|
const atTodaysRate = position.broker === "manual" && !!positionCurrency && lotCostAtTodaysRate(position, positionCurrency, currency);
|
|
441
|
-
if (atTodaysRate && metrics.hasCostBasis)
|
|
465
|
+
if (atTodaysRate && metrics.hasCostBasis) {
|
|
466
|
+
costAtTodaysRate.add(ticker.metadata.ticker);
|
|
467
|
+
(purchaseDateFx && position.dateAcquired ? costFxUnread : costFxUndated).add(ticker.metadata.ticker);
|
|
468
|
+
}
|
|
442
469
|
const costFx = boughtRate !== null ? { rate: boughtRate, currency } : atTodaysRate ? null : undefined;
|
|
443
470
|
const currentValueBase = resolvePortfolioMarketValue(baseMetrics,
|
|
444
471
|
valuationQuote ? await toBase(valuationQuote.price, quoteCurrency) : null)?.gross ?? null;
|
|
@@ -481,7 +508,7 @@ export async function valuePortfolioPositions({
|
|
|
481
508
|
|
|
482
509
|
const exposure = portfolioExposure(values.map((entry) => entry.position ? entry.row.marketValue as number | null : null));
|
|
483
510
|
return { basis, positions: values, holdings, totalPnl, unavailablePnl, unavailableCost, unavailableMarketValue, brokerPnlSymbols,
|
|
484
|
-
unknownContractSize, unsettled, costAtTodaysRate, exposure };
|
|
511
|
+
unknownContractSize, unsettled, costAtTodaysRate, costFxUndated, costFxUnread, exposure };
|
|
485
512
|
}
|
|
486
513
|
|
|
487
514
|
/**
|
|
@@ -686,7 +713,7 @@ async function showCollectionWithMarketData(
|
|
|
686
713
|
name: string,
|
|
687
714
|
ctx: CliCommandContext,
|
|
688
715
|
{ config, store, dataProvider, persistence }: MarketContext,
|
|
689
|
-
{ explain = false, basis = "latest-print", drip, dividendDeadlineMs = DIVIDEND_READ_DEADLINE_MS, futuresSources }: ShowCollectionOptions,
|
|
716
|
+
{ explain = false, basis = "latest-print", drip, dividendDeadlineMs = DIVIDEND_READ_DEADLINE_MS, futuresSources, costFxHistory = apiClient }: ShowCollectionOptions,
|
|
690
717
|
) {
|
|
691
718
|
const tickers = (await store.loadAllTickers()).sort((left, right) =>
|
|
692
719
|
left.metadata.ticker.localeCompare(right.metadata.ticker)
|
|
@@ -702,10 +729,10 @@ async function showCollectionWithMarketData(
|
|
|
702
729
|
|
|
703
730
|
const matchedPortfolio = collection.kind === "portfolio" ? collection.portfolio : undefined;
|
|
704
731
|
if (!matchedPortfolio && basis === "regular-close") {
|
|
705
|
-
ctx.fail(`--close values a portfolio; "${collection.name}" is a watchlist.`, "Usage:
|
|
732
|
+
ctx.fail(`--close values a portfolio; "${collection.name}" is a watchlist.`, "Usage: gloom portfolio show <portfolio> --close");
|
|
706
733
|
}
|
|
707
734
|
if (!matchedPortfolio && drip) {
|
|
708
|
-
ctx.fail(`--drip projects a portfolio's dividends; "${collection.name}" is a watchlist.`, "Usage:
|
|
735
|
+
ctx.fail(`--drip projects a portfolio's dividends; "${collection.name}" is a watchlist.`, "Usage: gloom portfolio show <portfolio> --drip");
|
|
709
736
|
}
|
|
710
737
|
const isPortfolio = !!matchedPortfolio;
|
|
711
738
|
const id = collection.id;
|
|
@@ -731,12 +758,13 @@ async function showCollectionWithMarketData(
|
|
|
731
758
|
|
|
732
759
|
const futuresHeld = filtered.filter((ticker) => isFuturesTicker(ticker)
|
|
733
760
|
&& ticker.metadata.positions.some((position) => position.portfolio === id && position.shares !== 0));
|
|
734
|
-
const [quotes, futures] = await Promise.all([
|
|
761
|
+
const [quotes, futures, purchaseDateFx] = await Promise.all([
|
|
735
762
|
loadCollectionQuotes(filtered, collection, dataProvider),
|
|
736
763
|
isPortfolio ? loadPortfolioFuturesTerms(futuresHeld, {
|
|
737
764
|
settlement: basis === "regular-close",
|
|
738
765
|
sources: { history: dailyFuturesHistory(dataProvider), ...futuresSources },
|
|
739
766
|
}) : undefined,
|
|
767
|
+
isPortfolio ? loadPurchaseDateCostFx(filtered, { into: currency, history: costFxHistory, portfolioId: id }) : undefined,
|
|
740
768
|
]);
|
|
741
769
|
// Worst of across the holdings' quotes, as the PORT and watchlist reports state it.
|
|
742
770
|
const broker = !!(matchedPortfolio?.brokerId || matchedPortfolio?.brokerInstanceId);
|
|
@@ -756,7 +784,7 @@ async function showCollectionWithMarketData(
|
|
|
756
784
|
}
|
|
757
785
|
|
|
758
786
|
if (matchedPortfolio) {
|
|
759
|
-
const valuation = await valuePortfolioPositions({ tickers: filtered, quotes, portfolioId: id, currency, baseCurrency: config.baseCurrency, toBase, basis, futures });
|
|
787
|
+
const valuation = await valuePortfolioPositions({ tickers: filtered, quotes, portfolioId: id, currency, baseCurrency: config.baseCurrency, toBase, basis, futures, purchaseDateFx });
|
|
760
788
|
// Exports carry no header line, so their source line names the basis.
|
|
761
789
|
freshness = portfolioValuationFreshness(valuation, source, { note: structured });
|
|
762
790
|
const {
|
|
@@ -774,7 +802,8 @@ async function showCollectionWithMarketData(
|
|
|
774
802
|
const { allocation, cash } = await valuePortfolioAllocation({ valuation, portfolio: matchedPortfolio, account, toBase });
|
|
775
803
|
const allocationBySymbol = new Map(allocation.rows.map((row) => [row.symbol, row]));
|
|
776
804
|
// What each holding pays a year: trailing dividends per share times its shares, in the portfolio's currency.
|
|
777
|
-
|
|
805
|
+
// By symbol: a lot whose cost converts at its purchase date's FX close is valued on a copy of its record.
|
|
806
|
+
const held = filtered.filter((ticker) => valued.some((entry) => entry.ticker.metadata.ticker === ticker.metadata.ticker && entry.position));
|
|
778
807
|
const { dividends } = await loadHoldingDividends(held, quotes, dataProvider, { deadlineMs: dividendDeadlineMs });
|
|
779
808
|
// Lots without a position or shares are no lot of income; a row of their own keeps its place with none.
|
|
780
809
|
const income = await portfolioIncome(valued.map((entry) => ({
|
|
@@ -853,7 +882,7 @@ async function showCollectionWithMarketData(
|
|
|
853
882
|
const symbol = ticker.metadata.ticker;
|
|
854
883
|
const dividend = dividends.get(symbol);
|
|
855
884
|
if (!dividend) continue;
|
|
856
|
-
const shares = valued.filter((entry) => entry.ticker ===
|
|
885
|
+
const shares = valued.filter((entry) => entry.ticker.metadata.ticker === symbol && entry.position && entry.metrics)
|
|
857
886
|
.reduce((sum, entry) => sum + entry.metrics!.totalShares, 0);
|
|
858
887
|
if (shares === 0) continue;
|
|
859
888
|
// Income the table could not show is not projected either; the note under it says why.
|
|
@@ -930,7 +959,7 @@ async function showCollectionWithMarketData(
|
|
|
930
959
|
exposure,
|
|
931
960
|
...(unknownContractSize.size > 0 ? { unknownContractSizeSymbols: [...unknownContractSize] } : {}),
|
|
932
961
|
...(unsettled.size > 0 ? { unsettledSymbols: [...unsettled] } : {}),
|
|
933
|
-
// Holdings in another currency
|
|
962
|
+
// Holdings in another currency whose cost converts at today's rate: no purchase date or cost FX rate, or the date's close was not read.
|
|
934
963
|
...(costAtTodaysRate.size > 0 ? { costAtTodaysRateSymbols: [...costAtTodaysRate] } : {}),
|
|
935
964
|
accountingBasis, ...(manualAccounting ? { manualAccounting } : {}),
|
|
936
965
|
...(matchedPortfolio.importedFrom ? { importedFrom: matchedPortfolio.importedFrom } : {}),
|
|
@@ -959,8 +988,8 @@ async function showCollectionWithMarketData(
|
|
|
959
988
|
return [weight, target, drift, trade, tradeValue];
|
|
960
989
|
};
|
|
961
990
|
|
|
962
|
-
// Income and its yield, once any share or fund has one
|
|
963
|
-
const showIncome = income
|
|
991
|
+
// Income and its yield, once any share or fund has one or only lacks a rate into the portfolio's currency; otherwise the note under the table says why.
|
|
992
|
+
const showIncome = showsIncomeColumns(income);
|
|
964
993
|
const incomeCells = (income: number | null | undefined, yieldPercent: number | null | undefined): string[] =>
|
|
965
994
|
showIncome ? [money(income), formatIncomeYield(yieldPercent)] : [];
|
|
966
995
|
const extendedSessions = extendedSessionsOf(valued.map(({ extended }) => extended?.session));
|
|
@@ -1086,7 +1115,7 @@ async function showCollectionWithMarketData(
|
|
|
1086
1115
|
const targetNote = describeTargetSum(allocation.targetSum, allocation.weightBasis);
|
|
1087
1116
|
if (targetNote) notes.push(cliStyles.muted(targetNote));
|
|
1088
1117
|
if (brokerPnlSymbols.size > 0) notes.push(cliStyles.muted(`P&L for ${named(brokerPnlSymbols)} is the broker's last snapshot.`));
|
|
1089
|
-
|
|
1118
|
+
notes.push(...costAtTodaysRateNotes(valuation, named).map((note) => cliStyles.muted(note)));
|
|
1090
1119
|
if (unknownContractSize.size > 0) {
|
|
1091
1120
|
notes.push(cliStyles.warning(`No contract size for ${named(unknownContractSize)}, so ${unknownContractSize.size === 1 ? "its" : "their"} value, cost and P&L are not shown.`));
|
|
1092
1121
|
}
|
|
@@ -91,9 +91,9 @@ export function misplacedSymbolList(
|
|
|
91
91
|
const more = collections.length - names.length;
|
|
92
92
|
const existing = names.length > 0
|
|
93
93
|
? `${label}: ${names.join(", ")}${more > 0 ? ` and ${more} more` : ""}`
|
|
94
|
-
: `no ${label} yet, create one with \`
|
|
94
|
+
: `no ${label} yet, create one with \`gloom ${noun} create <name>\``;
|
|
95
95
|
return {
|
|
96
|
-
message: `"${preview}" reads as a list of symbols, not a ${noun} name; did you mean \`
|
|
96
|
+
message: `"${preview}" reads as a list of symbols, not a ${noun} name; did you mean \`gloom ${noun} ${verb} <name> <list>\`; ${existing}`,
|
|
97
97
|
details: usage,
|
|
98
98
|
};
|
|
99
99
|
}
|
|
@@ -146,6 +146,6 @@ export function rejectCashSymbol(symbol: string, exchange: string | undefined, p
|
|
|
146
146
|
if (!isCashArgument(symbol, exchange)) return;
|
|
147
147
|
throw new PortfolioCliError(
|
|
148
148
|
"CASH is the portfolio's cash line, not a ticker.",
|
|
149
|
-
`Record cash with:
|
|
149
|
+
`Record cash with: gloom portfolio cash set "${portfolioName}" <amount> [currency]. For the stock that trades as CASH, name its exchange: CASH:NASDAQ.`,
|
|
150
150
|
);
|
|
151
151
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { saveConfig } from "../../../../data/config/store";
|
|
2
|
-
import { withConfigData
|
|
2
|
+
import { withConfigData } from "../../../../cli/scoped-context";
|
|
3
|
+
import { withCollectionConfigData, withCollectionMarketData } from "../../../../cli/suffixed-listing-rows";
|
|
3
4
|
import { countCollectionTickers, findWatchlist } from "../../../../cli/helpers";
|
|
4
5
|
import { slugifyName } from "../../../../utils/slugify";
|
|
5
6
|
import { takeOption } from "../../../../cli/commands/command-utils";
|
|
6
|
-
import { EXCHANGE_OPTION,
|
|
7
|
+
import { EXCHANGE_OPTION, requireSavedListing, savedListingName } from "../../../../cli/listing-arg";
|
|
7
8
|
import {
|
|
8
9
|
cliStyles,
|
|
9
10
|
renderSection,
|
|
@@ -21,14 +22,12 @@ import {
|
|
|
21
22
|
} from "../../../../portfolio/mutations";
|
|
22
23
|
import { showCollection } from "./render";
|
|
23
24
|
import { listingFields, misplacedSymbolList, refuseDryRun, takeCollectionName } from "./shared";
|
|
24
|
-
import { addOneSymbol, addSymbols, FILE_OPTION, printSymbolRows, removeSymbols, requireSymbolList, retryNotice, SYMBOL_LIST_HELP } from "./bulk-symbols";
|
|
25
|
+
import { addOneSymbol, addSymbols, FILE_OPTION, printSymbolRows, removeSymbols, requireSymbolList, retryNotice, shellWord, SYMBOL_LIST_HELP } from "./bulk-symbols";
|
|
25
26
|
import { readNameEntries } from "../../../../cli/name-entries";
|
|
26
27
|
import { CLI_COMMAND_GROUPS } from "../../../../cli/help";
|
|
27
28
|
|
|
28
|
-
const ADD_USAGE = "Usage:
|
|
29
|
-
const REMOVE_USAGE = "Usage:
|
|
30
|
-
/** A collection's name as a command argument: quoted when it has spaces. */
|
|
31
|
-
const quotedName = (name: string) => /\s/.test(name) ? `"${name}"` : name;
|
|
29
|
+
const ADD_USAGE = "Usage: gloom watchlist add <watchlist> <symbols...> [--file <path>]";
|
|
30
|
+
const REMOVE_USAGE = "Usage: gloom watchlist remove <watchlist> <symbols...> [--file <path>]";
|
|
32
31
|
|
|
33
32
|
/** Actions that change a watchlist without a preview, so --dry-run would change it anyway. add previews. */
|
|
34
33
|
const MUTATING_ACTIONS = new Set(["create", "delete", "rm", "remove"]);
|
|
@@ -59,7 +58,7 @@ function requireWatchlistArgs(
|
|
|
59
58
|
async function createWatchlist(name: string, ctx: CliCommandContext) {
|
|
60
59
|
await withConfigData(ctx, async ({ config }) => {
|
|
61
60
|
const trimmedName = name.trim();
|
|
62
|
-
if (!trimmedName) ctx.fail("Usage:
|
|
61
|
+
if (!trimmedName) ctx.fail("Usage: gloom watchlist create <name>");
|
|
63
62
|
|
|
64
63
|
const id = slugifyName(trimmedName, "watchlist");
|
|
65
64
|
const duplicate = config.watchlists.some((watchlist) =>
|
|
@@ -78,7 +77,7 @@ async function createWatchlist(name: string, ctx: CliCommandContext) {
|
|
|
78
77
|
}
|
|
79
78
|
|
|
80
79
|
async function deleteWatchlist(name: string, ctx: CliCommandContext) {
|
|
81
|
-
await
|
|
80
|
+
await withCollectionConfigData(ctx, async ({ config, store }) => {
|
|
82
81
|
const watchlist = findWatchlist(config, name);
|
|
83
82
|
if (!watchlist) ctx.fail(`Watchlist "${name}" was not found.`);
|
|
84
83
|
|
|
@@ -93,26 +92,29 @@ async function deleteWatchlist(name: string, ctx: CliCommandContext) {
|
|
|
93
92
|
});
|
|
94
93
|
}
|
|
95
94
|
|
|
96
|
-
async function addTickerToWatchlistCommand(
|
|
95
|
+
async function addTickerToWatchlistCommand(
|
|
96
|
+
watchlist: Watchlist, symbol: string, notes: readonly string[], exchange: string | undefined, ctx: CliCommandContext, market: MarketContext,
|
|
97
|
+
) {
|
|
97
98
|
// A bare symbol is stored on the listing `quote` reads it as, and the notes say which; a match a list would leave for a choice fails.
|
|
98
99
|
await addOneSymbol(ctx, market, {
|
|
99
100
|
symbol,
|
|
100
101
|
exchange,
|
|
101
102
|
collection: { kind: "watchlist", name: watchlist.name },
|
|
102
|
-
|
|
103
|
+
notes,
|
|
104
|
+
retry: (key) => `gloom watchlist add ${shellWord(watchlist.name)} ${key}`,
|
|
103
105
|
add: (ticker) => addTickerToWatchlist(ticker, watchlist.id),
|
|
104
106
|
});
|
|
105
107
|
}
|
|
106
108
|
|
|
107
109
|
async function addToWatchlistCommand(args: string[], file: string | undefined, exchange: string | undefined, ctx: CliCommandContext) {
|
|
108
|
-
await
|
|
110
|
+
await withCollectionMarketData(ctx, async (market) => {
|
|
109
111
|
const { watchlist, rest } = requireWatchlistArgs(market.config, args, file, "add", ADD_USAGE, ctx);
|
|
110
112
|
const list = await requireSymbolList(ctx, rest, file, ADD_USAGE, (entries) => readNameEntries(entries, market.dataProvider));
|
|
111
113
|
if (list.single) {
|
|
112
|
-
await addTickerToWatchlistCommand(watchlist, list.single, exchange, ctx, market);
|
|
114
|
+
await addTickerToWatchlistCommand(watchlist, list.single, list.notes, exchange, ctx, market);
|
|
113
115
|
return;
|
|
114
116
|
}
|
|
115
|
-
const retry = (key: string) => `
|
|
117
|
+
const retry = (key: string) => `gloom watchlist add ${shellWord(watchlist.name)} ${key}`;
|
|
116
118
|
const dryRun = ctx.cliOptions.dryRun;
|
|
117
119
|
const rows = await addSymbols({
|
|
118
120
|
symbols: list.symbols,
|
|
@@ -129,33 +131,36 @@ async function addToWatchlistCommand(args: string[], file: string | undefined, e
|
|
|
129
131
|
});
|
|
130
132
|
}
|
|
131
133
|
|
|
132
|
-
async function removeTickerFromWatchlist(
|
|
134
|
+
async function removeTickerFromWatchlist(
|
|
135
|
+
watchlist: Watchlist, symbol: string, notes: readonly string[], exchange: string | undefined, ctx: CliCommandContext, { store }: ConfigContext,
|
|
136
|
+
) {
|
|
133
137
|
// SAN:EPA and SAN --exchange EPA name the stored listing, which a bare SAN may hold under another venue.
|
|
134
|
-
|
|
135
|
-
const ticker = await
|
|
138
|
+
// GARAN.IS is the row of GARAN:BIST, else a row still saved under that key (a broker's).
|
|
139
|
+
const { listing, ticker } = await requireSavedListing(symbol, exchange, ctx, store, (row) => row.metadata.watchlists.includes(watchlist.id));
|
|
136
140
|
if (!ticker) ctx.fail(`Ticker "${listing.key}" was not found in your local data.`);
|
|
137
141
|
const saved = savedListingName(ticker);
|
|
138
142
|
const result = removeWatchlistMembership(ticker, watchlist.id);
|
|
139
143
|
if (!result.changed) ctx.fail(`${saved.key} is not in "${watchlist.name}".`);
|
|
140
144
|
|
|
141
145
|
await store.saveTicker(result.ticker);
|
|
142
|
-
ctx.printResult({ data: { changed: true, ...listingFields(saved), watchlist: watchlist.name } }, {
|
|
146
|
+
ctx.printResult({ data: { changed: true, ...listingFields(saved), watchlist: watchlist.name }, ...notes.length > 0 ? { warnings: [...notes] } : {} }, {
|
|
143
147
|
text: () => cliStyles.success(`Removed ${saved.label} from "${watchlist.name}".`),
|
|
144
148
|
});
|
|
145
149
|
}
|
|
146
150
|
|
|
147
151
|
async function removeFromWatchlistCommand(args: string[], file: string | undefined, exchange: string | undefined, ctx: CliCommandContext) {
|
|
148
|
-
await
|
|
152
|
+
await withCollectionConfigData(ctx, async (context) => {
|
|
149
153
|
const { watchlist, rest } = requireWatchlistArgs(context.config, args, file, "remove", REMOVE_USAGE, ctx);
|
|
150
154
|
const list = await requireSymbolList(ctx, rest, file, REMOVE_USAGE);
|
|
151
155
|
if (list.single) {
|
|
152
|
-
await removeTickerFromWatchlist(watchlist, list.single, exchange, ctx, context);
|
|
156
|
+
await removeTickerFromWatchlist(watchlist, list.single, list.notes, exchange, ctx, context);
|
|
153
157
|
return;
|
|
154
158
|
}
|
|
155
159
|
const rows = await removeSymbols({
|
|
156
160
|
symbols: list.symbols,
|
|
157
161
|
exchange,
|
|
158
162
|
store: context.store,
|
|
163
|
+
holds: (ticker) => ticker.metadata.watchlists.includes(watchlist.id),
|
|
159
164
|
remove: (ticker) => removeWatchlistMembership(ticker, watchlist.id),
|
|
160
165
|
});
|
|
161
166
|
printSymbolRows(ctx, rows, { verb: "remove", collection: { kind: "watchlist", name: watchlist.name }, repeated: list.repeated, notes: list.notes });
|
|
@@ -247,21 +252,21 @@ export const watchlistCliCommand: CliCommandDef = {
|
|
|
247
252
|
|
|
248
253
|
if (action === "show") {
|
|
249
254
|
const name = args.slice(1).join(" ");
|
|
250
|
-
if (!name) ctx.fail("Usage:
|
|
255
|
+
if (!name) ctx.fail("Usage: gloom watchlist show <name>");
|
|
251
256
|
await showCollection(name, ctx);
|
|
252
257
|
return;
|
|
253
258
|
}
|
|
254
259
|
|
|
255
260
|
if (action === "create") {
|
|
256
261
|
const name = args.slice(1).join(" ");
|
|
257
|
-
if (!name) ctx.fail("Usage:
|
|
262
|
+
if (!name) ctx.fail("Usage: gloom watchlist create <name>");
|
|
258
263
|
await createWatchlist(name, ctx);
|
|
259
264
|
return;
|
|
260
265
|
}
|
|
261
266
|
|
|
262
267
|
if (action === "delete" || action === "rm") {
|
|
263
268
|
const name = args.slice(1).join(" ");
|
|
264
|
-
if (!name) ctx.fail("Usage:
|
|
269
|
+
if (!name) ctx.fail("Usage: gloom watchlist delete <name>");
|
|
265
270
|
await deleteWatchlist(name, ctx);
|
|
266
271
|
return;
|
|
267
272
|
}
|
|
@@ -282,7 +287,7 @@ export const watchlistCliCommand: CliCommandDef = {
|
|
|
282
287
|
const path = /\.\w+$/.test(rest.at(-1) ?? "") ? rest.at(-1)! : null;
|
|
283
288
|
const name = (path ? rest.slice(0, -1) : rest).join(" ") || "<watchlist>";
|
|
284
289
|
ctx.fail(
|
|
285
|
-
`watchlist has no import. To add the symbols in ${path ?? "a file"}, run:
|
|
290
|
+
`watchlist has no import. To add the symbols in ${path ?? "a file"}, run: gloom watchlist add ${/\s/.test(name) ? `"${name}"` : name} --file ${path ?? "<path>"}`,
|
|
286
291
|
ADD_USAGE,
|
|
287
292
|
);
|
|
288
293
|
}
|
|
@@ -24,13 +24,14 @@ import {
|
|
|
24
24
|
valuationTimeText,
|
|
25
25
|
valuePortfolioAllocation,
|
|
26
26
|
valuePortfolioPositions,
|
|
27
|
-
|
|
27
|
+
costAtTodaysRateNotes,
|
|
28
28
|
type CollectionMatch,
|
|
29
29
|
type PortfolioValuation,
|
|
30
30
|
} from "./cli/render";
|
|
31
31
|
import { valuationBasisLabel, type PortfolioValuationBasis } from "../../../portfolio/valuation-basis";
|
|
32
32
|
import { futuresQuantityText, isFuturesTicker } from "../../../portfolio/futures-positions";
|
|
33
33
|
import { dailyFuturesHistory, loadPortfolioFuturesTerms } from "../../../portfolio/futures-terms";
|
|
34
|
+
import { loadPurchaseDateCostFx } from "../../../portfolio/cost-fx";
|
|
34
35
|
import { EXTENDED_SESSION_LABELS, quoteHeadlineTime, type ExtendedSession } from "../../../market-data/market/status";
|
|
35
36
|
import {
|
|
36
37
|
BROKER_ACCOUNT_MISSING_NOTE,
|
|
@@ -289,12 +290,13 @@ async function portfolioHoldings(
|
|
|
289
290
|
const currency = resolvePortfolioTotalsCurrency(target.portfolio, ctx.config.baseCurrency);
|
|
290
291
|
const futuresHeld = tickers.filter((ticker) => isFuturesTicker(ticker)
|
|
291
292
|
&& ticker.metadata.positions.some((position) => position.portfolio === target.id && position.shares !== 0));
|
|
292
|
-
const [quotes, futures] = await Promise.all([
|
|
293
|
+
const [quotes, futures, purchaseDateFx] = await Promise.all([
|
|
293
294
|
loadCollectionQuotes(tickers, target, ctx.marketData),
|
|
294
295
|
loadPortfolioFuturesTerms(futuresHeld, {
|
|
295
296
|
settlement: basis === "regular-close",
|
|
296
297
|
sources: { history: dailyFuturesHistory(ctx.marketData) },
|
|
297
298
|
}),
|
|
299
|
+
loadPurchaseDateCostFx(tickers, { into: currency, history: ctx.apiClient, portfolioId: target.id }),
|
|
298
300
|
]);
|
|
299
301
|
ctx.signal.throwIfAborted();
|
|
300
302
|
const toBase = createBaseConverter(ctx.marketData, currency);
|
|
@@ -307,6 +309,7 @@ async function portfolioHoldings(
|
|
|
307
309
|
toBase,
|
|
308
310
|
basis,
|
|
309
311
|
futures,
|
|
312
|
+
purchaseDateFx,
|
|
310
313
|
});
|
|
311
314
|
const { allocation, cash } = await valuePortfolioAllocation({ valuation, portfolio: resolved.portfolio, account: resolved.account, toBase });
|
|
312
315
|
ctx.signal.throwIfAborted();
|
|
@@ -402,7 +405,7 @@ async function portfolioHoldings(
|
|
|
402
405
|
: []),
|
|
403
406
|
...(targetNote ? [targetNote] : []),
|
|
404
407
|
...(target.portfolio.brokerInstanceId && !resolved.account ? [BROKER_ACCOUNT_MISSING_NOTE] : []),
|
|
405
|
-
...(valuation
|
|
408
|
+
...costAtTodaysRateNotes(valuation, (symbols) => [...symbols].join(", ")),
|
|
406
409
|
];
|
|
407
410
|
|
|
408
411
|
const positionColumns = allocation.weightBasis === "gross"
|
|
@@ -2,6 +2,7 @@ import type { DividendData } from "../dividend-yield/client";
|
|
|
2
2
|
import { fetchProviderDividendData } from "../dividend-yield/provider-client";
|
|
3
3
|
import { refusedLock } from "../shared/cloud-denied";
|
|
4
4
|
import { ApiRequestError } from "../../../api-client/errors";
|
|
5
|
+
import { isNetworkFailure } from "../../../utils/network-failure";
|
|
5
6
|
import { regularSessionValuationPrice } from "../../../market-data/quotes/regular-session-valuation";
|
|
6
7
|
import { resolveTickerInstrumentKind } from "../../../tickers/instrument-kind";
|
|
7
8
|
import { mapWithConcurrency } from "../../../utils/concurrency";
|
|
@@ -65,7 +66,7 @@ function unreadWhy(error: unknown): "sign-in" | "offline" | "failed" {
|
|
|
65
66
|
current = current instanceof Error ? current.cause : undefined;
|
|
66
67
|
}
|
|
67
68
|
// A request that never got an answer: no connection, DNS, a refused socket.
|
|
68
|
-
return /fetch failed|network|ECONN|ENOTFOUND|EAI_AGAIN|Unable to connect|socket|offline/i.test(String(error instanceof Error ? error.message : error))
|
|
69
|
+
return isNetworkFailure(error) || /fetch failed|network|ECONN|ENOTFOUND|EAI_AGAIN|Unable to connect|socket|offline/i.test(String(error instanceof Error ? error.message : error))
|
|
69
70
|
? "offline" : "failed";
|
|
70
71
|
}
|
|
71
72
|
|
|
@@ -184,6 +185,16 @@ export async function portfolioIncome(
|
|
|
184
185
|
};
|
|
185
186
|
}
|
|
186
187
|
|
|
188
|
+
/**
|
|
189
|
+
* Whether `portfolio show` keeps its Income and Yield columns: once any
|
|
190
|
+
* holding's income is known, or a holding's is unknown only for want of a
|
|
191
|
+
* rate into the portfolio's currency, whose rows then show no figure. Income
|
|
192
|
+
* that could not be read at all gives the columns up to the note alone.
|
|
193
|
+
*/
|
|
194
|
+
export function showsIncomeColumns(income: PortfolioIncome): boolean {
|
|
195
|
+
return income.knownHoldings > 0 || [...income.gaps.values()].some((gap) => gap.cause === "fx");
|
|
196
|
+
}
|
|
197
|
+
|
|
187
198
|
const UNREAD_WORDS: Record<"timed-out" | "sign-in" | "offline" | "failed", (seconds: number) => string> = {
|
|
188
199
|
"timed-out": (seconds) => `dividends not read within ${seconds}s`,
|
|
189
200
|
"sign-in": () => "dividends not read without a Gloom sign-in",
|
|
@@ -209,7 +220,7 @@ export function incomeGapNote(
|
|
|
209
220
|
groups.set(key, [...(groups.get(key) ?? []), symbol]);
|
|
210
221
|
}
|
|
211
222
|
const causes = [...groups].map(([cause, symbols]) => `${cause} for ${name(symbols)}`).join("; ");
|
|
212
|
-
if (income.knownHoldings === 0) return `Income not shown: ${causes}.`;
|
|
223
|
+
if (income.knownHoldings === 0) return `Income ${showsIncomeColumns(income) ? "unavailable" : "not shown"}: ${causes}.`;
|
|
213
224
|
const others = income.knownHoldings;
|
|
214
225
|
return `Income unavailable: ${causes}. The other ${others === 1 ? "holding pays" : `${others} holdings pay`} ${money(income.knownIncome)} a year.`;
|
|
215
226
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { PaneTemplateContext, PaneTemplateInstanceConfig } from "../../../types/plugin";
|
|
1
|
+
import type { PaneTemplateContext, PaneTemplateInstanceConfig, ShortcutArgError } from "../../../types/plugin";
|
|
2
2
|
import type { PluginModule } from "../plugin-module";
|
|
3
|
+
import { unknownCollectionArgError } from "../../../portfolio/collection-name";
|
|
3
4
|
import { PortfolioListPane } from "./pane";
|
|
4
5
|
import {
|
|
5
6
|
buildPortfolioPaneSettingsDef,
|
|
@@ -28,6 +29,11 @@ function resolveCollectionIdForKind(context: PaneTemplateContext, kind: "portfol
|
|
|
28
29
|
: (context.config.watchlists[0]?.id ?? null);
|
|
29
30
|
}
|
|
30
31
|
|
|
32
|
+
/** `PF Nope`: no portfolio or watchlist has that name or id, so the bar names those that do. */
|
|
33
|
+
function unknownCollectionArg(arg: string, context: PaneTemplateContext): ShortcutArgError | null {
|
|
34
|
+
return unknownCollectionArgError(arg, [...context.config.portfolios, ...context.config.watchlists], "portfolio or watchlist");
|
|
35
|
+
}
|
|
36
|
+
|
|
31
37
|
function createCollectionPaneInstance(
|
|
32
38
|
context: PaneTemplateContext,
|
|
33
39
|
kind?: "portfolio" | "watchlist",
|
|
@@ -91,7 +97,8 @@ export const portfolioListModule: PluginModule = {
|
|
|
91
97
|
"portfolio", "watchlist", "collection", "pane", "list",
|
|
92
98
|
"portfolio rebalance", "allocation drift", "target weights", "asset allocation", "cash balance",
|
|
93
99
|
],
|
|
94
|
-
|
|
100
|
+
// The argument is the report's: `PF Book` opens Book, by name or id in any case.
|
|
101
|
+
shortcut: { prefix: "PF", argError: unknownCollectionArg },
|
|
95
102
|
headless: collectionHoldingsHeadless,
|
|
96
103
|
canCreate: (context) => resolveCollectionPaneId(context) !== null,
|
|
97
104
|
createInstance: (context, options) => createCollectionPaneInstance(context, undefined, options?.arg),
|
|
@@ -102,7 +102,9 @@ import { useColumnClock } from "../use-column-clock";
|
|
|
102
102
|
import { liveMarketCapitalization } from "../../../../market-data/quotes/live-valuation";
|
|
103
103
|
import { hasUnknownOptionMultiplier } from "../../../../portfolio/position-metrics";
|
|
104
104
|
import { withFuturesContractSizes } from "../../../../portfolio/futures-positions";
|
|
105
|
+
import { withPurchaseDateCostFx } from "../../../../portfolio/cost-fx";
|
|
105
106
|
import { usePortfolioFuturesTerms } from "./futures-terms";
|
|
107
|
+
import { usePurchaseDateCostFx } from "./purchase-date-fx";
|
|
106
108
|
import {
|
|
107
109
|
allocationWeightBase,
|
|
108
110
|
buildPortfolioAllocation,
|
|
@@ -177,11 +179,18 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
|
|
|
177
179
|
() => getCollectionTickersFromConfig(config, tickersBySymbol, activeCollectionId),
|
|
178
180
|
[activeCollectionId, config, tickersBySymbol],
|
|
179
181
|
);
|
|
182
|
+
// Totals, money columns and account values are in the portfolio's currency.
|
|
183
|
+
const totalsCurrency = useMemo(
|
|
184
|
+
() => resolvePortfolioTotalsCurrency(currentPortfolio, config.baseCurrency),
|
|
185
|
+
[config.baseCurrency, currentPortfolio],
|
|
186
|
+
);
|
|
180
187
|
// A future counts contracts of the size its terms give, and at the close is valued at its settlement.
|
|
181
188
|
const futuresTerms = usePortfolioFuturesTerms(collectionTickers, { enabled: isPortfolioTab, settlement: valuationBasis === "regular-close" });
|
|
189
|
+
// A dated lot in another currency costs what its purchase date's FX close says in that currency, as portfolio show values it.
|
|
190
|
+
const purchaseDateFx = usePurchaseDateCostFx(collectionTickers, { enabled: isPortfolioTab, portfolioId: activeCollectionId, into: totalsCurrency });
|
|
182
191
|
const tickers = useMemo(
|
|
183
|
-
() => withFuturesContractSizes(collectionTickers, futuresTerms.terms),
|
|
184
|
-
[collectionTickers, futuresTerms.terms],
|
|
192
|
+
() => withPurchaseDateCostFx(withFuturesContractSizes(collectionTickers, futuresTerms.terms), purchaseDateFx, totalsCurrency, activeCollectionId),
|
|
193
|
+
[activeCollectionId, collectionTickers, futuresTerms.terms, purchaseDateFx, totalsCurrency],
|
|
185
194
|
);
|
|
186
195
|
const financialsInstrumentOptions = useMemo(() => ({
|
|
187
196
|
portfolioId: isPortfolioTab ? activeCollectionId : undefined,
|
|
@@ -200,11 +209,6 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
|
|
|
200
209
|
// The positions stay as last synced while the broker is away, dated, with one key to bring it back.
|
|
201
210
|
const offlineBrokerFooter = useOfflineBrokerFooter(brokerPortfolio ? offline : null);
|
|
202
211
|
const portfolioTargets = currentPortfolio?.targetWeights;
|
|
203
|
-
// Totals, money columns and account values are in the portfolio's currency.
|
|
204
|
-
const totalsCurrency = useMemo(
|
|
205
|
-
() => resolvePortfolioTotalsCurrency(currentPortfolio, config.baseCurrency),
|
|
206
|
-
[config.baseCurrency, currentPortfolio],
|
|
207
|
-
);
|
|
208
212
|
// A boolean, so a quote tick does not rebuild the columns.
|
|
209
213
|
const otherCurrencies = holdsOtherCurrencies(tickers, financialsMap, totalsCurrency);
|
|
210
214
|
const columns = useMemo(
|
|
@@ -214,7 +218,9 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
|
|
|
214
218
|
const supplementalData = usePortfolioSupplementalData(tickers, columns, appActive, financialsMap);
|
|
215
219
|
// One lookup for the whole list, only while a perpetual column is on screen.
|
|
216
220
|
const showsPerpetuals = viewMode === "table" && columns.some((column) => PERPETUAL_COLUMN_IDS.has(column.id));
|
|
217
|
-
|
|
221
|
+
// The rows in view, from the last render: their contracts follow the quote stream.
|
|
222
|
+
const [perpetualsInView, setPerpetualsInView] = useState<ReadonlySet<string>>(() => new Set());
|
|
223
|
+
const perpetuals = useListPerpetuals(tickers, showsPerpetuals, perpetualsInView);
|
|
218
224
|
const openPerpMarket = useOpenPerpMarket();
|
|
219
225
|
const visibleWarmupRequirements = useMemo(
|
|
220
226
|
() => resolveVisibleWarmupRequirements(columns),
|
|
@@ -550,6 +556,13 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
|
|
|
550
556
|
}
|
|
551
557
|
), [height, sortedTickers.length, streamWindow, viewMode]);
|
|
552
558
|
|
|
559
|
+
const perpetualsInViewKey = showsPerpetuals
|
|
560
|
+
? sortedTickers.slice(effectiveStreamWindow.start, effectiveStreamWindow.end).map((ticker) => ticker.metadata.ticker).join("\u001f")
|
|
561
|
+
: "";
|
|
562
|
+
useEffect(() => {
|
|
563
|
+
setPerpetualsInView(new Set(perpetualsInViewKey ? perpetualsInViewKey.split("\u001f") : []));
|
|
564
|
+
}, [perpetualsInViewKey]);
|
|
565
|
+
|
|
553
566
|
usePortfolioPaneStreaming({
|
|
554
567
|
appActive,
|
|
555
568
|
activeCollectionId: isPortfolioTab ? activeCollectionId : undefined,
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { apiClient } from "../../../../api-client";
|
|
3
|
+
import { loadPurchaseDateCostFx, purchaseDatesToRead, type PurchaseDateCostFx } from "../../../../portfolio/cost-fx";
|
|
4
|
+
import type { TickerRecord } from "../../../../types/ticker";
|
|
5
|
+
|
|
6
|
+
/** A past close does not change; a date that could not be read is tried again this often. */
|
|
7
|
+
const REFRESH_MS = 30 * 60_000;
|
|
8
|
+
const NO_RATES: PurchaseDateCostFx = new Map();
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The FX closes of the purchase dates of the portfolio's dated lots, as
|
|
12
|
+
* `portfolio show` reads them, so their cost converts at the rate of the day
|
|
13
|
+
* they were bought into `into`, the currency the pane values the portfolio
|
|
14
|
+
* in. Read again only when the dated lots or the currency change. Nothing is
|
|
15
|
+
* read for a portfolio with no such lot.
|
|
16
|
+
*/
|
|
17
|
+
export function usePurchaseDateCostFx(
|
|
18
|
+
tickers: readonly TickerRecord[],
|
|
19
|
+
{ enabled, portfolioId, into }: { enabled: boolean; portfolioId: string; into: string },
|
|
20
|
+
): PurchaseDateCostFx {
|
|
21
|
+
const key = useMemo(() => enabled ? [...purchaseDatesToRead(tickers, into, portfolioId).keys()].sort().join(",") : "", [enabled, into, portfolioId, tickers]);
|
|
22
|
+
const tickersRef = useRef(tickers);
|
|
23
|
+
tickersRef.current = tickers;
|
|
24
|
+
// Rates are by currency and date, so those read before a lot was added still hold while the new date is read.
|
|
25
|
+
const scope = `${into}|${portfolioId}`;
|
|
26
|
+
const [state, setState] = useState<{ scope: string; rates: PurchaseDateCostFx }>({ scope: "", rates: NO_RATES });
|
|
27
|
+
const [refresh, setRefresh] = useState(0);
|
|
28
|
+
const complete = !!key && state.scope === scope && key.split(",").every((date) => state.rates.has(date));
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (!key || complete) return;
|
|
32
|
+
const timer = setInterval(() => setRefresh((count) => count + 1), REFRESH_MS);
|
|
33
|
+
return () => clearInterval(timer);
|
|
34
|
+
}, [complete, key]);
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (!key) return;
|
|
38
|
+
let cancelled = false;
|
|
39
|
+
void loadPurchaseDateCostFx(tickersRef.current, { into, history: apiClient, portfolioId }).then((rates) => {
|
|
40
|
+
if (!cancelled) setState({ scope: `${into}|${portfolioId}`, rates });
|
|
41
|
+
});
|
|
42
|
+
return () => { cancelled = true; };
|
|
43
|
+
}, [into, key, portfolioId, refresh]);
|
|
44
|
+
|
|
45
|
+
return key && state.scope === scope ? state.rates : NO_RATES;
|
|
46
|
+
}
|