@gloom-sh/terminal 0.18.5 → 0.19.1
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/package.json +1 -1
- package/patches/electrobun@1.18.1.patch +163 -8
- package/src/api-client/app-attention.ts +3 -0
- package/src/api-client/beneficial-owners.ts +3 -0
- package/src/api-client/company-kpis.ts +3 -0
- package/src/api-client/cot.ts +6 -2
- package/src/api-client/credit-documents.ts +6 -0
- package/src/api-client/data.ts +19 -7
- package/src/api-client/equity-screener.ts +24 -0
- package/src/api-client/fund-facts.ts +45 -4
- package/src/api-client/hiring.ts +3 -0
- package/src/api-client/index.ts +15 -0
- package/src/api-client/ipo.ts +24 -1
- package/src/api-client/market-discovery.ts +10 -0
- package/src/api-client/market-movers.ts +7 -0
- package/src/api-client/members.ts +1 -1
- package/src/api-client/mna.ts +3 -0
- package/src/api-client/paths.ts +9 -1
- package/src/api-client/perps.ts +43 -0
- package/src/api-client/research-activity.ts +3 -2
- package/src/api-client/roadmap.ts +85 -0
- package/src/api-client/types.ts +82 -2
- package/src/app/pane-runtime/plugin-bindings.ts +9 -5
- package/src/app/runtime/broker-import.ts +0 -2
- package/src/app/runtime/plugin-bindings.ts +73 -56
- package/src/architecture/core-builtin-allowlist.json +2 -2
- package/src/architecture/pane-tabs-allowlist.json +3 -0
- package/src/architecture/ttl-caches-allowlist.json +19 -0
- package/src/brokers/sync-broker-instance.ts +2 -8
- package/src/capabilities/chart-series.ts +1 -1
- package/src/cli/commands/crypto-hints.ts +40 -24
- package/src/cli/commands/market.ts +107 -38
- package/src/cli/commands/news-search.ts +22 -0
- package/src/cli/commands/options-chain.ts +48 -7
- package/src/cli/commands/options-leaps.ts +9 -3
- package/src/cli/commands/overview.ts +147 -32
- package/src/cli/commands/search.ts +21 -1
- package/src/cli/commands/themes.ts +11 -2
- package/src/cli/commands/ticker.ts +87 -36
- package/src/cli/company-name-hint.ts +41 -0
- package/src/cli/earnings-calendar.ts +1 -1
- package/src/cli/errors.ts +25 -2
- package/src/cli/glossary.ts +31 -2
- package/src/cli/history-rows.ts +57 -9
- package/src/cli/index-roots.ts +0 -7
- package/src/cli/index.ts +2 -0
- package/src/cli/listing-arg.ts +235 -60
- package/src/cli/output-file.ts +68 -0
- package/src/cli/pane-functions/capabilities.ts +4 -0
- package/src/cli/pane-functions/catalog.ts +80 -7
- package/src/cli/pane-functions/discovery.ts +21 -1
- package/src/cli/pane-functions/dom.ts +13 -3
- package/src/cli/pane-functions/freshness.ts +93 -4
- package/src/cli/pane-functions/function-help.ts +20 -10
- package/src/cli/pane-functions/headless.ts +17 -7
- package/src/cli/pane-functions/index.ts +54 -16
- package/src/cli/pane-functions/market-session.ts +66 -4
- package/src/cli/pane-functions/options.ts +19 -1
- package/src/cli/pane-functions/resolver.ts +19 -8
- package/src/cli/pane-functions/screenshot-assessment.ts +6 -4
- package/src/cli/pane-functions/screenshot-types.ts +5 -0
- package/src/cli/quote-answer.ts +22 -11
- package/src/cli/saved-copy-persistence.ts +88 -0
- package/src/cli/ticker-resolution.ts +3 -2
- package/src/components/chart/composite/composite-chart.tsx +4 -0
- package/src/components/chart/composite/interactions.ts +6 -0
- package/src/components/chart/composite/legend.tsx +45 -7
- package/src/components/chart/composite/panel-gestures.ts +33 -0
- package/src/components/chart/composite/panel-surface.tsx +52 -3
- package/src/components/chart/composite/rasterizer.ts +24 -13
- package/src/components/chart/composite/scene.ts +39 -4
- package/src/components/chart/composite/series-cues.ts +14 -0
- package/src/components/chart/composite/text-renderer.ts +9 -2
- package/src/components/chart/composite/tool-catalog.ts +36 -0
- package/src/components/chart/composite/tools.ts +203 -44
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +11 -4
- package/src/components/command-bar/assist/inventory.ts +2 -1
- package/src/components/command-bar/commands/direct/index.ts +28 -13
- package/src/components/command-bar/list/model.ts +5 -0
- package/src/components/command-bar/pane-templates/items.ts +3 -2
- package/src/components/command-bar/routes/root/runtime.ts +6 -7
- package/src/components/command-bar/selection-runtime.ts +52 -3
- package/src/components/command-bar/surface/index.tsx +2 -0
- package/src/components/command-bar/workflow/collection-actions.ts +3 -3
- package/src/components/layout/pane/capture-stamp.ts +2 -2
- package/src/components/layout/pane/footer/index.tsx +22 -6
- package/src/components/layout/pane/footer/model.ts +83 -15
- package/src/components/layout/pane/status-footer.ts +35 -2
- package/src/components/layout/status-widget-space.ts +9 -0
- package/src/components/onboarding/onboarding-wizard.tsx +4 -1
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +12 -7
- package/src/components/onboarding/wizard-broker-sync.ts +0 -1
- package/src/components/onboarding/wizard-positions.ts +3 -3
- package/src/components/ticker/list-table-view.tsx +8 -21
- package/src/components/ui/choice-dialog.tsx +23 -18
- package/src/components/ui/choice-groups.ts +18 -0
- package/src/components/ui/data-table/opentui/index.tsx +9 -7
- package/src/components/ui/data-table/opentui/model.ts +26 -1
- package/src/components/ui/data-table/types.ts +2 -0
- package/src/components/ui/display.tsx +18 -3
- package/src/components/ui/icon.tsx +4 -1
- package/src/components/ui/list-view.tsx +8 -4
- package/src/components/ui/query-bar-keys.tsx +2 -0
- package/src/components/ui/query-bar.tsx +1 -0
- package/src/components/ui/select-button.tsx +5 -1
- package/src/components/ui/select-field.tsx +1 -0
- package/src/components/ui/table-layout.ts +8 -5
- package/src/core/app-runtime.ts +2 -0
- package/src/core/app-services.ts +2 -2
- package/src/data/config/chart-settings.ts +1 -1
- package/src/data/json-ticker-repository.ts +17 -8
- package/src/data/plugin-cache.ts +5 -3
- package/src/data/saved-copies.ts +8 -0
- package/src/data/ticker-repository.ts +16 -9
- package/src/data/ticker-writes.ts +81 -0
- package/src/data/ttl-cache.ts +165 -0
- package/src/docs/snapshot.json +103 -142
- package/src/i18n/es.ts +20 -6
- package/src/i18n/ja.ts +20 -6
- package/src/i18n/ko.ts +20 -6
- package/src/i18n/zh-cn.ts +20 -6
- package/src/i18n/zh-tw.ts +20 -6
- package/src/market-data/depositary-pair.ts +27 -3
- package/src/market-data/fund-facts.ts +50 -0
- package/src/market-data/market/change-basis.ts +16 -3
- package/src/market-data/market/format.ts +25 -0
- package/src/market-data/market/freshness.ts +2 -1
- package/src/market-data/options-alternatives.ts +81 -4
- package/src/market-data/quotes/metadata.ts +7 -0
- package/src/news/aggregator.ts +119 -9
- package/src/news/cloud-session.ts +21 -0
- package/src/news/hooks.ts +1 -0
- package/src/news/news-model.ts +1 -0
- package/src/news/types.ts +17 -0
- package/src/plugins/builtin/alerts/alert-engine.ts +20 -1
- package/src/plugins/builtin/alerts/alert-log.ts +33 -0
- package/src/plugins/builtin/alerts/calendar-events.ts +10 -4
- package/src/plugins/builtin/alerts/cli-forms.ts +216 -0
- package/src/plugins/builtin/alerts/cli.ts +362 -80
- package/src/plugins/builtin/alerts/command.ts +25 -1
- package/src/plugins/builtin/alerts/event-rows.ts +24 -3
- package/src/plugins/builtin/alerts/events-pane.tsx +34 -10
- package/src/plugins/builtin/alerts/fired-log.ts +73 -9
- package/src/plugins/builtin/alerts/format.ts +75 -5
- package/src/plugins/builtin/alerts/headless.ts +34 -12
- package/src/plugins/builtin/alerts/history-rows.ts +3 -2
- package/src/plugins/builtin/alerts/history.ts +1 -1
- package/src/plugins/builtin/alerts/index.tsx +79 -16
- package/src/plugins/builtin/alerts/metric-command.ts +77 -4
- package/src/plugins/builtin/alerts/metric-data.ts +54 -13
- package/src/plugins/builtin/alerts/metric-model.ts +163 -14
- package/src/plugins/builtin/alerts/metric-parity-fixture.json +1 -1
- package/src/plugins/builtin/alerts/pane.tsx +61 -23
- package/src/plugins/builtin/alerts/quotes.ts +6 -0
- package/src/plugins/builtin/alerts/storage.ts +12 -8
- package/src/plugins/builtin/alerts/types.ts +4 -0
- package/src/plugins/builtin/analytics/index.tsx +2 -1
- package/src/plugins/builtin/analytics/risk-client.ts +16 -5
- package/src/plugins/builtin/analytics/risk-fx.ts +70 -15
- package/src/plugins/builtin/analytics/risk-headless.ts +27 -0
- package/src/plugins/builtin/analytics/risk-model.ts +55 -9
- package/src/plugins/builtin/analytics/risk-pane.tsx +8 -2
- package/src/plugins/builtin/attention/index.tsx +2 -1
- package/src/plugins/builtin/attention/listing.ts +14 -0
- package/src/plugins/builtin/broker-manager/index.tsx +7 -3
- package/src/plugins/builtin/buildout/cells.tsx +12 -4
- package/src/plugins/builtin/buildout/format.ts +38 -0
- package/src/plugins/builtin/buildout/model/normalizers.ts +36 -1
- package/src/plugins/builtin/buildout/pane/index.tsx +4 -1
- package/src/plugins/builtin/buildout/table-model.ts +23 -2
- package/src/plugins/builtin/builtin-plugin-meta.ts +6 -2
- package/src/plugins/builtin/cds/client.ts +142 -30
- package/src/plugins/builtin/cds/headless.ts +35 -8
- package/src/plugins/builtin/cds/model.ts +145 -18
- package/src/plugins/builtin/cds/pane.tsx +16 -5
- package/src/plugins/builtin/changelog/index.tsx +9 -6
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +3 -0
- package/src/plugins/builtin/chart-composer/cli-options.ts +4 -0
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +7 -0
- package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -2
- package/src/plugins/builtin/chart-composer/follow-binding.ts +14 -2
- package/src/plugins/builtin/chart-composer/headless-schema.ts +7 -1
- package/src/plugins/builtin/chart-composer/headless.ts +6 -1
- package/src/plugins/builtin/chart-composer/index.tsx +5 -6
- package/src/plugins/builtin/chart-composer/pane.tsx +37 -8
- package/src/plugins/builtin/chart-composer/settings.ts +27 -0
- package/src/plugins/builtin/chat/content/command-suggestions.ts +1 -0
- package/src/plugins/builtin/chat/controller/index.ts +5 -1
- package/src/plugins/builtin/chat/controller/notifications.ts +33 -3
- package/src/plugins/builtin/chat/controller/state.ts +25 -2
- package/src/plugins/builtin/chat/controller/unread-people.ts +89 -23
- package/src/plugins/builtin/chat/controller/utils.ts +7 -2
- package/src/plugins/builtin/chat/pane-links/commands.ts +7 -1
- package/src/plugins/builtin/chat/status-preview.ts +79 -0
- package/src/plugins/builtin/chat/status-widget.tsx +147 -10
- package/src/plugins/builtin/chat/unread-badge.ts +51 -10
- package/src/plugins/builtin/clinical-trials/client.ts +49 -4
- package/src/plugins/builtin/clinical-trials/model.ts +86 -31
- package/src/plugins/builtin/clinical-trials/pane.tsx +61 -49
- package/src/plugins/builtin/clinical-trials/sponsor-listing.ts +90 -0
- package/src/plugins/builtin/clinical-trials/sponsor-tickers.ts +95 -15
- package/src/plugins/builtin/clinical-trials/trial-pages.ts +50 -0
- package/src/plugins/builtin/cloud/askg/manifest.ts +2 -0
- package/src/plugins/builtin/company-attention/building.tsx +5 -1
- package/src/plugins/builtin/company-attention/client.ts +8 -9
- package/src/plugins/builtin/company-attention/evidence.ts +4 -1
- package/src/plugins/builtin/company-attention/headless.ts +2 -1
- package/src/plugins/builtin/company-attention/moves.tsx +5 -1
- package/src/plugins/builtin/company-attention/pane.tsx +12 -2
- package/src/plugins/builtin/company-attention/signals.tsx +5 -1
- package/src/plugins/builtin/company-kpis/headless.ts +8 -3
- package/src/plugins/builtin/company-kpis/model.ts +73 -5
- package/src/plugins/builtin/company-kpis/pane.tsx +15 -7
- package/src/plugins/builtin/composite-plugins.ts +2 -1
- package/src/plugins/builtin/correlation/headless.ts +13 -5
- package/src/plugins/builtin/correlation/history.ts +22 -0
- package/src/plugins/builtin/cot/client.ts +22 -18
- package/src/plugins/builtin/cot/headless.ts +15 -10
- package/src/plugins/builtin/cot/model.ts +14 -1
- package/src/plugins/builtin/cot/pane.tsx +22 -14
- package/src/plugins/builtin/credit-boards/client.ts +6 -10
- package/src/plugins/builtin/credit-conditions/headless.ts +8 -2
- package/src/plugins/builtin/credit-conditions/index.tsx +5 -1
- package/src/plugins/builtin/credit-conditions/model.ts +4 -0
- package/src/plugins/builtin/credit-conditions/series.ts +3 -1
- package/src/plugins/builtin/credit-documents/detail.tsx +2 -2
- package/src/plugins/builtin/credit-documents/export.ts +173 -0
- package/src/plugins/builtin/credit-documents/headless.ts +10 -10
- package/src/plugins/builtin/credit-documents/model.ts +104 -14
- package/src/plugins/builtin/credit-documents/pane.tsx +12 -5
- package/src/plugins/builtin/custom-view/sources.ts +2 -0
- package/src/plugins/builtin/dividend-yield/client.ts +131 -23
- package/src/plugins/builtin/dividend-yield/headless.ts +44 -16
- package/src/plugins/builtin/dividend-yield/model.ts +8 -5
- package/src/plugins/builtin/dividend-yield/pane.tsx +38 -13
- package/src/plugins/builtin/dividend-yield/ranking.ts +37 -14
- package/src/plugins/builtin/dividend-yield/types.ts +20 -2
- package/src/plugins/builtin/dividend-yield/view.ts +30 -2
- package/src/plugins/builtin/docs/targets.ts +5 -1
- package/src/plugins/builtin/doe/headless.ts +3 -2
- package/src/plugins/builtin/doe/pane.tsx +13 -3
- package/src/plugins/builtin/earnings/board-model.ts +16 -15
- package/src/plugins/builtin/earnings/board.tsx +62 -71
- package/src/plugins/builtin/earnings/headless.ts +40 -4
- package/src/plugins/builtin/earnings/scope.ts +31 -43
- package/src/plugins/builtin/earnings-calls/calendar.tsx +2 -2
- package/src/plugins/builtin/earnings-calls/data.ts +18 -6
- package/src/plugins/builtin/earnings-calls/format.ts +31 -2
- package/src/plugins/builtin/earnings-calls/headless.ts +20 -5
- package/src/plugins/builtin/earnings-calls/model.ts +6 -1
- package/src/plugins/builtin/earnings-calls/pane.tsx +12 -4
- package/src/plugins/builtin/econ/calendar-model.ts +48 -1
- package/src/plugins/builtin/econ/calendar-source.ts +4 -2
- package/src/plugins/builtin/econ/detail-view.tsx +2 -2
- package/src/plugins/builtin/econ/figures.ts +48 -0
- package/src/plugins/builtin/econ/index.tsx +14 -5
- package/src/plugins/builtin/econ/print-watch.ts +3 -1
- package/src/plugins/builtin/econ/types.ts +2 -0
- package/src/plugins/builtin/econ-statistics/client.ts +11 -0
- package/src/plugins/builtin/econ-statistics/defs.ts +6 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +16 -6
- package/src/plugins/builtin/econ-statistics/pane.tsx +8 -4
- package/src/plugins/builtin/econ-statistics/stats.ts +39 -9
- package/src/plugins/builtin/equity-screener/categories.ts +179 -0
- package/src/plugins/builtin/equity-screener/client.ts +4 -2
- package/src/plugins/builtin/equity-screener/headless.ts +144 -13
- package/src/plugins/builtin/equity-screener/ideas.ts +49 -0
- package/src/plugins/builtin/equity-screener/model.ts +99 -10
- package/src/plugins/builtin/equity-screener/pane.tsx +68 -13
- package/src/plugins/builtin/fixed-income/pane.tsx +2 -1
- package/src/plugins/builtin/futures/use-board-terms.ts +42 -28
- package/src/plugins/builtin/futures/use-front-returns.ts +45 -28
- package/src/plugins/builtin/fx-matrix/client.ts +6 -3
- package/src/plugins/builtin/fx-matrix/headless.ts +1 -1
- package/src/plugins/builtin/fx-matrix/index.tsx +4 -2
- package/src/plugins/builtin/fx-matrix/live-legs.ts +42 -3
- package/src/plugins/builtin/gpu/headless.ts +8 -2
- package/src/plugins/builtin/help/function-index.ts +4 -1
- package/src/plugins/builtin/help/index.tsx +62 -59
- package/src/plugins/builtin/help/shortcut-model.ts +1 -1
- package/src/plugins/builtin/help/shortcut-table.tsx +5 -6
- package/src/plugins/builtin/help/table-cells.tsx +13 -2
- package/src/plugins/builtin/holders/beneficial-client.ts +5 -1
- package/src/plugins/builtin/holders/beneficial-view.tsx +3 -0
- package/src/plugins/builtin/holders/fund-holders.ts +51 -0
- package/src/plugins/builtin/holders/headless.ts +22 -3
- package/src/plugins/builtin/holders/pane.tsx +3 -0
- package/src/plugins/builtin/holders/report-rows.ts +4 -1
- package/src/plugins/builtin/insider/headless.ts +2 -2
- package/src/plugins/builtin/ipo-calendar/client.ts +18 -2
- package/src/plugins/builtin/ipo-calendar/headless.ts +75 -11
- package/src/plugins/builtin/ipo-calendar/listing-ipo.ts +160 -0
- package/src/plugins/builtin/ipo-calendar/model.ts +98 -2
- package/src/plugins/builtin/iv-history/client.ts +52 -11
- package/src/plugins/builtin/iv-history/format.ts +36 -23
- package/src/plugins/builtin/iv-history/headless.ts +33 -18
- package/src/plugins/builtin/iv-history/index.tsx +2 -2
- package/src/plugins/builtin/iv-history/model.ts +163 -27
- package/src/plugins/builtin/iv-history/pane.tsx +10 -6
- package/src/plugins/builtin/iv-history/screen-pane.tsx +22 -15
- package/src/plugins/builtin/iv-history/universe.ts +5 -1
- package/src/plugins/builtin/jobs/client.ts +25 -29
- package/src/plugins/builtin/kelly-sizer/model.ts +12 -8
- package/src/plugins/builtin/kelly-sizer/pane.tsx +9 -9
- package/src/plugins/builtin/kelly-sizer/sections.tsx +19 -10
- package/src/plugins/builtin/kelly-sizer/types.ts +10 -4
- package/src/plugins/builtin/macro-day/headless.ts +12 -5
- package/src/plugins/builtin/macro-day/index.tsx +1 -1
- package/src/plugins/builtin/macro-day/model.ts +39 -5
- package/src/plugins/builtin/macro-day/pane.tsx +27 -19
- package/src/plugins/builtin/macro-day/release-table.ts +2 -2
- package/src/plugins/builtin/market-heatmap/data.ts +8 -33
- package/src/plugins/builtin/market-movers/client.ts +27 -7
- package/src/plugins/builtin/market-movers/headless.ts +34 -12
- package/src/plugins/builtin/market-movers/index.tsx +26 -14
- package/src/plugins/builtin/market-movers/min-float.ts +74 -0
- package/src/plugins/builtin/market-movers/model.ts +4 -1
- package/src/plugins/builtin/market-movers/screener.ts +22 -4
- package/src/plugins/builtin/market-movers/session-body.tsx +13 -8
- package/src/plugins/builtin/market-movers/session-table.ts +4 -3
- package/src/plugins/builtin/market-movers/table.ts +17 -5
- package/src/plugins/builtin/members/breadth-pane.tsx +2 -1
- package/src/plugins/builtin/mna/headless.ts +2 -0
- package/src/plugins/builtin/mna/pane.tsx +3 -1
- package/src/plugins/builtin/news/headless.ts +3 -1
- package/src/plugins/builtin/news/index.tsx +4 -0
- package/src/plugins/builtin/news/wire/categories.ts +19 -3
- package/src/plugins/builtin/news/wire/industry-pane.tsx +1 -0
- package/src/plugins/builtin/news/wire/news/footer.ts +31 -5
- package/src/plugins/builtin/news/wire/news/preset-pane.tsx +6 -1
- package/src/plugins/builtin/news/wire/news/table.tsx +2 -2
- package/src/plugins/builtin/openfda/client.ts +14 -2
- package/src/plugins/builtin/openfda/index.tsx +3 -2
- package/src/plugins/builtin/openfda/model.ts +9 -0
- package/src/plugins/builtin/openfda/pane.tsx +42 -6
- package/src/plugins/builtin/options/analytics.ts +29 -5
- package/src/plugins/builtin/options/enrichment.ts +17 -5
- package/src/plugins/builtin/options/table.ts +5 -2
- package/src/plugins/builtin/options/types.ts +2 -0
- package/src/plugins/builtin/options/view.tsx +17 -4
- package/src/plugins/builtin/options-positioning/client.ts +11 -0
- package/src/plugins/builtin/options-positioning/headless.ts +21 -8
- package/src/plugins/builtin/options-positioning/index.tsx +1 -1
- package/src/plugins/builtin/options-positioning/model.ts +78 -9
- package/src/plugins/builtin/options-positioning/pane.tsx +21 -6
- package/src/plugins/builtin/options-scenario/client.ts +116 -47
- package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +142 -10
- package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +206 -55
- package/src/plugins/builtin/options-scenario/csp-screen.ts +63 -23
- package/src/plugins/builtin/options-scenario/csp.ts +8 -2
- package/src/plugins/builtin/options-scenario/index.tsx +9 -7
- package/src/plugins/builtin/options-scenario/strategy-screen.ts +532 -0
- package/src/plugins/builtin/pe-band/model.ts +12 -49
- package/src/plugins/builtin/perps/cascade-tabs.tsx +161 -0
- package/src/plugins/builtin/perps/cascade.ts +236 -0
- package/src/plugins/builtin/perps/client.ts +56 -2
- package/src/plugins/builtin/perps/headless.ts +65 -9
- package/src/plugins/builtin/perps/index.tsx +7 -5
- package/src/plugins/builtin/perps/model.ts +18 -4
- package/src/plugins/builtin/perps/pane.tsx +19 -22
- package/src/plugins/builtin/perps/status-line.ts +25 -0
- package/src/plugins/builtin/plugin-module.ts +5 -1
- package/src/plugins/builtin/portfolio-list/cached-account.ts +3 -1
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +2 -8
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +4 -4
- package/src/plugins/builtin/portfolio-list/cli/render.ts +7 -5
- package/src/plugins/builtin/portfolio-list/pane/futures-front.ts +40 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +6 -7
- package/src/plugins/builtin/portfolio-list/pane/streaming.ts +5 -2
- package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +3 -2
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +0 -14
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +5 -2
- package/src/plugins/builtin/portfolio-list/table.tsx +15 -9
- package/src/plugins/builtin/primary-dealers/client.ts +13 -38
- package/src/plugins/builtin/realized-vol/client.ts +13 -5
- package/src/plugins/builtin/realized-vol/evidence.ts +29 -4
- package/src/plugins/builtin/realized-vol/headless.ts +8 -4
- package/src/plugins/builtin/realized-vol/index.tsx +2 -2
- package/src/plugins/builtin/realized-vol/model.ts +37 -6
- package/src/plugins/builtin/realized-vol/pane.tsx +11 -9
- package/src/plugins/builtin/relative-rotation/client.ts +18 -4
- package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
- package/src/plugins/builtin/relative-rotation/index.tsx +2 -1
- package/src/plugins/builtin/relative-rotation/model.ts +16 -40
- package/src/plugins/builtin/relative-rotation/pane.tsx +3 -2
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +3 -2
- package/src/plugins/builtin/research/event-model.ts +40 -12
- package/src/plugins/builtin/research/headless.ts +1 -1
- package/src/plugins/builtin/research/index.tsx +7 -3
- package/src/plugins/builtin/research/relative-valuation-headless.ts +13 -26
- package/src/plugins/builtin/research/relative-valuation-model.ts +31 -3
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +59 -20
- package/src/plugins/builtin/research/relative-valuation-peers.ts +217 -20
- package/src/plugins/builtin/research/relative-valuation-settings.ts +44 -0
- package/src/plugins/builtin/reverse-dcf/headless.ts +5 -3
- package/src/plugins/builtin/reverse-dcf/model.ts +61 -6
- package/src/plugins/builtin/reverse-dcf/pane.tsx +7 -4
- package/src/plugins/builtin/risk-factors/data.ts +4 -2
- package/src/plugins/builtin/risk-factors/headless.ts +5 -2
- package/src/plugins/builtin/roadmap/index.tsx +28 -0
- package/src/plugins/builtin/roadmap/model.ts +67 -0
- package/src/plugins/builtin/roadmap/pane.tsx +244 -0
- package/src/plugins/builtin/scanner/flow-model.ts +50 -4
- package/src/plugins/builtin/scanner/flow-pane.tsx +367 -65
- package/src/plugins/builtin/scanner/flow-session.ts +146 -0
- package/src/plugins/builtin/scanner/headless.ts +204 -35
- package/src/plugins/builtin/scanner/index.ts +16 -5
- package/src/plugins/builtin/scanner/live-headless.ts +48 -5
- package/src/plugins/builtin/scanner/live-model.ts +11 -0
- package/src/plugins/builtin/scanner/live-pane.tsx +3 -3
- package/src/plugins/builtin/scanner/lock-note.ts +3 -2
- package/src/plugins/builtin/seasonality/headless.ts +10 -1
- package/src/plugins/builtin/sec/fund-facts-view.tsx +5 -2
- package/src/plugins/builtin/sec/fund-facts.ts +116 -34
- package/src/plugins/builtin/sec/headless.ts +4 -2
- package/src/plugins/builtin/sec/index.tsx +3 -0
- package/src/plugins/builtin/series-inventory.ts +2 -0
- package/src/plugins/builtin/shared/cloud-resource.ts +16 -7
- package/src/plugins/builtin/shared/cloud-upgrade.ts +4 -3
- package/src/plugins/builtin/shared/earnings-calendar.ts +6 -2
- package/src/plugins/builtin/shared/earnings-report.ts +2 -2
- package/src/plugins/builtin/shared/headless-market-data.ts +2 -2
- package/src/plugins/builtin/shared/job-posting.ts +1 -0
- package/src/plugins/builtin/shared/members-menu.tsx +3 -2
- package/src/plugins/builtin/shared/pro-lock-note.ts +12 -12
- package/src/plugins/builtin/shared/report-freshness.ts +11 -2
- package/src/plugins/builtin/shared/research-cells.tsx +1 -1
- package/src/plugins/builtin/shared/series-cache.ts +4 -4
- package/src/plugins/builtin/shared/ticker-choice.tsx +2 -1
- package/src/plugins/builtin/shared/ticker-company.ts +77 -0
- package/src/plugins/builtin/shared/use-quote-board.ts +2 -1
- package/src/plugins/builtin/shared/volatility/live-session.ts +34 -8
- package/src/plugins/builtin/shared/volatility/pricing.ts +19 -0
- package/src/plugins/builtin/shared/wall-view-lifecycle.ts +3 -1
- package/src/plugins/builtin/themes/model.ts +16 -7
- package/src/plugins/builtin/themes/pane.tsx +5 -5
- package/src/plugins/builtin/thirteenf/api.ts +12 -1
- package/src/plugins/builtin/thirteenf/data.ts +7 -7
- package/src/plugins/builtin/thirteenf/headless.ts +31 -4
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +43 -18
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +3 -2
- package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +62 -0
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +83 -46
- package/src/plugins/builtin/ticker-detail/headless.ts +31 -16
- package/src/plugins/builtin/ticker-detail/overview/model.ts +11 -3
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +2 -1
- package/src/plugins/builtin/ticker-detail/pane.tsx +14 -8
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -1
- package/src/plugins/builtin/ticker-detail/settings.ts +1 -0
- package/src/plugins/builtin/time-sales/pane.tsx +31 -19
- package/src/plugins/builtin/treasury-auctions/headless.ts +21 -12
- package/src/plugins/builtin/treasury-auctions/pane.tsx +9 -3
- package/src/plugins/builtin/treasury-daily/client.ts +41 -5
- package/src/plugins/builtin/treasury-daily/headless.ts +2 -2
- package/src/plugins/builtin/treasury-daily/index.tsx +1 -1
- package/src/plugins/builtin/treasury-daily/model.ts +50 -3
- package/src/plugins/builtin/treasury-daily/pane.tsx +81 -2
- package/src/plugins/builtin/vol-surface/client.ts +3 -13
- package/src/plugins/builtin/vol-surface/headless.ts +3 -3
- package/src/plugins/builtin/vol-surface/index.tsx +1 -1
- package/src/plugins/builtin/vol-surface/pane.tsx +7 -5
- package/src/plugins/builtin/volatility/index.tsx +2 -2
- package/src/plugins/builtin/volatility/pane.tsx +7 -4
- package/src/plugins/builtin/world-venue-map/headless.ts +3 -3
- package/src/plugins/builtin/yield-curve/client.ts +61 -1
- package/src/plugins/builtin/yield-curve/headless.ts +9 -6
- package/src/plugins/builtin/yield-curve/index.tsx +34 -10
- package/src/plugins/builtin/yield-curve/swaps.tsx +9 -5
- package/src/plugins/catalog-browser.ts +2 -1
- package/src/plugins/catalog-manifest.ts +2 -1
- package/src/plugins/host-link.ts +1 -1
- package/src/plugins/marketplace/model.ts +18 -5
- package/src/portfolio/column-values.ts +11 -7
- package/src/portfolio/futures-positions.ts +6 -3
- package/src/portfolio/position-quantity.ts +15 -9
- package/src/remote/resources.ts +2 -1
- package/src/renderers/dom/data-table/row.tsx +26 -0
- package/src/renderers/dom/desktop/icons.tsx +7 -0
- package/src/renderers/dom/desktop/list-view.tsx +13 -10
- package/src/renderers/dom/desktop/query-bar.tsx +4 -2
- package/src/renderers/dom/desktop/select-field.tsx +4 -2
- package/src/renderers/dom/host/chart-surface.tsx +21 -0
- package/src/renderers/electrobun/bun/desktop/app-name.ts +3 -3
- package/src/renderers/electrobun/bun/desktop/backend.ts +21 -10
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +15 -0
- package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -0
- package/src/renderers/electrobun/bun/desktop/installer-folder.ts +731 -0
- package/src/renderers/electrobun/bun/desktop/relaunch.ts +102 -10
- package/src/renderers/electrobun/bun/desktop/update.ts +115 -14
- package/src/renderers/electrobun/bun/desktop/view-ids.ts +52 -0
- package/src/renderers/electrobun/bun/desktop/windows-script.ts +92 -0
- package/src/renderers/electrobun/bun/index.ts +26 -2
- package/src/renderers/electrobun/bun/window/create.ts +43 -4
- package/src/renderers/electrobun/bun/window/events.ts +20 -0
- package/src/renderers/electrobun/bun/window/windows-custom-chrome.ts +9 -2
- package/src/renderers/electrobun/bun/window/windows-native.ts +78 -0
- package/src/renderers/electrobun/bun/window/windows-quit.ts +57 -0
- package/src/renderers/electrobun/shared/app-name.ts +13 -0
- package/src/renderers/electrobun/shared/protocol.ts +12 -0
- package/src/renderers/electrobun/view/backend-rpc.ts +6 -0
- package/src/renderers/electrobun/view/main.tsx +24 -1
- package/src/renderers/electrobun/view/news-source.ts +5 -1
- package/src/renderers/electrobun/view/remote/ticker-repository.ts +14 -7
- package/src/renderers/electrobun/view/ui-host.tsx +8 -0
- package/src/renderers/electrobun/view/view-ids.ts +85 -0
- package/src/renderers/opentui/start.tsx +5 -0
- package/src/series/registry.ts +1 -0
- package/src/series/types.ts +6 -0
- package/src/series/validate.ts +1 -0
- package/src/sources/gloomberb-cloud/fred-series.ts +3 -1
- package/src/sources/gloomberb-cloud/index.ts +43 -8
- package/src/sources/gloomberb-cloud/news.ts +47 -7
- package/src/sources/provider-router/financials.ts +15 -3
- package/src/sources/provider-router/index.ts +8 -5
- package/src/state/ticker-cleanup.ts +50 -0
- package/src/sync/controller.ts +4 -3
- package/src/sync/core-contributors.ts +90 -31
- package/src/telemetry/stall-reports-dom.ts +38 -0
- package/src/telemetry/stall-reports-node.ts +75 -0
- package/src/telemetry/stall-reports.ts +214 -0
- package/src/test-support/preload.ts +14 -0
- package/src/theme/themes.ts +10 -0
- package/src/tickers/company-name-listing.ts +53 -13
- package/src/tickers/company-name.ts +50 -4
- package/src/tickers/index-roots.ts +7 -0
- package/src/tickers/listing-fate.ts +2 -2
- package/src/tickers/listing-venues.ts +15 -3
- package/src/tickers/search/index.ts +6 -2
- package/src/tickers/search/ranking.ts +5 -1
- package/src/tickers/search/upsert.ts +13 -0
- package/src/tickers/terminal-codes.ts +19 -0
- package/src/tickers/ticker-changes.ts +8 -4
- package/src/time-series/alignment.ts +1 -1
- package/src/time-series/economic.ts +18 -4
- package/src/time-series/field-catalog.ts +1 -1
- package/src/time-series/filed-trailing-eps.ts +197 -0
- package/src/time-series/fundamentals.ts +44 -1
- package/src/time-series/ice-credit.ts +3 -0
- package/src/time-series/price-comparison.ts +30 -2
- package/src/time-series/resolve-context.ts +3 -1
- package/src/time-series/resolve.ts +56 -4
- package/src/time-series/session-bar.ts +11 -0
- package/src/time-series/spec.ts +3 -2
- package/src/time-series/studies.ts +8 -2
- package/src/time-series/total-return.ts +160 -0
- package/src/time-series/transforms.ts +2 -3
- package/src/time-series/types.ts +22 -1
- package/src/types/company-from.ts +40 -0
- package/src/types/data-provider.ts +7 -0
- package/src/types/financials.ts +59 -1
- package/src/types/headless.ts +27 -3
- package/src/types/news-source.ts +1 -0
- package/src/types/plugin.ts +9 -0
- package/src/ui/host.tsx +3 -0
- package/src/updater/failure.ts +4 -1
- package/src/utils/cli-output.ts +42 -1
- package/src/utils/crypto-pair.ts +165 -7
- package/src/utils/declared-dividends.ts +1 -1
- package/src/utils/forward-dividend.ts +2 -0
- package/src/utils/fundamentals.ts +60 -8
- package/src/utils/fx-market-hours.ts +26 -3
- package/src/utils/main-thread-stall.ts +35 -2
- package/src/utils/market-capitalization.ts +24 -1
- package/src/utils/price-history.ts +7 -1
- package/src/utils/shell-word.ts +8 -0
- package/src/utils/trailing-dividend.ts +53 -4
- package/src/version.ts +2 -2
- package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +0 -17
|
@@ -9,6 +9,8 @@ import type { CloudCdsHistoryParams } from "../../../api-client/paths";
|
|
|
9
9
|
import type { InstrumentSearchResult } from "../../../types/instrument";
|
|
10
10
|
import {
|
|
11
11
|
cdsReferenceEntity,
|
|
12
|
+
closestCoveredIssuers,
|
|
13
|
+
coveredIssuerMatch,
|
|
12
14
|
issuerNameOf,
|
|
13
15
|
normalizeCdsTrades,
|
|
14
16
|
spreadLevelsOf,
|
|
@@ -29,6 +31,12 @@ export interface CdsActivity {
|
|
|
29
31
|
query: string | null;
|
|
30
32
|
/** The issuer name actually sent, after any symbol lookup. */
|
|
31
33
|
issuer: string | null;
|
|
34
|
+
/**
|
|
35
|
+
* Set when a name matched no covered issuer and was sent as typed or as its
|
|
36
|
+
* listing's name: the covered issuers closest to what was typed, for the
|
|
37
|
+
* view to offer when the tape has nothing under it either.
|
|
38
|
+
*/
|
|
39
|
+
unmatched?: { nearest: string[] } | null;
|
|
32
40
|
/** How many days of the tape the trades cover. */
|
|
33
41
|
days: number;
|
|
34
42
|
trades: CdsTrade[];
|
|
@@ -38,61 +46,164 @@ export type CdsActivityLoader = (issuer: string | null) => Promise<CdsActivity>;
|
|
|
38
46
|
|
|
39
47
|
export type CdsFetch = (params: { issuer?: string; days?: number; limit?: number }) => Promise<CloudCdsResponse>;
|
|
40
48
|
export type InstrumentSearch = (query: string, limit?: number) => Promise<InstrumentSearchResult[]>;
|
|
49
|
+
/** The names of the issuers whose 5Y line has a level, as the tape spells them. */
|
|
50
|
+
export type CoveredIssuers = () => Promise<readonly string[]>;
|
|
41
51
|
|
|
42
52
|
/**
|
|
43
|
-
* A
|
|
44
|
-
*
|
|
45
|
-
* name it.
|
|
53
|
+
* A ticker as typed: symbol punctuation, no spaces, and no lowercase letter.
|
|
54
|
+
* `WHR` and `BRK.B` are tickers; `goodyear` and `Paramount` are names.
|
|
46
55
|
*/
|
|
47
|
-
const TICKER_LIKE = /^[A-
|
|
56
|
+
const TICKER_LIKE = /^[A-Z0-9][A-Z0-9.^:-]{0,11}$/;
|
|
48
57
|
const US_PRIMARY_EXCHANGES = new Set(["AMEX", "NASDAQ", "NYSE", "NYSEAMERICAN", "NYSEARCA"]);
|
|
49
58
|
|
|
59
|
+
/** The US venues besides the primary exchanges a listing can trade on: a receipt's or a delisted company's line. */
|
|
60
|
+
const US_OTHER_EXCHANGES = new Set(["ARCA", "BATS", "IEX", "OTC", "OTCMKTS", "PNK"]);
|
|
61
|
+
|
|
62
|
+
const listingExchange = (result: InstrumentSearchResult) => (result.primaryExchange || result.exchange).toUpperCase().replace(/[^A-Z]/g, "");
|
|
63
|
+
|
|
50
64
|
function isPrimaryUsCommonStock(result: InstrumentSearchResult): boolean {
|
|
51
|
-
const exchange = (result.primaryExchange || result.exchange).toUpperCase().replace(/[^A-Z]/g, "");
|
|
52
65
|
const type = result.type.toLowerCase();
|
|
53
66
|
return result.currency === "USD"
|
|
54
|
-
&& US_PRIMARY_EXCHANGES.has(
|
|
67
|
+
&& US_PRIMARY_EXCHANGES.has(listingExchange(result))
|
|
55
68
|
&& (type === "stk" || type === "equity" || type.includes("common stock"));
|
|
56
69
|
}
|
|
57
70
|
|
|
71
|
+
/** A line on a US venue in dollars (a receipt, a line over the counter); a listing abroad is not one. */
|
|
72
|
+
function isUsLine(result: InstrumentSearchResult): boolean {
|
|
73
|
+
const exchange = listingExchange(result);
|
|
74
|
+
return (!result.currency || result.currency === "USD") && (US_PRIMARY_EXCHANGES.has(exchange) || US_OTHER_EXCHANGES.has(exchange));
|
|
75
|
+
}
|
|
76
|
+
|
|
58
77
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* metadata to expand it, and its quote name never arrives for a fixed
|
|
64
|
-
* binding, so the shared instrument search is the only reliable expansion. A
|
|
65
|
-
* search outage falls back to the raw input rather than taking the CDS
|
|
66
|
-
* request down with it.
|
|
78
|
+
* Whether a listing carries what was typed: the words in its name or a name
|
|
79
|
+
* search knows it by (`searchAliases`), or a ticker it had (`formerIssuer`:
|
|
80
|
+
* BRCM on Broadcom Inc.). The first US hit for a name that does not is
|
|
81
|
+
* another company.
|
|
67
82
|
*/
|
|
83
|
+
function carriesTyped(result: InstrumentSearchResult, typed: string): boolean {
|
|
84
|
+
const symbol = typed.toUpperCase();
|
|
85
|
+
if (result.formerIssuer?.symbol?.toUpperCase() === symbol) return true;
|
|
86
|
+
return [result.name, ...result.searchAliases ?? [], result.formerIssuer?.name]
|
|
87
|
+
.some((name) => !!name && coveredIssuerMatch(typed, [name]) != null);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** The covered issuers' names, from the same request as their levels. */
|
|
91
|
+
export function coveredIssuersFrom(fetchLevels: CdsLevelsFetch): CoveredIssuers {
|
|
92
|
+
return async () => ((await fetchLevels()).levels ?? []).flatMap((level) => (typeof level.issuer === "string" ? [level.issuer] : []));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const defaultCoveredIssuers = coveredIssuersFrom(() => apiClient.getCloudCdsLevels());
|
|
96
|
+
|
|
97
|
+
async function searchOrNone(searchInstruments: InstrumentSearch, query: string): Promise<InstrumentSearchResult[]> {
|
|
98
|
+
try {
|
|
99
|
+
return await searchInstruments(query);
|
|
100
|
+
} catch {
|
|
101
|
+
// Intentional ignore: a search outage sends the name as typed instead of failing the CDS request.
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function coveredOrNone(coveredIssuers: CoveredIssuers): Promise<readonly string[]> {
|
|
107
|
+
try {
|
|
108
|
+
return await coveredIssuers();
|
|
109
|
+
} catch {
|
|
110
|
+
// Intentional ignore: without the covered list the name goes on to the listing and the tape.
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
interface CdsIssuerResolution {
|
|
116
|
+
/** The name the tape is asked for. */
|
|
117
|
+
issuer: string;
|
|
118
|
+
/** Set when a name matched no covered issuer; see `CdsActivity.unmatched`. */
|
|
119
|
+
unmatched: { nearest: string[] } | null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* The backend matches DTCC issuer names, so what was typed has to become one.
|
|
124
|
+
*
|
|
125
|
+
* Any one-word input, whatever its case (`CHTR`, `chtr`), is first looked up
|
|
126
|
+
* among the tickers whose debt sits with another entity: CHTR is CCO
|
|
127
|
+
* Holdings, LLC.
|
|
128
|
+
*
|
|
129
|
+
* A ticker (`WHR`) becomes the listed company's name without its share class
|
|
130
|
+
* ("Alphabet Inc.", not "Alphabet Inc. Class A Common Stock"): its primary US
|
|
131
|
+
* common stock where exchanges reuse the symbol, else its US line. An
|
|
132
|
+
* untracked symbol has no local metadata to expand it, and its quote name
|
|
133
|
+
* never arrives for a fixed binding, so the shared instrument search is the
|
|
134
|
+
* only reliable expansion.
|
|
135
|
+
*
|
|
136
|
+
* Then the names of the covered issuers (`goodyear`, `GOODYEAR`, `paramount `
|
|
137
|
+
* are The Goodyear Tire & Rubber Company and Paramount Global), by words of
|
|
138
|
+
* three letters or more: `f` and `ge` go to the symbol they are. Only then a
|
|
139
|
+
* listing abroad with that exact symbol, and only when it names a covered
|
|
140
|
+
* issuer: Goodyear India, the first hit for `goodyear`, is no CDS name. Last,
|
|
141
|
+
* the primary US common stock with the symbol, or the first one whose name
|
|
142
|
+
* carries what was typed. Nothing matched, the input goes to the tape as
|
|
143
|
+
* typed, with the covered issuers closest to it.
|
|
144
|
+
*
|
|
145
|
+
* A longer name in capitals and lowercase is already a company name and is
|
|
146
|
+
* sent as written. A search outage falls back to the raw input rather than
|
|
147
|
+
* taking the CDS request down with it.
|
|
148
|
+
*/
|
|
149
|
+
async function resolveCdsIssuer(
|
|
150
|
+
query: string,
|
|
151
|
+
searchInstruments: InstrumentSearch,
|
|
152
|
+
coveredIssuers: CoveredIssuers = defaultCoveredIssuers,
|
|
153
|
+
): Promise<CdsIssuerResolution> {
|
|
154
|
+
const ticker = TICKER_LIKE.test(query);
|
|
155
|
+
const oneWord = !/\s/.test(query);
|
|
156
|
+
if (!oneWord && query !== query.toLowerCase()) return { issuer: issuerNameOf(query), unmatched: null };
|
|
157
|
+
const referenceEntity = oneWord ? cdsReferenceEntity(query) : null;
|
|
158
|
+
if (referenceEntity) return { issuer: referenceEntity, unmatched: null };
|
|
159
|
+
const symbol = query.toUpperCase();
|
|
160
|
+
let results: InstrumentSearchResult[] | null = null;
|
|
161
|
+
let abroad: InstrumentSearchResult | undefined;
|
|
162
|
+
if (ticker) {
|
|
163
|
+
results = await searchOrNone(searchInstruments, query);
|
|
164
|
+
const exactMatches = results.filter((result) => result.symbol.toUpperCase() === symbol);
|
|
165
|
+
const name = (exactMatches.find(isPrimaryUsCommonStock) ?? exactMatches.find(isUsLine))?.name?.trim();
|
|
166
|
+
if (name) return { issuer: issuerNameOf(name), unmatched: null };
|
|
167
|
+
abroad = exactMatches.find((result) => !!result.name?.trim());
|
|
168
|
+
}
|
|
169
|
+
const covered = await coveredOrNone(coveredIssuers);
|
|
170
|
+
const named = coveredIssuerMatch(query, covered);
|
|
171
|
+
if (named) return { issuer: named, unmatched: null };
|
|
172
|
+
// A line abroad never wins on its own: only as the covered issuer it names.
|
|
173
|
+
const abroadIssuer = abroad ? coveredIssuerMatch(issuerNameOf(abroad.name.trim()), covered) : null;
|
|
174
|
+
if (abroadIssuer) return { issuer: abroadIssuer, unmatched: null };
|
|
175
|
+
results ??= await searchOrNone(searchInstruments, query);
|
|
176
|
+
const primary = results.filter(isPrimaryUsCommonStock);
|
|
177
|
+
const listing = (primary.find((result) => result.symbol.toUpperCase() === symbol) ?? primary.find((result) => carriesTyped(result, query)))?.name?.trim();
|
|
178
|
+
if (listing) {
|
|
179
|
+
const issuer = issuerNameOf(listing);
|
|
180
|
+
const listed = coveredIssuerMatch(issuer, covered);
|
|
181
|
+
return listed
|
|
182
|
+
? { issuer: listed, unmatched: null }
|
|
183
|
+
: { issuer, unmatched: { nearest: closestCoveredIssuers(query, covered) } };
|
|
184
|
+
}
|
|
185
|
+
return { issuer: ticker ? query : issuerNameOf(query), unmatched: { nearest: closestCoveredIssuers(query, covered) } };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** The name `resolveCdsIssuer` sends to the tape, for a caller that only needs that. */
|
|
68
189
|
export async function resolveIssuerName(
|
|
69
190
|
issuer: string,
|
|
70
191
|
searchInstruments: InstrumentSearch,
|
|
192
|
+
coveredIssuers?: CoveredIssuers,
|
|
71
193
|
): Promise<string> {
|
|
72
|
-
|
|
73
|
-
const referenceEntity = cdsReferenceEntity(issuer);
|
|
74
|
-
if (referenceEntity) return referenceEntity;
|
|
75
|
-
try {
|
|
76
|
-
const results = await searchInstruments(issuer);
|
|
77
|
-
const symbol = issuer.toUpperCase();
|
|
78
|
-
const exactMatches = results.filter((result) => result.symbol.toUpperCase() === symbol);
|
|
79
|
-
const match = exactMatches.find(isPrimaryUsCommonStock) ?? exactMatches[0] ?? results[0];
|
|
80
|
-
const name = match?.name?.trim();
|
|
81
|
-
return name ? issuerNameOf(name) : issuer;
|
|
82
|
-
} catch {
|
|
83
|
-
return issuer;
|
|
84
|
-
}
|
|
194
|
+
return (await resolveCdsIssuer(issuer, searchInstruments, coveredIssuers)).issuer;
|
|
85
195
|
}
|
|
86
196
|
|
|
87
197
|
export async function loadCdsActivity(
|
|
88
198
|
issuer: string | null,
|
|
89
199
|
fetchCds: CdsFetch = (params) => apiClient.getCloudCds(params),
|
|
90
200
|
searchInstruments: InstrumentSearch = (query, limit) => apiClient.searchInstruments(query, limit),
|
|
201
|
+
coveredIssuers: CoveredIssuers = defaultCoveredIssuers,
|
|
91
202
|
): Promise<CdsActivity> {
|
|
92
203
|
const query = issuer?.trim() || null;
|
|
93
|
-
const resolved = query ? await
|
|
204
|
+
const resolved = query ? await resolveCdsIssuer(query, searchInstruments, coveredIssuers) : null;
|
|
94
205
|
const response = await fetchCds({
|
|
95
|
-
...(resolved ? { issuer: resolved } : {}),
|
|
206
|
+
...(resolved ? { issuer: resolved.issuer } : {}),
|
|
96
207
|
days: CDS_TRADE_DAYS,
|
|
97
208
|
limit: CDS_TRADE_LIMIT,
|
|
98
209
|
});
|
|
@@ -100,7 +211,8 @@ export async function loadCdsActivity(
|
|
|
100
211
|
source: response.source,
|
|
101
212
|
asOf: response.asOf,
|
|
102
213
|
query,
|
|
103
|
-
issuer: resolved,
|
|
214
|
+
issuer: resolved?.issuer ?? null,
|
|
215
|
+
...(resolved?.unmatched ? { unmatched: resolved.unmatched } : {}),
|
|
104
216
|
days: CDS_TRADE_DAYS,
|
|
105
217
|
trades: normalizeCdsTrades(response.trades ?? []),
|
|
106
218
|
};
|
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
} from "../../../types/plugin";
|
|
10
10
|
import {
|
|
11
11
|
CDS_TRADE_DAYS,
|
|
12
|
+
coveredIssuersFrom,
|
|
12
13
|
loadCdsActivity,
|
|
13
14
|
loadCdsSpreadHistory,
|
|
14
15
|
loadCdsSpreadLevels,
|
|
@@ -17,6 +18,7 @@ import {
|
|
|
17
18
|
type CdsHistoryFetch,
|
|
18
19
|
type CdsLevelsFetch,
|
|
19
20
|
type CdsSpreadHistory,
|
|
21
|
+
type CoveredIssuers,
|
|
20
22
|
type InstrumentSearch,
|
|
21
23
|
} from "./client";
|
|
22
24
|
import { formatContract } from "../credit-boards/model";
|
|
@@ -35,6 +37,7 @@ import {
|
|
|
35
37
|
formatSpreadMove,
|
|
36
38
|
formatSpreadRange,
|
|
37
39
|
formatUpfront,
|
|
40
|
+
hasPointsQuotes,
|
|
38
41
|
issuerListSort,
|
|
39
42
|
quotedLevel,
|
|
40
43
|
lastTradeOf,
|
|
@@ -154,7 +157,7 @@ function tradeForFormatting(row: Record<string, unknown>): CdsTrade {
|
|
|
154
157
|
return row as unknown as CdsTrade;
|
|
155
158
|
}
|
|
156
159
|
|
|
157
|
-
const TRADE_COLUMNS = [
|
|
160
|
+
const TRADE_COLUMNS: HeadlessPaneColumn[] = [
|
|
158
161
|
{ key: "eventAt", header: "Time UTC", shrink: false, format: (value: unknown) => formatEventTime(Number(value)) },
|
|
159
162
|
{ key: "issuer", header: "Issuer" },
|
|
160
163
|
{ key: "maturity", header: "Maturity" },
|
|
@@ -175,6 +178,22 @@ const TRADE_COLUMNS = [
|
|
|
175
178
|
},
|
|
176
179
|
];
|
|
177
180
|
|
|
181
|
+
/**
|
|
182
|
+
* A print that quoted points upfront in its spread field reads in a Points
|
|
183
|
+
* column, shown when one did; exports write the number as quoted.
|
|
184
|
+
*/
|
|
185
|
+
const POINTS_COLUMN: HeadlessPaneColumn = {
|
|
186
|
+
key: "pointsUpfront",
|
|
187
|
+
header: "Points",
|
|
188
|
+
align: "right",
|
|
189
|
+
format: (value: unknown) => (typeof value === "number" ? String(value) : "--"),
|
|
190
|
+
textFormat: (value: unknown) => formatPoints(numberOrNull(value)),
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const tradeColumns = (points: boolean): HeadlessPaneColumn[] => (
|
|
194
|
+
points ? [...TRADE_COLUMNS.slice(0, -1), POINTS_COLUMN, TRADE_COLUMNS.at(-1)!] : TRADE_COLUMNS
|
|
195
|
+
);
|
|
196
|
+
|
|
178
197
|
/**
|
|
179
198
|
* The pane's figures over its 5Y chart, as label and value lines: the level,
|
|
180
199
|
* its date, the 1W and 1M moves through the roll and the range charted, in
|
|
@@ -227,24 +246,29 @@ interface CdsReportInputs {
|
|
|
227
246
|
function projectCdsHeadless({ activity, history, levels, sort, days = DAILY_DAYS.defaultValue }: CdsReportInputs): HeadlessBundleResult {
|
|
228
247
|
const errors: string[] = [];
|
|
229
248
|
const notes: string[] = [];
|
|
230
|
-
const empty = noTradesMessage({ query: activity.query, issuer: activity.issuer, days: activity.days });
|
|
231
249
|
const metadata = { issuer: activity.issuer, days: activity.days };
|
|
232
250
|
if (activity.query) {
|
|
233
251
|
const line = history instanceof Error || !history ? null : history;
|
|
234
252
|
if (history instanceof Error) errors.push("5Y spread history unavailable.");
|
|
253
|
+
// A name that matched no covered issuer, with no trades and no line under it on the tape either.
|
|
254
|
+
const unmatched = activity.unmatched && !activity.trades.length && line && !line.issuer ? activity.unmatched : null;
|
|
255
|
+
const empty = noTradesMessage({ query: activity.query, issuer: activity.issuer, days: activity.days, unmatched });
|
|
235
256
|
const entries = line ? spreadEntries(line) : [];
|
|
236
|
-
// The name the tape was queried for heads the figures, as in the pane, so a ticker says what it became
|
|
237
|
-
|
|
257
|
+
// The name the tape was queried for heads the figures, as in the pane, so a ticker says what it became;
|
|
258
|
+
// a name sent as typed takes the one the tape answered with.
|
|
259
|
+
const name = displayIssuerName((activity.unmatched ? line?.issuer : null) ?? activity.issuer ?? line?.issuer ?? activity.query);
|
|
238
260
|
const why = line ? noLevelMessage(line.noLevelReason, line.points.at(-1)?.date ?? null) : null;
|
|
239
261
|
if (why) notes.push(`${why}.`);
|
|
240
|
-
else if (
|
|
262
|
+
else if (unmatched) {
|
|
263
|
+
if (!unmatched.nearest.length) notes.push("fn CDS lists the covered issuers.");
|
|
264
|
+
} else if (line && entries.length === 0) notes.push(`No 5Y spread level for ${name} in the last two years.`);
|
|
241
265
|
// The 5Y figures are dated by their level's day, each trade and each daily level by its own.
|
|
242
266
|
const levelDate = line ? spreadSummary(line)?.date : undefined;
|
|
243
267
|
const sections: HeadlessBundleSection[] = [
|
|
244
268
|
...(entries.length ? [{ title: name, entries, symbol: name, ...(levelDate ? { asOf: levelDate } : {}) }] : []),
|
|
245
269
|
{
|
|
246
270
|
title: "Trades",
|
|
247
|
-
columns:
|
|
271
|
+
columns: tradeColumns(hasPointsQuotes(activity.trades)),
|
|
248
272
|
rows: sortTrades(activity.trades, DEFAULT_TRADE_SORT).map((trade) => ({ ...trade })),
|
|
249
273
|
empty,
|
|
250
274
|
rowSymbolKey: "issuer",
|
|
@@ -265,6 +289,7 @@ function projectCdsHeadless({ activity, history, levels, sort, days = DAILY_DAYS
|
|
|
265
289
|
...(notes.length ? { notes } : {}),
|
|
266
290
|
};
|
|
267
291
|
}
|
|
292
|
+
const empty = noTradesMessage({ query: null, issuer: null, days: activity.days });
|
|
268
293
|
if (levels instanceof Error) errors.push("5Y spreads unavailable.");
|
|
269
294
|
const issuers = withSpreadLevels(summarizeIssuers(activity.trades), levels instanceof Error ? null : levels ?? null);
|
|
270
295
|
return {
|
|
@@ -294,14 +319,15 @@ export interface CdsHeadlessDependencies {
|
|
|
294
319
|
issuer: string | null,
|
|
295
320
|
fetchCds: CdsFetch,
|
|
296
321
|
searchInstruments: InstrumentSearch,
|
|
322
|
+
coveredIssuers: CoveredIssuers,
|
|
297
323
|
): Promise<CdsActivity>;
|
|
298
324
|
loadHistory?(issuer: string, fetchHistory: CdsHistoryFetch): Promise<CdsSpreadHistory>;
|
|
299
325
|
loadLevels?: typeof loadCdsSpreadLevels;
|
|
300
326
|
}
|
|
301
327
|
|
|
302
328
|
const defaultDependencies: CdsHeadlessDependencies = {
|
|
303
|
-
load: (_args, issuer, fetchCds, searchInstruments) => (
|
|
304
|
-
loadCdsActivity(issuer, fetchCds, searchInstruments)
|
|
329
|
+
load: (_args, issuer, fetchCds, searchInstruments, coveredIssuers) => (
|
|
330
|
+
loadCdsActivity(issuer, fetchCds, searchInstruments, coveredIssuers)
|
|
305
331
|
),
|
|
306
332
|
loadHistory: (issuer, fetchHistory) => loadCdsSpreadHistory(issuer, fetchHistory),
|
|
307
333
|
loadLevels: loadCdsSpreadLevels,
|
|
@@ -353,6 +379,7 @@ export function createCdsHeadless(
|
|
|
353
379
|
issuer,
|
|
354
380
|
(params) => ctx.apiClient.getCloudCds(params),
|
|
355
381
|
(query, limit) => ctx.apiClient.searchInstruments(query, limit),
|
|
382
|
+
coveredIssuersFrom(fetchLevels),
|
|
356
383
|
);
|
|
357
384
|
if (activity.query) {
|
|
358
385
|
// The line follows the name the tape was queried for, as the pane's does.
|
|
@@ -5,6 +5,7 @@ import type { HeadlessPaneFreshness } from "../../../types/headless";
|
|
|
5
5
|
import type { TickerRecord } from "../../../types/ticker";
|
|
6
6
|
import { formatCompact } from "../../../utils/format";
|
|
7
7
|
import { compareSortValues, type SortPreference } from "../../../utils/sort-values";
|
|
8
|
+
import { typoDistance } from "../../../utils/typo-distance";
|
|
8
9
|
import { formatMove } from "../credit-boards/model";
|
|
9
10
|
|
|
10
11
|
export const CDS_PANE_ID = "cds";
|
|
@@ -20,7 +21,7 @@ const DECIMAL_TO_BP = 10_000;
|
|
|
20
21
|
|
|
21
22
|
export interface CdsTrade {
|
|
22
23
|
id: string;
|
|
23
|
-
/**
|
|
24
|
+
/** The issuer's best spelling on the tape, the same on every print of it (see `normalizeCdsTrades`). */
|
|
24
25
|
issuer: string;
|
|
25
26
|
/** Alias-collapsed grouping key. Internal only; never shown or sent. */
|
|
26
27
|
issuerKey: string;
|
|
@@ -31,8 +32,13 @@ export interface CdsTrade {
|
|
|
31
32
|
notionalCapped: boolean;
|
|
32
33
|
currency: string | null;
|
|
33
34
|
couponBp: number | null;
|
|
34
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* Only what the report carried. Never derived from upfront or coupon, and
|
|
37
|
+
* empty when the field held points upfront (`pointsUpfront`).
|
|
38
|
+
*/
|
|
35
39
|
spreadBp: number | null;
|
|
40
|
+
/** The quote of a print whose spread field held points upfront, not bp. */
|
|
41
|
+
pointsUpfront: number | null;
|
|
36
42
|
/** Source inputs retained even when their notation cannot supply a bp rate. */
|
|
37
43
|
reportedSpread: number | null;
|
|
38
44
|
spreadNotation: string | null;
|
|
@@ -143,6 +149,66 @@ export function issuerGroupKey(name: string): string {
|
|
|
143
149
|
return (meaningful.length > 0 ? meaningful : tokens).join(" ") || name.trim().toLowerCase();
|
|
144
150
|
}
|
|
145
151
|
|
|
152
|
+
/** Fewer letters than this are a symbol, not words of a name: `f` is Ford's ticker, not "F&G Annuities & Life". */
|
|
153
|
+
const MIN_NAME_LETTERS = 3;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* The covered issuer a name stands for, by its words: the issuer of that very
|
|
157
|
+
* name, else one whose name holds those words in a row (`goodyear` is "The
|
|
158
|
+
* Goodyear Tire & Rubber Company"), one that starts with them first, then the
|
|
159
|
+
* shortest, so `ford` is Ford Motor Company and not Ford Motor Credit. Null
|
|
160
|
+
* when none does, and for fewer than three letters (`f`, `ge`), which are a
|
|
161
|
+
* symbol to look up.
|
|
162
|
+
*/
|
|
163
|
+
export function coveredIssuerMatch(name: string, covered: readonly string[]): string | null {
|
|
164
|
+
const wanted = issuerGroupKey(displayIssuerName(name));
|
|
165
|
+
if (wanted.replace(/[^\p{L}\p{N}]/gu, "").length < MIN_NAME_LETTERS) return null;
|
|
166
|
+
let best: { issuer: string; leading: boolean; words: number } | null = null;
|
|
167
|
+
for (const issuer of covered) {
|
|
168
|
+
const key = issuerGroupKey(displayIssuerName(issuer));
|
|
169
|
+
if (key === wanted) return displayIssuerName(issuer);
|
|
170
|
+
if (!` ${key} `.includes(` ${wanted} `)) continue;
|
|
171
|
+
const candidate = { issuer: displayIssuerName(issuer), leading: key.startsWith(`${wanted} `), words: key.split(" ").length };
|
|
172
|
+
if (!best
|
|
173
|
+
|| (candidate.leading !== best.leading ? candidate.leading
|
|
174
|
+
: candidate.words !== best.words ? candidate.words < best.words
|
|
175
|
+
: candidate.issuer.localeCompare(best.issuer) < 0)) best = candidate;
|
|
176
|
+
}
|
|
177
|
+
return best?.issuer ?? null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** How many covered issuers an unmatched name offers. */
|
|
181
|
+
const CLOSEST_ISSUERS = 3;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* How near a word is to one of a name's: a slip of the keys, or the same first
|
|
185
|
+
* letters (`goodyer`, `paramo`). Short words never count, or every name with
|
|
186
|
+
* "co" in it would be close.
|
|
187
|
+
*/
|
|
188
|
+
function wordCloseness(typed: string, word: string): number {
|
|
189
|
+
if (typed.length < 3 || word.length < 3) return 0;
|
|
190
|
+
if (typed.length >= 4 && typoDistance(typed, word) <= 1) return typed.length;
|
|
191
|
+
let shared = 0;
|
|
192
|
+
while (shared < Math.min(typed.length, word.length) && typed[shared] === word[shared]) shared += 1;
|
|
193
|
+
return shared >= 4 || (shared >= 3 && shared === typed.length) ? shared : 0;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** The covered issuers closest to a name that matched none, closest first; none when nothing is near. */
|
|
197
|
+
export function closestCoveredIssuers(name: string, covered: readonly string[]): string[] {
|
|
198
|
+
const typed = issuerGroupKey(displayIssuerName(name)).split(" ").filter(Boolean);
|
|
199
|
+
const scored = new Map<string, number>();
|
|
200
|
+
for (const issuer of covered) {
|
|
201
|
+
const words = issuerGroupKey(displayIssuerName(issuer)).split(" ");
|
|
202
|
+
const score = typed.reduce((sum, word) => sum + Math.max(0, ...words.map((other) => wordCloseness(word, other))), 0);
|
|
203
|
+
const shown = displayIssuerName(issuer);
|
|
204
|
+
if (score > 0 && score > (scored.get(shown) ?? 0)) scored.set(shown, score);
|
|
205
|
+
}
|
|
206
|
+
return [...scored]
|
|
207
|
+
.sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0]))
|
|
208
|
+
.slice(0, CLOSEST_ISSUERS)
|
|
209
|
+
.map(([issuer]) => issuer);
|
|
210
|
+
}
|
|
211
|
+
|
|
146
212
|
/**
|
|
147
213
|
* DTCC writes a comma inside a field as `;` ("CCO Holdings;LLC",
|
|
148
214
|
* "Amazon.com;Inc."), so a name gets its comma back before it is shown,
|
|
@@ -207,6 +273,37 @@ function couponToBasisPoints(fixedRate: number | null): number | null {
|
|
|
207
273
|
return fixedRate * DECIMAL_TO_BP;
|
|
208
274
|
}
|
|
209
275
|
|
|
276
|
+
/**
|
|
277
|
+
* How far a reported quote may sit from the points its upfront works out to
|
|
278
|
+
* and still be read as those points: accrued and rounding move the amount by
|
|
279
|
+
* about a tenth of a point.
|
|
280
|
+
*/
|
|
281
|
+
const POINTS_MATCH_PTS = 0.5;
|
|
282
|
+
const POINTS_MATCH_SHARE = 0.05;
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Some desks key a distressed name's points upfront into the spread field and
|
|
286
|
+
* leave the coupon blank: Whirlpool's Dec 2028 contract printed `0.00065`,
|
|
287
|
+
* 6.5 read as bp, beside 319,861 upfront on 5M, which is 6.4 points. Without a
|
|
288
|
+
* coupon nothing makes the field a running spread, and when the amount over
|
|
289
|
+
* the notional reads as the same number in points, it is that many points.
|
|
290
|
+
* A real spread that low on a running coupon would need the upfront to land on
|
|
291
|
+
* the same number by chance, below 5bp.
|
|
292
|
+
*/
|
|
293
|
+
function pointsUpfrontOf(
|
|
294
|
+
spreadBp: number | null,
|
|
295
|
+
couponBp: number | null,
|
|
296
|
+
upfront: number | null,
|
|
297
|
+
notional: number | null,
|
|
298
|
+
): number | null {
|
|
299
|
+
if (couponBp != null || spreadBp == null || !(spreadBp > 0)) return null;
|
|
300
|
+
if (upfront == null || !Number.isFinite(upfront) || notional == null || !(notional > 0)) return null;
|
|
301
|
+
const impliedPts = (Math.abs(upfront) / notional) * 100;
|
|
302
|
+
const tolerance = Math.max(POINTS_MATCH_PTS, impliedPts * POINTS_MATCH_SHARE);
|
|
303
|
+
// The decimal the field holds carries float noise (0.001525 is 15.249999...).
|
|
304
|
+
return Math.abs(spreadBp - impliedPts) <= tolerance ? Math.round(spreadBp * 1e6) / 1e6 : null;
|
|
305
|
+
}
|
|
306
|
+
|
|
210
307
|
/**
|
|
211
308
|
* When the trade was struck, not when the tape carried it. A lifecycle
|
|
212
309
|
* correction is disseminated long after the fact, so using the event time would
|
|
@@ -232,32 +329,46 @@ function issuerOf(trade: CloudCdsTradePayload): string | null {
|
|
|
232
329
|
return underlier && identifiesIssuer(underlier) ? displayIssuerName(underlier) : null;
|
|
233
330
|
}
|
|
234
331
|
|
|
332
|
+
/**
|
|
333
|
+
* The tape's prints as rows. One issuer reads as one name on every print:
|
|
334
|
+
* the tape spells Whirlpool three ways in a week ("WHIRLPOOL CORPORATION",
|
|
335
|
+
* "Whirlpool Corp", "Whirlpool Corporation"), and each row takes the spelling
|
|
336
|
+
* the issuer list shows for them all.
|
|
337
|
+
*/
|
|
235
338
|
export function normalizeCdsTrades(trades: readonly CloudCdsTradePayload[]): CdsTrade[] {
|
|
236
339
|
const rows: CdsTrade[] = [];
|
|
340
|
+
const names = new Map<string, string>();
|
|
237
341
|
for (const trade of trades) {
|
|
238
342
|
const eventAt = tapeTime(trade);
|
|
239
343
|
if (eventAt == null) continue;
|
|
240
344
|
const issuer = issuerOf(trade);
|
|
241
345
|
// Nothing names the reference entity, so the row would invent one.
|
|
242
346
|
if (!issuer) continue;
|
|
347
|
+
const issuerKey = issuerGroupKey(issuer);
|
|
348
|
+
const named = names.get(issuerKey);
|
|
349
|
+
names.set(issuerKey, named ? preferredIssuerName(named, issuer) : issuer);
|
|
350
|
+
const couponBp = couponToBasisPoints(trade.fixedRate);
|
|
351
|
+
const reportedBp = spreadToBasisPoints(trade.reportedSpread, trade.spreadNotation);
|
|
352
|
+
const pointsUpfront = pointsUpfrontOf(reportedBp, couponBp, trade.upfrontAmount, trade.notionalAmount);
|
|
243
353
|
rows.push({
|
|
244
354
|
id: trade.disseminationId,
|
|
245
355
|
issuer,
|
|
246
|
-
issuerKey
|
|
356
|
+
issuerKey,
|
|
247
357
|
eventAt,
|
|
248
358
|
maturity: trade.maturityDate ?? trade.expirationDate,
|
|
249
359
|
notional: trade.notionalAmount,
|
|
250
360
|
notionalCapped: trade.notionalCapped,
|
|
251
361
|
currency: trade.notionalCurrency,
|
|
252
|
-
couponBp
|
|
253
|
-
spreadBp:
|
|
362
|
+
couponBp,
|
|
363
|
+
spreadBp: pointsUpfront == null ? reportedBp : null,
|
|
364
|
+
pointsUpfront,
|
|
254
365
|
reportedSpread: trade.reportedSpread,
|
|
255
366
|
spreadNotation: trade.spreadNotation,
|
|
256
367
|
upfront: trade.upfrontAmount,
|
|
257
368
|
upfrontCurrency: trade.upfrontCurrency,
|
|
258
369
|
});
|
|
259
370
|
}
|
|
260
|
-
return rows;
|
|
371
|
+
return rows.map((row) => ({ ...row, issuer: names.get(row.issuerKey) ?? row.issuer }));
|
|
261
372
|
}
|
|
262
373
|
|
|
263
374
|
/**
|
|
@@ -405,13 +516,23 @@ export function cdsFreshness(lastTrade: number | string | null): HeadlessPaneFre
|
|
|
405
516
|
* What an empty view says: the window searched and, for one name, the
|
|
406
517
|
* reference entity the query became, with what was typed when that differs.
|
|
407
518
|
*/
|
|
408
|
-
export function noTradesMessage({ query, issuer, days }: {
|
|
519
|
+
export function noTradesMessage({ query, issuer, days, unmatched = null }: {
|
|
409
520
|
query: string | null;
|
|
410
521
|
issuer: string | null;
|
|
411
522
|
days: number;
|
|
523
|
+
/**
|
|
524
|
+
* A name that matched no covered issuer, once the tape has no trades and no
|
|
525
|
+
* line under it either: what the view says instead is that no issuer
|
|
526
|
+
* matches, with the covered ones closest to what was typed.
|
|
527
|
+
*/
|
|
528
|
+
unmatched?: { nearest: readonly string[] } | null;
|
|
412
529
|
}): string {
|
|
413
530
|
const window = `in the last ${days} days`;
|
|
414
531
|
if (!query) return `No single-name CDS trades ${window}.`;
|
|
532
|
+
if (unmatched) {
|
|
533
|
+
const nearest = unmatched.nearest.length ? ` Closest covered issuers: ${unmatched.nearest.join(", ")}.` : "";
|
|
534
|
+
return `No CDS issuer matches ${query}.${nearest}`;
|
|
535
|
+
}
|
|
415
536
|
const name = issuer && issuer.toUpperCase() !== query.toUpperCase() ? `${issuer} (${query})` : issuer ?? query;
|
|
416
537
|
return `No CDS trades for ${name} ${window}.`;
|
|
417
538
|
}
|
|
@@ -610,22 +731,25 @@ export function sortIssuers(
|
|
|
610
731
|
});
|
|
611
732
|
}
|
|
612
733
|
|
|
613
|
-
export type TradeColumnId = "time" | "maturity" | "notional" | "currency" | "coupon" | "spread" | "upfront";
|
|
734
|
+
export type TradeColumnId = "time" | "maturity" | "notional" | "currency" | "coupon" | "spread" | "points" | "upfront";
|
|
614
735
|
export type TradeColumn = DataTableColumn & { id: TradeColumnId };
|
|
615
736
|
export type TradeSortPreference = SortPreference<TradeColumnId>;
|
|
616
737
|
|
|
617
|
-
export const TRADE_SORT_COLUMN_IDS: readonly TradeColumnId[] = [
|
|
618
|
-
"time",
|
|
619
|
-
"maturity",
|
|
620
|
-
"notional",
|
|
621
|
-
"coupon",
|
|
622
|
-
"spread",
|
|
623
|
-
"upfront",
|
|
624
|
-
];
|
|
625
738
|
export const DEFAULT_TRADE_SORT: TradeSortPreference = { columnId: "time", direction: "desc" };
|
|
626
739
|
|
|
627
|
-
|
|
628
|
-
|
|
740
|
+
/** Whether any print was quoted in points upfront, which is when the trades show a Points column. */
|
|
741
|
+
export function hasPointsQuotes(trades: readonly Pick<CdsTrade, "pointsUpfront">[]): boolean {
|
|
742
|
+
return trades.some((trade) => trade.pointsUpfront != null);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
/** The columns `]` and `[` cycle the trades' sort through: the ones shown. */
|
|
746
|
+
export function tradeSortColumnIds(points: boolean): readonly TradeColumnId[] {
|
|
747
|
+
return ["time", "maturity", "notional", "coupon", "spread", ...(points ? ["points" as const] : []), "upfront"];
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
/** A Points column sits beside Spread only when a print was quoted in points. */
|
|
751
|
+
export function buildTradeColumns(width: number, points = false): TradeColumn[] {
|
|
752
|
+
const maturityWidth = Math.max(10, Math.min(12, width - 59 - (points ? 9 : 0)));
|
|
629
753
|
return [
|
|
630
754
|
{ id: "time", label: "TIME UTC", width: 16, align: "left" },
|
|
631
755
|
{ id: "maturity", label: "MATURITY", width: maturityWidth, align: "left" },
|
|
@@ -633,6 +757,7 @@ export function buildTradeColumns(width: number): TradeColumn[] {
|
|
|
633
757
|
{ id: "currency", label: "CCY", width: 5, align: "left" },
|
|
634
758
|
{ id: "coupon", label: "COUPON", width: 9, align: "right" },
|
|
635
759
|
{ id: "spread", label: "SPREAD", width: 10, align: "right" },
|
|
760
|
+
...(points ? [{ id: "points" as const, label: "POINTS", width: 9, align: "right" as const }] : []),
|
|
636
761
|
{ id: "upfront", label: "ABS UPFRONT", width: 13, align: "right" },
|
|
637
762
|
];
|
|
638
763
|
}
|
|
@@ -651,6 +776,8 @@ function tradeSortValue(columnId: TradeColumnId, row: CdsTrade): string | number
|
|
|
651
776
|
return row.couponBp;
|
|
652
777
|
case "spread":
|
|
653
778
|
return row.spreadBp;
|
|
779
|
+
case "points":
|
|
780
|
+
return row.pointsUpfront;
|
|
654
781
|
case "upfront":
|
|
655
782
|
return row.upfront;
|
|
656
783
|
}
|