gloomberb 0.18.3 → 0.18.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/README.zh-CN.md +11 -11
- package/bin/{gloomberb → gloom} +3 -1
- package/package.json +6 -2
- package/src/account/checkout-handoff.tsx +225 -0
- package/src/account/device-signin-dialog.tsx +2 -2
- package/src/account/device-signin.ts +2 -2
- package/src/account/upgrade-dialog.tsx +1 -1
- package/src/api-client/askg.ts +2 -2
- package/src/api-client/auth.ts +2 -2
- package/src/api-client/central-bank-rates.ts +6 -0
- package/src/api-client/collections.ts +5 -1
- package/src/api-client/cot.ts +2 -0
- package/src/api-client/crypto-etf-flows.ts +37 -0
- package/src/api-client/crypto-markets.ts +60 -0
- package/src/api-client/data.ts +84 -5
- package/src/api-client/doe.ts +15 -0
- package/src/api-client/equity-screener.ts +28 -0
- package/src/api-client/exchange-announcements.ts +38 -0
- package/src/api-client/fund-facts.ts +39 -0
- package/src/api-client/futures-curve.ts +9 -1
- package/src/api-client/hiring.ts +301 -0
- package/src/api-client/index.ts +22 -5
- package/src/api-client/market-discovery.ts +14 -0
- package/src/api-client/members.ts +6 -0
- package/src/api-client/mna.ts +6 -0
- package/src/api-client/paths.ts +18 -1
- package/src/api-client/request.ts +21 -4
- package/src/api-client/short-side-publications.ts +37 -0
- package/src/api-client/socket.ts +64 -4
- package/src/api-client/swap-curve.ts +35 -0
- package/src/api-client/themes.ts +7 -1
- package/src/api-client/types.ts +90 -2
- package/src/app/pane-runtime/plugin-bindings.ts +9 -2
- package/src/app/runtime/desktop-deeplink.ts +5 -5
- package/src/app/runtime/plugin-bindings.ts +2 -2
- package/src/app/runtime/startup.ts +13 -0
- package/src/app/star-prompt/status-line.tsx +2 -2
- package/src/architecture/core-builtin-allowlist.json +5 -2
- package/src/architecture/ui-literals-allowlist.json +3 -3
- package/src/architecture/ui-tokens-allowlist.json +1 -1
- package/src/brokers/broker-portfolio-sync.ts +37 -0
- package/src/brokers/directory.ts +11 -0
- package/src/brokers/logos.ts +3 -1
- package/src/brokers/signed-in/adapter.ts +304 -26
- package/src/brokers/signed-in/client.ts +14 -2
- package/src/brokers/signed-in/connect.ts +10 -2
- package/src/brokers/sync-broker-instance.ts +9 -1
- package/src/capabilities/chart-series.ts +22 -6
- package/src/cli/bank-section.ts +1 -1
- package/src/cli/base-converter.ts +23 -14
- package/src/cli/central-bank-events.ts +1 -1
- package/src/cli/command-options.ts +59 -4
- package/src/cli/commands/api.ts +9 -6
- package/src/cli/commands/broker.ts +2 -2
- package/src/cli/commands/command-utils.ts +2 -2
- package/src/cli/commands/crypto-hints.ts +7 -20
- package/src/cli/commands/fred-series.ts +4 -2
- package/src/cli/commands/keybindings.ts +2 -2
- package/src/cli/commands/market.ts +1117 -264
- package/src/cli/commands/news-hints.ts +2 -2
- package/src/cli/commands/news-search.ts +59 -6
- package/src/cli/commands/options-leaps.ts +41 -26
- package/src/cli/commands/overview.ts +121 -48
- package/src/cli/commands/plugins.ts +9 -9
- package/src/cli/commands/remote.ts +13 -10
- package/src/cli/commands/search.ts +64 -44
- package/src/cli/commands/system.ts +27 -19
- package/src/cli/commands/themes.ts +1 -1
- package/src/cli/commands/ticker.ts +192 -47
- package/src/cli/context.ts +3 -2
- package/src/cli/desktop-pane-shot-view.ts +2 -2
- package/src/cli/desktop-pane-shot.ts +1 -1
- package/src/cli/earnings-calendar.ts +4 -4
- package/src/cli/entry.ts +18 -1
- package/src/cli/errors.ts +20 -2
- package/src/cli/exit-codes.ts +1 -1
- package/src/cli/export-source.ts +10 -4
- package/src/cli/freshness.ts +2 -8
- package/src/cli/fx-forward.ts +130 -0
- package/src/cli/fx-pair.ts +10 -9
- package/src/cli/glossary.ts +64 -20
- package/src/cli/help.ts +19 -13
- package/src/cli/history-export.ts +126 -0
- package/src/cli/history-rows.ts +196 -43
- package/src/cli/index-roots.ts +5 -45
- package/src/cli/index.ts +24 -18
- package/src/cli/known-gaps.ts +118 -25
- package/src/cli/listing-arg.ts +300 -41
- package/src/cli/name-entries.ts +30 -18
- package/src/cli/native-smoke.ts +2 -0
- package/src/cli/not-a-ticker.ts +19 -9
- package/src/cli/opentui-libc.ts +5 -0
- package/src/cli/options.ts +12 -0
- package/src/cli/pane-functions/capabilities.ts +75 -20
- package/src/cli/pane-functions/catalog.ts +24 -23
- package/src/cli/pane-functions/discovery.ts +1 -1
- package/src/cli/pane-functions/dom.ts +10 -7
- package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
- package/src/cli/pane-functions/freshness.ts +174 -23
- package/src/cli/pane-functions/function-help.ts +66 -27
- package/src/cli/pane-functions/headless.ts +24 -11
- package/src/cli/pane-functions/index.ts +18 -16
- package/src/cli/pane-functions/options.ts +22 -2
- package/src/cli/pane-functions/report-notices.ts +12 -4
- package/src/cli/pane-functions/report.ts +5 -5
- package/src/cli/pane-functions/resolver.ts +47 -10
- package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
- package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
- package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
- package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
- package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
- package/src/cli/pane-functions/screenshot-payload.ts +453 -0
- package/src/cli/pane-functions/screenshot-render.ts +316 -0
- package/src/cli/pane-functions/screenshot-types.ts +162 -0
- package/src/cli/pane-functions/shot-options.ts +8 -3
- package/src/cli/peso-dollar-rates.ts +79 -0
- package/src/cli/quote-answer.ts +38 -3
- package/src/cli/report-tables.ts +61 -16
- package/src/cli/restore-plugins.ts +29 -14
- package/src/cli/result.ts +111 -22
- package/src/cli/series-search.ts +5 -5
- package/src/cli/statement-filings.ts +19 -0
- package/src/cli/suffixed-listing-rows.ts +49 -0
- package/src/cli/symbol-args.ts +50 -15
- package/src/cli/symbol-cells.ts +120 -0
- package/src/cli/symbol-list.ts +198 -68
- package/src/cli/symbol-rows.ts +131 -25
- package/src/cli/ticker-resolution.ts +108 -11
- package/src/cli/treasury-yields.ts +5 -5
- package/src/cli/types.ts +2 -0
- package/src/cli/uncovered-instrument.ts +3 -3
- package/src/cli/unknown-command.ts +6 -6
- package/src/components/chart/composite/chart-layout.ts +131 -0
- package/src/components/chart/composite/composite-chart.tsx +373 -16
- package/src/components/chart/composite/interactions.ts +7 -2
- package/src/components/chart/composite/legend.tsx +75 -3
- package/src/components/chart/composite/levels.ts +5 -0
- package/src/components/chart/composite/panel-gestures.ts +41 -0
- package/src/components/chart/composite/panel-labels.ts +2 -1
- package/src/components/chart/composite/panel-surface.tsx +305 -11
- package/src/components/chart/composite/price-axis-labels.tsx +27 -3
- package/src/components/chart/composite/rasterizer.ts +44 -19
- package/src/components/chart/composite/scene.ts +16 -4
- package/src/components/chart/composite/text-renderer.ts +48 -21
- package/src/components/chart/composite/toolbar.tsx +52 -5
- package/src/components/chart/composite/types.ts +13 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
- package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
- package/src/components/chart/composite/use-composite-viewport.ts +12 -3
- package/src/components/chart/composite/value-scale.ts +149 -0
- package/src/components/chart/composite/volume-profile-paint.ts +6 -3
- package/src/components/chart/core/pointer.ts +2 -0
- package/src/components/chart-table/index.ts +2 -0
- package/src/components/chart-table/read.tsx +74 -0
- package/src/components/command-bar/commands/collection-list.ts +41 -19
- package/src/components/command-bar/commands/collection.ts +9 -3
- package/src/components/command-bar/commands/direct/index.ts +1 -1
- package/src/components/command-bar/commands/direct/runtime.ts +3 -2
- package/src/components/command-bar/pane-templates/items.ts +59 -6
- package/src/components/command-bar/pane-templates/workflow.ts +10 -1
- package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
- package/src/components/command-bar/routes/root/provider-search.ts +42 -11
- package/src/components/command-bar/routes/root/results.ts +18 -4
- package/src/components/command-bar/routes/root/runtime.ts +15 -3
- package/src/components/command-bar/routes/root/search-providers.ts +25 -2
- package/src/components/command-bar/routes/root/selection.ts +6 -1
- package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
- package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
- package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
- package/src/components/command-bar/selection-runtime.ts +50 -10
- package/src/components/command-bar/surface/index.tsx +24 -2
- package/src/components/command-bar/view-model.ts +7 -0
- package/src/components/command-bar/workflow/broker.ts +2 -2
- package/src/components/command-bar/workflow/collection-actions.ts +46 -7
- package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
- package/src/components/command-bar/workflow/fields.ts +8 -2
- package/src/components/command-bar/workflow/ops.ts +18 -4
- package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
- package/src/components/command-bar/workflow/submit.ts +3 -2
- package/src/components/command-bar/workflow/tickers.ts +5 -1
- package/src/components/company-logo.tsx +39 -0
- package/src/components/data-table/sections.ts +4 -2
- package/src/components/form-modal/confirm.tsx +2 -1
- package/src/components/form-modal/request.ts +5 -0
- package/src/components/form-modal/routes.ts +4 -1
- package/src/components/index.ts +12 -6
- package/src/components/layout/header.tsx +7 -6
- package/src/components/layout/market-summary.ts +9 -6
- package/src/components/layout/pane/capture-status.ts +1 -1
- package/src/components/layout/pane/footer/model.ts +11 -5
- package/src/components/layout/shell/chrome.ts +19 -6
- package/src/components/layout/shell/index.tsx +2 -1
- package/src/components/layout/shell/pane/layers.tsx +19 -1
- package/src/components/layout/status-bar.tsx +2 -2
- package/src/components/market-board/index.tsx +11 -3
- package/src/components/onboarding/onboarding-wizard.tsx +1 -0
- package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
- package/src/components/onboarding/wizard-broker-sync.ts +4 -1
- package/src/components/pane-settings-dialog/desktop.tsx +20 -7
- package/src/components/pane-settings-dialog/tui.tsx +17 -9
- package/src/components/pane-settings-dialog/value.ts +8 -1
- package/src/components/pane-settings-dialog.tsx +44 -13
- package/src/components/sign-in-code-panel.tsx +27 -19
- package/src/components/ui/column-grid.tsx +48 -4
- package/src/components/ui/country-flag-art.tsx +180 -0
- package/src/components/ui/country-flag.tsx +118 -12
- package/src/components/ui/data-table/opentui/index.tsx +61 -2
- package/src/components/ui/data-table/opentui/model.ts +109 -2
- package/src/components/ui/data-table/types.ts +1 -1
- package/src/components/ui/display.tsx +5 -1
- package/src/components/ui/index.ts +3 -1
- package/src/components/ui/logo-mark.tsx +11 -2
- package/src/components/ui/query-bar.tsx +1 -1
- package/src/components/ui/row-notes.ts +79 -0
- package/src/core/state/app/layout.ts +4 -4
- package/src/data/cached-query.ts +8 -1
- package/src/data/config/chart-settings.ts +3 -3
- package/src/data/config/home.ts +10 -2
- package/src/data/config/layout.ts +4 -1
- package/src/data/config/store/node.ts +4 -0
- package/src/data/config/store/normalize.ts +13 -3
- package/src/data/config/store/portfolio-as-of-column.ts +2 -2
- package/src/data/json-storage.ts +2 -0
- package/src/data/saved-copies.ts +84 -0
- package/src/docs/snapshot.json +65 -32
- package/src/i18n/es.ts +29 -12
- package/src/i18n/ja.ts +29 -12
- package/src/i18n/ko.ts +29 -12
- package/src/i18n/zh-cn.ts +29 -12
- package/src/i18n/zh-tw.ts +29 -12
- package/src/layout/desks.ts +1 -1
- package/src/layout/launch-layout.ts +1 -1
- package/src/layout/pane-manager/floating-actions.ts +5 -3
- package/src/layout/pane-manager/floating.ts +43 -1
- package/src/layout/pane-manager/index.ts +2 -0
- package/src/layout/selected-ticker.ts +74 -0
- package/src/market-data/depositary-pair.ts +251 -0
- package/src/market-data/futures-board.ts +1 -1
- package/src/market-data/futures-contract.ts +124 -40
- package/src/market-data/fx-closes.ts +17 -2
- package/src/market-data/hooks.tsx +19 -11
- package/src/market-data/market/change-basis.ts +49 -7
- package/src/market-data/market/freshness.ts +34 -5
- package/src/market-data/market/period-return.ts +163 -0
- package/src/market-data/market/trading-sessions.ts +13 -0
- package/src/market-data/market/year-to-date.ts +8 -13
- package/src/market-data/performance.ts +20 -14
- package/src/market-data/perpetual-premium.ts +32 -0
- package/src/market-data/published-apac-sessions.ts +2 -1
- package/src/market-data/published-futures-sessions.ts +69 -0
- package/src/market-data/quotes/contributions.ts +5 -1
- package/src/market-data/quotes/freshness.ts +42 -0
- package/src/market-data/quotes/intraday-bar.ts +37 -0
- package/src/market-data/quotes/regular-session-valuation.ts +13 -8
- package/src/market-data/quotes/resolution.ts +4 -2
- package/src/market-data/tax-equivalent.ts +1 -1
- package/src/market-data/ticker-price-returns.ts +3 -1
- package/src/news/aggregator.ts +5 -1
- package/src/news/news-model.ts +4 -0
- package/src/news/types.ts +11 -0
- package/src/notifications/app-notifier.ts +1 -1
- package/src/plugins/auto-update.ts +2 -2
- package/src/plugins/builtin/account-management/index.tsx +1 -0
- package/src/plugins/builtin/account-management/pane.tsx +9 -8
- package/src/plugins/builtin/alerts/alert-engine.ts +29 -19
- package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
- package/src/plugins/builtin/alerts/cli.ts +485 -76
- package/src/plugins/builtin/alerts/command.ts +5 -10
- package/src/plugins/builtin/alerts/event-rows.ts +9 -5
- package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
- package/src/plugins/builtin/alerts/events.ts +107 -5
- package/src/plugins/builtin/alerts/fired-log.ts +78 -0
- package/src/plugins/builtin/alerts/format.ts +2 -1
- package/src/plugins/builtin/alerts/headless.ts +100 -39
- package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
- package/src/plugins/builtin/alerts/history-rows.ts +89 -0
- package/src/plugins/builtin/alerts/index.tsx +45 -18
- package/src/plugins/builtin/alerts/iv-level.ts +365 -0
- package/src/plugins/builtin/alerts/levels.ts +3 -3
- package/src/plugins/builtin/alerts/pane.tsx +97 -29
- package/src/plugins/builtin/alerts/price.ts +35 -0
- package/src/plugins/builtin/alerts/quotes.ts +24 -0
- package/src/plugins/builtin/alerts/research-builder.ts +84 -11
- package/src/plugins/builtin/alerts/research-rules.ts +76 -3
- package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
- package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
- package/src/plugins/builtin/alerts/scheduled.ts +188 -29
- package/src/plugins/builtin/alerts/storage.ts +13 -10
- package/src/plugins/builtin/alerts/targets.ts +12 -3
- package/src/plugins/builtin/analytics/index.tsx +8 -2
- package/src/plugins/builtin/analytics/metrics.ts +1 -1
- package/src/plugins/builtin/analytics/risk-book.ts +215 -0
- package/src/plugins/builtin/analytics/risk-client.ts +13 -6
- package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
- package/src/plugins/builtin/analytics/risk-math.ts +6 -3
- package/src/plugins/builtin/analytics/risk-model.ts +297 -104
- package/src/plugins/builtin/analytics/risk-options.ts +17 -2
- package/src/plugins/builtin/analytics/risk-pane.tsx +97 -36
- package/src/plugins/builtin/attention/pane.tsx +6 -2
- package/src/plugins/builtin/awards/headless.ts +7 -3
- package/src/plugins/builtin/awards/model.ts +18 -0
- package/src/plugins/builtin/awards/pane.tsx +6 -3
- package/src/plugins/builtin/backtest/headless.ts +3 -3
- package/src/plugins/builtin/backtest/rules.ts +41 -5
- package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
- package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
- package/src/plugins/builtin/broker-manager/footer.ts +27 -11
- package/src/plugins/builtin/broker-manager/index.tsx +21 -12
- package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
- package/src/plugins/builtin/broker-manager/model.ts +12 -2
- package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
- package/src/plugins/builtin/broker-manager/table.ts +28 -12
- package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
- package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
- package/src/plugins/builtin/broker-trading/controller.ts +45 -13
- package/src/plugins/builtin/broker-trading/dock.tsx +22 -4
- package/src/plugins/builtin/broker-trading/headless.ts +2 -1
- package/src/plugins/builtin/broker-trading/index.tsx +7 -1
- package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
- package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
- package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
- package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
- package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
- package/src/plugins/builtin/broker-trading/pane.tsx +110 -23
- package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
- package/src/plugins/builtin/broker-trading/ticket.tsx +112 -31
- package/src/plugins/builtin/buildout/cells.tsx +4 -0
- package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
- package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
- package/src/plugins/builtin/buildout/pane/index.tsx +25 -12
- package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
- package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
- package/src/plugins/builtin/catalysts/detail.tsx +3 -2
- package/src/plugins/builtin/catalysts/index.tsx +1 -1
- package/src/plugins/builtin/catalysts/model.ts +49 -4
- package/src/plugins/builtin/catalysts/pane.tsx +6 -8
- package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
- package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
- package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
- package/src/plugins/builtin/changelog/index.tsx +1 -0
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
- package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
- package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
- package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
- package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
- package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
- package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
- package/src/plugins/builtin/chart-composer/headless.ts +253 -35
- package/src/plugins/builtin/chart-composer/index.tsx +12 -2
- package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
- package/src/plugins/builtin/chart-composer/pane.tsx +127 -28
- package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
- package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
- package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
- package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
- package/src/plugins/builtin/chart-composer/settings.ts +31 -19
- package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
- package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
- package/src/plugins/builtin/chat/attachments/model.ts +3 -1
- package/src/plugins/builtin/chat/content/index.tsx +1 -1
- package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
- package/src/plugins/builtin/chat/people.ts +1 -1
- package/src/plugins/builtin/clinical-trials/client.ts +5 -2
- package/src/plugins/builtin/clinical-trials/model.ts +13 -4
- package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
- package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
- package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
- package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
- package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
- package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
- package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
- package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
- package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
- package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
- package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
- package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
- package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
- package/src/plugins/builtin/commodity-balances/pane.tsx +11 -4
- package/src/plugins/builtin/company-attention/app-rank.tsx +7 -5
- package/src/plugins/builtin/company-attention/building-model.ts +222 -0
- package/src/plugins/builtin/company-attention/building.tsx +172 -0
- package/src/plugins/builtin/company-attention/client.ts +117 -1
- package/src/plugins/builtin/company-attention/evidence.ts +16 -3
- package/src/plugins/builtin/company-attention/headless.ts +101 -5
- package/src/plugins/builtin/company-attention/index.tsx +6 -3
- package/src/plugins/builtin/company-attention/model.ts +33 -7
- package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
- package/src/plugins/builtin/company-attention/moves.tsx +159 -0
- package/src/plugins/builtin/company-attention/pane.tsx +79 -23
- package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
- package/src/plugins/builtin/company-attention/signals.tsx +160 -0
- package/src/plugins/builtin/company-kpis/headless.ts +3 -2
- package/src/plugins/builtin/company-kpis/model.ts +2 -2
- package/src/plugins/builtin/company-kpis/pane.tsx +1 -1
- package/src/plugins/builtin/composite-plugins.ts +2 -1
- package/src/plugins/builtin/congress-trades/headless.ts +1 -1
- package/src/plugins/builtin/connections/index.ts +1 -0
- package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
- package/src/plugins/builtin/correlation/headless.ts +5 -3
- package/src/plugins/builtin/cot/headless.ts +28 -6
- package/src/plugins/builtin/cot/model.ts +12 -0
- package/src/plugins/builtin/cot/pane.tsx +3 -2
- package/src/plugins/builtin/cpi/headless.ts +5 -1
- package/src/plugins/builtin/cpi/pane.tsx +11 -9
- package/src/plugins/builtin/credit-boards/model.ts +2 -0
- package/src/plugins/builtin/credit-documents/headless.ts +1 -1
- package/src/plugins/builtin/crypto-board/client.ts +86 -0
- package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
- package/src/plugins/builtin/crypto-board/defi.ts +239 -0
- package/src/plugins/builtin/crypto-board/headless.ts +117 -6
- package/src/plugins/builtin/crypto-board/index.tsx +8 -3
- package/src/plugins/builtin/crypto-board/model.ts +40 -8
- package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
- package/src/plugins/builtin/crypto-board/series.ts +19 -1
- package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
- package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
- package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
- package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
- package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
- package/src/plugins/builtin/debug/index.tsx +1 -0
- package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
- package/src/plugins/builtin/docs/index.tsx +1 -1
- package/src/plugins/builtin/docs/pane.tsx +2 -2
- package/src/plugins/builtin/docs/targets.ts +1 -1
- package/src/plugins/builtin/doe/client.ts +5 -1
- package/src/plugins/builtin/doe/headless.ts +12 -6
- package/src/plugins/builtin/doe/model.ts +43 -6
- package/src/plugins/builtin/doe/pane.tsx +18 -11
- package/src/plugins/builtin/earnings/board-model.ts +13 -6
- package/src/plugins/builtin/earnings/board-table.ts +4 -1
- package/src/plugins/builtin/earnings/board.tsx +253 -50
- package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
- package/src/plugins/builtin/earnings/calendar.tsx +338 -0
- package/src/plugins/builtin/earnings/client.ts +4 -3
- package/src/plugins/builtin/earnings/headless.ts +53 -15
- package/src/plugins/builtin/earnings/history-model.ts +53 -36
- package/src/plugins/builtin/earnings/index.tsx +15 -22
- package/src/plugins/builtin/earnings/model.ts +17 -12
- package/src/plugins/builtin/earnings/scope.ts +89 -0
- package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
- package/src/plugins/builtin/earnings-calls/data.ts +146 -2
- package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
- package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
- package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
- package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
- package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
- package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
- package/src/plugins/builtin/econ/calendar-model.ts +132 -20
- package/src/plugins/builtin/econ/detail-view.tsx +48 -10
- package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
- package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
- package/src/plugins/builtin/econ/index.tsx +112 -25
- package/src/plugins/builtin/econ/print-watch.ts +2 -1
- package/src/plugins/builtin/econ/types.ts +32 -1
- package/src/plugins/builtin/econ-statistics/client.ts +16 -3
- package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
- package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
- package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
- package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
- package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
- package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
- package/src/plugins/builtin/econ-statistics/view.ts +16 -1
- package/src/plugins/builtin/equity-screener/client.ts +21 -3
- package/src/plugins/builtin/equity-screener/headless.ts +68 -6
- package/src/plugins/builtin/equity-screener/live.ts +1 -1
- package/src/plugins/builtin/equity-screener/model.ts +6 -0
- package/src/plugins/builtin/equity-screener/pane.tsx +45 -10
- package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
- package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
- package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
- package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
- package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
- package/src/plugins/builtin/exposure/headless.ts +51 -6
- package/src/plugins/builtin/exposure/index.tsx +28 -2
- package/src/plugins/builtin/exposure/model.ts +7 -0
- package/src/plugins/builtin/exposure/pane.tsx +6 -1
- package/src/plugins/builtin/fear-greed/index.tsx +1 -1
- package/src/plugins/builtin/filing-events/index.tsx +1 -1
- package/src/plugins/builtin/futures/model.ts +10 -9
- package/src/plugins/builtin/futures/returns.ts +8 -36
- package/src/plugins/builtin/futures/table.tsx +1 -1
- package/src/plugins/builtin/futures-curve/client.ts +40 -9
- package/src/plugins/builtin/futures-curve/headless.ts +39 -17
- package/src/plugins/builtin/futures-curve/model.ts +258 -69
- package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
- package/src/plugins/builtin/fx-matrix/client.ts +15 -8
- package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
- package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
- package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
- package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
- package/src/plugins/builtin/gpu/headless.ts +9 -4
- package/src/plugins/builtin/help/index.tsx +13 -3
- package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
- package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
- package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
- package/src/plugins/builtin/holders/client.ts +13 -1
- package/src/plugins/builtin/holders/format.ts +28 -17
- package/src/plugins/builtin/holders/headless.ts +46 -7
- package/src/plugins/builtin/holders/index-holders.ts +264 -0
- package/src/plugins/builtin/holders/pane.tsx +79 -15
- package/src/plugins/builtin/holders/report-rows.ts +35 -7
- package/src/plugins/builtin/holders/table-model.ts +2 -1
- package/src/plugins/builtin/holders/treemap.tsx +2 -2
- package/src/plugins/builtin/insider/headless.ts +1 -1
- package/src/plugins/builtin/insider/signals-client.ts +1 -1
- package/src/plugins/builtin/insider/signals.tsx +1 -1
- package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
- package/src/plugins/builtin/iv-history/client.ts +20 -0
- package/src/plugins/builtin/iv-history/headless.ts +4 -4
- package/src/plugins/builtin/iv-history/index.tsx +1 -1
- package/src/plugins/builtin/iv-history/model.ts +13 -4
- package/src/plugins/builtin/iv-history/series.ts +3 -1
- package/src/plugins/builtin/jobs/lock-note.ts +1 -1
- package/src/plugins/builtin/jobs/model.ts +4 -15
- package/src/plugins/builtin/jobs/pane.tsx +7 -5
- package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
- package/src/plugins/builtin/jodi/pane.tsx +10 -4
- package/src/plugins/builtin/layout-manager/index.tsx +1 -0
- package/src/plugins/builtin/macro-day/headless.ts +20 -7
- package/src/plugins/builtin/macro-day/index.tsx +3 -2
- package/src/plugins/builtin/macro-day/model.ts +29 -8
- package/src/plugins/builtin/macro-day/pane.tsx +46 -10
- package/src/plugins/builtin/macro-day/releases.ts +55 -13
- package/src/plugins/builtin/market-heatmap/data.ts +9 -2
- package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
- package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
- package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
- package/src/plugins/builtin/market-heatmap/model.ts +10 -7
- package/src/plugins/builtin/market-movers/client.ts +33 -19
- package/src/plugins/builtin/market-movers/headless.ts +8 -2
- package/src/plugins/builtin/market-movers/index.tsx +16 -10
- package/src/plugins/builtin/market-movers/screener.ts +29 -8
- package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
- package/src/plugins/builtin/market-movers/session-table.ts +4 -2
- package/src/plugins/builtin/market-movers/table.ts +4 -1
- package/src/plugins/builtin/market-valuation/headless.ts +2 -0
- package/src/plugins/builtin/market-valuation/view.ts +5 -0
- package/src/plugins/builtin/members/headless.ts +6 -5
- package/src/plugins/builtin/members/pane.tsx +11 -4
- package/src/plugins/builtin/mna/client.ts +1 -0
- package/src/plugins/builtin/mna/detail.tsx +20 -32
- package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
- package/src/plugins/builtin/mna/distress/model.ts +3 -2
- package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
- package/src/plugins/builtin/mna/headless.ts +6 -13
- package/src/plugins/builtin/mna/model.ts +93 -15
- package/src/plugins/builtin/mna/pane.tsx +5 -4
- package/src/plugins/builtin/news/headless.ts +12 -6
- package/src/plugins/builtin/news/index.tsx +10 -1
- package/src/plugins/builtin/news/wire/index.tsx +3 -2
- package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
- package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
- package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
- package/src/plugins/builtin/notes/cli.ts +49 -14
- package/src/plugins/builtin/openfda/pane.tsx +1 -1
- package/src/plugins/builtin/options/carry.ts +2 -2
- package/src/plugins/builtin/options/index.tsx +1 -1
- package/src/plugins/builtin/options/view.tsx +10 -10
- package/src/plugins/builtin/options-calculator/headless.ts +46 -7
- package/src/plugins/builtin/options-scenario/client.ts +123 -28
- package/src/plugins/builtin/options-scenario/collar.ts +8 -6
- package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
- package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
- package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
- package/src/plugins/builtin/options-scenario/csp.ts +101 -21
- package/src/plugins/builtin/options-scenario/headless.ts +36 -15
- package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
- package/src/plugins/builtin/options-scenario/index.tsx +28 -3
- package/src/plugins/builtin/options-scenario/model.ts +13 -0
- package/src/plugins/builtin/options-scenario/pane.tsx +9 -5
- package/src/plugins/builtin/perps/equity-row.tsx +11 -3
- package/src/plugins/builtin/perps/freshness.ts +8 -5
- package/src/plugins/builtin/perps/headless.ts +3 -1
- package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
- package/src/plugins/builtin/perps/live-rows.ts +161 -0
- package/src/plugins/builtin/perps/markets-section.tsx +154 -0
- package/src/plugins/builtin/perps/pane.tsx +36 -17
- package/src/plugins/builtin/perps/venue-markets.ts +96 -0
- package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +143 -59
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +72 -24
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
- package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
- package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
- package/src/plugins/builtin/portfolio-list/income.ts +13 -2
- package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
- package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
- package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
- package/src/plugins/builtin/power/client.ts +4 -1
- package/src/plugins/builtin/power/evidence.ts +22 -7
- package/src/plugins/builtin/power/gas.tsx +5 -1
- package/src/plugins/builtin/power/pane.tsx +8 -1
- package/src/plugins/builtin/power/prices.tsx +10 -3
- package/src/plugins/builtin/research/analyst-headless.ts +25 -8
- package/src/plugins/builtin/research/analyst-model.ts +68 -3
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
- package/src/plugins/builtin/research/event-model.ts +3 -1
- package/src/plugins/builtin/research/event-sources.ts +12 -4
- package/src/plugins/builtin/research/index.tsx +2 -1
- package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
- package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
- package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
- package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
- package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
- package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
- package/src/plugins/builtin/reverse-dcf/model.ts +6 -2
- package/src/plugins/builtin/risk-factors/index.tsx +2 -2
- package/src/plugins/builtin/scanner/lock-note.ts +1 -1
- package/src/plugins/builtin/sec/forms.ts +13 -0
- package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
- package/src/plugins/builtin/sec/fund-facts.ts +68 -8
- package/src/plugins/builtin/sec/headless.ts +85 -8
- package/src/plugins/builtin/sec/index.tsx +58 -12
- package/src/plugins/builtin/sectors/client.ts +2 -1
- package/src/plugins/builtin/sectors/sector-model.ts +11 -15
- package/src/plugins/builtin/series-inventory.ts +2 -0
- package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
- package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
- package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
- package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
- package/src/plugins/builtin/shared/earnings-report.ts +3 -3
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
- package/src/plugins/builtin/shared/job-posting.ts +129 -0
- package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
- package/src/plugins/builtin/shared/report-freshness.ts +3 -0
- package/src/plugins/builtin/shared/research-trading.tsx +21 -0
- package/src/plugins/builtin/shared/series-cache.ts +2 -0
- package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
- package/src/plugins/builtin/short-interest/client.ts +2 -0
- package/src/plugins/builtin/short-interest/headless.ts +41 -12
- package/src/plugins/builtin/short-interest/index.tsx +23 -1
- package/src/plugins/builtin/short-interest/model.ts +70 -19
- package/src/plugins/builtin/short-interest/pane.tsx +19 -2
- package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
- package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
- package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
- package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
- package/src/plugins/builtin/short-interest/schedule.ts +35 -2
- package/src/plugins/builtin/short-interest/surface.tsx +11 -4
- package/src/plugins/builtin/short-interest/types.ts +9 -0
- package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
- package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
- package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
- package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
- package/src/plugins/builtin/supply-chain/model.ts +51 -3
- package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
- package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
- package/src/plugins/builtin/themes/headless.ts +8 -5
- package/src/plugins/builtin/themes/model.ts +14 -4
- package/src/plugins/builtin/themes/pane.tsx +24 -5
- package/src/plugins/builtin/thirteenf/headless.ts +5 -5
- package/src/plugins/builtin/thirteenf/signals.ts +3 -1
- package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
- package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
- package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
- package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
- package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
- package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
- package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
- package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
- package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
- package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
- package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
- package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
- package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
- package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
- package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
- package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
- package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
- package/src/plugins/builtin/vol-surface/client.ts +5 -4
- package/src/plugins/builtin/vol-surface/headless.ts +12 -3
- package/src/plugins/builtin/vol-surface/model.ts +4 -2
- package/src/plugins/builtin/volatility/model.ts +5 -10
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
- package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
- package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
- package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
- package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
- package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
- package/src/plugins/builtin/world-venue-map/index.ts +3 -26
- package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
- package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
- package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
- package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
- package/src/plugins/builtin/yield-curve/client.ts +25 -0
- package/src/plugins/builtin/yield-curve/curves.ts +7 -4
- package/src/plugins/builtin/yield-curve/headless.ts +38 -4
- package/src/plugins/builtin/yield-curve/history.ts +4 -3
- package/src/plugins/builtin/yield-curve/index.tsx +12 -6
- package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
- package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
- package/src/plugins/bundle.ts +1 -1
- package/src/plugins/catalog-browser.ts +2 -1
- package/src/plugins/compat.ts +3 -3
- package/src/plugins/dependencies.ts +75 -14
- package/src/plugins/extracted-plugins.ts +132 -34
- package/src/plugins/host-link.ts +149 -34
- package/src/plugins/installer.ts +35 -10
- package/src/plugins/loader.ts +206 -38
- package/src/plugins/manager-node.ts +2 -2
- package/src/plugins/marketplace/deactivation.ts +22 -0
- package/src/plugins/marketplace/model.ts +2 -2
- package/src/plugins/marketplace/packs.ts +1 -1
- package/src/plugins/ownership.ts +1 -1
- package/src/plugins/peer-retry.ts +155 -0
- package/src/plugins/registry/contributions.ts +3 -1
- package/src/plugins/registry/index.ts +4 -3
- package/src/plugins/registry/plugin-state.ts +3 -0
- package/src/plugins/seed-notice.ts +20 -0
- package/src/plugins/shortcut-argument.ts +39 -0
- package/src/portfolio/allocation.ts +1 -1
- package/src/portfolio/collection-name.ts +31 -0
- package/src/portfolio/column-values.ts +10 -8
- package/src/portfolio/cost-fx.ts +296 -19
- package/src/portfolio/manual-lots.ts +75 -0
- package/src/portfolio/mutations.ts +60 -22
- package/src/portfolio/suffixed-listings.ts +209 -0
- package/src/portfolio/totals-currency.ts +24 -0
- package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
- package/src/public/time-series.ts +11 -8
- package/src/remote/schema.ts +1 -1
- package/src/renderers/browser/config-host.ts +3 -0
- package/src/renderers/browser/main.tsx +23 -3
- package/src/renderers/dom/boot-frame-page.ts +187 -0
- package/src/renderers/dom/boot-frame.ts +237 -0
- package/src/renderers/dom/build-assets.ts +46 -8
- package/src/renderers/dom/dom-ui-host.tsx +4 -29
- package/src/renderers/dom/host/ascii-text.ts +16 -2
- package/src/renderers/dom/host/box.tsx +43 -2
- package/src/renderers/dom/host/chart-surface.tsx +2 -0
- package/src/renderers/dom/host/hls.chunk.ts +3 -0
- package/src/renderers/dom/host/image-surface.tsx +49 -0
- package/src/renderers/dom/host/media-surface.tsx +24 -18
- package/src/renderers/dom/host/mouse.ts +30 -0
- package/src/renderers/dom/host/size-observer.ts +1 -1
- package/src/renderers/dom/host/style.ts +1 -1
- package/src/renderers/dom/styles.css +76 -0
- package/src/renderers/dom/test-utils.tsx +2 -1
- package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +46 -3
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
- package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
- package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
- package/src/renderers/electrobun/bun/index.ts +11 -1
- package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
- package/src/renderers/electrobun/bun/window/create.ts +4 -1
- package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
- package/src/renderers/electrobun/shared/protocol.ts +6 -1
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
- package/src/renderers/electrobun/view/config-host.ts +3 -0
- package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
- package/src/renderers/electrobun/view/main.tsx +30 -4
- package/src/renderers/electrobun/view/news-source.ts +5 -5
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -1
- package/src/renderers/electrobun/view/ui-host.tsx +1 -1
- package/src/renderers/opentui/browser-open.ts +88 -0
- package/src/renderers/opentui/host.tsx +5 -14
- package/src/renderers/opentui/image/loader.ts +3 -2
- package/src/renderers/opentui/native-smoke.ts +10 -1
- package/src/renderers/opentui/pane-image/index.ts +2 -1
- package/src/renderers/opentui/render-lib.ts +253 -0
- package/src/renderers/opentui/render-timing-smoke.ts +1 -1
- package/src/renderers/opentui/start.tsx +1 -1
- package/src/renderers/share/layout-view.tsx +2 -2
- package/src/renderers/share/main.tsx +4 -4
- package/src/renderers/share/view.tsx +1 -1
- package/src/series/resolve.ts +22 -6
- package/src/series/standalone.ts +30 -2
- package/src/series/types.ts +8 -1
- package/src/shares/api.ts +4 -1
- package/src/shares/pane.ts +1 -1
- package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
- package/src/sources/gloomberb-cloud/index.ts +32 -16
- package/src/sources/gloomberb-cloud/news.ts +39 -0
- package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
- package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
- package/src/sources/listing-symbols.ts +37 -0
- package/src/sources/provider-errors.ts +16 -2
- package/src/sources/provider-router/financial-routes.ts +21 -3
- package/src/sources/provider-router/financials.ts +15 -2
- package/src/sources/provider-router/history.ts +30 -8
- package/src/sources/provider-router/primary.ts +1 -1
- package/src/state/app/bootstrap.ts +23 -0
- package/src/state/hooks/inline-tickers.ts +30 -5
- package/src/sync/controller.ts +1 -1
- package/src/sync/core-contributors.ts +46 -14
- package/src/team/collections-sync.ts +2 -1
- package/src/team/collections.ts +178 -17
- package/src/telemetry/crash-reports.ts +17 -4
- package/src/test-support/builtin-panes.ts +1 -1
- package/src/theme/colors.ts +3 -30
- package/src/theme/ui-tokens.ts +37 -1
- package/src/tickers/company-name-listing.ts +210 -33
- package/src/tickers/index-roots.ts +47 -0
- package/src/tickers/instrument-label.ts +5 -1
- package/src/tickers/metadata.ts +10 -0
- package/src/tickers/perpetual-listing.ts +5 -2
- package/src/tickers/search/home-listing.ts +75 -0
- package/src/tickers/search/index.ts +76 -27
- package/src/tickers/search/ranking.ts +54 -4
- package/src/tickers/search/upsert.ts +29 -0
- package/src/tickers/terminal-codes.ts +416 -40
- package/src/time-series/bar-aggregation.ts +243 -0
- package/src/time-series/base-series.ts +307 -0
- package/src/time-series/chart-bounds.ts +349 -0
- package/src/time-series/chart-seed.ts +142 -0
- package/src/time-series/economic.ts +5 -0
- package/src/time-series/fundamentals.ts +18 -3
- package/src/time-series/history-acquisition.ts +499 -0
- package/src/time-series/leverage.ts +100 -0
- package/src/time-series/market-resolution.ts +4 -2
- package/src/time-series/market.ts +2 -1
- package/src/time-series/price-comparison.ts +175 -30
- package/src/time-series/range.ts +9 -1
- package/src/time-series/resolution.ts +174 -16
- package/src/time-series/resolve-context.ts +157 -0
- package/src/time-series/resolve.ts +126 -1577
- package/src/time-series/series-name.ts +38 -0
- package/src/time-series/series-presentation.ts +208 -0
- package/src/time-series/spec.ts +11 -6
- package/src/time-series/studies.ts +109 -12
- package/src/time-series/tail-reconcile.ts +121 -0
- package/src/time-series/types.ts +29 -2
- package/src/time-series/use-chart-resolution.ts +4 -5
- package/src/types/broker.ts +10 -0
- package/src/types/config.ts +14 -0
- package/src/types/data-provider.ts +14 -0
- package/src/types/exchange-rate.ts +6 -0
- package/src/types/financials.ts +104 -7
- package/src/types/headless.ts +76 -6
- package/src/types/instrument.ts +3 -0
- package/src/types/plugin.ts +65 -8
- package/src/types/price-history.ts +2 -0
- package/src/types/ticker.ts +13 -0
- package/src/types/trading.ts +59 -1
- package/src/ui/ascii-font.ts +13 -1
- package/src/ui/host.tsx +6 -1
- package/src/updater/command-names.ts +175 -0
- package/src/updater/index.ts +10 -5
- package/src/utils/calendar-date.ts +32 -15
- package/src/utils/cash-runway.ts +241 -0
- package/src/utils/central-banks.ts +42 -0
- package/src/utils/cli-output.ts +259 -80
- package/src/utils/contract-month.ts +16 -0
- package/src/utils/crypto-pair.ts +61 -3
- package/src/utils/currency-units.ts +29 -0
- package/src/utils/datetime-format.ts +10 -0
- package/src/utils/debug-log.ts +1 -1
- package/src/utils/decimal-comma.ts +39 -6
- package/src/utils/exchange-announcements.ts +71 -0
- package/src/utils/exchange-rate-snapshot.ts +10 -0
- package/src/utils/financial-statements.ts +83 -4
- package/src/utils/format.ts +34 -16
- package/src/utils/fundamentals.ts +150 -34
- package/src/utils/fx-market-hours.ts +10 -1
- package/src/utils/latest-financial-period.ts +8 -0
- package/src/utils/linux-libc.ts +54 -0
- package/src/utils/market-capitalization.ts +111 -15
- package/src/utils/max-drawdown.ts +64 -0
- package/src/utils/network-failure.ts +83 -0
- package/src/utils/option-expiry.ts +139 -7
- package/src/utils/price-earnings.ts +11 -5
- package/src/utils/price-history.ts +18 -8
- package/src/utils/price-window.ts +131 -0
- package/src/utils/release-date.ts +47 -0
- package/src/utils/sec.ts +3 -0
- package/src/utils/throttled-fetch.ts +11 -4
- package/src/utils/trailing-eps.ts +67 -0
- package/src/utils/typed-text.ts +21 -0
- package/src/utils/utc-time.ts +24 -1
- package/src/version.ts +6 -0
- package/src/cli/pane-functions/screenshot.ts +0 -2122
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { Box } from "../../../ui";
|
|
3
|
+
import {
|
|
4
|
+
DataTableView,
|
|
5
|
+
QueryBar,
|
|
6
|
+
StatGrid,
|
|
7
|
+
statGridRows,
|
|
8
|
+
usePaneFooter,
|
|
9
|
+
usePaneNoticeFooter,
|
|
10
|
+
useQueryBarSearch,
|
|
11
|
+
type DataTableColumn,
|
|
12
|
+
type StatItem,
|
|
13
|
+
} from "../../../components";
|
|
14
|
+
import { FILL_REST } from "../../../components/ui/fill";
|
|
15
|
+
import { usePaneRefreshKey } from "../../../components/data-table/table-pane";
|
|
16
|
+
import { useAsyncResource } from "../../../public/react";
|
|
17
|
+
import { isAccessDenied } from "../../../api-client/errors";
|
|
18
|
+
import type { ScreenDefinition } from "../../../api-client/equity-screener";
|
|
19
|
+
import { useThemeColors } from "../../../theme/theme-context";
|
|
20
|
+
import { fetchScreenCheck } from "./client";
|
|
21
|
+
import { checkRows, screenCheckSummary } from "./screen-check";
|
|
22
|
+
|
|
23
|
+
interface ScreenTickerCheckProps {
|
|
24
|
+
definition: ScreenDefinition;
|
|
25
|
+
snapshotId?: string;
|
|
26
|
+
width: number;
|
|
27
|
+
height: number;
|
|
28
|
+
focused: boolean;
|
|
29
|
+
fetcher?: typeof fetchScreenCheck;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** A check keeps the screen's snapshot; streaming prices never change its decisions. */
|
|
33
|
+
export function ScreenTickerCheck({
|
|
34
|
+
definition,
|
|
35
|
+
snapshotId,
|
|
36
|
+
width,
|
|
37
|
+
height,
|
|
38
|
+
focused,
|
|
39
|
+
fetcher = fetchScreenCheck,
|
|
40
|
+
}: ScreenTickerCheckProps) {
|
|
41
|
+
const colors = useThemeColors();
|
|
42
|
+
const [draft, setDraft] = useState("");
|
|
43
|
+
const [ticker, setTicker] = useState<string | null>(null);
|
|
44
|
+
const search = useQueryBarSearch();
|
|
45
|
+
const controller = useRef<AbortController | null>(null);
|
|
46
|
+
const loader = useCallback(async () => {
|
|
47
|
+
controller.current?.abort();
|
|
48
|
+
const request = new AbortController();
|
|
49
|
+
controller.current = request;
|
|
50
|
+
return fetcher(definition, ticker!, snapshotId, request.signal);
|
|
51
|
+
}, [definition, fetcher, snapshotId, ticker]);
|
|
52
|
+
useEffect(() => () => controller.current?.abort(), [loader]);
|
|
53
|
+
useEffect(() => { search.focus(); }, [search.focus]);
|
|
54
|
+
const resource = useAsyncResource(ticker ? loader : null, { clearOnError: isAccessDenied });
|
|
55
|
+
const { data, loading, error } = resource;
|
|
56
|
+
const submit = (value: string) => {
|
|
57
|
+
const next = value.trim();
|
|
58
|
+
if (!next) return;
|
|
59
|
+
search.blur();
|
|
60
|
+
if (next === ticker) void resource.reload();
|
|
61
|
+
else setTicker(next);
|
|
62
|
+
};
|
|
63
|
+
usePaneRefreshKey(() => { void resource.reload(); }, { focused, enabled: !!ticker && !search.active });
|
|
64
|
+
usePaneFooter("equity-screener:check", () => ({
|
|
65
|
+
info: [
|
|
66
|
+
...(loading ? [{ id: "loading", parts: [{ text: "checking ticker", tone: "muted" as const }] }] : []),
|
|
67
|
+
...(data ? [{
|
|
68
|
+
id: "snapshot",
|
|
69
|
+
parts: [{ text: `snapshot ${data.snapshot.assembledAt.slice(0, 16).replace("T", " ")} UTC`, tone: "muted" as const }],
|
|
70
|
+
}] : []),
|
|
71
|
+
],
|
|
72
|
+
hints: [{
|
|
73
|
+
id: "check",
|
|
74
|
+
key: "c",
|
|
75
|
+
label: "heck ticker",
|
|
76
|
+
onPress: () => submit(draft),
|
|
77
|
+
disabled: !draft.trim() || loading,
|
|
78
|
+
}],
|
|
79
|
+
}), [draft, ticker, loading, data, submit]);
|
|
80
|
+
usePaneNoticeFooter({
|
|
81
|
+
registrationId: "equity-screener:check-notices",
|
|
82
|
+
focused,
|
|
83
|
+
notices: [...(data?.warnings ?? []), ...(error ? [error] : [])],
|
|
84
|
+
});
|
|
85
|
+
const rows = data ? checkRows(data) : [];
|
|
86
|
+
const columns: DataTableColumn[] = [
|
|
87
|
+
{ id: "criterion", label: "Criterion", width: Math.max(26, ...rows.map((row) => row.criterion.length)), flexGrow: 1, align: "left" },
|
|
88
|
+
{ id: "value", label: "Value", width: Math.max(12, ...rows.map((row) => row.value.length)), align: "right" },
|
|
89
|
+
{ id: "result", label: "Result", width: Math.max(6, ...rows.map((row) => row.result.length)), align: "left" },
|
|
90
|
+
{ id: "asOf", label: "As of", width: Math.max(10, ...rows.map((row) => row.asOf.length)), align: "left" },
|
|
91
|
+
...(rows.some((row) => row.state !== "available" && row.state !== "missing")
|
|
92
|
+
? [{ id: "state", label: "Data", width: 12, align: "left" as const }]
|
|
93
|
+
: []),
|
|
94
|
+
...(rows.some((row) => row.reason)
|
|
95
|
+
? [{ id: "reason", label: "Reason", width: 30, align: "left" as const }]
|
|
96
|
+
: []),
|
|
97
|
+
];
|
|
98
|
+
const stats: StatItem[] = data ? [
|
|
99
|
+
{ label: "Listing", value: data.row ? `${data.row.symbol}:${data.row.exchange}` : data.symbol, detail: data.row?.name ?? undefined },
|
|
100
|
+
{ label: "Result", value: screenCheckSummary(data), tone: data.matches === null ? "muted" : data.matches ? "positive" : "negative" },
|
|
101
|
+
] : [];
|
|
102
|
+
return (
|
|
103
|
+
<Box width={width} flexDirection="column" {...FILL_REST}>
|
|
104
|
+
<QueryBar
|
|
105
|
+
width={width}
|
|
106
|
+
filters={[{
|
|
107
|
+
kind: "text",
|
|
108
|
+
id: "ticker",
|
|
109
|
+
label: "Ticker",
|
|
110
|
+
value: draft,
|
|
111
|
+
onChange: setDraft,
|
|
112
|
+
placeholder: "NVDA or NVDA:NASDAQ",
|
|
113
|
+
focused,
|
|
114
|
+
...search.searchProps,
|
|
115
|
+
debounceMs: 0,
|
|
116
|
+
width: 24,
|
|
117
|
+
onSubmit: submit,
|
|
118
|
+
}]}
|
|
119
|
+
/>
|
|
120
|
+
{data ? <StatGrid width={width} items={stats} /> : null}
|
|
121
|
+
<DataTableView
|
|
122
|
+
columns={columns}
|
|
123
|
+
items={rows}
|
|
124
|
+
getItemKey={(row) => row.id}
|
|
125
|
+
selection={{ kind: "none" }}
|
|
126
|
+
focused={focused && !search.active}
|
|
127
|
+
rootWidth={width}
|
|
128
|
+
rootHeight={Math.max(1, height - 1 - statGridRows(stats, width))}
|
|
129
|
+
status={{
|
|
130
|
+
loading: loading && !data,
|
|
131
|
+
error: !data ? error : null,
|
|
132
|
+
empty: !ticker,
|
|
133
|
+
subject: "ticker check",
|
|
134
|
+
emptyTitle: "Enter a ticker to check this screen.",
|
|
135
|
+
}}
|
|
136
|
+
renderCell={(row, column) => ({
|
|
137
|
+
text: column.id === "reason" ? row.reason ?? "--" : row[column.id as "criterion" | "value" | "result" | "asOf" | "state"],
|
|
138
|
+
color: column.id === "result"
|
|
139
|
+
? row.passes === null ? colors.textMuted : row.passes ? colors.positive : colors.negative
|
|
140
|
+
: column.id === "reason" || column.id === "state" || column.id === "asOf" ? colors.textMuted : colors.text,
|
|
141
|
+
})}
|
|
142
|
+
sortColumnId={null}
|
|
143
|
+
sortDirection="asc"
|
|
144
|
+
emptyStateTitle="No criteria in this screen."
|
|
145
|
+
/>
|
|
146
|
+
</Box>
|
|
147
|
+
);
|
|
148
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { HeadlessPaneDefinition } from "../../../types/plugin";
|
|
2
2
|
import { explainRefusal } from "../shared/cloud-denied";
|
|
3
|
+
import { DATE_OPTION_EXAMPLES } from "../../../utils/calendar-date";
|
|
3
4
|
import { fetchEstimates } from "./client";
|
|
4
5
|
import { estimateRevisionsLockNote } from "./lock-note";
|
|
5
6
|
import { estimateCurrent, periodLabel, pinnedEstimatePeriods } from "./model";
|
|
@@ -15,7 +16,7 @@ export const estimateRevisionsHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
15
16
|
{
|
|
16
17
|
key: "period",
|
|
17
18
|
type: "string",
|
|
18
|
-
description:
|
|
19
|
+
description: `Optional fiscal end date, as ${DATE_OPTION_EXAMPLES}.`,
|
|
19
20
|
settingKey: "period",
|
|
20
21
|
},
|
|
21
22
|
{
|
|
@@ -56,6 +57,7 @@ export const estimateRevisionsHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
56
57
|
data.periods,
|
|
57
58
|
args.options.period,
|
|
58
59
|
args.options.frequency,
|
|
60
|
+
"--period",
|
|
59
61
|
);
|
|
60
62
|
return {
|
|
61
63
|
sections: [
|
|
@@ -6,7 +6,7 @@ import { proLockNote, type FreeRoute } from "../shared/pro-lock-note";
|
|
|
6
6
|
|
|
7
7
|
/** GUIDE's free preview, where it holds guidance for the company: Apple issues none, so GUIDE has no AAPL rows. */
|
|
8
8
|
const GUIDE_ROUTE: FreeRoute = {
|
|
9
|
-
text: (ticker, company) => `
|
|
9
|
+
text: (ticker, company) => `gloom fn GUIDE ${ticker} lists ${company}'s latest guidance ranges, with the date each was issued.`,
|
|
10
10
|
answers: async (symbol, context) => {
|
|
11
11
|
const data = await fetchCompanyData("guidance", symbol, {}, context.apiClient, await resolveHeadlessIssuerListing(context, symbol), context.signal);
|
|
12
12
|
return "guidance" in data && data.guidance.length + data.history.length > 0;
|
|
@@ -15,12 +15,12 @@ const GUIDE_ROUTE: FreeRoute = {
|
|
|
15
15
|
|
|
16
16
|
/** The company's 8-Ks, where results and any guidance it gives are filed, for a company that files them. */
|
|
17
17
|
const EIGHT_K_ROUTE: FreeRoute = {
|
|
18
|
-
text: (ticker, company) => `
|
|
18
|
+
text: (ticker, company) => `gloom filings ${ticker} --form 8-K lists ${company}'s 8-Ks, where it files its results and any guidance, each with its items and a link to the filing.`,
|
|
19
19
|
answers: (symbol, context) => filesForm(symbol, "8-K", context),
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
const EARNINGS_ROUTE: FreeRoute = {
|
|
23
|
-
text: (ticker, company) => `
|
|
23
|
+
text: (ticker, company) => `gloom earnings ${ticker} lists ${company}'s next report date with its consensus EPS estimate.`,
|
|
24
24
|
answers: async (symbol, context) => (await context.marketData.getEarningsCalendar?.([symbol]) ?? []).length > 0,
|
|
25
25
|
};
|
|
26
26
|
|
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
EstimateRevisionsPayload,
|
|
5
5
|
} from "../../../api-client/estimate-revisions";
|
|
6
6
|
import type { DataTableColumn } from "../../../components";
|
|
7
|
+
import { dateOptionError, readCalendarDate } from "../../../utils/calendar-date";
|
|
7
8
|
export const estimateNumber = (value: number | null | undefined) =>
|
|
8
9
|
value == null
|
|
9
10
|
? "--"
|
|
@@ -84,20 +85,17 @@ export function sortPeriods(
|
|
|
84
85
|
});
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
/** The periods ending on a fiscal end date, as a date option reads one; `option` is how a command line types it (`--period`). */
|
|
87
89
|
export function pinnedEstimatePeriods(
|
|
88
90
|
periods: EstimatePeriod[],
|
|
89
|
-
|
|
91
|
+
requestedEnd: unknown,
|
|
90
92
|
frequency: unknown = "quarterly",
|
|
93
|
+
option = "",
|
|
91
94
|
): EstimatePeriod[] {
|
|
92
|
-
if (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
!Number.isFinite(Date.parse(periodEnd)) ||
|
|
97
|
-
new Date(periodEnd).toISOString().slice(0, 10) !== periodEnd
|
|
98
|
-
) {
|
|
99
|
-
throw new Error("Fiscal end must be a valid YYYY-MM-DD date.");
|
|
100
|
-
}
|
|
95
|
+
if (requestedEnd == null || requestedEnd === "") return periods;
|
|
96
|
+
const text = typeof requestedEnd === "string" ? requestedEnd.trim() : String(requestedEnd);
|
|
97
|
+
const periodEnd = readCalendarDate(text);
|
|
98
|
+
if (!periodEnd) throw new Error(dateOptionError(text, option, { subject: "a fiscal end date" }));
|
|
101
99
|
if (frequency !== "quarterly" && frequency !== "annual")
|
|
102
100
|
throw new Error("Frequency must be quarterly or annual.");
|
|
103
101
|
const matches = periods.filter(
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { HeadlessPaneColumn, HeadlessPaneDefinition, HeadlessPaneRow } from "../../../types/plugin";
|
|
2
|
-
import type { ExposureExtensionObservation, ExposurePayload, ExposureRequest } from "../../../api-client/exposure";
|
|
2
|
+
import type { ExposureExtensionObservation, ExposurePayload, ExposureRequest, ExposureScenario } from "../../../api-client/exposure";
|
|
3
3
|
import { cliTerminalWidth } from "../../../utils/cli-output";
|
|
4
4
|
import { clipToDisplayWidth, displayWidth } from "../../../utils/format";
|
|
5
5
|
import { fiscalLabel } from "../company-kpis/model";
|
|
6
6
|
import { humanLabel } from "../shared/research-cells";
|
|
7
|
+
import { freePreviewNote } from "../shared/free-preview";
|
|
7
8
|
import { fetchExposure, fetchScenarios } from "./client";
|
|
8
|
-
import { DEFAULT_SCENARIO, exposureCellText, parseCustomScenario, parseHoldings, pathRows, portfolioRows, scenarioTitle, tableRows, TABS, type ExposureRow } from "./model";
|
|
9
|
+
import { DEFAULT_SCENARIO, exposureCellText, LIBRARY_SCENARIO_IDS, parseCustomScenario, parseHoldings, pathRows, portfolioRows, scenarioTitle, tableRows, TABS, type ExposureRow } from "./model";
|
|
9
10
|
import { portfolioHoldings, watchlistHoldings } from "./holdings";
|
|
10
11
|
import { describeCollections, findNamedCollection } from "../../../portfolio/collection-name";
|
|
11
12
|
import { driverAmount, driverRows, driverScope } from "./drivers";
|
|
@@ -183,6 +184,45 @@ function portfolioColumns(data: ExposurePayload, concentration: boolean, items:
|
|
|
183
184
|
|
|
184
185
|
const CONCENTRATION_VIEWS = ["country", "supplier", "customer"] as const;
|
|
185
186
|
|
|
187
|
+
/** The server's own line about a preview ("Free preview covers the first holding at depth 1. ..."): what the view is, not what failed. */
|
|
188
|
+
const PREVIEW_NOTE = /^Free preview\b/i;
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* A free preview's Pro line in the words every report uses, and what the
|
|
192
|
+
* server says about the preview as a note: its first sentence is the Pro
|
|
193
|
+
* line's, the rest (how the totals are weighted) stays. The other unknowns
|
|
194
|
+
* are the report's errors.
|
|
195
|
+
*/
|
|
196
|
+
function previewLines(data: Pick<ExposurePayload, "access" | "lockedHoldings" | "unknowns">): { lock: string[]; notes: string[]; unknowns: string[] } {
|
|
197
|
+
const preview = data.access === "preview";
|
|
198
|
+
const notes = preview ? data.unknowns.filter(line => PREVIEW_NOTE.test(line))
|
|
199
|
+
.map(line => line.replace(/^Free preview[^.]*\.\s*/i, "").trim()).filter(Boolean) : [];
|
|
200
|
+
const others = preview ? data.unknowns.filter(line => !PREVIEW_NOTE.test(line)) : data.unknowns;
|
|
201
|
+
const lock = preview ? [freePreviewNote({ shows: "the first holding, one relationship hop deep",
|
|
202
|
+
adds: `${data.lockedHoldings === 1 ? "the other holding and " : data.lockedHoldings > 1 ? `the other ${data.lockedHoldings} holdings and ` : ""}paths up to four hops` })] : [];
|
|
203
|
+
return { lock, notes, unknowns: others };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** Library ids as a list: `a, b or c`. */
|
|
207
|
+
function scenarioIds(library: readonly ExposureScenario[]): string {
|
|
208
|
+
const ids = library.flatMap(s => s.id ? [s.id] : []);
|
|
209
|
+
return ids.length > 1 ? `${ids.slice(0, -1).join(", ")} or ${ids.at(-1)}` : ids[0] ?? "";
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** An id the library does not have: the ids it does, the one it was likely meant for (`rates` for rates-up), and --custom. */
|
|
213
|
+
function unknownScenarioMessage(id: string, library: readonly ExposureScenario[]): string {
|
|
214
|
+
const typed = id.trim().toLowerCase();
|
|
215
|
+
const near = typed ? library.filter(s => s.id?.split("-").includes(typed) || s.id?.startsWith(typed)) : [];
|
|
216
|
+
return [`Unknown scenario: ${id}.`, ...(near.length === 1 ? [`Did you mean ${near[0]!.id}?`] : []),
|
|
217
|
+
...(library.length ? [`Scenarios: ${scenarioIds(library)}.`] : []), "Or describe your own with --custom."].join(" ");
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** The note a report run on the default scenario carries: which one it is, and how to pick another. */
|
|
221
|
+
function defaultScenarioNote(scenario: ExposureScenario, library: readonly ExposureScenario[]): string {
|
|
222
|
+
const others = library.filter(s => s.id !== scenario.id);
|
|
223
|
+
return `${scenario.label} (${scenario.id}) is the default scenario. Pick another with --scenario${others.length ? ` (${scenarioIds(others)})` : ""}, or describe your own with --custom.`;
|
|
224
|
+
}
|
|
225
|
+
|
|
186
226
|
export const exposureHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
187
227
|
shape: "bundle",
|
|
188
228
|
freshness: { status: "not-a-feed", basis: "company disclosures" },
|
|
@@ -190,7 +230,8 @@ export const exposureHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
190
230
|
discovery: { aliases: ["EXPO"], dataRequirements: ["Gloom Cloud geographic revenue, disclosed supply chains, KPIs, guidance and credit disclosures", "Portfolio NAV for local PORT weights"],
|
|
191
231
|
limitations: ["Pro: full holdings and up to four-hop paths; free: one holding, one hop.", "Operating exposure estimates, never predicted stock returns.", "Missing relationships and sensitivities remain unknown.", "Basis and reporting period are kept separate."] },
|
|
192
232
|
options: [
|
|
193
|
-
{ key: "scenario", type: "string", settingKey: "scenario", defaultValue:
|
|
233
|
+
{ key: "scenario", type: "string", settingKey: "scenario", defaultValue: DEFAULT_SCENARIO.id!, values: LIBRARY_SCENARIO_IDS.map(value => ({ value })),
|
|
234
|
+
description: "Library scenario id, or use --custom." },
|
|
194
235
|
{ key: "custom", type: "string", settingKey: "customScenario", description: "JSON scenario with label and shocks; supports multiple shocks and explicit transmission assumptions." },
|
|
195
236
|
{ key: "depth", type: "integer", settingKey: "depth", defaultValue: 2, minimum: 1, maximum: 4, description: "Maximum relationship hops." },
|
|
196
237
|
{ key: "nav", type: "string", settingKey: "nav", description: "Positive portfolio NAV in its configured currency; required for PORT." },
|
|
@@ -217,8 +258,9 @@ export const exposureHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
217
258
|
holdings = watchlistHoldings(tickers, findNamedCollection(ctx.config.watchlists, source[2])?.id ?? source[2]!);
|
|
218
259
|
} else holdings = parseHoldings(input);
|
|
219
260
|
const id = String(args.options.scenario ?? DEFAULT_SCENARIO.id);
|
|
220
|
-
const
|
|
221
|
-
|
|
261
|
+
const library = args.options.custom ? [] : await fetchScenarios(ctx.apiClient);
|
|
262
|
+
const scenario = args.options.custom ? parseCustomScenario(String(args.options.custom)) : library.find(s => s.id === id);
|
|
263
|
+
if (!scenario) throw new Error(unknownScenarioMessage(id, library));
|
|
222
264
|
const cashWeight = args.options.cash === undefined ? undefined : Number(args.options.cash);
|
|
223
265
|
if (cashWeight !== undefined && (!Number.isFinite(cashWeight) || Math.abs(cashWeight) > 10)) throw new Error("Cash must be a NAV fraction between -10 and 10.");
|
|
224
266
|
if (ctx.signal.aborted) throw new Error("Exposure analysis cancelled.");
|
|
@@ -227,8 +269,11 @@ export const exposureHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
227
269
|
const stress = withNotes(portfolioRows(data, "stress"), row => row.incomplete ? row.unknowns : []);
|
|
228
270
|
const concentrations = CONCENTRATION_VIEWS.flatMap(kind => portfolioRows(data, kind).map(row => ({ ...row, kind })));
|
|
229
271
|
const holdingRows = tableRows(data), paths = pathRows(data);
|
|
272
|
+
const preview = previewLines(data);
|
|
273
|
+
// The library's first scenario runs unless another is asked for: the report says so, and what else there is.
|
|
274
|
+
const notes = [...(!args.options.custom && scenario.id === DEFAULT_SCENARIO.id ? [defaultScenarioNote(scenario, library)] : []), ...preview.notes];
|
|
230
275
|
return { complete: data.lockedHoldings === 0 && data.holdings.every(h => h.status === "quantified") && data.unknowns.length === 0,
|
|
231
|
-
errors: [...
|
|
276
|
+
errors: [...preview.lock, ...preview.unknowns], ...(notes.length ? { notes } : {}),
|
|
232
277
|
sections: [
|
|
233
278
|
{ title: "Holdings", rows: data.holdings.map(h => ({ symbol: h.symbol, weight: h.weight, status: h.status, measures: h.measures, coverage: h.coverage, unknowns: h.unknowns })),
|
|
234
279
|
textColumns: fitted(holdingColumns(data), holdingRows), textRows: textRows(holdingRows) },
|
|
@@ -1,14 +1,40 @@
|
|
|
1
|
+
import type { PaneTemplateContext, ShortcutArgError } from "../../../types/plugin";
|
|
2
|
+
import { findNamedCollection, unknownCollectionArgError } from "../../../portfolio/collection-name";
|
|
1
3
|
import type { PluginModule } from "../plugin-module";
|
|
2
4
|
import { exposureHeadless } from "./headless";
|
|
3
5
|
import { ExposurePane } from "./pane";
|
|
4
6
|
|
|
7
|
+
const SOURCE = /^(PORT|WATCH):(.+)$/i;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* `EXPO PORT:Book` names a portfolio, and `WATCH:Watchlist` a watchlist, by
|
|
11
|
+
* name or id in any case, as `fn EXPO` reads them. The pane keeps its source
|
|
12
|
+
* by id (`PORT:book`), so the name is rewritten to the id it names.
|
|
13
|
+
*/
|
|
14
|
+
function sourceInput(arg: string, context: PaneTemplateContext): string {
|
|
15
|
+
const source = SOURCE.exec(arg.trim());
|
|
16
|
+
if (!source) return arg;
|
|
17
|
+
const prefix = source[1]!.toUpperCase();
|
|
18
|
+
const match = findNamedCollection(prefix === "PORT" ? context.config.portfolios : context.config.watchlists, source[2]);
|
|
19
|
+
return match ? `${prefix}:${match.id}` : arg;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** `EXPO PORT:Nope` or `EXPO WATCH:Nope` names a portfolio or watchlist nothing has; tickers and weights are read by the pane. */
|
|
23
|
+
function unknownSourceArg(arg: string, context: PaneTemplateContext): ShortcutArgError | null {
|
|
24
|
+
const source = SOURCE.exec(arg.trim());
|
|
25
|
+
if (!source) return null;
|
|
26
|
+
return source[1]!.toUpperCase() === "PORT"
|
|
27
|
+
? unknownCollectionArgError(source[2]!, context.config.portfolios, "portfolio", (name) => `PORT:${name}`)
|
|
28
|
+
: unknownCollectionArgError(source[2]!, context.config.watchlists, "watchlist", (name) => `WATCH:${name}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
5
31
|
export const exposureModule: PluginModule = {
|
|
6
32
|
panes: [{ id: "exposure", name: "Exposure", icon: "E", component: ExposurePane, defaultPosition: "right", defaultMode: "floating", defaultFloatingSize: { width: 138, height: 31 }, tableExport: true, headless: exposureHeadless,
|
|
7
33
|
personalData: "holdings",
|
|
8
34
|
portableShare: { private: { params: true, settings: true, state: true } } }],
|
|
9
35
|
paneTemplates: [{ id: "exposure-pane", paneId: "exposure", label: "Exposure", description: "Pro scenario exposures across holdings, geographic revenue and supply chains, with source evidence and portfolio concentrations.",
|
|
10
36
|
keywords: ["exposure", "scenario", "stress", "portfolio", "supply", "country", "tariff", "pro"],
|
|
11
|
-
shortcut: { prefix: "EXPO", argKind: "text", argOptional: true, argPlaceholder: "AAPL=60% NVDA=40%" }, headless: exposureHeadless,
|
|
12
|
-
createInstance: (
|
|
37
|
+
shortcut: { prefix: "EXPO", argKind: "text", argOptional: true, argPlaceholder: "AAPL=60% NVDA=40%", argError: unknownSourceArg }, headless: exposureHeadless,
|
|
38
|
+
createInstance: (context, options) => ({ params: { input: sourceInput(options?.arg ?? "", context) } }),
|
|
13
39
|
}],
|
|
14
40
|
};
|
|
@@ -3,6 +3,13 @@ import { humanLabel } from "../shared/research-cells";
|
|
|
3
3
|
|
|
4
4
|
export const TABS = [{ value: "table", label: "Table" }, { value: "drivers", label: "Drivers" }, { value: "paths", label: "Paths" }, { value: "portfolio", label: "Portfolio" }];
|
|
5
5
|
export const DEFAULT_SCENARIO: ExposureScenario = { id: "taiwan-disruption", label: "Taiwan disruption", shocks: [{ id: "taiwan", kind: "country", target: "TW", changePct: -100 }] };
|
|
6
|
+
/**
|
|
7
|
+
* The ids of Gloom Cloud's scenario library, which the catalog lists for
|
|
8
|
+
* `--scenario`. A report reads the library itself, so an id added there runs
|
|
9
|
+
* before it is listed here.
|
|
10
|
+
*/
|
|
11
|
+
export const LIBRARY_SCENARIO_IDS = ["taiwan-disruption", "china-demand", "europe-demand", "china-semiconductor-ban", "china-tariff",
|
|
12
|
+
"oil-up", "rates-up", "usd-up", "tsmc-outage", "microsoft-capex"] as const;
|
|
6
13
|
export const basisLabel = (basis: string | null) => basis?.replaceAll("_", " ") ?? "Unknown basis";
|
|
7
14
|
const pct = (value: number) => `${value.toFixed(1)}%`;
|
|
8
15
|
export const rangeText = (range: ExposureRange | null) => !range ? "Unknown" : range.low === range.high ? pct(range.low) : `${range.low.toFixed(1)} to ${range.high.toFixed(1)}%`;
|
|
@@ -8,6 +8,7 @@ import { useAppSelector, useAsyncResource, useAutoRefresh, useMarketData, usePan
|
|
|
8
8
|
import { useThemeColors } from "../../../theme/theme-context";
|
|
9
9
|
import type { PaneProps } from "../../../types/plugin";
|
|
10
10
|
import { Box, ScrollBox, Text, useRendererHost, useUiCapabilities } from "../../../ui";
|
|
11
|
+
import { withCountryFlag } from "../../../components/ui/country-flag";
|
|
11
12
|
import { logFailure } from "../../../utils/log-failure";
|
|
12
13
|
import { SignInWall } from "../cloud/auth-actions";
|
|
13
14
|
import { CLOUD_PLAN_KEY, useCloudUpgradeAction } from "../shared/cloud-upgrade";
|
|
@@ -212,7 +213,11 @@ export function ExposurePane({ width, height, focused }: PaneProps) {
|
|
|
212
213
|
case "value": return { text: row.driver ? driverValue(row.driver) : "--", value: row.driver?.value ?? null, color: colors.textBright };
|
|
213
214
|
case "units": return { text: row.driver ? driverUnits(row.driver) : "", color: colors.textDim };
|
|
214
215
|
case "scope": return { text: row.driver ? driverScope(row.driver) : "", color: colors.textDim };
|
|
215
|
-
case "label":
|
|
216
|
+
case "label": {
|
|
217
|
+
const cell = { text: exposureCellText(row, "label"), color: unknown ? colors.textDim : colors.text };
|
|
218
|
+
// Grouped by country, each target leads with its flag on the desktop and the web.
|
|
219
|
+
return concentration && view === "country" ? withCountryFlag(cell, row.label, desktop) : cell;
|
|
220
|
+
}
|
|
216
221
|
case "basis": return row.basis ? { text: exposureCellText(row, "basis"), color: colors.textDim } : missingCell(colors);
|
|
217
222
|
case "exposure": return row.exposure ? { text: exposureCellText(row, "exposure"), value: row.exposure.high, color: colors.textBright } : { text: exposureCellText(row, "exposure"), value: null, color: colors.textMuted };
|
|
218
223
|
// Disclosed figures stand out; estimates read plainly, and the word says which is which.
|
|
@@ -63,7 +63,7 @@ export const fearGreedPlugin: GloomPlugin = {
|
|
|
63
63
|
},
|
|
64
64
|
],
|
|
65
65
|
|
|
66
|
-
// `
|
|
66
|
+
// `gloom fear-greed`, as before the plugin moved out of the host. Runs
|
|
67
67
|
// without the pane cache attached when invoked from the CLI, so it always
|
|
68
68
|
// fetches, which is what a CLI call wants anyway.
|
|
69
69
|
cliCommands: [
|
|
@@ -22,7 +22,7 @@ function filingEventsLockNote(lock: PaneLock): Promise<string> {
|
|
|
22
22
|
does: "it reads each 8-K and sums up what it said and who it names",
|
|
23
23
|
shows: "them",
|
|
24
24
|
free: [{
|
|
25
|
-
text: (ticker, company) => `
|
|
25
|
+
text: (ticker, company) => `gloom fn SEC ${ticker} lists ${company}'s recent filings, 8-Ks among them, each with its filing date and its items by number and name.`,
|
|
26
26
|
answers: (symbol, context) => filesForm(symbol, "8-K", context),
|
|
27
27
|
}],
|
|
28
28
|
});
|
|
@@ -4,6 +4,7 @@ import { compareSortValues, type SortDirection } from "../../../utils/sort-value
|
|
|
4
4
|
import type { BoardQuoteMap } from "../shared/use-quote-board";
|
|
5
5
|
import { FUTURES_SECTOR_ORDER, type FuturesContract, type FuturesSector } from "../../../market-data/futures-board";
|
|
6
6
|
import { futuresPriceUnit } from "../../../market-data/futures-contract";
|
|
7
|
+
import { contractMonthLabel } from "../../../utils/contract-month";
|
|
7
8
|
import type { FuturesReturnHorizon } from "./returns";
|
|
8
9
|
import type { FuturesTermsMap } from "./use-board-terms";
|
|
9
10
|
import type { FrontReturnsMap } from "./use-front-returns";
|
|
@@ -41,20 +42,20 @@ export function futuresRowId(row: FuturesTableRow): string {
|
|
|
41
42
|
return row.type === "header" ? `header-${row.sector}` : row.contract.symbol;
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
/** "Nov 26" or "Futures,Nov-2026"; a hyphen takes only a whole year, since "Futures,Nov-20" is 2026 cut short. */
|
|
45
|
+
/** "Nov 2026", "Nov 26" or "Futures,Nov-2026"; a hyphen takes only a whole year, since "Futures,Nov-20" is 2026 cut short. */
|
|
45
46
|
const CONTRACT_MONTH = /\b(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)(?: (\d{4}|\d{2})|-(\d{4}))$/i;
|
|
46
47
|
|
|
47
48
|
/**
|
|
48
49
|
* The alias stays the row identity while its quoted contract rolls, so the
|
|
49
50
|
* label is the catalog name plus the quoted contract's month ("30-Year T-Bond
|
|
50
|
-
* Dec
|
|
51
|
-
* or cut off mid-month ("Futures,Dec-"); a month
|
|
52
|
-
* rather than guessed.
|
|
51
|
+
* Dec 2026"). Quote names arrive as "Crude Oil Nov 2026", "Crude Oil Nov 26",
|
|
52
|
+
* "Corn Futures,Dec-2026" or cut off mid-month ("Futures,Dec-"); a month
|
|
53
|
+
* without a year is dropped rather than guessed.
|
|
53
54
|
*/
|
|
54
55
|
export function futuresContractName(contract: FuturesContract, quote?: Quote | null): string {
|
|
55
56
|
const month = quotedContractMonth(contract, quote);
|
|
56
57
|
if (!month) return contract.name;
|
|
57
|
-
return `${contract.name} ${
|
|
58
|
+
return `${contract.name} ${contractMonthLabel(month.year, month.month)}`;
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
const MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
@@ -82,9 +83,9 @@ function dayMonth(date: string): string {
|
|
|
82
83
|
* The row's headline: the contract its quote prices, as futuresContractName
|
|
83
84
|
* words it: the root's front month until its roll date. Two notes follow,
|
|
84
85
|
* each from the day's facts. Once the continuous symbol has rolled while the
|
|
85
|
-
* nearer month still trades, that month's last trade: "WTI Crude Oil Dec
|
|
86
|
+
* nearer month still trades, that month's last trade: "WTI Crude Oil Dec 2026,
|
|
86
87
|
* rolled (Nov expires 20 Oct)". When the day's volume put another month first,
|
|
87
|
-
* that month: "WTI Crude Oil Nov
|
|
88
|
+
* that month: "WTI Crude Oil Nov 2026, Dec most active". The terms only add a
|
|
88
89
|
* note when they name the month the quote prices, so a roll between the two
|
|
89
90
|
* loads never mixes months, and place the month when the quote's name carries
|
|
90
91
|
* none. A name column too narrow for a note drops it, the last one first.
|
|
@@ -104,7 +105,7 @@ export function futuresContractHeadline(
|
|
|
104
105
|
const month = agree ? quoted ?? termsMonth : quoted;
|
|
105
106
|
if (!month) return contract.name;
|
|
106
107
|
const priced = `${month.year}-${String(month.month + 1).padStart(2, "0")}`;
|
|
107
|
-
const plain = `${contract.name} ${
|
|
108
|
+
const plain = `${contract.name} ${contractMonthLabel(month.year, month.month)}`;
|
|
108
109
|
if (!agree) return plain;
|
|
109
110
|
const notes: Array<{ text: string; min: string }> = [];
|
|
110
111
|
const nearest = terms?.nearest;
|
|
@@ -117,7 +118,7 @@ export function futuresContractHeadline(
|
|
|
117
118
|
if (active && /^\d{4}-\d{2}$/.test(active.deliveryMonth) && active.deliveryMonth !== priced) {
|
|
118
119
|
// Another year's month says which year it is.
|
|
119
120
|
const name = MONTH_NAMES[Number(active.deliveryMonth.slice(5, 7)) - 1];
|
|
120
|
-
const label = active.deliveryMonth.slice(0, 4) === String(month.year) ? name : `${name} ${active.deliveryMonth.slice(
|
|
121
|
+
const label = active.deliveryMonth.slice(0, 4) === String(month.year) ? name : `${name} ${active.deliveryMonth.slice(0, 4)}`;
|
|
121
122
|
notes.push({ text: `, ${label} most active`, min: `, ${label} most active` });
|
|
122
123
|
}
|
|
123
124
|
// The month the quote prices leads, so a column that clips the tail still shows it; a note keeps its place
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PricePoint, Quote } from "../../../types/financials";
|
|
2
|
-
import {
|
|
2
|
+
import { periodReturn } from "../../../market-data/market/period-return";
|
|
3
3
|
import type { FuturesContract } from "../../../market-data/futures-board";
|
|
4
4
|
import { quotedContractMonth } from "./model";
|
|
5
5
|
|
|
@@ -9,7 +9,6 @@ export type FuturesReturnValues = Readonly<Record<FuturesReturnHorizon, number |
|
|
|
9
9
|
export const NO_FUTURES_RETURNS: FuturesReturnValues = { "1W": null, "1M": null, YTD: null };
|
|
10
10
|
|
|
11
11
|
const MONTH_CODES = "FGHJKMNQUVXZ";
|
|
12
|
-
const DAY_MS = 86_400_000;
|
|
13
12
|
|
|
14
13
|
/** Gloom symbol of one listed contract: LEZ26.CME. */
|
|
15
14
|
function listedContractSymbol(contract: FuturesContract, year: number, month: number): string {
|
|
@@ -51,10 +50,6 @@ function utcDay(value: Date | string | number): string | null {
|
|
|
51
50
|
return Number.isFinite(date.getTime()) ? date.toISOString().slice(0, 10) : null;
|
|
52
51
|
}
|
|
53
52
|
|
|
54
|
-
function shiftDay(day: string, days: number): string {
|
|
55
|
-
return new Date(Date.parse(`${day}T00:00:00Z`) + days * DAY_MS).toISOString().slice(0, 10);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
53
|
/** Dated closes, one per day, oldest first. History that crossed a JSON bridge carries string dates. */
|
|
59
54
|
function dailyCloses(history: readonly PricePoint[]): DailyClose[] {
|
|
60
55
|
const byDay = new Map<string, number>();
|
|
@@ -86,25 +81,10 @@ export function pickFrontContract(
|
|
|
86
81
|
return best?.symbol ?? null;
|
|
87
82
|
}
|
|
88
83
|
|
|
89
|
-
/**
|
|
90
|
-
* A baseline further than this before its target date is a hole in the
|
|
91
|
-
* contract's trading (or a contract listed after the target), not its close.
|
|
92
|
-
*/
|
|
93
|
-
const MAX_BASELINE_GAP_DAYS = 10;
|
|
94
|
-
|
|
95
|
-
function closeOnOrBefore(closes: readonly DailyClose[], target: string): number | null {
|
|
96
|
-
const earliest = shiftDay(target, -MAX_BASELINE_GAP_DAYS);
|
|
97
|
-
for (let index = closes.length - 1; index >= 0; index -= 1) {
|
|
98
|
-
const bar = closes[index]!;
|
|
99
|
-
if (bar.day > target) continue;
|
|
100
|
-
return bar.day >= earliest && bar.close > 0 ? bar.close : null;
|
|
101
|
-
}
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
84
|
/**
|
|
106
85
|
* One contract's returns: the latest price against that same contract's close
|
|
107
|
-
* a week
|
|
86
|
+
* on or before the same date a week and a calendar month earlier, and its
|
|
87
|
+
* last close of the year before (periodReturn). The continuous alias's own
|
|
108
88
|
* series jumps at every roll (LE=F fell 6.3% on a July roll day), so its
|
|
109
89
|
* history is never the baseline. `price` is the live quote, dated `asOf`;
|
|
110
90
|
* without one the contract's last close stands in.
|
|
@@ -116,17 +96,9 @@ export function frontContractReturns(
|
|
|
116
96
|
): FuturesReturnValues {
|
|
117
97
|
const closes = dailyCloses(history);
|
|
118
98
|
const live = price != null && Number.isFinite(price) && asOf != null && Number.isFinite(asOf);
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
if (latest
|
|
122
|
-
const change = (
|
|
123
|
-
|
|
124
|
-
return base == null ? null : (latest / base - 1) * 100;
|
|
125
|
-
};
|
|
126
|
-
const monthBack = calendarMonthsBefore(new Date(`${latestDay}T00:00:00Z`), 1).toISOString().slice(0, 10);
|
|
127
|
-
return {
|
|
128
|
-
"1W": change(shiftDay(latestDay, -7)),
|
|
129
|
-
"1M": change(monthBack),
|
|
130
|
-
YTD: change(`${Number(latestDay.slice(0, 4)) - 1}-12-31`),
|
|
131
|
-
};
|
|
99
|
+
const liveDay = live ? utcDay(asOf) : null;
|
|
100
|
+
const latest = live && liveDay ? { day: liveDay, close: price } : closes.at(-1);
|
|
101
|
+
if (!latest) return NO_FUTURES_RETURNS;
|
|
102
|
+
const change = (period: FuturesReturnHorizon) => periodReturn(closes, period, latest)?.percent ?? null;
|
|
103
|
+
return { "1W": change("1W"), "1M": change("1M"), YTD: change("YTD") };
|
|
132
104
|
}
|
|
@@ -43,7 +43,7 @@ const DEFAULT_FUTURES_COLUMN_IDS = FUTURES_COLUMN_DEFS.map((column) => column.id
|
|
|
43
43
|
* which the change in percent still gives. The previous close (the last price
|
|
44
44
|
* less the change) goes first, then each row's quote time (the status line
|
|
45
45
|
* dates the newest), which leaves a 1280-pixel shot room for "WTI Crude Oil
|
|
46
|
-
* Dec
|
|
46
|
+
* Dec 2026, rolled (Nov expires 20 Oct)".
|
|
47
47
|
*/
|
|
48
48
|
const COLUMN_MIN_PANE_WIDTH: Partial<Record<FuturesColumnId, number>> = {
|
|
49
49
|
change: 100,
|