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
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { formatFxRate } from "../cli/fx-pair";
|
|
2
|
+
import type { EnterpriseValueCheck, Fundamentals, Quote, TickerFinancials } from "../types/financials";
|
|
3
|
+
import { quotedFxPair } from "./currency-pair";
|
|
2
4
|
import { resolveCurrencyUnit } from "./currency-units";
|
|
3
5
|
import { formatCompact } from "./format";
|
|
6
|
+
import { formatUtcTime } from "./utc-time";
|
|
4
7
|
|
|
5
8
|
export const RETRACTABLE_VALUATION_FIELDS = ["enterpriseValue", "enterpriseToRevenue"] as const;
|
|
6
9
|
|
|
@@ -26,44 +29,72 @@ const finiteNumber = (value: unknown): value is number => typeof value === "numb
|
|
|
26
29
|
|
|
27
30
|
/**
|
|
28
31
|
* The served check of the enterprise value beside it, when it describes that value: a provider EV the check labels or
|
|
29
|
-
* matches is the one shown,
|
|
32
|
+
* matches is the one shown, a computed one is the check's own figure, and a withdrawn or not meaningful one is no
|
|
33
|
+
* longer shown. A check merged beside another source's EV is none.
|
|
30
34
|
*/
|
|
31
35
|
export function enterpriseValueCheck(
|
|
32
36
|
fundamentals: Pick<Fundamentals, "enterpriseValue" | "enterpriseValueCheck" | "unavailableFields"> | undefined,
|
|
33
37
|
): EnterpriseValueCheck | undefined {
|
|
34
38
|
const check = fundamentals?.enterpriseValueCheck;
|
|
35
|
-
if (!check
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
if (!check) return undefined;
|
|
40
|
+
const withdrawn = fundamentals?.enterpriseValue === undefined && !!fundamentals?.unavailableFields?.includes("enterpriseValue");
|
|
41
|
+
// Not meaningful needs no figure of its own: a source EV below zero may come with no cap or currency.
|
|
42
|
+
if (check.status === "not-meaningful") return withdrawn ? check : undefined;
|
|
43
|
+
if (!check.currency) return undefined;
|
|
44
|
+
if (check.status === "withdrawn") return withdrawn && finiteNumber(check.computed) && finiteNumber(check.source) ? check : undefined;
|
|
45
|
+
if (check.status === "computed") {
|
|
46
|
+
return finiteNumber(check.computed) && fundamentals?.enterpriseValue === check.computed ? check : undefined;
|
|
39
47
|
}
|
|
40
|
-
return fundamentals?.enterpriseValue === check.source ? check : undefined;
|
|
48
|
+
return finiteNumber(check.source) && fundamentals?.enterpriseValue === check.source ? check : undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Why a source EV below zero that nothing checked is not meaningful: its cash and investments exceed the rest. */
|
|
52
|
+
const SOURCE_ENTERPRISE_VALUE_NOT_POSITIVE = "Cash and investments exceed market cap + debt in the source's EV";
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Why the enterprise value is not meaningful, if it is: Gloom Cloud's reason for an EV that comes out at or below
|
|
56
|
+
* zero, or for an EV below zero from any source that served no check. A bank's 0 is a gap, not N/M. EV/S, EV/EBITDA
|
|
57
|
+
* and a reverse DCF over it are N/M too.
|
|
58
|
+
*/
|
|
59
|
+
export function enterpriseValueNotMeaningful(fundamentals: Parameters<typeof enterpriseValueCheck>[0]): string | undefined {
|
|
60
|
+
const check = enterpriseValueCheck(fundamentals);
|
|
61
|
+
if (check?.status === "not-meaningful") return check.reason?.trim() || SOURCE_ENTERPRISE_VALUE_NOT_POSITIVE;
|
|
62
|
+
const value = fundamentals?.enterpriseValue;
|
|
63
|
+
return finiteNumber(value) && value < 0 ? SOURCE_ENTERPRISE_VALUE_NOT_POSITIVE : undefined;
|
|
41
64
|
}
|
|
42
65
|
|
|
43
66
|
/**
|
|
44
67
|
* Whether the provider's EV was withdrawn: retracted (`unavailableFields`) and none served in its place, by the
|
|
45
|
-
* served check or by Gloom Cloud's own validation of the source observation, which leaves no check.
|
|
68
|
+
* served check or by Gloom Cloud's own validation of the source observation, which leaves no check. Not one that is
|
|
69
|
+
* not meaningful (enterpriseValueNotMeaningful), which says N/M instead.
|
|
46
70
|
*/
|
|
47
71
|
export function enterpriseValueWithdrawn(fundamentals: Parameters<typeof enterpriseValueCheck>[0]): boolean {
|
|
48
|
-
return fundamentals?.enterpriseValue === undefined && !!fundamentals?.unavailableFields?.includes("enterpriseValue")
|
|
72
|
+
return fundamentals?.enterpriseValue === undefined && !!fundamentals?.unavailableFields?.includes("enterpriseValue")
|
|
73
|
+
&& enterpriseValueNotMeaningful(fundamentals) === undefined;
|
|
49
74
|
}
|
|
50
75
|
|
|
51
|
-
/** "(provider)" beside an EV more than 5% from market cap + debt - cash,
|
|
52
|
-
export function enterpriseValueLabel(fundamentals: Parameters<typeof enterpriseValueCheck>[0]): "provider" | "unavailable" | undefined {
|
|
76
|
+
/** "(provider)" beside an EV more than 5% from market cap + debt - cash, "unavailable" for a withdrawn one, N/M for one at or below zero. */
|
|
77
|
+
export function enterpriseValueLabel(fundamentals: Parameters<typeof enterpriseValueCheck>[0]): "provider" | "unavailable" | "not-meaningful" | undefined {
|
|
78
|
+
if (enterpriseValueNotMeaningful(fundamentals)) return "not-meaningful";
|
|
53
79
|
const status = enterpriseValueCheck(fundamentals)?.status;
|
|
54
80
|
return status === "differs" ? "provider" : status === "withdrawn" || enterpriseValueWithdrawn(fundamentals) ? "unavailable" : undefined;
|
|
55
81
|
}
|
|
56
82
|
|
|
57
83
|
/**
|
|
58
|
-
* The reconciliation line under a labelled or
|
|
59
|
-
* cap + total debt - cash (balance sheet 2026-06-30)."
|
|
60
|
-
*
|
|
61
|
-
*
|
|
84
|
+
* The reconciliation line under a labelled, withdrawn or not meaningful EV: "EV 61.75B USD (provider) vs 63.75B
|
|
85
|
+
* computed from market cap + total debt - cash (balance sheet 2026-06-30).", "EV N/M: cash and short-term investments
|
|
86
|
+
* exceed market cap + total debt (balance sheet 2026-06-30)." For an EV withdrawn without a check, that the source
|
|
87
|
+
* failed validation. Undefined when the EV matches, is unchecked or computed, or has no check. Read it from the
|
|
88
|
+
* fundamentals the rows show (atRegularSessionPrice moves the check with the EV and the market cap), so its figures
|
|
89
|
+
* are theirs.
|
|
62
90
|
*/
|
|
63
91
|
export function enterpriseValueReconciliationNote(fundamentals: Parameters<typeof enterpriseValueCheck>[0]): string | undefined {
|
|
92
|
+
const notMeaningful = enterpriseValueNotMeaningful(fundamentals);
|
|
93
|
+
if (notMeaningful) return `EV N/M: ${notMeaningful.charAt(0).toLowerCase()}${notMeaningful.slice(1)}.`;
|
|
64
94
|
const check = enterpriseValueCheck(fundamentals);
|
|
65
95
|
if (!check && enterpriseValueWithdrawn(fundamentals)) return "EV unavailable: the provider's figure failed validation.";
|
|
66
|
-
if (!check || !finiteNumber(check.computed) || (check.
|
|
96
|
+
if (!check || !finiteNumber(check.computed) || !finiteNumber(check.source)
|
|
97
|
+
|| (check.status !== "differs" && check.status !== "withdrawn")) return undefined;
|
|
67
98
|
const source = `${formatCompact(check.source)} ${check.currency}`;
|
|
68
99
|
const computed = formatCompact(check.computed);
|
|
69
100
|
const basis = `market cap + total debt - cash${check.balanceSheetDate ? ` (balance sheet ${check.balanceSheetDate})` : ""}`;
|
|
@@ -72,19 +103,39 @@ export function enterpriseValueReconciliationNote(fundamentals: Parameters<typeo
|
|
|
72
103
|
return `EV unavailable: the provider's ${source}${ratio} the ${computed} computed from ${basis}.`;
|
|
73
104
|
}
|
|
74
105
|
|
|
75
|
-
/**
|
|
106
|
+
/**
|
|
107
|
+
* What `valuation` says of an insurer's or a holding company's EV, which Gloom Cloud computes rather than takes from
|
|
108
|
+
* the provider: "EV 1.23T USD is market cap + total debt - 40.61B of cash and equivalents (balance sheet 2026-06-30);
|
|
109
|
+
* investments stay in." Undefined for any other EV. The overview stat says it in two words ("investments in").
|
|
110
|
+
*/
|
|
111
|
+
export function computedEnterpriseValueNote(fundamentals: Parameters<typeof enterpriseValueCheck>[0]): string | undefined {
|
|
112
|
+
const check = enterpriseValueCheck(fundamentals);
|
|
113
|
+
if (check?.status !== "computed" || !finiteNumber(check.computed) || !finiteNumber(check.cash)) return undefined;
|
|
114
|
+
const sheet = check.balanceSheetDate ? ` (balance sheet ${check.balanceSheetDate})` : "";
|
|
115
|
+
return `EV ${formatCompact(check.computed)} ${check.currency} is market cap + total debt - ${formatCompact(check.cash)} of cash and equivalents${sheet}; investments stay in.`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** What names the currency of the trailing figures: the fundamentals' own labels, else the statements' on a listing that trades in theirs. */
|
|
76
119
|
type FundamentalsCurrencies = Pick<TickerFinancials, "financialCurrency"> & {
|
|
77
|
-
fundamentals?: Pick<Fundamentals, "financialCurrency" | "epsCurrency"> | null;
|
|
120
|
+
fundamentals?: Pick<Fundamentals, "financialCurrency" | "epsCurrency" | "marketCapCurrency"> | null;
|
|
121
|
+
quote?: Pick<Quote, "currency"> | null;
|
|
78
122
|
};
|
|
79
123
|
|
|
80
124
|
/**
|
|
81
|
-
* The currency of the trailing EPS, revenue, income and cash flows: the one the fundamentals declare
|
|
82
|
-
*
|
|
125
|
+
* The currency of the trailing EPS, revenue, income and cash flows: the one the fundamentals declare for themselves.
|
|
126
|
+
* A block that declares none is in the statements' currency only when the listing trades in it; on a listing quoted
|
|
127
|
+
* in another (a receipt in USD beside TWD books, YPFD in ARS beside USD statements) its currency is unknown, since
|
|
128
|
+
* Gloom Cloud labels every block whose currency it can tell. Never the quote's.
|
|
83
129
|
*/
|
|
84
130
|
export function fundamentalsCurrency(
|
|
85
131
|
financials: FundamentalsCurrencies | null | undefined,
|
|
86
132
|
): string | undefined {
|
|
87
|
-
|
|
133
|
+
const declared = financials?.fundamentals?.financialCurrency?.trim();
|
|
134
|
+
if (declared) return declared;
|
|
135
|
+
const statements = financials?.financialCurrency?.trim();
|
|
136
|
+
if (!statements) return undefined;
|
|
137
|
+
const listed = financials?.fundamentals?.marketCapCurrency?.trim() || financials?.quote?.currency?.trim();
|
|
138
|
+
return !listed || resolveCurrencyUnit(listed).currency === resolveCurrencyUnit(statements).currency ? statements : undefined;
|
|
88
139
|
}
|
|
89
140
|
|
|
90
141
|
/**
|
|
@@ -99,22 +150,87 @@ export function fundamentalsEpsCurrency(
|
|
|
99
150
|
|
|
100
151
|
const ISO_DAY = /^\d{4}-\d{2}-\d{2}$/;
|
|
101
152
|
|
|
153
|
+
const usableRate = (rate: number | null | undefined): rate is number => typeof rate === "number" && Number.isFinite(rate) && rate > 0;
|
|
154
|
+
|
|
155
|
+
/** The currency a trailing block was converted from into another it is labelled with; undefined for a block in the reporting currency. */
|
|
156
|
+
function ttmConvertedFrom(fundamentals: Pick<Fundamentals, "financialCurrency" | "ttmConversion"> | undefined): string | undefined {
|
|
157
|
+
const from = fundamentals?.ttmConversion?.from?.trim();
|
|
158
|
+
const to = fundamentals?.financialCurrency?.trim();
|
|
159
|
+
return from && to && from !== to ? from : undefined;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** A rate the app converts at, the one `fx` reports: units of the target currency per unit of the source one, and when it was observed. */
|
|
163
|
+
export interface AppFxRate {
|
|
164
|
+
rate: number;
|
|
165
|
+
/** Epoch ms of the older leg's observation; null when the source did not date it. */
|
|
166
|
+
asOf: number | null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** One currency's US dollar rate as the app holds it, a minor unit's by its major currency. */
|
|
170
|
+
type UsdLeg = (currency: string) => AppFxRate | null | undefined;
|
|
171
|
+
|
|
102
172
|
/**
|
|
103
|
-
*
|
|
104
|
-
*
|
|
173
|
+
* The app's rate for a converted trailing block: units of its currency per unit of the one it was converted from,
|
|
174
|
+
* through the two US dollar legs `fx` reads, dated by the older. Null for an unconverted block or a missing leg.
|
|
175
|
+
*/
|
|
176
|
+
export function appTtmRate(fundamentals: Pick<Fundamentals, "financialCurrency" | "ttmConversion"> | undefined, usd: UsdLeg): AppFxRate | null {
|
|
177
|
+
const from = ttmConvertedFrom(fundamentals);
|
|
178
|
+
if (!from || !usableRate(fundamentals?.ttmConversion?.rate)) return null;
|
|
179
|
+
const leg = (currency: string) => {
|
|
180
|
+
const major = resolveCurrencyUnit(currency).currency;
|
|
181
|
+
return major === "USD" ? { rate: 1, asOf: null } : usd(major);
|
|
182
|
+
};
|
|
183
|
+
const source = leg(from), target = leg(fundamentals!.financialCurrency!.trim());
|
|
184
|
+
if (!usableRate(source?.rate) || !usableRate(target?.rate)) return null;
|
|
185
|
+
const dates = [source!.asOf, target!.asOf].filter((time): time is number => time != null && Number.isFinite(time));
|
|
186
|
+
return { rate: source!.rate / target!.rate, asOf: dates.length > 0 ? Math.min(...dates) : null };
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const TTM_AMOUNTS = ["revenue", "netIncome", "operatingCashFlow", "freeCashFlow"] as const;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* A converted trailing block at the app's own rate, so a screen converts at one rate, the one `fx` reports: revenue,
|
|
193
|
+
* income and cash flows the source converted at `ttmConversion.rate` go back to the reporting currency and are
|
|
194
|
+
* converted again at `rate`, which the conversion then names with its time. EPS stays at report-date rates. The block
|
|
195
|
+
* as served when it is not converted, states no rate, or the app has none.
|
|
196
|
+
*/
|
|
197
|
+
export function ttmAtAppRate<T extends Fundamentals>(fundamentals: T, rate: AppFxRate | null | undefined): T {
|
|
198
|
+
const conversion = fundamentals.ttmConversion;
|
|
199
|
+
if (!rate || !usableRate(rate.rate) || !conversion || !ttmConvertedFrom(fundamentals) || !usableRate(conversion.rate)) return fundamentals;
|
|
200
|
+
const factor = rate.rate / conversion.rate;
|
|
201
|
+
const shown: T = { ...fundamentals };
|
|
202
|
+
for (const key of TTM_AMOUNTS) {
|
|
203
|
+
const value = fundamentals[key];
|
|
204
|
+
if (finiteNumber(value)) (shown as Fundamentals)[key] = Math.round(value * factor);
|
|
205
|
+
}
|
|
206
|
+
const { asOf: _served, ...kept } = conversion;
|
|
207
|
+
shown.ttmConversion = { ...kept, rate: rate.rate, ...(rate.asOf != null ? { asOf: new Date(rate.asOf).toISOString() } : {}) };
|
|
208
|
+
return shown;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** `2026-10-09`, or `2026-10-23 21:29 UTC` for the time of a rate. */
|
|
212
|
+
function conversionTime(asOf: string | undefined): string | undefined {
|
|
213
|
+
if (!asOf) return undefined;
|
|
214
|
+
if (ISO_DAY.test(asOf)) return asOf;
|
|
215
|
+
const time = Date.parse(asOf);
|
|
216
|
+
return Number.isFinite(time) ? formatUtcTime(new Date(time)) || undefined : undefined;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* "TTM converted from ARS at USD/ARS 1529, as of 2026-10-23 21:29 UTC; EPS at report-date rates.": what a converted
|
|
221
|
+
* trailing block was converted from, at which rate, as markets quote the pair and `fx` reads it, and when. Undefined
|
|
222
|
+
* for a block in the currency the company reports in.
|
|
105
223
|
*/
|
|
106
224
|
export function ttmConversionNote(fundamentals: Pick<Fundamentals, "financialCurrency" | "ttmConversion"> | undefined): string | undefined {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
const rate =
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const asOf = conversion.asOf && ISO_DAY.test(conversion.asOf) ? conversion.asOf : undefined;
|
|
115
|
-
const basis = [rate, asOf].filter(Boolean).join(", ");
|
|
225
|
+
const from = ttmConvertedFrom(fundamentals);
|
|
226
|
+
if (!from) return undefined;
|
|
227
|
+
const conversion = fundamentals!.ttmConversion!;
|
|
228
|
+
const quoted = usableRate(conversion.rate) ? quotedFxPair(from, fundamentals!.financialCurrency!, conversion.rate) : undefined;
|
|
229
|
+
const rate = quoted ? ` at ${quoted.pair} ${formatFxRate(quoted.rate)}` : "";
|
|
230
|
+
const time = conversionTime(conversion.asOf);
|
|
231
|
+
const when = time ? `${rate ? "," : ""} as of ${time}` : "";
|
|
116
232
|
const eps = conversion.eps === "report_date" ? "; EPS at report-date rates" : "";
|
|
117
|
-
return `TTM converted from ${from}${
|
|
233
|
+
return `TTM converted from ${from}${rate}${when}${eps}.`;
|
|
118
234
|
}
|
|
119
235
|
|
|
120
236
|
/**
|
|
@@ -147,7 +263,7 @@ export function convertedPriceEarningsNote(fundamentals: PriceEarningsBasis | un
|
|
|
147
263
|
if (from && to && from !== to && typeof conversion?.rate === "number" && Number.isFinite(conversion.rate) && conversion.rate > 0) {
|
|
148
264
|
return `P/E (TTM): price over EPS converted at 1 ${from} = ${Number(conversion.rate.toPrecision(5))} ${to}.`;
|
|
149
265
|
}
|
|
150
|
-
return (
|
|
266
|
+
return (ttmConvertedFrom(fundamentals) && fundamentals?.ttmConversion?.eps === "report_date") || epsConversionNote(fundamentals)
|
|
151
267
|
? "P/E (TTM): spot price over EPS at report-date rates."
|
|
152
268
|
: undefined;
|
|
153
269
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { canonicalExchange, parsePublicTickerKey } from "./exchanges";
|
|
2
|
-
import { zonedDateTimeParts, zonedWallClockToUtcMs } from "./zoned-date-time";
|
|
2
|
+
import { zonedDateKey, zonedDateTimeParts, zonedWallClockToUtcMs } from "./zoned-date-time";
|
|
3
3
|
|
|
4
4
|
const HOUR_MS = 60 * 60_000;
|
|
5
5
|
const DAY_MS = 24 * HOUR_MS;
|
|
@@ -29,6 +29,15 @@ export function isFxMarketOpen(time: number): boolean {
|
|
|
29
29
|
return true;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* The FX trading day an instant belongs to, as "YYYY-MM-DD": the day rolls
|
|
34
|
+
* at 17:00 New York time, so Wednesday 18:00 New York is Thursday's.
|
|
35
|
+
*/
|
|
36
|
+
export function fxTradingDay(time: number): string {
|
|
37
|
+
// The roll is 17:00, seven hours before New York's midnight, daylight saving or not.
|
|
38
|
+
return zonedDateKey(time + 7 * HOUR_MS, NEW_YORK);
|
|
39
|
+
}
|
|
40
|
+
|
|
32
41
|
/** The latest 17:00 New York on `weekday` (0 is Sunday) at or before `time`. */
|
|
33
42
|
function latestNewYorkFivePm(time: number, weekday: number): number | null {
|
|
34
43
|
if (!Number.isFinite(time)) return null;
|
|
@@ -24,3 +24,11 @@ export function latestFinancialPeriod<T>(
|
|
|
24
24
|
}
|
|
25
25
|
return latest;
|
|
26
26
|
}
|
|
27
|
+
|
|
28
|
+
/** The newest reported period end across the annual and quarterly statements: the period the trailing figures run through. */
|
|
29
|
+
export function latestReportedPeriod(financials: {
|
|
30
|
+
annualStatements?: readonly { date: string }[];
|
|
31
|
+
quarterlyStatements?: readonly { date: string }[];
|
|
32
|
+
}): string | null {
|
|
33
|
+
return latestFinancialPeriod([...financials.annualStatements ?? [], ...financials.quarterlyStatements ?? []], (row) => row.date)?.date ?? null;
|
|
34
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which C library a Linux process runs on. The terminal's native render
|
|
3
|
+
* library and the release binary each have a glibc and a musl build, and the
|
|
4
|
+
* wrong one fails to load: the glibc library on Alpine stops at startup with
|
|
5
|
+
* "getcontext: symbol not found".
|
|
6
|
+
*/
|
|
7
|
+
export type LinuxLibc = "glibc" | "musl";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Reads the libraries mapped into the process (`/proc/self/maps`). musl is
|
|
11
|
+
* checked first because a glibc program started through gcompat still runs on
|
|
12
|
+
* musl underneath, and the musl library is the one it can load.
|
|
13
|
+
*/
|
|
14
|
+
export function libcFromProcessMaps(maps: string): LinuxLibc | null {
|
|
15
|
+
if (maps.includes("/ld-musl-") || maps.includes("/libc.musl-")) return "musl";
|
|
16
|
+
if (maps.includes("/libc.so.6") || maps.includes("/ld-linux-")) return "glibc";
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Reads the system's `ldd`, a script that names its C library, for when `/proc` is not mounted. */
|
|
21
|
+
export function libcFromLdd(script: string): LinuxLibc | null {
|
|
22
|
+
if (script.includes("musl")) return "musl";
|
|
23
|
+
if (/GNU C Library|glibc/i.test(script)) return "glibc";
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function readText(path: string): string | null {
|
|
28
|
+
try {
|
|
29
|
+
return process.getBuiltinModule("fs").readFileSync(path, "utf8");
|
|
30
|
+
} catch {
|
|
31
|
+
// Intentional ignore: a missing or unreadable file only means this source cannot tell.
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let detected: LinuxLibc | null | undefined;
|
|
37
|
+
|
|
38
|
+
/** The C library this process runs on, or null off Linux or when nothing says. */
|
|
39
|
+
export function detectLinuxLibc(): LinuxLibc | null {
|
|
40
|
+
if (globalThis.process?.platform !== "linux") return null;
|
|
41
|
+
if (detected !== undefined) return detected;
|
|
42
|
+
detected = libcFromProcessMaps(readText("/proc/self/maps") ?? "")
|
|
43
|
+
?? libcFromLdd(readText("/usr/bin/ldd") ?? "");
|
|
44
|
+
return detected;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @opentui/core loads its glibc library on Linux unless `OPENTUI_LIBC` says
|
|
49
|
+
* musl; it never looks at the system. Has to run before it is first imported.
|
|
50
|
+
* An `OPENTUI_LIBC` the user set is kept.
|
|
51
|
+
*/
|
|
52
|
+
export function selectOpenTuiLibc(env: Record<string, string | undefined>, libc: LinuxLibc | null): void {
|
|
53
|
+
if (!env.OPENTUI_LIBC && libc === "musl") env.OPENTUI_LIBC = "musl";
|
|
54
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Fundamentals, Quote } from "../types/financials";
|
|
1
|
+
import type { Fundamentals, Quote, SplitShareBasis } from "../types/financials";
|
|
2
2
|
import { formatCompact, formatNumber } from "./format";
|
|
3
3
|
|
|
4
4
|
export interface MarketCapitalization {
|
|
@@ -66,23 +66,119 @@ export function listedMarketCapitalization(value: number | null): number | null
|
|
|
66
66
|
return value != null && Number.isFinite(value) && value > 0 ? value : null;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
/**
|
|
69
|
+
/** Within this a provider's cap is the share count times the price at another moment, and is not worth a note. */
|
|
70
70
|
const SHARE_COUNT_TOLERANCE = 0.02;
|
|
71
|
+
/**
|
|
72
|
+
* How far a provider's cap may sit from the share count times the price and
|
|
73
|
+
* still be on that count, off by price timing or a recent issuance (EVN:ASX,
|
|
74
|
+
* 3% in October 2026). Past it the count is not the cap's: one class's count
|
|
75
|
+
* beside an all-class cap (NRDY).
|
|
76
|
+
*/
|
|
77
|
+
const SHARE_BASIS_LIMIT = 0.1;
|
|
78
|
+
|
|
79
|
+
/** A market cap a view shows, and how it stands against the share count shown beside it. */
|
|
80
|
+
export interface ViewMarketCapitalization extends MarketCapitalization {
|
|
81
|
+
/** Set when the cap shown is `shares` x `price` and the provider's sat more than 2% (and at most 10%) from it. */
|
|
82
|
+
computed?: { shares: number; price: number; providerValue: number };
|
|
83
|
+
/** Set when the provider's cap, shown, sits more than 10% from `shares` x `price`: the count is not the cap's. */
|
|
84
|
+
otherBasis?: { shares: number; price: number; product: number };
|
|
85
|
+
/** Set when a recent split put the share count and cap on the basis the listing trades on, with the count shown. */
|
|
86
|
+
split?: SplitShareBasis & { shares?: number };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const positiveFinite = (value: number | null | undefined): value is number => value != null && Number.isFinite(value) && value > 0;
|
|
71
90
|
|
|
72
91
|
/**
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
92
|
+
* The one market cap a view shows, so RV, `valuation` and EQS agree:
|
|
93
|
+
* the share count shown times the price, the provider's figure only as a
|
|
94
|
+
* noted fallback. The product stands while the provider's sits within 10% of
|
|
95
|
+
* it, named in the note when more than 2% off (price timing, a recent
|
|
96
|
+
* issuance); past 10% the count shown is not the cap's (one class's beside
|
|
97
|
+
* an all-class cap), and the provider's is shown with a note saying the two
|
|
98
|
+
* do not tie. `price` is the price the view measures at (the regular
|
|
99
|
+
* session's); without a count or a price in the cap's currency the
|
|
100
|
+
* provider's stands. Gloom Cloud's screener and earnings board apply the
|
|
101
|
+
* same rule (sharesTimesLast in the server's market-cap-basis.ts).
|
|
76
102
|
*/
|
|
77
|
-
export function
|
|
78
|
-
|
|
79
|
-
|
|
103
|
+
export function viewMarketCapitalization(
|
|
104
|
+
quote: Quote | undefined,
|
|
105
|
+
fundamentals: Fundamentals | undefined,
|
|
106
|
+
price: number | null | undefined = quote?.price,
|
|
107
|
+
): ViewMarketCapitalization | null {
|
|
108
|
+
const capitalization = viewCapitalization(quote, fundamentals, price);
|
|
109
|
+
const split = fundamentals?.splitShareBasis;
|
|
110
|
+
return capitalization && split
|
|
111
|
+
? { ...capitalization, split: { ...split, shares: fundamentals?.sharesOutstanding } }
|
|
112
|
+
: capitalization;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function viewCapitalization(
|
|
116
|
+
quote: Quote | undefined,
|
|
117
|
+
fundamentals: Fundamentals | undefined,
|
|
80
118
|
price: number | null | undefined,
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
119
|
+
): ViewMarketCapitalization | null {
|
|
120
|
+
const selected = selectMarketCapitalization(quote, fundamentals);
|
|
121
|
+
const shares = fundamentals?.sharesOutstanding;
|
|
122
|
+
if (!selected || !(selected.value > 0) || selected.currency !== quote?.currency) return selected;
|
|
123
|
+
if (!positiveFinite(shares) || !positiveFinite(price)) return selected;
|
|
124
|
+
// In whole units, as caps are served.
|
|
125
|
+
const product = Math.round(shares * price);
|
|
126
|
+
const gap = Math.abs(selected.value - product);
|
|
127
|
+
if (gap > SHARE_BASIS_LIMIT * product) return { ...selected, otherBasis: { shares, price, product } };
|
|
128
|
+
return {
|
|
129
|
+
value: product,
|
|
130
|
+
currency: selected.currency,
|
|
131
|
+
// Priced at the quote, whichever block the provider's figure came from.
|
|
132
|
+
provenance: { kind: "quote", source: quote.providerId },
|
|
133
|
+
...(gap > SHARE_COUNT_TOLERANCE * product ? { computed: { shares, price, providerValue: selected.value } } : {}),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** "1-for-15 reverse split" for a price factor of 15, "10-for-1 split" for 0.1. */
|
|
138
|
+
function splitRatio(priceFactor: number): string {
|
|
139
|
+
const ratio = (value: number) => String(Number(value.toPrecision(4)));
|
|
140
|
+
return priceFactor >= 1 ? `1-for-${ratio(priceFactor)} reverse split` : `${ratio(1 / priceFactor)}-for-1 split`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* What a view says when a recent split moved the share count shown:
|
|
145
|
+
* - a filed count: "12.77M shares: 191.61M filed 2026-07-31, adjusted for the 1-for-15 reverse split on 2026-08-19."
|
|
146
|
+
* - the provider's cap: "Provider's market cap; its 2.46B share count predates the 10-for-1 split on 2024-06-10."
|
|
147
|
+
*/
|
|
148
|
+
function splitShareCountNote(split: SplitShareBasis & { shares?: number }): string {
|
|
149
|
+
const ratio = splitRatio(split.priceFactor);
|
|
150
|
+
if (split.method === "provider_cap") {
|
|
151
|
+
return `Provider's market cap; its ${formatCompact(split.reportedShares)} share count predates the ${ratio} on ${split.exDate}.`;
|
|
152
|
+
}
|
|
153
|
+
const shown = positiveFinite(split.shares) ? `${formatCompact(split.shares)} shares: ` : "";
|
|
154
|
+
const filed = split.reportedAsOf ? ` filed ${split.reportedAsOf}` : " filed";
|
|
155
|
+
return `${shown}${formatCompact(split.reportedShares)}${filed}, adjusted for the ${ratio} on ${split.exDate}.`;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* What a view says when its market cap and the share count shown beside it are not the provider's cap alone:
|
|
160
|
+
* - the product shown: "Market cap 23.69B AUD is the 1.99B shares shown x 11.93 AUD; the provider's is 24.40B AUD."
|
|
161
|
+
* - the provider's shown, on another count: "Market cap 79.11M USD is the provider's and does not rest on the
|
|
162
|
+
* 72.23M shares shown (x 0.7133 USD = 51.52M)."
|
|
163
|
+
* A recent split that moved the count is said first (splitShareCountNote).
|
|
164
|
+
* Undefined when the provider's cap ties with the count and no split moved it.
|
|
165
|
+
*/
|
|
166
|
+
export function marketCapBasisNote(capitalization: ViewMarketCapitalization | null): string | undefined {
|
|
167
|
+
if (!capitalization) return undefined;
|
|
168
|
+
const { split } = capitalization;
|
|
169
|
+
const splitNote = split ? splitShareCountNote(split) : undefined;
|
|
170
|
+
const basisNote = shareBasisNote(capitalization);
|
|
171
|
+
return splitNote && basisNote ? `${splitNote} ${basisNote}` : splitNote ?? basisNote;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function shareBasisNote(capitalization: ViewMarketCapitalization): string | undefined {
|
|
175
|
+
const { currency, computed, otherBasis } = capitalization;
|
|
176
|
+
const priced = (price: number) => `${formatNumber(price, price < 1 ? 4 : 2)} ${currency}`;
|
|
177
|
+
if (computed) {
|
|
178
|
+
return `Market cap ${formatCompact(capitalization.value)} ${currency} is the ${formatCompact(computed.shares)} shares shown x ${priced(computed.price)}; the provider's is ${formatCompact(computed.providerValue)} ${currency}.`;
|
|
179
|
+
}
|
|
180
|
+
if (otherBasis) {
|
|
181
|
+
return `Market cap ${formatCompact(capitalization.value)} ${currency} is the provider's and does not rest on the ${formatCompact(otherBasis.shares)} shares shown (x ${priced(otherBasis.price)} = ${formatCompact(otherBasis.product)}).`;
|
|
182
|
+
}
|
|
183
|
+
return undefined;
|
|
88
184
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The largest fall from a close to a later close (docs/usage.md, under `history`):
|
|
3
|
+
* the peak it fell from and the trough it reached, each with its date, the
|
|
4
|
+
* fall as a fraction of the peak, and the first later close back at the peak,
|
|
5
|
+
* if any. Read off closes, as returns are; a missing or non-positive close is
|
|
6
|
+
* passed over. The earliest of equal falls is the one named.
|
|
7
|
+
*/
|
|
8
|
+
export interface MaxDrawdown {
|
|
9
|
+
peak: { date: string; close: number };
|
|
10
|
+
trough: { date: string; close: number };
|
|
11
|
+
/** trough / peak - 1: 0 when no close fell below an earlier one, else negative. */
|
|
12
|
+
drawdown: number;
|
|
13
|
+
/** The first date after the trough whose close is back at the peak; null when none is in the series. */
|
|
14
|
+
recovered: string | null;
|
|
15
|
+
/** The last date in the series, which a fall not yet recovered is measured to. */
|
|
16
|
+
through: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface ClosePoint {
|
|
20
|
+
/** An ISO date or instant; points sort by it. */
|
|
21
|
+
date: string;
|
|
22
|
+
close: number | null | undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** The series' max drawdown, or null with fewer than two closes. */
|
|
26
|
+
export function maxDrawdown(points: readonly ClosePoint[]): MaxDrawdown | null {
|
|
27
|
+
const closes = points
|
|
28
|
+
.filter((point): point is { date: string; close: number } => typeof point.close === "number" && Number.isFinite(point.close) && point.close > 0)
|
|
29
|
+
.toSorted((left, right) => left.date.localeCompare(right.date));
|
|
30
|
+
if (closes.length < 2) return null;
|
|
31
|
+
let peak = closes[0]!;
|
|
32
|
+
let worst = { peak, trough: peak, drawdown: 0 };
|
|
33
|
+
for (const point of closes) {
|
|
34
|
+
if (point.close > peak.close) peak = point;
|
|
35
|
+
const fall = point.close / peak.close - 1;
|
|
36
|
+
if (fall < worst.drawdown) worst = { peak, trough: point, drawdown: fall };
|
|
37
|
+
}
|
|
38
|
+
const recovered = worst.drawdown < 0
|
|
39
|
+
? closes.find((point) => point.date > worst.trough.date && point.close >= worst.peak.close)?.date ?? null
|
|
40
|
+
: null;
|
|
41
|
+
return {
|
|
42
|
+
peak: { date: worst.peak.date, close: worst.peak.close },
|
|
43
|
+
trough: { date: worst.trough.date, close: worst.trough.close },
|
|
44
|
+
drawdown: worst.drawdown,
|
|
45
|
+
recovered,
|
|
46
|
+
through: closes.at(-1)!.date,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The report line: `Max drawdown -69.6% (daily closes): peak 53.25 on 2007-05-30, trough 16.19 on 2009-03-09,
|
|
52
|
+
* not back to the peak by 2009-12-31`. `price` and `date` draw a close and a date as the table does.
|
|
53
|
+
*/
|
|
54
|
+
export function maxDrawdownText(
|
|
55
|
+
value: MaxDrawdown,
|
|
56
|
+
{ basis, price, date = (text) => text.slice(0, 10) }: { basis: string; price: (value: number) => string; date?: (text: string) => string },
|
|
57
|
+
): string {
|
|
58
|
+
const percent = (value.drawdown * 100).toFixed(1);
|
|
59
|
+
// A fall that rounds to nothing is still a fall, which -0.0% would hide.
|
|
60
|
+
const head = `Max drawdown ${percent === "-0.0" ? "under 0.1%" : `${percent}%`} (${basis})`;
|
|
61
|
+
if (value.drawdown === 0) return `${head}: no close fell below an earlier one`;
|
|
62
|
+
const back = value.recovered ? `back to the peak on ${date(value.recovered)}` : `not back to the peak by ${date(value.through)}`;
|
|
63
|
+
return `${head}: peak ${price(value.peak.close)} on ${date(value.peak.date)}, trough ${price(value.trough.close)} on ${date(value.trough.date)}, ${back}`;
|
|
64
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/** What every surface says when a request to Gloom's data service never got an answer. */
|
|
2
|
+
export const DATA_SERVICE_UNREACHABLE_MESSAGE = "Gloom couldn't reach its data service";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A request that never reached the data service: no connection, a proxy that
|
|
6
|
+
* refused it, a name that did not resolve. The fetch's own error is the
|
|
7
|
+
* `cause`, and its `code` (Bun's `ConnectionRefused`, Node's `ENOTFOUND`) is
|
|
8
|
+
* kept for code that classifies failures by it.
|
|
9
|
+
*/
|
|
10
|
+
export class DataServiceUnreachableError extends Error {
|
|
11
|
+
readonly code?: string;
|
|
12
|
+
|
|
13
|
+
constructor(cause: unknown) {
|
|
14
|
+
super(DATA_SERVICE_UNREACHABLE_MESSAGE, { cause });
|
|
15
|
+
this.name = "DataServiceUnreachableError";
|
|
16
|
+
const code = (cause as { code?: unknown } | null)?.code;
|
|
17
|
+
if (typeof code === "string") this.code = code;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Codes a fetch fails with when it never connected: Bun's, then Node's and
|
|
23
|
+
* the system's. A reset or a closed socket is not one: the request may have
|
|
24
|
+
* reached the server.
|
|
25
|
+
*/
|
|
26
|
+
const NO_CONNECTION_CODES = new Set([
|
|
27
|
+
"ConnectionRefused",
|
|
28
|
+
"FailedToOpenSocket",
|
|
29
|
+
"ECONNREFUSED",
|
|
30
|
+
"ENOTFOUND",
|
|
31
|
+
"EAI_AGAIN",
|
|
32
|
+
"ENETUNREACH",
|
|
33
|
+
"EHOSTUNREACH",
|
|
34
|
+
"ENETDOWN",
|
|
35
|
+
]);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The same failure in each fetch's exact words, so a server's or a broker's
|
|
39
|
+
* sentence that merely starts the same way ("Failed to fetch quote from
|
|
40
|
+
* upstream", "Unable to connect to IB Gateway") is not one: Bun's, which the
|
|
41
|
+
* desktop relays from its Bun process as a plain message, then a browser's
|
|
42
|
+
* (Chrome, Safari, Firefox).
|
|
43
|
+
*/
|
|
44
|
+
const NO_CONNECTION_MESSAGES = new Set([
|
|
45
|
+
"Unable to connect. Is the computer able to access the url?",
|
|
46
|
+
"Failed to fetch",
|
|
47
|
+
"Load failed",
|
|
48
|
+
"NetworkError when attempting to fetch resource.",
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
/** An answer came back: an HTTP status, or an error the server wrote. Its code is the server's, not a socket's. */
|
|
52
|
+
function cameFromServer(error: object): boolean {
|
|
53
|
+
const { name, status, statusCode } = error as { name?: unknown; status?: unknown; statusCode?: unknown };
|
|
54
|
+
return typeof status === "number" || typeof statusCode === "number" || name === "ApiRequestError";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Whether a request failed before any answer came back. A caller's abort and
|
|
59
|
+
* a timeout are not: the first is on purpose, and the second reached a server
|
|
60
|
+
* that did not answer in time. Nor is anything the server answered, whatever
|
|
61
|
+
* its text or code says.
|
|
62
|
+
*/
|
|
63
|
+
export function isNetworkFailure(error: unknown): boolean {
|
|
64
|
+
if (typeof error === "string") return NO_CONNECTION_MESSAGES.has(error.trim());
|
|
65
|
+
for (let current = error, depth = 0; current && typeof current === "object" && depth < 4; depth += 1) {
|
|
66
|
+
if (current instanceof DataServiceUnreachableError) return true;
|
|
67
|
+
if (cameFromServer(current)) return false;
|
|
68
|
+
const { name, code, message } = current as { name?: unknown; code?: unknown; message?: unknown };
|
|
69
|
+
if (name === "AbortError" || name === "TimeoutError") return false;
|
|
70
|
+
if (typeof code === "string" && NO_CONNECTION_CODES.has(code)) return true;
|
|
71
|
+
if (typeof message === "string" && NO_CONNECTION_MESSAGES.has(message.trim())) return true;
|
|
72
|
+
// Node's fetch says only "fetch failed" and puts the socket's error in `cause`.
|
|
73
|
+
current = (current as { cause?: unknown }).cause;
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** A network failure as `DataServiceUnreachableError`; anything else as it was. */
|
|
79
|
+
export function asDataServiceFailure(error: unknown): unknown {
|
|
80
|
+
return isNetworkFailure(error) && !(error instanceof DataServiceUnreachableError)
|
|
81
|
+
? new DataServiceUnreachableError(error)
|
|
82
|
+
: error;
|
|
83
|
+
}
|