gloomberb 0.18.4 → 0.19.0
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 +169 -5
- package/src/account/auth-model.ts +7 -3
- package/src/api-client/auth.ts +9 -4
- package/src/api-client/catalysts.ts +2 -1
- package/src/api-client/cot.ts +6 -2
- package/src/api-client/credit-documents.ts +6 -0
- package/src/api-client/data.ts +31 -6
- package/src/api-client/equity-screener.ts +24 -0
- package/src/api-client/fund-facts.ts +45 -4
- package/src/api-client/index.ts +171 -11
- package/src/api-client/live-scan.ts +91 -0
- package/src/api-client/market-discovery.ts +10 -0
- package/src/api-client/market-movers.ts +7 -0
- package/src/api-client/members.ts +13 -1
- package/src/api-client/perps.ts +43 -0
- package/src/api-client/request.ts +222 -41
- package/src/api-client/research-activity.ts +6 -12
- package/src/api-client/types.ts +74 -0
- package/src/app/keybindings/index.ts +3 -0
- package/src/app/keybindings/labels.ts +18 -1
- package/src/app/keybindings/resolve.ts +14 -0
- package/src/app/pane-runtime/plugin-bindings.ts +9 -5
- package/src/app/runtime/broker-import.ts +42 -27
- package/src/app/runtime/plugin-bindings.ts +73 -56
- package/src/architecture/core-builtin-allowlist.json +1 -1
- 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/fred-series.ts +5 -0
- package/src/cli/commands/keybindings.ts +23 -0
- package/src/cli/commands/market.ts +138 -46
- package/src/cli/commands/options-chain.ts +107 -10
- package/src/cli/commands/options-leaps.ts +9 -3
- package/src/cli/commands/overview.ts +176 -39
- package/src/cli/commands/search.ts +39 -3
- package/src/cli/commands/themes.ts +11 -2
- package/src/cli/commands/ticker.ts +57 -35
- package/src/cli/company-name-hint.ts +41 -0
- package/src/cli/earnings-calendar.ts +1 -1
- package/src/cli/errors.ts +10 -2
- package/src/cli/export-source.ts +29 -1
- package/src/cli/glossary.ts +73 -1
- package/src/cli/history-rows.ts +87 -16
- package/src/cli/index.ts +2 -0
- package/src/cli/known-gaps.ts +5 -2
- package/src/cli/listing-arg.ts +195 -56
- package/src/cli/output-file.ts +68 -0
- package/src/cli/pane-functions/capabilities.ts +3 -0
- package/src/cli/pane-functions/catalog.ts +80 -7
- package/src/cli/pane-functions/dom.ts +13 -3
- package/src/cli/pane-functions/freshness.ts +111 -16
- package/src/cli/pane-functions/function-help.ts +23 -13
- package/src/cli/pane-functions/headless.ts +56 -12
- package/src/cli/pane-functions/index.ts +58 -16
- package/src/cli/pane-functions/market-session.ts +81 -9
- package/src/cli/pane-functions/options.ts +19 -1
- package/src/cli/pane-functions/report.ts +5 -1
- package/src/cli/pane-functions/resolver.ts +35 -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 +30 -13
- package/src/cli/report-tables.ts +18 -7
- package/src/cli/restore-plugins.ts +13 -1
- package/src/cli/result.ts +57 -5
- package/src/cli/ticker-resolution.ts +3 -2
- package/src/components/chart/composite/composite-chart.tsx +26 -4
- package/src/components/chart/composite/format.ts +27 -0
- package/src/components/chart/composite/interactions.ts +6 -0
- package/src/components/chart/composite/legend.tsx +45 -7
- package/src/components/chart/composite/levels.ts +2 -0
- package/src/components/chart/composite/panel-gestures.ts +33 -0
- package/src/components/chart/composite/panel-series.ts +1 -0
- package/src/components/chart/composite/panel-surface.tsx +61 -5
- package/src/components/chart/composite/range-statistics.ts +62 -0
- package/src/components/chart/composite/rasterizer.ts +24 -13
- package/src/components/chart/composite/scene.ts +46 -7
- package/src/components/chart/composite/series-axis-tags.tsx +16 -9
- 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/types.ts +4 -0
- 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/pane-templates/items.ts +3 -2
- package/src/components/command-bar/panel/prompt-binding.ts +0 -8
- package/src/components/command-bar/workflow/alert.ts +1 -1
- package/src/components/command-bar/workflow/collection-actions.ts +3 -3
- package/src/components/layout/header.tsx +26 -40
- package/src/components/layout/pane/footer/index.tsx +1 -0
- package/src/components/layout/pane/footer/model.ts +27 -0
- package/src/components/onboarding/onboarding-frame.tsx +1 -1
- package/src/components/onboarding/onboarding-wizard.tsx +4 -1
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +14 -9
- 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 +4 -1
- 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 +5 -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/core/state/app/layout.ts +2 -0
- package/src/core/state/app/state.ts +9 -0
- package/src/core/state/app/types.ts +3 -0
- package/src/data/config/chart-settings.ts +1 -1
- package/src/data/json-ticker-repository.ts +17 -8
- package/src/data/saved-copies.ts +55 -16
- 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 +427 -216
- package/src/i18n/es.ts +19 -3
- package/src/i18n/ja.ts +19 -3
- package/src/i18n/ko.ts +19 -3
- package/src/i18n/zh-cn.ts +19 -3
- package/src/i18n/zh-tw.ts +19 -3
- package/src/market-data/coordinator/financials.ts +10 -2
- package/src/market-data/coordinator/index.ts +3 -1
- package/src/market-data/coordinator/quotes.ts +4 -2
- package/src/market-data/depositary-pair.ts +2 -2
- package/src/market-data/fund-facts.ts +50 -0
- package/src/market-data/market/change-basis.ts +48 -7
- package/src/market-data/market/dated-previous-close.ts +203 -0
- package/src/market-data/market/format.ts +25 -0
- package/src/market-data/market/freshness.ts +2 -1
- package/src/market-data/market/futures-week.ts +68 -0
- package/src/market-data/market/status.ts +16 -4
- package/src/market-data/options-alternatives.ts +141 -4
- package/src/market-data/quotes/contributions.ts +20 -2
- package/src/market-data/quotes/resolution.ts +3 -0
- package/src/market-data/selectors.ts +3 -0
- package/src/news/aggregator.ts +113 -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 +11 -0
- package/src/notifications/notification-log.ts +6 -4
- package/src/plugins/builtin/alerts/alert-engine.ts +25 -2
- package/src/plugins/builtin/alerts/alert-log.ts +33 -0
- package/src/plugins/builtin/alerts/calendar-events.ts +57 -6
- package/src/plugins/builtin/alerts/cli-forms.ts +216 -0
- package/src/plugins/builtin/alerts/cli.ts +380 -82
- package/src/plugins/builtin/alerts/command.ts +31 -0
- package/src/plugins/builtin/alerts/constants.ts +1 -1
- package/src/plugins/builtin/alerts/events-pane.tsx +19 -4
- package/src/plugins/builtin/alerts/fired-log.ts +113 -8
- package/src/plugins/builtin/alerts/format.ts +80 -4
- package/src/plugins/builtin/alerts/headless.ts +30 -7
- package/src/plugins/builtin/alerts/history-rows.ts +7 -3
- package/src/plugins/builtin/alerts/history.ts +2 -0
- package/src/plugins/builtin/alerts/index.tsx +135 -22
- package/src/plugins/builtin/alerts/live.ts +3 -3
- package/src/plugins/builtin/alerts/metric-command.ts +134 -0
- package/src/plugins/builtin/alerts/metric-data.ts +111 -0
- package/src/plugins/builtin/alerts/metric-model.ts +324 -0
- package/src/plugins/builtin/alerts/metric-parity-fixture.json +725 -0
- package/src/plugins/builtin/alerts/pane.tsx +90 -39
- package/src/plugins/builtin/alerts/quotes.ts +6 -0
- package/src/plugins/builtin/alerts/storage.ts +37 -10
- package/src/plugins/builtin/alerts/types.ts +7 -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/backtest/headless.ts +10 -5
- package/src/plugins/builtin/backtest/pane.tsx +9 -4
- package/src/plugins/builtin/backtest/presets.ts +29 -3
- package/src/plugins/builtin/broker-manager/index.tsx +10 -5
- package/src/plugins/builtin/broker-manager/model.ts +6 -1
- package/src/plugins/builtin/broker-trading/controller.ts +22 -12
- package/src/plugins/builtin/broker-trading/index.tsx +13 -1
- package/src/plugins/builtin/broker-trading/order-feed.ts +9 -4
- package/src/plugins/builtin/broker-trading/pane.tsx +1 -1
- 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 +7 -3
- package/src/plugins/builtin/catalysts/model.ts +2 -1
- package/src/plugins/builtin/changelog/index.tsx +9 -6
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +6 -1
- package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +1 -1
- package/src/plugins/builtin/chart-composer/cli-options.ts +9 -5
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +12 -2
- package/src/plugins/builtin/chart-composer/editor/controller.ts +4 -2
- package/src/plugins/builtin/chart-composer/editor/model.ts +2 -0
- package/src/plugins/builtin/chart-composer/editor.tsx +7 -5
- package/src/plugins/builtin/chart-composer/formula.ts +71 -18
- package/src/plugins/builtin/chart-composer/headless-schema.ts +21 -4
- package/src/plugins/builtin/chart-composer/headless.ts +19 -3
- package/src/plugins/builtin/chart-composer/index.tsx +1 -1
- package/src/plugins/builtin/chart-composer/pane.tsx +53 -9
- package/src/plugins/builtin/chart-composer/presets.ts +50 -15
- package/src/plugins/builtin/chart-composer/quick-add.tsx +40 -25
- package/src/plugins/builtin/chart-composer/session-history.ts +18 -9
- package/src/plugins/builtin/chart-composer/settings.ts +27 -0
- package/src/plugins/builtin/chart-composer/use-series-catalog.ts +40 -26
- package/src/plugins/builtin/chat/content/command-suggestions.ts +93 -0
- package/src/plugins/builtin/chat/content/composer.tsx +13 -6
- package/src/plugins/builtin/chat/content/footer.tsx +6 -3
- package/src/plugins/builtin/chat/content/index.tsx +50 -21
- package/src/plugins/builtin/chat/content/open-targets.ts +14 -3
- package/src/plugins/builtin/chat/controller/session-runtime.ts +4 -2
- package/src/plugins/builtin/chat/index.tsx +23 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +1 -0
- package/src/plugins/builtin/chat/message/inline-tokens.tsx +23 -0
- package/src/plugins/builtin/chat/message/pane-chip.tsx +50 -20
- package/src/plugins/builtin/chat/pane-links/commands.ts +271 -0
- package/src/plugins/builtin/chat/pane-links/model.ts +12 -3
- package/src/plugins/builtin/chat/pane-links/open.ts +8 -1
- package/src/plugins/builtin/chat/unread-inbox-pane.tsx +10 -1
- package/src/plugins/builtin/clinical-trials/model.ts +0 -9
- package/src/plugins/builtin/clinical-trials/pane.tsx +15 -22
- package/src/plugins/builtin/clinical-trials/sponsor-tickers.ts +8 -6
- package/src/plugins/builtin/cloud/askg/manifest.ts +2 -0
- package/src/plugins/builtin/cloud/plugin.tsx +1 -1
- 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/moves.tsx +5 -1
- package/src/plugins/builtin/company-attention/pane.tsx +9 -2
- package/src/plugins/builtin/company-attention/signals.tsx +5 -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 +7 -7
- 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/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/format.ts +31 -2
- package/src/plugins/builtin/earnings-calls/headless.ts +7 -2
- package/src/plugins/builtin/earnings-calls/model.ts +6 -1
- package/src/plugins/builtin/earnings-calls/pane.tsx +5 -4
- package/src/plugins/builtin/econ/calendar-model.ts +14 -9
- package/src/plugins/builtin/econ/figures.ts +72 -0
- package/src/plugins/builtin/econ/index.tsx +33 -3
- package/src/plugins/builtin/econ/types.ts +4 -0
- package/src/plugins/builtin/econ-statistics/defs.ts +6 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +85 -35
- package/src/plugins/builtin/econ-statistics/stats.ts +37 -9
- package/src/plugins/builtin/econ-statistics/view.ts +3 -0
- 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 +70 -15
- package/src/plugins/builtin/exposure/charts.tsx +2 -2
- package/src/plugins/builtin/exposure/model.ts +13 -1
- package/src/plugins/builtin/exposure/pane.tsx +4 -4
- package/src/plugins/builtin/fixed-income/pane.tsx +2 -1
- package/src/plugins/builtin/futures/index.tsx +1 -0
- package/src/plugins/builtin/futures/model.ts +2 -1
- package/src/plugins/builtin/futures/table.tsx +2 -2
- 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 +11 -3
- package/src/plugins/builtin/fx-matrix/headless.ts +6 -3
- package/src/plugins/builtin/fx-matrix/index.tsx +16 -4
- package/src/plugins/builtin/fx-matrix/live-legs.ts +54 -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 +1 -0
- package/src/plugins/builtin/help/keybindings-editor.tsx +18 -14
- package/src/plugins/builtin/help/shortcut-model.ts +1 -1
- package/src/plugins/builtin/holders/fund-holders.ts +51 -0
- package/src/plugins/builtin/holders/headless.ts +18 -1
- 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 +36 -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/pane.tsx +7 -5
- 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 +25 -7
- package/src/plugins/builtin/market-movers/footer.ts +2 -2
- package/src/plugins/builtin/market-movers/headless.ts +32 -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 +14 -0
- 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 +82 -0
- package/src/plugins/builtin/members/client.ts +19 -4
- package/src/plugins/builtin/members/headless.ts +20 -7
- package/src/plugins/builtin/members/index.tsx +9 -9
- package/src/plugins/builtin/members/model.ts +23 -4
- package/src/plugins/builtin/members/pane.tsx +25 -15
- package/src/plugins/builtin/news/index.tsx +1 -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 +54 -6
- package/src/plugins/builtin/options/enrichment.ts +17 -5
- package/src/plugins/builtin/options/model-spot.ts +5 -2
- package/src/plugins/builtin/options/strike-window.ts +2 -1
- package/src/plugins/builtin/options/table.ts +6 -9
- package/src/plugins/builtin/options/types.ts +2 -0
- package/src/plugins/builtin/options/view.tsx +42 -12
- package/src/plugins/builtin/options-positioning/client.ts +30 -0
- package/src/plugins/builtin/options-positioning/headless.ts +74 -21
- package/src/plugins/builtin/options-positioning/index.tsx +4 -4
- package/src/plugins/builtin/options-positioning/model.ts +122 -14
- package/src/plugins/builtin/options-positioning/pane.tsx +87 -42
- 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/freshness.ts +12 -10
- package/src/plugins/builtin/perps/headless.ts +65 -9
- package/src/plugins/builtin/perps/index.tsx +7 -5
- package/src/plugins/builtin/perps/live-rows.ts +10 -3
- package/src/plugins/builtin/perps/model.ts +18 -4
- package/src/plugins/builtin/perps/pane.tsx +32 -31
- 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 +12 -7
- package/src/plugins/builtin/portfolio-list/headless.ts +1 -1
- package/src/plugins/builtin/portfolio-list/pane/futures-front.ts +40 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +4 -1
- 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/resolution.ts +3 -1
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +11 -8
- package/src/plugins/builtin/portfolio-list/table.tsx +11 -3
- package/src/plugins/builtin/primary-dealers/client.ts +13 -38
- package/src/plugins/builtin/rate-path/pane.tsx +2 -2
- package/src/plugins/builtin/realized-vol/index.tsx +2 -2
- package/src/plugins/builtin/realized-vol/pane.tsx +3 -3
- 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 +10 -8
- package/src/plugins/builtin/research/headless.ts +1 -1
- package/src/plugins/builtin/research/relative-valuation-headless.ts +5 -1
- package/src/plugins/builtin/research/relative-valuation-model.ts +31 -3
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +11 -9
- 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/scanner/feed.ts +2 -2
- 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 +40 -6
- package/src/plugins/builtin/scanner/live-condition-editor.tsx +222 -0
- package/src/plugins/builtin/scanner/live-feed.ts +168 -0
- package/src/plugins/builtin/scanner/live-headless.ts +138 -0
- package/src/plugins/builtin/scanner/live-model.ts +362 -0
- package/src/plugins/builtin/scanner/live-pane.tsx +677 -0
- package/src/plugins/builtin/scanner/live-track.ts +186 -0
- 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 +2 -1
- package/src/plugins/builtin/series-inventory.ts +3 -0
- package/src/plugins/builtin/shared/cloud-resource.ts +3 -2
- 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/job-posting.ts +1 -0
- package/src/plugins/builtin/shared/macro-releases.ts +65 -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 +3 -2
- package/src/plugins/builtin/shared/scanner-capture.ts +3 -0
- 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 +10 -3
- package/src/plugins/builtin/shared/volatility/live-session.ts +34 -8
- package/src/plugins/builtin/shared/volatility/pricing.ts +26 -1
- package/src/plugins/builtin/shared/wall-view-lifecycle.ts +3 -1
- package/src/plugins/builtin/themes/headless.ts +6 -4
- package/src/plugins/builtin/themes/model.ts +17 -8
- package/src/plugins/builtin/themes/pane.tsx +7 -7
- 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 +1 -1
- package/src/plugins/builtin/ticker-detail/pane.tsx +3 -2
- package/src/plugins/builtin/ticker-detail/quote-footer.ts +6 -1
- 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-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/charts.tsx +9 -4
- package/src/plugins/builtin/vol-surface/client.ts +9 -17
- package/src/plugins/builtin/vol-surface/headless.ts +63 -14
- package/src/plugins/builtin/vol-surface/index.tsx +2 -2
- package/src/plugins/builtin/vol-surface/model.ts +22 -7
- package/src/plugins/builtin/vol-surface/pane.tsx +48 -9
- package/src/plugins/builtin/vol-surface/tables.ts +31 -3
- package/src/plugins/builtin/volatility/dvol.ts +46 -0
- package/src/plugins/builtin/volatility/index.tsx +2 -2
- package/src/plugins/builtin/volatility/pane.tsx +4 -4
- package/src/plugins/builtin/volatility/series.ts +26 -0
- package/src/plugins/builtin/world-indices/footer.ts +1 -1
- package/src/plugins/builtin/world-venue-map/headless.ts +3 -3
- package/src/plugins/catalog-browser.ts +13 -8
- package/src/plugins/catalog-manifest.ts +2 -1
- package/src/plugins/marketplace/model.ts +18 -5
- package/src/portfolio/column-values.ts +5 -5
- package/src/portfolio/futures-positions.ts +6 -3
- package/src/portfolio/position-quantity.ts +15 -9
- package/src/public/__snapshots__/public-api.test.ts.snap +1 -0
- package/src/remote/resources.ts +2 -1
- package/src/renderers/browser/app-services.ts +1 -7
- package/src/renderers/browser/config-host.ts +2 -55
- package/src/renderers/browser/main.tsx +7 -57
- package/src/renderers/dom/data-table/row.tsx +26 -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 +222 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +29 -7
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +7 -0
- package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -0
- package/src/renderers/electrobun/bun/desktop/relaunch.ts +74 -25
- package/src/renderers/electrobun/bun/desktop/state-broadcaster.ts +1 -0
- package/src/renderers/electrobun/bun/desktop/update.ts +173 -5
- package/src/renderers/electrobun/bun/desktop/view-ids.ts +52 -0
- package/src/renderers/electrobun/bun/desktop/workspace/index.ts +2 -0
- package/src/renderers/electrobun/bun/index.ts +25 -1
- package/src/renderers/electrobun/shared/app-name.ts +30 -0
- package/src/renderers/electrobun/shared/protocol.ts +10 -0
- package/src/renderers/electrobun/view/backend-rpc.ts +6 -0
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +3 -3
- package/src/renderers/electrobun/view/desktop/window/snapshot.ts +1 -0
- package/src/renderers/electrobun/view/main.tsx +24 -1
- package/src/renderers/electrobun/view/news-source.ts +3 -1
- package/src/renderers/electrobun/view/remote/ticker-repository.ts +14 -7
- package/src/renderers/electrobun/view/view-ids.ts +85 -0
- package/src/renderers/opentui/start.tsx +5 -0
- package/src/renderers/opentui/toast-host.tsx +71 -43
- 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/index.ts +1 -0
- package/src/sources/gloomberb-cloud/news.ts +47 -7
- package/src/sources/gloomberb-cloud/normalizers.ts +2 -0
- package/src/sources/provider-router/batches.ts +10 -2
- package/src/sources/provider-router/financial-routes.ts +3 -3
- package/src/sources/provider-router/financials.ts +15 -3
- package/src/sources/provider-router/history.ts +28 -7
- package/src/sources/provider-router/index.ts +149 -10
- package/src/sources/provider-router/search.ts +13 -2
- package/src/state/app/context/index.tsx +3 -0
- package/src/state/ticker-cleanup.ts +50 -0
- package/src/sync/auth-transition.ts +19 -9
- package/src/sync/baseline.ts +10 -4
- package/src/sync/controller.ts +70 -19
- package/src/sync/core-contributors.ts +90 -31
- package/src/sync/react.ts +4 -1
- package/src/sync/types.ts +3 -0
- 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/telemetry/usage-counts.ts +0 -18
- package/src/test-support/preload.ts +14 -0
- package/src/theme/colors.ts +8 -0
- package/src/theme/themes.ts +10 -0
- package/src/tickers/company-name.ts +103 -3
- package/src/tickers/listing-venues.ts +38 -3
- package/src/tickers/search/bare-symbol.ts +36 -0
- package/src/tickers/search/index.ts +36 -7
- package/src/tickers/search/ranking.ts +10 -1
- package/src/tickers/search/types.ts +5 -0
- package/src/tickers/terminal-codes.ts +19 -0
- package/src/time-series/alignment.ts +1 -1
- package/src/time-series/base-series.ts +13 -5
- package/src/time-series/daily-valuation.ts +62 -0
- package/src/time-series/economic.ts +18 -4
- package/src/time-series/field-catalog.ts +2 -4
- package/src/time-series/filed-trailing-eps.ts +197 -0
- package/src/time-series/forward-valuation.ts +32 -0
- package/src/time-series/fundamentals.ts +198 -7
- package/src/time-series/hooks.ts +1 -0
- package/src/time-series/ice-credit.ts +3 -0
- package/src/time-series/price-comparison.ts +30 -2
- package/src/time-series/price-units.ts +72 -2
- package/src/time-series/resolve-context.ts +7 -1
- package/src/time-series/resolve.ts +116 -15
- package/src/time-series/series-presentation.ts +40 -6
- package/src/time-series/session-bar.ts +11 -0
- package/src/time-series/spec.ts +5 -3
- package/src/time-series/studies.ts +278 -74
- package/src/time-series/total-return.ts +160 -0
- package/src/time-series/transforms.ts +3 -3
- package/src/time-series/types.ts +27 -1
- package/src/time-series/valuation-releases.ts +39 -0
- package/src/types/data-provider.ts +9 -1
- package/src/types/desktop-window.ts +2 -0
- package/src/types/financials.ts +73 -2
- package/src/types/headless.ts +61 -5
- package/src/types/instrument.ts +3 -0
- package/src/types/news-source.ts +1 -0
- package/src/types/plugin.ts +10 -1
- package/src/ui/host.tsx +3 -0
- package/src/updater/command-names.ts +12 -7
- package/src/updater/failure.ts +4 -1
- package/src/utils/cli-output.ts +42 -1
- package/src/utils/crypto-pair.ts +44 -0
- package/src/utils/financial-statements.ts +6 -1
- package/src/utils/forward-dividend.ts +2 -0
- package/src/utils/fundamentals.ts +24 -3
- 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/network-failure.ts +9 -6
- package/src/utils/option-expiry.ts +48 -1
- package/src/utils/options.ts +10 -0
- package/src/utils/plugin-proxy-hosts.json +1 -0
- package/src/utils/price-history.ts +12 -1
- package/src/utils/shell-word.ts +8 -0
- package/src/utils/trailing-dividend.ts +53 -4
- package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +0 -17
- package/src/renderers/browser/first-screen.ts +0 -193
|
@@ -25,6 +25,7 @@ import { formatMarketPriceWithCurrency, quoteFormatOptions } from "../../market-
|
|
|
25
25
|
import { formerIssuerLine, startTickerChangeLookup, type TickerChangeLookup } from "../../tickers/ticker-changes";
|
|
26
26
|
import { fail, failRetryable } from "../errors";
|
|
27
27
|
import { isProviderBusy, SEARCH_BUSY_CODE, SEARCH_BUSY_MESSAGE } from "../../sources/provider-errors";
|
|
28
|
+
import { isNetworkFailure } from "../../utils/network-failure";
|
|
28
29
|
import type { MarketContext } from "../types";
|
|
29
30
|
import type { CliCommandContext, GloomPlugin } from "../../types/plugin";
|
|
30
31
|
import { indexRootTryLine } from "../index-roots";
|
|
@@ -132,11 +133,13 @@ export async function searchCandidatesForCli({
|
|
|
132
133
|
const quote = BARE_SYMBOL.test(symbol) && candidates.some((candidate) => candidate.symbol.toUpperCase() === symbol)
|
|
133
134
|
? await (quoted ?? loadSearchedQuote(symbol, savedExchange, dataProvider))
|
|
134
135
|
: null;
|
|
135
|
-
return withQuotedNames(symbol, withHomeListingPrimary(trimmedQuery, withPrimaryListingFirst(symbol, candidates, quote)), quote)
|
|
136
|
+
return withQuotedNames(symbol, withUsLineOfPrimary(withHomeListingPrimary(trimmedQuery, withPrimaryListingFirst(symbol, candidates, quote))), quote)
|
|
136
137
|
.slice(0, totalLimit);
|
|
137
138
|
} catch (error) {
|
|
138
139
|
// Not "No matches found": a script or a reader would take that for a name nothing lists.
|
|
139
140
|
if (isProviderBusy(error)) failRetryable(SEARCH_BUSY_MESSAGE, SEARCH_BUSY_CODE);
|
|
141
|
+
// Nor is no answer at all: the command fails as "couldn't reach", as any command offline does.
|
|
142
|
+
if (isNetworkFailure(error)) throw error;
|
|
140
143
|
logFailure("cli.commands-search", "Search ticker candidates failed")(error);
|
|
141
144
|
return [];
|
|
142
145
|
}
|
|
@@ -204,9 +207,19 @@ function formerIssuerNote(candidate: TickerSearchCandidate): string | null {
|
|
|
204
207
|
return formerIssuerLine(former.symbol, former, former.successor ?? { symbol: candidate.label, name: resolveSearchName(candidate) });
|
|
205
208
|
}
|
|
206
209
|
|
|
207
|
-
/**
|
|
210
|
+
/**
|
|
211
|
+
* A row search found by the name its company had before it was renamed
|
|
212
|
+
* ("cassava" finds Filana Therapeutics' FLNA): says what it was called.
|
|
213
|
+
*/
|
|
214
|
+
function formerNameNote(candidate: TickerSearchCandidate): string | null {
|
|
215
|
+
const formerName = candidate.result?.formerName;
|
|
216
|
+
if (typeof formerName !== "string" || !formerName.trim()) return null;
|
|
217
|
+
return `${candidate.label} is ${resolveSearchName(candidate)}, formerly ${formerName.trim()}`;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** The merged companies' and renamed companies' lines, once each, unless the symbol's own line already says it. */
|
|
208
221
|
function formerIssuerNotes(candidates: readonly TickerSearchCandidate[], fate: SearchFate): string[] {
|
|
209
|
-
const notes = new Set(candidates.flatMap((candidate) => formerIssuerNote(candidate) ?? []));
|
|
222
|
+
const notes = new Set(candidates.flatMap((candidate) => formerIssuerNote(candidate) ?? formerNameNote(candidate) ?? []));
|
|
210
223
|
return [...notes].filter((note) => !fate.notes.some((line) => line.split(" ")[0] === note.split(" ")[0]));
|
|
211
224
|
}
|
|
212
225
|
|
|
@@ -286,6 +299,26 @@ function withHomeListingPrimary(query: string, candidates: TickerSearchCandidate
|
|
|
286
299
|
return [...rest.slice(0, at), { ...home, category: "Primary Listing" as const }, { ...primary, category: "Other Listings" as const }, ...rest.slice(at + 1)];
|
|
287
300
|
}
|
|
288
301
|
|
|
302
|
+
/**
|
|
303
|
+
* A company whose primary listing is abroad lists the US line of the same
|
|
304
|
+
* symbol right after it: the line `quote SHEL` reads (a bare symbol is its US
|
|
305
|
+
* listing), which a name search ("shell") would otherwise rank below the
|
|
306
|
+
* company's lines on other venues and cut. Any other list keeps its order.
|
|
307
|
+
*/
|
|
308
|
+
function withUsLineOfPrimary(candidates: TickerSearchCandidate[]): TickerSearchCandidate[] {
|
|
309
|
+
const primary = candidates.find((candidate) => candidate.category === "Primary Listing");
|
|
310
|
+
if (!primary || primary.kind !== "search" || isUsListingExchange(candidateExchange(primary))) return candidates;
|
|
311
|
+
const symbol = primary.symbol.toUpperCase();
|
|
312
|
+
const company = resolveSearchName(primary);
|
|
313
|
+
const us = candidates.find((candidate) => candidate !== primary && candidate.kind === "search" && !candidate.contractKey
|
|
314
|
+
&& candidate.category !== "Funds & Derivatives" && candidate.symbol.toUpperCase() === symbol
|
|
315
|
+
&& isUsListingExchange(candidateExchange(candidate)) && sameCompany(resolveSearchName(candidate), company));
|
|
316
|
+
if (!us) return candidates;
|
|
317
|
+
const rest = candidates.filter((candidate) => candidate !== us);
|
|
318
|
+
const at = rest.indexOf(primary) + 1;
|
|
319
|
+
return [...rest.slice(0, at), { ...us, category: "Other Listings" as const }, ...rest.slice(at)];
|
|
320
|
+
}
|
|
321
|
+
|
|
289
322
|
/** The candidate on the venue the quote prices; the US exchanges share one symbol, so a quote on any of them is its one US line. */
|
|
290
323
|
function quotedCandidate(candidates: readonly TickerSearchCandidate[], quote: Quote | null): TickerSearchCandidate | undefined {
|
|
291
324
|
const quoted = canonicalExchange(quote?.listingExchangeName || quote?.exchangeName);
|
|
@@ -366,6 +399,9 @@ function searchCandidateRows(candidates: TickerSearchCandidate[]) {
|
|
|
366
399
|
saved: candidate.kind === "ticker",
|
|
367
400
|
// The company that merged into this one, whose old name the query is.
|
|
368
401
|
...candidate.result?.formerIssuer ? { formerIssuer: candidate.result.formerIssuer } : {},
|
|
402
|
+
// The name a renamed company had, which the query is.
|
|
403
|
+
...typeof candidate.result?.formerName === "string" && candidate.result.formerName.trim()
|
|
404
|
+
? { formerName: candidate.result.formerName.trim() } : {},
|
|
369
405
|
}));
|
|
370
406
|
}
|
|
371
407
|
|
|
@@ -16,14 +16,23 @@ function themeChoicesText(): string {
|
|
|
16
16
|
return `Themes: ${choices}. gloom config themes lists them with notes.`;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
/** `Light themes: paper (Paper), github-light (GitHub Light), ...`, for `light` or `dark` typed as a theme; null for anything else. */
|
|
20
|
+
function appearanceHint(input: string): string | null {
|
|
21
|
+
const appearance = input.trim().toLowerCase();
|
|
22
|
+
if (appearance !== "light" && appearance !== "dark") return null;
|
|
23
|
+
const matching = listThemes().filter((theme) => theme.appearance === appearance).map(({ id, name }) => `${id} (${name})`);
|
|
24
|
+
return matching.length > 0 ? ` ${appearance === "light" ? "Light" : "Dark"} themes: ${matching.join(", ")}.` : null;
|
|
25
|
+
}
|
|
26
|
+
|
|
19
27
|
/**
|
|
20
28
|
* The id `input` names, by id or display name in any case. Anything else
|
|
21
|
-
* fails with the closest id when there is one, and every id with its name
|
|
29
|
+
* fails with the closest id when there is one, and every id with its name;
|
|
30
|
+
* `light` or `dark` with the themes of that look.
|
|
22
31
|
*/
|
|
23
32
|
export function requireThemeId(input: string): string {
|
|
24
33
|
const lookup = resolveThemeId(input);
|
|
25
34
|
if (lookup.ok) return lookup.id;
|
|
26
|
-
const hint = lookup.suggestion ? ` Did you mean ${describeThemeId(lookup.suggestion)}?` : "";
|
|
35
|
+
const hint = appearanceHint(input) ?? (lookup.suggestion ? ` Did you mean ${describeThemeId(lookup.suggestion)}?` : "");
|
|
27
36
|
return fail(`Unknown theme "${input.trim()}".${hint}`, themeChoicesText());
|
|
28
37
|
}
|
|
29
38
|
|
|
@@ -3,12 +3,12 @@ import { formatShortDate, parseDisplayDate } from "../../utils/datetime-format";
|
|
|
3
3
|
import { formatReportedMoney } from "../../utils/reported-money";
|
|
4
4
|
import {
|
|
5
5
|
appTtmRate, computedEnterpriseValueNote, convertedPriceEarningsNote, enterpriseValueLabel, enterpriseValueReconciliationNote, epsConversionNote,
|
|
6
|
-
fundamentalsCurrency, reportedEnterpriseValue, ttmAtAppRate, ttmConversionNote,
|
|
6
|
+
fundamentalsCurrency, reportedEnterpriseValue, trailingEpsSourceNote, ttmAtAppRate, ttmConversionNote,
|
|
7
7
|
} from "../../utils/fundamentals";
|
|
8
8
|
import { latestFinancialPeriod } from "../../utils/latest-financial-period";
|
|
9
9
|
import { burnsCash, cashRunway, SHORT_RUNWAY_HISTORY, formatRunwayMonths, offeringNote, offeringsAfter, runwayMethod, type CashRunway, type OfferingFiling, type RunwayEstimate } from "../../utils/cash-runway";
|
|
10
10
|
import { exportedFundamentals, formatPriceEarnings, NOT_MEANINGFUL, priceEarningsOnEarnings } from "../../utils/price-earnings";
|
|
11
|
-
import { describeFundamentalMarketCap, marketCapBasisNote, selectMarketCapitalization, viewMarketCapitalization } from "../../utils/market-capitalization";
|
|
11
|
+
import { describeFundamentalMarketCap, marketCapBasisNote, selectMarketCapitalization, viewMarketCapitalization, withheldMarketCap } from "../../utils/market-capitalization";
|
|
12
12
|
import {
|
|
13
13
|
formatCompact,
|
|
14
14
|
formatCurrency,
|
|
@@ -76,7 +76,7 @@ import { isKnownNonUsListing, secFilingItemCodes, US_FUND_FACTS_ONLY } from "../
|
|
|
76
76
|
import { currentReportItemsLabel, hiddenFilingsNote, loadLatestFilings, type HiddenFilings } from "../../utils/sec-filings";
|
|
77
77
|
import { canonicalExchange, exchangeLabel, isKnownExchangeCode, isUsListingExchange } from "../../utils/exchanges";
|
|
78
78
|
import {
|
|
79
|
-
failIfNotTraded, failMovedSymbol, ListingArgError, listingChoiceNotes, listingFateLoader, listingIdentity, loadBareVenues,
|
|
79
|
+
coinListingNotes, failIfNotTraded, failMovedSymbol, ListingArgError, listingChoiceNotes, listingFateLoader, listingIdentity, loadBareVenues,
|
|
80
80
|
resolveCliListing, type CliListing, type ListingDataRequest,
|
|
81
81
|
} from "../listing-arg";
|
|
82
82
|
import { movedAwayChange } from "../../tickers/ticker-changes";
|
|
@@ -92,12 +92,12 @@ import { fundamentalsFreshness, quotesFreshness } from "../freshness";
|
|
|
92
92
|
import { distributionHistory, forwardDividendBasis, forwardDividendMayHaveLapsed, lapsedDividend, noCurrentDividend, TRAILING_DIVIDEND_BASIS, type DistributionHistory, type DividendLapse } from "../../utils/forward-dividend";
|
|
93
93
|
import { declaredDividends } from "../../utils/declared-dividends";
|
|
94
94
|
import { historyTrailingDividendYield, measuresTrailingYield } from "../../market-data/quotes/live-valuation";
|
|
95
|
-
import { notTheCoinNote } from "./crypto-hints";
|
|
96
95
|
import { loadOfferingFilings, loadStatementFilings, resultsReleaseText, statementPeriodText, type StatementFilingsReport } from "../statement-filings";
|
|
97
96
|
import type { BankFiguresPayload } from "../../api-client/bank-figures";
|
|
98
97
|
import { bankSection } from "../bank-section";
|
|
99
|
-
import type { FundBondFacts } from "../../api-client/fund-facts";
|
|
100
|
-
import { bondFigures,
|
|
98
|
+
import type { FundBondFacts, FundFactsPayload } from "../../api-client/fund-facts";
|
|
99
|
+
import { bondFigures, NOT_SEC_YIELD } from "../../market-data/bond-funds";
|
|
100
|
+
import { readFundFacts } from "../../market-data/fund-facts";
|
|
101
101
|
import { taxEquivalentLines, type TaxEquivalentAnalysis } from "../../market-data/tax-equivalent";
|
|
102
102
|
import { isRoundTheClockCoin } from "../../utils/crypto-pair";
|
|
103
103
|
import { coinNewsFallbackNotice } from "../../sources/gloomberb-cloud/news";
|
|
@@ -667,21 +667,23 @@ function isYieldMetric(label: string): boolean {
|
|
|
667
667
|
}
|
|
668
668
|
|
|
669
669
|
/**
|
|
670
|
-
* A US-listed fund's
|
|
671
|
-
*
|
|
670
|
+
* A US-listed fund's facts for the report: the bond figures its yield lines
|
|
671
|
+
* read, and whether `fn ETF` has figures to point to. Null for any other
|
|
672
|
+
* listing, and when they cannot be read, which leaves the yield as it was
|
|
673
|
+
* and points nowhere.
|
|
672
674
|
*/
|
|
673
|
-
export async function
|
|
675
|
+
export async function loadReportFundFacts(
|
|
674
676
|
symbol: string,
|
|
675
677
|
exchange: string | undefined,
|
|
676
678
|
financials: Pick<TickerFinancials, "quote" | "quoteMetadata">,
|
|
677
679
|
tickerFile: TickerRecord | null = null,
|
|
678
|
-
load: (symbol: string) => Promise<
|
|
679
|
-
): Promise<
|
|
680
|
+
load: (symbol: string) => Promise<FundFactsPayload> = (ticker) => readFundFacts(ticker),
|
|
681
|
+
): Promise<FundFactsPayload | null> {
|
|
680
682
|
if (resolveTickerInstrumentKind(tickerFile, financials) !== "fund" || (exchange && !isUsListingExchange(exchange))) return null;
|
|
681
683
|
try {
|
|
682
684
|
return await load(symbol);
|
|
683
685
|
} catch (error) {
|
|
684
|
-
logFailure("cli.commands-ticker", "Read
|
|
686
|
+
logFailure("cli.commands-ticker", "Read fund facts failed")(error);
|
|
685
687
|
return null;
|
|
686
688
|
}
|
|
687
689
|
}
|
|
@@ -712,7 +714,8 @@ function fundamentalsMetrics(
|
|
|
712
714
|
{ label: "P/E (TTM)", ...multipleFigure(priceEarningsOnEarnings(fundamentals?.trailingPE, fundamentals?.eps)) },
|
|
713
715
|
{ label: "Forward P/E", ...multipleFigure(priceEarningsOnEarnings(fundamentals?.forwardPE, fundamentals?.forwardEps)) },
|
|
714
716
|
{ label: "PEG", ...multipleFigure(fundamentals?.pegRatio) },
|
|
715
|
-
//
|
|
717
|
+
// EPS (TTM) is the last four filed quarters' (filed-trailing-eps), so its twelve months can end before those of
|
|
718
|
+
// the flows below, Gloom Cloud's trailing block; Gloom Cloud's EPS standing in is noted (trailingEpsSourceNote).
|
|
716
719
|
{ label: "EPS (TTM)", ...reportedMoney(fundamentals?.eps, fundamentals?.epsCurrency?.trim() || reportingCurrency, true, codes) },
|
|
717
720
|
{
|
|
718
721
|
label: dividendYieldLabel(fundamentals?.dividendYieldBasis, bond),
|
|
@@ -797,6 +800,7 @@ function fundamentalsNotes(
|
|
|
797
800
|
: undefined;
|
|
798
801
|
const conversion = [...TRAILING_MONEY_METRICS].some(shown) ? ttmConversionNote(fundamentals) : undefined;
|
|
799
802
|
const eps = shown("EPS (TTM)") ? epsConversionNote(fundamentals) : undefined;
|
|
803
|
+
const epsSource = trailingEpsSourceNote(fundamentals, { eps: shown("EPS (TTM)"), pe: shown("P/E (TTM)") });
|
|
800
804
|
const priceEarnings = metrics.some((metric) => metric.label === "P/E (TTM)" && typeof metric.value === "number")
|
|
801
805
|
? convertedPriceEarningsNote(fundamentals, quoteCurrency)
|
|
802
806
|
: undefined;
|
|
@@ -804,7 +808,9 @@ function fundamentalsNotes(
|
|
|
804
808
|
const enterpriseValue = shown("Enterprise Value")
|
|
805
809
|
? enterpriseValueReconciliationNote(fundamentals) ?? computedEnterpriseValueNote(fundamentals)
|
|
806
810
|
: undefined;
|
|
807
|
-
|
|
811
|
+
// A cap Gloom Cloud withheld says why, as RV and EQS do.
|
|
812
|
+
const withheld = withheldMarketCap(fundamentals)?.note;
|
|
813
|
+
return [withheld, shareBasis, enterpriseValue, conversion, eps, epsSource, priceEarnings].filter((note): note is string => !!note);
|
|
808
814
|
}
|
|
809
815
|
|
|
810
816
|
// The share count is the market cap's basis: the cap is the count times the price, or a note says why not.
|
|
@@ -814,8 +820,10 @@ type FundamentalsReportData = TickerFinancials & {
|
|
|
814
820
|
symbol: string;
|
|
815
821
|
exchange?: string;
|
|
816
822
|
distributions?: DividendDistributions | null;
|
|
817
|
-
/** A bond fund's SEC yield, yield to worst and duration (
|
|
823
|
+
/** A bond fund's SEC yield, yield to worst and duration (loadReportFundFacts). */
|
|
818
824
|
bondFund?: FundBondFacts | null;
|
|
825
|
+
/** A US-listed fund's facts (loadReportFundFacts): the note points to `fn ETF` only when they cover it. */
|
|
826
|
+
fundFacts?: FundFactsPayload | null;
|
|
819
827
|
/** `fundamentals --tax-rate`: the tax-equivalent yield and muni/Treasury ratio. */
|
|
820
828
|
taxEquivalent?: TaxEquivalentAnalysis | null;
|
|
821
829
|
/** The filings behind the latest statements, and a newer quarter's results release. */
|
|
@@ -839,20 +847,25 @@ function statementFilingsNotes(report: StatementFilingsReport | null | undefined
|
|
|
839
847
|
}
|
|
840
848
|
|
|
841
849
|
/**
|
|
842
|
-
* Where a fund's facts are: for a US listing, the ETF function
|
|
843
|
-
* premium, net assets)
|
|
844
|
-
* fund
|
|
850
|
+
* Where a fund's facts are: for a US listing, the ETF function, naming the
|
|
851
|
+
* figures it has (fee, NAV, premium, net assets), and only when it has some:
|
|
852
|
+
* a fund it has none for, or whose facts could not be read, gets no pointer
|
|
853
|
+
* to a pane that would only say why. A fund listed elsewhere has none yet.
|
|
854
|
+
* Only for a fund: a stock's report says nothing of it.
|
|
845
855
|
*/
|
|
846
856
|
function fundFactsNote(
|
|
847
857
|
symbol: string,
|
|
848
858
|
exchange: string | undefined,
|
|
849
859
|
financials: Pick<TickerFinancials, "quote" | "quoteMetadata">,
|
|
850
860
|
tickerFile: TickerRecord | null = null,
|
|
861
|
+
facts: FundFactsPayload | null = null,
|
|
851
862
|
): string | null {
|
|
852
863
|
if (resolveTickerInstrumentKind(tickerFile, financials) !== "fund") return null;
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
864
|
+
if (exchange && !isUsListingExchange(exchange)) return US_FUND_FACTS_ONLY;
|
|
865
|
+
if (!facts?.covered) return null;
|
|
866
|
+
const figures = [facts.expenseRatio && "fee", facts.nav && "NAV", facts.premiumDiscount && "premium", facts.netAssets && "net assets"]
|
|
867
|
+
.filter((figure): figure is string => !!figure);
|
|
868
|
+
return `Fund facts${figures.length ? ` (${figures.join(", ")})` : ""}: fn ETF ${symbol}.`;
|
|
856
869
|
}
|
|
857
870
|
|
|
858
871
|
/**
|
|
@@ -947,7 +960,7 @@ export function renderFundamentalsReport(
|
|
|
947
960
|
const before = lines.length;
|
|
948
961
|
const metrics = fundamentalsReportMetrics(financials, view);
|
|
949
962
|
appendMetricSection(lines, view === "valuation" ? "Valuation" : "Fundamentals", metricLines(metrics));
|
|
950
|
-
const fund = fundFactsNote(symbol, financials.exchange || quote?.exchangeName, financials);
|
|
963
|
+
const fund = fundFactsNote(symbol, financials.exchange || quote?.exchangeName, financials, null, financials.fundFacts);
|
|
951
964
|
if (lines.length === before) lines.push("", cliStyles.muted([`No ${view} reported for ${financials.symbol}.`, fund].filter(Boolean).join(" ")));
|
|
952
965
|
else if (fund) lines.push(cliStyles.muted(fund));
|
|
953
966
|
for (const note of fundamentalsNotes(atRegularSessionPrice(financials), metrics, quote?.currency)) lines.push(cliStyles.muted(note));
|
|
@@ -987,7 +1000,8 @@ export function fundamentalsReportTables(
|
|
|
987
1000
|
freshness: ReportFreshness,
|
|
988
1001
|
): CliReportTables {
|
|
989
1002
|
const metrics = fundamentalsReportMetrics(financials, view);
|
|
990
|
-
const fund = fundFactsNote(financials.quote?.symbol ?? financials.symbol, financials.exchange || financials.quote?.exchangeName, financials
|
|
1003
|
+
const fund = fundFactsNote(financials.quote?.symbol ?? financials.symbol, financials.exchange || financials.quote?.exchangeName, financials, null,
|
|
1004
|
+
financials.fundFacts);
|
|
991
1005
|
const tables = [exportEntriesTable(
|
|
992
1006
|
view === "valuation" ? "Valuation" : "Fundamentals",
|
|
993
1007
|
metrics.map((metric) => ({ label: metric.label, value: metric.value, formatted: metric.text, unit: metric.unit })),
|
|
@@ -1064,6 +1078,7 @@ export async function buildTickerReport({
|
|
|
1064
1078
|
distributions = null,
|
|
1065
1079
|
statementFilings = null,
|
|
1066
1080
|
bondFund = null,
|
|
1081
|
+
fundFacts = null,
|
|
1067
1082
|
memberships,
|
|
1068
1083
|
offerings = [],
|
|
1069
1084
|
}: {
|
|
@@ -1074,8 +1089,10 @@ export async function buildTickerReport({
|
|
|
1074
1089
|
statementFilings?: StatementFilingsReport | null;
|
|
1075
1090
|
/** The company's latest offering prospectuses (424B5, 424B4); those after the latest balance sheet get a note. */
|
|
1076
1091
|
offerings?: readonly OfferingFiling[];
|
|
1077
|
-
/** A bond fund's SEC yield, yield to worst and duration (
|
|
1092
|
+
/** A bond fund's SEC yield, yield to worst and duration (loadReportFundFacts). */
|
|
1078
1093
|
bondFund?: FundBondFacts | null;
|
|
1094
|
+
/** A US-listed fund's facts (loadReportFundFacts): the report points to `fn ETF` only when they cover it. */
|
|
1095
|
+
fundFacts?: FundFactsPayload | null;
|
|
1079
1096
|
/** The distributions a dividend yield is read with (loadDividendDistributions). */
|
|
1080
1097
|
distributions?: DividendDistributions | null;
|
|
1081
1098
|
/** The exchange the command named, as a canonical code. */
|
|
@@ -1091,7 +1108,7 @@ export async function buildTickerReport({
|
|
|
1091
1108
|
notes?: string;
|
|
1092
1109
|
/** Why there is no quote, when a source said; "Quote unavailable." otherwise. */
|
|
1093
1110
|
quoteNote?: string;
|
|
1094
|
-
/** "CAR = Avis Budget Group, NASDAQ (
|
|
1111
|
+
/** "CAR = Avis Budget Group, NASDAQ (different companies on XETRA, ASX)", for a bare symbol several companies list. */
|
|
1095
1112
|
listingNote?: string;
|
|
1096
1113
|
recentNews?: NewsArticle[];
|
|
1097
1114
|
recentSecFilings?: SecFilingItem[];
|
|
@@ -1254,7 +1271,8 @@ export async function buildTickerReport({
|
|
|
1254
1271
|
if (lines.length > beforeFundamentals) for (const note of conversionNotes(toBase, convertedCurrencies, rates)) lines.push(cliStyles.muted(note));
|
|
1255
1272
|
// Where a fund's facts would go: under its fundamentals, or in their place.
|
|
1256
1273
|
const fund = fundFactsNote(quote?.symbol ?? symbol,
|
|
1257
|
-
quote?.tradingExchangeName || listingExchange || quote?.listingExchangeName || quote?.exchangeName || tickerFile?.metadata.exchange, financials, tickerFile
|
|
1274
|
+
quote?.tradingExchangeName || listingExchange || quote?.listingExchangeName || quote?.exchangeName || tickerFile?.metadata.exchange, financials, tickerFile,
|
|
1275
|
+
fundFacts);
|
|
1258
1276
|
if (fund) lines.push(...lines.length === beforeFundamentals ? [""] : [], cliStyles.muted(fund));
|
|
1259
1277
|
|
|
1260
1278
|
if (capitalization?.provenance.kind === "fundamentals") {
|
|
@@ -1494,7 +1512,8 @@ export async function ticker(symbol: string, dependencies: TickerCommandDependen
|
|
|
1494
1512
|
|
|
1495
1513
|
let financials: TickerFinancials | null = null;
|
|
1496
1514
|
try {
|
|
1497
|
-
|
|
1515
|
+
// The Change line says what the move is from.
|
|
1516
|
+
financials = await dataProvider.getTickerFinancials(requestSymbol, exchange, { datesChangeBasis: true });
|
|
1498
1517
|
} catch (error) {
|
|
1499
1518
|
// A known exchange the symbol is not listed on: say where it is.
|
|
1500
1519
|
await failIfNotTraded(listing, { store, dataProvider }, { fail: failCommand });
|
|
@@ -1534,10 +1553,11 @@ export async function ticker(symbol: string, dependencies: TickerCommandDependen
|
|
|
1534
1553
|
// The yield's distributions, read beside the rest when a trailing yield, a forward basis or its lapse needs them; they never fail the report.
|
|
1535
1554
|
const distributions = loadDividendDistributions(dataProvider, { symbol: requestSymbol, exchange }, resolvedFinancials,
|
|
1536
1555
|
{ declared: !dependencies.printResult });
|
|
1537
|
-
// A
|
|
1538
|
-
const
|
|
1556
|
+
// A fund's facts: its bond figures beside its distribution yield, and whether fn ETF has any to point to.
|
|
1557
|
+
const fundFacts = loadReportFundFacts(requestSymbol,
|
|
1539
1558
|
quote?.tradingExchangeName || exchange || quote?.listingExchangeName || quote?.exchangeName || tickerFile?.metadata.exchange,
|
|
1540
1559
|
resolvedFinancials, tickerFile);
|
|
1560
|
+
const bondFund = fundFacts.then((facts) => facts?.bond ?? null);
|
|
1541
1561
|
const statementFilings = loadStatementFilings(statementSources, { symbol: requestSymbol, exchange }, {
|
|
1542
1562
|
quarter: latestFinancialPeriod(resolvedFinancials.quarterlyStatements, (row) => row.date),
|
|
1543
1563
|
annual: latestFinancialPeriod(resolvedFinancials.annualStatements, (row) => row.date),
|
|
@@ -1588,17 +1608,18 @@ export async function ticker(symbol: string, dependencies: TickerCommandDependen
|
|
|
1588
1608
|
// The quote is the feed in this report; without one, the fundamentals date it.
|
|
1589
1609
|
const freshness = quote ? quotesFreshness([quote]) : fundamentalsFreshness(resolvedFinancials);
|
|
1590
1610
|
const quoteNote = quote ? undefined : await quoteUnavailableNote(dataProvider, requestSymbol, exchange);
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1611
|
+
// A bare coin ticker read as another listing says where the coin is, as `quote` does: from the quote, else from the saved listing.
|
|
1612
|
+
const choiceNotes = [
|
|
1613
|
+
...await listingChoiceNotes(listing, { store, dataProvider }, quote, venues),
|
|
1614
|
+
...quote || !tickerFile ? [] : coinListingNotes(listing, { name: tickerFile.metadata.name, instrumentType: tickerFile.metadata.assetCategory }),
|
|
1615
|
+
];
|
|
1616
|
+
const listingNote = choiceNotes.join("\n") || undefined;
|
|
1596
1617
|
const memberships = await membershipsLoad;
|
|
1597
1618
|
// A converted TTM block at the rate the rest of the report converts at, the one `fx` reports.
|
|
1598
1619
|
const shownFinancials = await atReportTtmRate(resolvedFinancials, toBase);
|
|
1599
1620
|
if (dependencies.printResult) {
|
|
1600
1621
|
const newsNote = recentNews[0]?.searchedFor ? coinNewsFallbackNotice(requestSymbol, recentNews[0].searchedFor) : null;
|
|
1601
|
-
const warnings = [
|
|
1622
|
+
const warnings = [...choiceNotes, quoteNote, newsNote].filter((note): note is string => !!note);
|
|
1602
1623
|
dependencies.printResult({
|
|
1603
1624
|
freshness,
|
|
1604
1625
|
warnings: warnings.length > 0 ? warnings : undefined,
|
|
@@ -1642,6 +1663,7 @@ export async function ticker(symbol: string, dependencies: TickerCommandDependen
|
|
|
1642
1663
|
distributions: await distributions,
|
|
1643
1664
|
statementFilings: await statementFilings,
|
|
1644
1665
|
bondFund: await bondFund,
|
|
1666
|
+
fundFacts: await fundFacts,
|
|
1645
1667
|
memberships,
|
|
1646
1668
|
offerings: await offerings,
|
|
1647
1669
|
}));
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { CliListing } from "./listing-arg";
|
|
2
|
+
import { companyNameSuggestion, isUnsettledNoProvider, type ListingDeps } from "./listing-arg";
|
|
3
|
+
import { describeSuggestion } from "./listing-suggestion";
|
|
4
|
+
import { isNotATickerMessage, withListingSuggestion } from "./not-a-ticker";
|
|
5
|
+
|
|
6
|
+
type SearchDeps = Pick<ListingDeps, "dataProvider">;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* "Not a ticker: PALANTIR TECHNOLOGIES. Did you mean PLTR (Palantir
|
|
10
|
+
* Technologies Inc.)?" for words typed where one ticker goes, with the
|
|
11
|
+
* company search names for them. Without one the sentence ends at the
|
|
12
|
+
* symbol, and the error printer adds the search to try.
|
|
13
|
+
*/
|
|
14
|
+
export async function notATickerWords(typed: string, deps: SearchDeps): Promise<string> {
|
|
15
|
+
const symbol = typed.trim().replace(/^\$/, "").toUpperCase();
|
|
16
|
+
const message = `Not a ticker: ${symbol}.`;
|
|
17
|
+
const suggestion = await companyNameSuggestion(typed, deps);
|
|
18
|
+
return suggestion ? withListingSuggestion(message, describeSuggestion(suggestion)) : message;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Why a command stops on a listing whose own quote failed with `error`, when
|
|
23
|
+
* the word typed for it is no ticker, or null when it is not known to be: the
|
|
24
|
+
* source's "Not a ticker: PALANTIR.", and a word a source could not answer for
|
|
25
|
+
* (a timeout, a rate limit) that search resolves to a company all the same, as
|
|
26
|
+
* `quote` says it of a name. Both name the company beside it. A real ticker a
|
|
27
|
+
* source failed to quote is not stopped here: it is not a company's name.
|
|
28
|
+
*/
|
|
29
|
+
export async function notATickerStop(
|
|
30
|
+
error: unknown,
|
|
31
|
+
listing: Pick<CliListing, "symbol" | "exchange" | "typed">,
|
|
32
|
+
deps: SearchDeps,
|
|
33
|
+
): Promise<string | null> {
|
|
34
|
+
const message = error instanceof Error ? error.message : null;
|
|
35
|
+
const notATicker = isNotATickerMessage(message);
|
|
36
|
+
if (!notATicker && !isUnsettledNoProvider(error)) return null;
|
|
37
|
+
if (listing.exchange || !listing.typed) return notATicker ? message : null;
|
|
38
|
+
const suggestion = await companyNameSuggestion(listing.typed, deps);
|
|
39
|
+
if (!suggestion) return notATicker ? message : null;
|
|
40
|
+
return withListingSuggestion(notATicker ? message! : `Not a ticker: ${listing.symbol}.`, describeSuggestion(suggestion));
|
|
41
|
+
}
|
|
@@ -43,7 +43,7 @@ export async function noListingCalendarNote(
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
|
-
* "SAN = Banco Santander, NYSE (
|
|
46
|
+
* "SAN = Banco Santander, NYSE (different companies on EPA, LSE)" for a bare symbol whose
|
|
47
47
|
* calendar date is its US line's, when several companies list the symbol:
|
|
48
48
|
* the event names the company the date is for.
|
|
49
49
|
*/
|
package/src/cli/errors.ts
CHANGED
|
@@ -9,9 +9,11 @@ import { DATA_SERVICE_UNREACHABLE_MESSAGE, isNetworkFailure } from "../utils/net
|
|
|
9
9
|
|
|
10
10
|
const USAGE_PREFIX = "Usage: ";
|
|
11
11
|
/** The code of every error a command fails with: bad input, nothing found, an option it does not take. */
|
|
12
|
-
const CLI_ERROR_CODE = "cli_error";
|
|
12
|
+
export const CLI_ERROR_CODE = "cli_error";
|
|
13
|
+
/** The code of a command that ran, and the data service has nothing for what it asked. */
|
|
14
|
+
export const NO_DATA_CODE = "no_data";
|
|
13
15
|
/** The code of a command whose requests never reached the data service. */
|
|
14
|
-
const SERVICE_UNREACHABLE_CODE = "service_unreachable";
|
|
16
|
+
export const SERVICE_UNREACHABLE_CODE = "service_unreachable";
|
|
15
17
|
|
|
16
18
|
/** What to check when nothing answered: the connection, and the proxy when one is set. */
|
|
17
19
|
function unreachableHint(): string {
|
|
@@ -61,6 +63,12 @@ export function failWithFields(message: string, code: string, fields: Record<str
|
|
|
61
63
|
throw new CliFailure(message, undefined, code, undefined, fields);
|
|
62
64
|
}
|
|
63
65
|
|
|
66
|
+
/** Fails as `error` says: its code, message, details and whether to retry, and any field it carries beside them. */
|
|
67
|
+
export function failWithError(error: CliErrorObject): never {
|
|
68
|
+
const { code, message, details, retryable, ...fields } = error;
|
|
69
|
+
throw new CliFailure(message, details, code, retryable, Object.keys(fields).length > 0 ? fields : undefined);
|
|
70
|
+
}
|
|
71
|
+
|
|
64
72
|
/** Fails with what asking again shortly may get past (a busy service): `--json` marks it `retryable`. */
|
|
65
73
|
export function failRetryable(message: string, code: string): never {
|
|
66
74
|
throw new CliFailure(message, undefined, code, true);
|
package/src/cli/export-source.ts
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* writes CSV or JSON, so an export can go in an audit file as it is: CSV ends
|
|
4
4
|
* with `#` lines and JSON carries a `source` object with the same fields.
|
|
5
5
|
* CSV and NDJSON rows also end with five fixed columns naming what each row
|
|
6
|
-
* is (`EXPORT_IDENTITY_COLUMNS`), less any the table already has by name
|
|
6
|
+
* is (`EXPORT_IDENTITY_COLUMNS`), less any the table already has by name; a
|
|
7
|
+
* dated export adds `period`, `released` and `retrieved` after them.
|
|
7
8
|
*/
|
|
8
9
|
import { formatFreshnessLine, type ReportFreshness } from "./pane-functions/freshness";
|
|
9
10
|
import { parseReportTime } from "../utils/utc-time";
|
|
@@ -54,6 +55,14 @@ export function exportSource(freshness: ReportFreshness): ExportSource {
|
|
|
54
55
|
*/
|
|
55
56
|
export const EXPORT_IDENTITY_COLUMNS = ["symbol_or_series", "currency_or_unit", "interval", "source", "as_of"] as const;
|
|
56
57
|
|
|
58
|
+
/**
|
|
59
|
+
* The columns a dated export (`econ`, `fred`, `fn ECST`) ends with after the
|
|
60
|
+
* five: the period a figure covers, when it was released, and when this export
|
|
61
|
+
* retrieved it. `as_of` is then the release, and these three say the rest, so a
|
|
62
|
+
* row never has to be read against the closing lines to be dated.
|
|
63
|
+
*/
|
|
64
|
+
export const EXPORT_DATING_COLUMNS = ["period", "released", "retrieved"] as const;
|
|
65
|
+
|
|
57
66
|
/** What a command knows about the rows it exports; source and as-of come from its freshness. */
|
|
58
67
|
export interface ExportIdentity {
|
|
59
68
|
/** The symbol or series ID asked for: `USDZAR=X`, `SAN:EPA`, `DEXSFUS`. */
|
|
@@ -68,6 +77,10 @@ export interface ExportIdentity {
|
|
|
68
77
|
* blank; absent, it is the closing lines' observation date.
|
|
69
78
|
*/
|
|
70
79
|
asOf?: string | null;
|
|
80
|
+
/** In a dated export: the period the figure covers, as its publisher names it (`Sep 2026`, `2026-09-01`). */
|
|
81
|
+
period?: string | null;
|
|
82
|
+
/** In a dated export: when the figure was released, an ISO date or instant; null when the data does not say. */
|
|
83
|
+
released?: string | null;
|
|
71
84
|
}
|
|
72
85
|
|
|
73
86
|
/** A row's own as-of in the closing lines' form: a date stays a date, an instant is ISO in UTC. */
|
|
@@ -94,6 +107,21 @@ export function exportIdentityCells(freshness: ReportFreshness, identity: Export
|
|
|
94
107
|
];
|
|
95
108
|
}
|
|
96
109
|
|
|
110
|
+
/**
|
|
111
|
+
* The cells of `EXPORT_DATING_COLUMNS` for a row: its period and release as
|
|
112
|
+
* the data states them, blank when it does not, and the time this export
|
|
113
|
+
* retrieved the data.
|
|
114
|
+
*/
|
|
115
|
+
export function exportDatingCells(freshness: ReportFreshness, identity: ExportIdentity = {}): string[] {
|
|
116
|
+
return [identity.period?.trim() ?? "", rowAsOf(identity.released ?? null), exportSource(freshness).retrievalTime];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** The three dating fields of an NDJSON row, null where blank. */
|
|
120
|
+
export function exportDatingFields(freshness: ReportFreshness, identity: ExportIdentity = {}): Record<string, string | null> {
|
|
121
|
+
const cells = exportDatingCells(freshness, identity);
|
|
122
|
+
return Object.fromEntries(EXPORT_DATING_COLUMNS.map((column, index) => [column, cells[index] || null]));
|
|
123
|
+
}
|
|
124
|
+
|
|
97
125
|
/** The same five as fields of an NDJSON row, null where blank. */
|
|
98
126
|
export function exportIdentityFields(freshness: ReportFreshness, identity: ExportIdentity = {}): Record<string, string | null> {
|
|
99
127
|
const cells = exportIdentityCells(freshness, identity);
|
package/src/cli/glossary.ts
CHANGED
|
@@ -714,7 +714,30 @@ export const GLOSSARY: readonly GlossaryEntry[] = [
|
|
|
714
714
|
},
|
|
715
715
|
{
|
|
716
716
|
term: "Other reportables", aliases: ["other reportable", "other reportable traders"], functions: ["COT"], shown: ["Other Reportables"],
|
|
717
|
-
definition: "The disaggregated
|
|
717
|
+
definition: "The disaggregated and TFF reports' large traders that fit none of their other classes, such as proprietary traders and family offices.",
|
|
718
|
+
},
|
|
719
|
+
// The Traders in Financial Futures report's classes, and the options it can count.
|
|
720
|
+
{
|
|
721
|
+
term: "Traders in Financial Futures", short: "TFF", aliases: ["tff report", "financial futures report", "financial traders report"], functions: ["COT"], shown: ["Financial (TFF)"],
|
|
722
|
+
definition: "The CFTC's report on financial futures, such as rates, currencies, stock indexes and VIX. "
|
|
723
|
+
+ "It splits large traders into dealers, asset managers, leveraged funds and other reportables.",
|
|
724
|
+
},
|
|
725
|
+
{
|
|
726
|
+
term: "Leveraged funds", aliases: ["leveraged fund", "leveraged money", "lev funds"], functions: ["COT"], shown: ["Leveraged Funds"],
|
|
727
|
+
definition: "The TFF report's hedge funds, CTAs and other money managers trading for clients or with borrowed money: the speculators most watched in rates, currencies and indexes.",
|
|
728
|
+
},
|
|
729
|
+
{
|
|
730
|
+
term: "Asset manager/institutional", aliases: ["asset manager", "asset managers", "institutional", "real money"], functions: ["COT"], shown: ["Asset Manager/Institutional"],
|
|
731
|
+
definition: "The TFF report's pension funds, insurers, mutual funds and endowments, investing for the long run; usually net long stock index futures.",
|
|
732
|
+
},
|
|
733
|
+
{
|
|
734
|
+
term: "Dealer/intermediary", aliases: ["dealer intermediary", "intermediary", "intermediaries"], functions: ["COT"], shown: ["Dealer/Intermediary"],
|
|
735
|
+
definition: "The TFF report's banks and dealers on the sell side, taking the other side of their clients' trades and hedging it.",
|
|
736
|
+
},
|
|
737
|
+
{
|
|
738
|
+
term: "Futures and options combined", aliases: ["futures + options", "futures and options", "combined report", "combined positions"], functions: ["COT"], shown: ["Futures + options"],
|
|
739
|
+
definition: "A COT report that adds each group's options to its futures, delta-adjusted: an option counts as the futures it moves like. "
|
|
740
|
+
+ "Futures only, the default, counts futures alone.",
|
|
718
741
|
},
|
|
719
742
|
// Futures basis and curve shape (CTM, FUT, PERP).
|
|
720
743
|
{
|
|
@@ -778,6 +801,42 @@ export const GLOSSARY: readonly GlossaryEntry[] = [
|
|
|
778
801
|
definition: "Cboe's index of the 30-day volatility that VIX options price: the VIX of the VIX. A high reading means traders are paying up "
|
|
779
802
|
+ "to protect against sudden jumps in VIX itself.",
|
|
780
803
|
},
|
|
804
|
+
// Options positioning (OPX, GEX) and the volatility surface (OVDV).
|
|
805
|
+
{
|
|
806
|
+
term: "Max pain", aliases: ["max-pain", "maximum pain", "max pain strike", "pain strike"], functions: ["OPX", "GEX"],
|
|
807
|
+
definition: "The settlement price at which one expiry's options would pay their holders the least, summed over every call's and put's open interest: "
|
|
808
|
+
+ "the strike where Payout $ is lowest. It says where option holders collect least at expiry, not where the price will go. "
|
|
809
|
+
+ "Deribit's BTC and ETH options settle at 08:00 UTC on the day named, against its index averaged over the 30 minutes before.",
|
|
810
|
+
},
|
|
811
|
+
{
|
|
812
|
+
term: "Payout $", aliases: ["payout", "expiry payout", "option payout", "payout at expiry"], functions: ["OPX", "GEX"], shown: ["Payout $"],
|
|
813
|
+
definition: "What an expiry's options would pay their holders, in dollars, if the underlying settled at that strike: each call's open interest times "
|
|
814
|
+
+ "how far the strike is above the call's, plus each put's times how far it is below, times the contract size (100 shares for a US listing, "
|
|
815
|
+
+ "1 BTC or 1 ETH on Deribit). Max pain is the strike where it is lowest.",
|
|
816
|
+
},
|
|
817
|
+
{
|
|
818
|
+
term: "Call wall", aliases: ["put wall", "walls", "gamma wall", "gamma walls"], functions: ["OPX", "GEX"], shown: ["Call wall", "Put wall"],
|
|
819
|
+
definition: "The strike with the most dealer gamma from calls (call wall) or from puts (put wall), across every expiry or within one. "
|
|
820
|
+
+ "Hedging flows are largest there, so it is often read as resistance above spot and support below it.",
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
term: "Risk reversal", short: "RR", aliases: ["25d risk reversal", "25-delta risk reversal", "25 delta risk reversal", "rr25", "risk reversals"],
|
|
824
|
+
functions: ["OVDV"], shown: ["RR"],
|
|
825
|
+
definition: "The 25-delta call's implied volatility minus the 25-delta put's, in vol points, for one expiry. Negative means puts cost more than calls "
|
|
826
|
+
+ "as far from the forward (downside protection is bid), positive that upside calls are. OVDV, VCA and HIVG's rr25d all sign it call minus put.",
|
|
827
|
+
},
|
|
828
|
+
{
|
|
829
|
+
term: "Butterfly", short: "BF", aliases: ["25d butterfly", "25-delta butterfly", "25 delta butterfly", "bf25", "smile curvature", "fly"],
|
|
830
|
+
functions: ["OVDV"], shown: ["BF"],
|
|
831
|
+
definition: "The average of the 25-delta call and put implied volatilities minus the implied volatility at the forward, in vol points, for one expiry: "
|
|
832
|
+
+ "how much the wings cost over the middle of the smile. A higher butterfly prices larger moves in either direction.",
|
|
833
|
+
},
|
|
834
|
+
{
|
|
835
|
+
term: "DVOL", aliases: ["deribit volatility index", "bitcoin volatility index", "ether volatility index", "btc dvol", "eth dvol", "crypto vix"],
|
|
836
|
+
functions: ["OVDV", "G"], shown: ["DVOL"],
|
|
837
|
+
definition: "Deribit's volatility index for BTC or ETH: the 30-day implied volatility its options price, in vol points, computed from the whole "
|
|
838
|
+
+ "strip of strikes as VIX is. OVDV shows it beside the coin's surface; chart it as CAP:volatility:dvol-btc or CAP:volatility:dvol-eth.",
|
|
839
|
+
},
|
|
781
840
|
// The economic calendar (ECO).
|
|
782
841
|
{
|
|
783
842
|
term: "Actual", aliases: ["actual release", "actual value"], functions: ["ECO"], shown: ["ACTUAL", "Actual"],
|
|
@@ -795,6 +854,19 @@ export const GLOSSARY: readonly GlossaryEntry[] = [
|
|
|
795
854
|
term: "Impact", short: "IMP", aliases: ["importance", "event impact", "high impact"], functions: ["ECO"],
|
|
796
855
|
definition: "How much a release usually moves markets: HIGH for the big ones (CPI, jobs, rate decisions), MED and LOW for speeches and smaller data.",
|
|
797
856
|
},
|
|
857
|
+
{
|
|
858
|
+
term: "Purchasing managers' index", short: "PMI", aliases: ["pmis", "purchasing managers", "purchasing managers index", "ism", "ism pmi",
|
|
859
|
+
"flash pmi", "caixin pmi", "ratingdog pmi"], functions: ["ECO"],
|
|
860
|
+
definition: "A monthly survey of companies' purchasing managers on orders, output, jobs and prices: 50 is no change from the month before, "
|
|
861
|
+
+ "above it growth, below it contraction. A flash PMI is the month's early read, the final a week or so later. ECO lists each as a release: "
|
|
862
|
+
+ "ISM for the US, S&P Global's elsewhere, NBS and RatingDog (formerly Caixin) for China, most at medium or low impact.",
|
|
863
|
+
},
|
|
864
|
+
// Economic statistics (ECST).
|
|
865
|
+
{
|
|
866
|
+
term: "Nowcast", aliases: ["nowcasts", "nowcasting", "gdpnow", "gdp nowcast"], functions: ["ECST", "ECO"], shown: ["GDPNow"],
|
|
867
|
+
definition: "An estimate of this quarter's GDP growth from the data already out, revised as each release lands until the official figure. "
|
|
868
|
+
+ "ECST shows the Atlanta Fed's GDPNow, annualized, against its own history; ECO lists each update as a release.",
|
|
869
|
+
},
|
|
798
870
|
];
|
|
799
871
|
|
|
800
872
|
const ANSI = /\x1b\[[0-9;]*m/g;
|