gloomberb 0.18.1 → 0.18.3
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/package.json +1 -1
- package/patches/electrobun@1.18.1.patch +106 -5
- package/src/api-client/commodity-balances.ts +6 -0
- package/src/api-client/company-kpis.ts +9 -0
- package/src/api-client/crypto-markets.ts +9 -0
- package/src/api-client/data.ts +21 -5
- package/src/api-client/equity-screener.ts +2 -0
- package/src/api-client/index.ts +2 -0
- package/src/api-client/request.ts +5 -3
- package/src/api-client/telemetry.ts +17 -0
- package/src/api-client/types.ts +5 -0
- package/src/app/global-shortcuts.ts +1 -16
- package/src/app/pane-runtime/plugin-bindings.ts +3 -1
- package/src/app/pane-runtime/ticker-open-runtime.ts +17 -5
- package/src/app/runtime/plugin-bindings.ts +6 -2
- package/src/app/runtime/update.ts +28 -8
- package/src/architecture/pane-tabs-allowlist.json +65 -0
- package/src/brokers/logos.ts +66 -0
- package/src/brokers/profile-form.ts +3 -0
- package/src/brokers/remote-broker-adapter.ts +13 -3
- package/src/capabilities/index.ts +1 -1
- package/src/capabilities/service-capabilities.ts +7 -1
- package/src/cli/base-converter.ts +60 -18
- package/src/cli/commands/market.ts +354 -187
- package/src/cli/commands/news-search.ts +35 -8
- package/src/cli/commands/system.ts +35 -1
- package/src/cli/commands/ticker.ts +167 -60
- package/src/cli/currency-hints.ts +27 -0
- package/src/cli/fx-pair.ts +41 -4
- package/src/cli/glossary.ts +57 -4
- package/src/cli/help.ts +1 -1
- package/src/cli/helpers.ts +36 -3
- package/src/cli/index.ts +12 -1
- package/src/cli/issuer-membership.ts +103 -0
- package/src/cli/known-gaps.ts +37 -1
- package/src/cli/listing-arg.ts +51 -3
- package/src/cli/name-entries.ts +51 -12
- package/src/cli/pane-functions/capabilities.ts +2 -0
- package/src/cli/pane-functions/catalog.ts +19 -1
- package/src/cli/pane-functions/discovery.ts +15 -1
- package/src/cli/pane-functions/dom.ts +11 -5
- package/src/cli/pane-functions/freshness.ts +4 -4
- package/src/cli/pane-functions/function-help.ts +27 -3
- package/src/cli/pane-functions/headless.ts +31 -11
- package/src/cli/pane-functions/index.ts +67 -7
- package/src/cli/pane-functions/lock-note.ts +7 -4
- package/src/cli/pane-functions/resolver.ts +21 -6
- package/src/cli/quote-answer.ts +179 -0
- package/src/cli/report-tables.ts +136 -18
- package/src/cli/result.ts +12 -4
- package/src/cli/series-search.ts +2 -1
- package/src/cli/symbol-list.ts +47 -11
- package/src/cli/types.ts +4 -0
- package/src/components/chart/composite/composite-chart.tsx +25 -7
- package/src/components/chart/composite/drawing-store.ts +26 -6
- package/src/components/chart/composite/format.ts +13 -1
- package/src/components/chart/composite/interactions.ts +2 -1
- package/src/components/chart/composite/level-labels.ts +30 -0
- package/src/components/chart/composite/levels.ts +17 -6
- package/src/components/chart/composite/panel-surface.tsx +69 -8
- package/src/components/chart/composite/types.ts +6 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +1 -1
- package/src/components/command-bar/routes/root/command-items.ts +32 -6
- package/src/components/command-bar/routes/ticker-search/actions.ts +6 -0
- package/src/components/data-table/view.tsx +23 -3
- package/src/components/index.ts +3 -0
- package/src/components/layout/detached-pane-shell.tsx +1 -0
- package/src/components/layout/floating-pane.tsx +1 -0
- package/src/components/layout/header.tsx +228 -55
- package/src/components/layout/pane/content.tsx +16 -14
- package/src/components/layout/pane/footer/index.tsx +22 -3
- package/src/components/layout/pane/footer/model.ts +99 -4
- package/src/components/layout/pane/header-tabs.tsx +15 -1
- package/src/components/layout/pane/header.tsx +10 -3
- package/src/components/layout/pane/index.tsx +1 -0
- package/src/components/layout/pane/pane-tabs.tsx +9 -1
- package/src/components/onboarding/onboarding-frame.tsx +9 -11
- package/src/components/onboarding/use-onboarding-broker-form.ts +5 -2
- package/src/components/onboarding/wizard-model.ts +10 -3
- package/src/components/ui/button.tsx +11 -4
- package/src/components/ui/choice-dialog.tsx +8 -5
- package/src/components/ui/display.tsx +11 -6
- package/src/components/ui/fields.tsx +100 -20
- package/src/components/ui/icon.tsx +6 -1
- package/src/components/ui/list-row-lines.tsx +87 -0
- package/src/components/ui/list-view.tsx +14 -0
- package/src/components/ui/logo-mark.tsx +64 -0
- package/src/components/ui/number-step.ts +54 -0
- package/src/components/ui/select-button.tsx +5 -4
- package/src/components/ui/select-field.tsx +3 -3
- package/src/components/ui/stat-grid.tsx +28 -3
- package/src/components/ui/status.tsx +20 -4
- package/src/components/ui/tabs.tsx +9 -1
- package/src/components/ui/toggle.tsx +17 -3
- package/src/core/app-services.ts +4 -0
- package/src/core/state/app/instrument.ts +8 -3
- package/src/data/config/store/normalize.ts +4 -1
- package/src/data/plugin-cache.ts +32 -6
- package/src/docs/snapshot.json +5 -5
- package/src/i18n/es.ts +31 -3
- package/src/i18n/ja.ts +31 -3
- package/src/i18n/ko.ts +31 -3
- package/src/i18n/zh-cn.ts +32 -4
- package/src/i18n/zh-tw.ts +32 -4
- package/src/market-data/commodity-names.ts +80 -0
- package/src/market-data/coordinator/auxiliary.ts +3 -1
- package/src/market-data/coordinator/chart.ts +3 -1
- package/src/market-data/futures-board.ts +38 -1
- package/src/market-data/futures-contract.ts +91 -0
- package/src/market-data/fx-closes.ts +78 -1
- package/src/market-data/market/change-basis.ts +219 -0
- package/src/market-data/market/format.ts +28 -12
- package/src/market-data/market/freshness.ts +38 -0
- package/src/market-data/market/status.ts +55 -9
- package/src/market-data/market/year-to-date.ts +46 -0
- package/src/market-data/quotes/contributions.ts +12 -0
- package/src/market-data/quotes/delisting.ts +34 -0
- package/src/market-data/quotes/live-valuation.ts +23 -0
- package/src/market-data/quotes/resolution.ts +8 -2
- package/src/market-data/tax-equivalent.ts +10 -2
- package/src/notifications/app-notifier.ts +2 -2
- package/src/notifications/notification-log.ts +8 -6
- package/src/plugins/builtin/alerts/alert-engine.ts +3 -1
- package/src/plugins/builtin/alerts/cli.ts +26 -18
- package/src/plugins/builtin/alerts/events.ts +1 -0
- package/src/plugins/builtin/alerts/headless.ts +1 -1
- package/src/plugins/builtin/alerts/index.tsx +13 -4
- package/src/plugins/builtin/alerts/research-rules.ts +1 -0
- package/src/plugins/builtin/analytics/risk-pane.tsx +10 -7
- package/src/plugins/builtin/attention/pane.tsx +16 -14
- package/src/plugins/builtin/attention/trending.tsx +8 -6
- package/src/plugins/builtin/awards/pane.tsx +6 -6
- package/src/plugins/builtin/backtest/client.ts +5 -2
- package/src/plugins/builtin/backtest/export.ts +1 -1
- package/src/plugins/builtin/backtest/window.ts +16 -3
- package/src/plugins/builtin/broker-manager/add-flow.tsx +40 -8
- package/src/plugins/builtin/broker-manager/detail.tsx +26 -1
- package/src/plugins/builtin/broker-manager/index.tsx +20 -9
- package/src/plugins/builtin/broker-manager/model.ts +5 -0
- package/src/plugins/builtin/broker-manager/pane-actions.tsx +8 -1
- package/src/plugins/builtin/broker-manager/table.ts +5 -1
- package/src/plugins/builtin/broker-trading/account-picker.tsx +91 -0
- package/src/plugins/builtin/broker-trading/chart-levels.ts +54 -0
- package/src/plugins/builtin/broker-trading/command.ts +103 -0
- package/src/plugins/builtin/broker-trading/controller.ts +688 -0
- package/src/plugins/builtin/broker-trading/dock.tsx +184 -0
- package/src/plugins/builtin/broker-trading/headless.ts +76 -0
- package/src/plugins/builtin/broker-trading/index.tsx +77 -0
- package/src/plugins/builtin/broker-trading/order-feed.ts +383 -0
- package/src/plugins/builtin/broker-trading/orders-data.ts +133 -0
- package/src/plugins/builtin/broker-trading/orders.tsx +437 -0
- package/src/plugins/builtin/broker-trading/overview-orders.tsx +121 -0
- package/src/plugins/builtin/broker-trading/pane-model.ts +207 -0
- package/src/plugins/builtin/broker-trading/pane.tsx +507 -0
- package/src/plugins/builtin/broker-trading/strategy.ts +153 -0
- package/src/plugins/builtin/broker-trading/ticket-parts.tsx +117 -0
- package/src/plugins/builtin/broker-trading/ticket.tsx +578 -0
- package/src/plugins/builtin/buildout/data-runtime.ts +1 -1
- package/src/plugins/builtin/buildout/format.ts +1 -0
- package/src/plugins/builtin/buildout/model/index.ts +16 -7
- package/src/plugins/builtin/buildout/pane/index.tsx +11 -7
- package/src/plugins/builtin/buildout/pane/status.tsx +3 -3
- package/src/plugins/builtin/catalysts/client.ts +2 -2
- package/src/plugins/builtin/catalysts/pane.tsx +3 -3
- package/src/plugins/builtin/chart-composer/cli-options.ts +19 -0
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
- package/src/plugins/builtin/chart-composer/headless-schema.ts +3 -3
- package/src/plugins/builtin/chart-composer/headless.ts +2 -1
- package/src/plugins/builtin/chart-composer/option-range.ts +39 -0
- package/src/plugins/builtin/chart-composer/pane.tsx +32 -11
- package/src/plugins/builtin/chart-composer/presets.ts +2 -2
- package/src/plugins/builtin/chart-composer/series-catalog.ts +4 -2
- package/src/plugins/builtin/chart-composer/shortcuts.ts +3 -3
- package/src/plugins/builtin/chart-composer/viewport-labels.ts +5 -2
- package/src/plugins/builtin/chat/index.tsx +1 -1
- package/src/plugins/builtin/chat/status-widget.tsx +1 -1
- package/src/plugins/builtin/chat/unread-inbox-pane.tsx +6 -1
- package/src/plugins/builtin/chat/unread-inbox.ts +1 -1
- package/src/plugins/builtin/commodity-balances/client.ts +6 -4
- package/src/plugins/builtin/commodity-balances/headless.ts +41 -7
- package/src/plugins/builtin/commodity-balances/index.tsx +19 -4
- package/src/plugins/builtin/commodity-balances/model.ts +22 -0
- package/src/plugins/builtin/commodity-balances/pane.tsx +39 -9
- package/src/plugins/builtin/company-attention/app-rank.tsx +4 -5
- package/src/plugins/builtin/company-attention/pane.tsx +13 -11
- package/src/plugins/builtin/company-kpis/client.ts +3 -2
- package/src/plugins/builtin/company-kpis/headless.ts +5 -7
- package/src/plugins/builtin/company-kpis/model.ts +85 -2
- package/src/plugins/builtin/company-kpis/pane.tsx +30 -15
- package/src/plugins/builtin/composite-plugins.ts +3 -2
- package/src/plugins/builtin/correlation/headless.ts +2 -1
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -0
- package/src/plugins/builtin/correlation/settings.ts +1 -0
- package/src/plugins/builtin/cot/headless.ts +1 -1
- package/src/plugins/builtin/cot/index.tsx +1 -1
- package/src/plugins/builtin/cot/model.ts +35 -12
- package/src/plugins/builtin/cot/pane.tsx +4 -3
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +2 -1
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +2 -1
- package/src/plugins/builtin/credit-conditions/index.tsx +2 -1
- package/src/plugins/builtin/credit-documents/pane.tsx +8 -7
- package/src/plugins/builtin/crypto-board/client.ts +33 -2
- package/src/plugins/builtin/crypto-board/headless.ts +5 -2
- package/src/plugins/builtin/crypto-board/model.ts +28 -8
- package/src/plugins/builtin/debt-maturities/pane.tsx +4 -3
- package/src/plugins/builtin/dividend-yield/headless.ts +30 -8
- package/src/plugins/builtin/dividend-yield/provider-client.ts +3 -1
- package/src/plugins/builtin/doe/pane.tsx +1 -1
- package/src/plugins/builtin/earnings-calls/headless.ts +4 -4
- package/src/plugins/builtin/earnings-calls/lock-note.ts +12 -3
- package/src/plugins/builtin/econ/calendar-model.ts +35 -0
- package/src/plugins/builtin/econ/index.tsx +31 -4
- package/src/plugins/builtin/econ/print-watch.ts +279 -0
- package/src/plugins/builtin/equity-screener/headless.ts +30 -5
- package/src/plugins/builtin/equity-screener/model.ts +68 -2
- package/src/plugins/builtin/equity-screener/pane.tsx +129 -119
- package/src/plugins/builtin/estimate-revisions/headless.ts +3 -2
- package/src/plugins/builtin/estimate-revisions/lock-note.ts +29 -7
- package/src/plugins/builtin/exposure/client.ts +4 -1
- package/src/plugins/builtin/exposure/editor.tsx +3 -3
- package/src/plugins/builtin/exposure/evidence.ts +4 -1
- package/src/plugins/builtin/exposure/holdings.ts +3 -1
- package/src/plugins/builtin/exposure/pane.tsx +43 -21
- package/src/plugins/builtin/filing-events/index.tsx +9 -3
- package/src/plugins/builtin/futures/table.tsx +6 -3
- package/src/plugins/builtin/futures-curve/pane.tsx +2 -2
- package/src/plugins/builtin/gpu/board.tsx +4 -1
- package/src/plugins/builtin/gpu/changes.tsx +10 -10
- package/src/plugins/builtin/gpu/equities.tsx +4 -1
- package/src/plugins/builtin/gpu/history.tsx +4 -2
- package/src/plugins/builtin/gpu/pane.tsx +5 -3
- package/src/plugins/builtin/holders/client.ts +2 -1
- package/src/plugins/builtin/holders/headless.ts +2 -1
- package/src/plugins/builtin/holders/thirteenf-match.ts +3 -1
- package/src/plugins/builtin/insider/base-values.ts +76 -0
- package/src/plugins/builtin/insider/client.ts +3 -0
- package/src/plugins/builtin/insider/headless.ts +48 -10
- package/src/plugins/builtin/insider/index.tsx +17 -8
- package/src/plugins/builtin/insider/issuer.ts +34 -4
- package/src/plugins/builtin/insider/signals-client.ts +2 -2
- package/src/plugins/builtin/insider/table-model.ts +35 -13
- package/src/plugins/builtin/insider/table.tsx +5 -2
- package/src/plugins/builtin/iv-history/events.ts +145 -0
- package/src/plugins/builtin/iv-history/format.ts +3 -0
- package/src/plugins/builtin/iv-history/headless.ts +91 -7
- package/src/plugins/builtin/jobs/headless.ts +2 -2
- package/src/plugins/builtin/jobs/lock-note.ts +14 -3
- package/src/plugins/builtin/jodi/pane.tsx +4 -4
- package/src/plugins/builtin/market-halts/model.ts +31 -6
- package/src/plugins/builtin/market-halts/pane.tsx +3 -0
- package/src/plugins/builtin/market-movers/client.ts +4 -3
- package/src/plugins/builtin/market-movers/screener.ts +4 -3
- package/src/plugins/builtin/market-valuation/pane.tsx +2 -1
- package/src/plugins/builtin/members/pane.tsx +8 -3
- package/src/plugins/builtin/news/wire/feed-config.ts +29 -12
- package/src/plugins/builtin/news/wire/index.tsx +7 -2
- package/src/plugins/builtin/news/wire/news/preset-pane.tsx +11 -3
- package/src/plugins/builtin/news/wire/rss/cli.ts +3 -2
- package/src/plugins/builtin/news/wire/rss/source.ts +13 -4
- package/src/plugins/builtin/notes/cli.ts +1 -1
- package/src/plugins/builtin/notes/export.ts +17 -6
- package/src/plugins/builtin/notes/files.ts +16 -5
- package/src/plugins/builtin/options/enrichment-model.ts +10 -9
- package/src/plugins/builtin/options/footer.ts +25 -20
- package/src/plugins/builtin/options/live-quotes.ts +33 -18
- package/src/plugins/builtin/options/model-spot.ts +70 -4
- package/src/plugins/builtin/options/view.tsx +118 -35
- package/src/plugins/builtin/options-calculator/pane.tsx +7 -4
- package/src/plugins/builtin/options-positioning/headless.ts +11 -3
- package/src/plugins/builtin/options-positioning/model.ts +24 -0
- package/src/plugins/builtin/options-positioning/pane.tsx +10 -12
- package/src/plugins/builtin/options-scenario/client.ts +19 -1
- package/src/plugins/builtin/options-scenario/headless.ts +13 -6
- package/src/plugins/builtin/options-scenario/pane.tsx +54 -11
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +5 -4
- package/src/plugins/builtin/portfolio-list/account-metrics.ts +3 -0
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +8 -5
- package/src/plugins/builtin/portfolio-list/cli/render.ts +34 -10
- package/src/plugins/builtin/portfolio-list/headless.ts +1 -1
- package/src/plugins/builtin/portfolio-list/pane/data.ts +23 -1
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +33 -14
- package/src/plugins/builtin/portfolio-list/settings.ts +20 -2
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +12 -0
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +24 -3
- package/src/plugins/builtin/power/client.ts +2 -2
- package/src/plugins/builtin/power/pane.tsx +36 -31
- package/src/plugins/builtin/primary-dealers/client.ts +137 -62
- package/src/plugins/builtin/primary-dealers/headless.ts +30 -5
- package/src/plugins/builtin/primary-dealers/index.tsx +3 -2
- package/src/plugins/builtin/primary-dealers/model.ts +179 -129
- package/src/plugins/builtin/primary-dealers/pane.tsx +135 -15
- package/src/plugins/builtin/research/analyst-model.ts +5 -1
- package/src/plugins/builtin/reverse-dcf/client.ts +2 -1
- package/src/plugins/builtin/reverse-dcf/model.ts +4 -3
- package/src/plugins/builtin/risk-factors/index.tsx +12 -3
- package/src/plugins/builtin/scanner/feed.ts +6 -1
- package/src/plugins/builtin/scanner/headless.ts +1 -1
- package/src/plugins/builtin/scanner/lock-note.ts +3 -2
- package/src/plugins/builtin/seasonality/client.ts +2 -1
- package/src/plugins/builtin/sectors/client.ts +4 -3
- package/src/plugins/builtin/series-inventory.ts +1 -0
- package/src/plugins/builtin/shared/cloud-denied.ts +7 -6
- package/src/plugins/builtin/shared/cloud-resource.ts +15 -2
- package/src/plugins/builtin/shared/cloud-upgrade.ts +10 -11
- package/src/plugins/builtin/shared/free-routes.ts +24 -0
- package/src/plugins/builtin/shared/headless-options.ts +11 -0
- package/src/plugins/builtin/shared/pro-lock-note.ts +89 -7
- package/src/plugins/builtin/shared/research-trading.tsx +64 -0
- package/src/plugins/builtin/shared/series-list-detail.tsx +3 -1
- package/src/plugins/builtin/shared/volatility/options.ts +2 -1
- package/src/plugins/builtin/social-mentions/client.ts +2 -1
- package/src/plugins/builtin/social-mentions/headless.ts +1 -1
- package/src/plugins/builtin/social-mentions/lock-note.ts +1 -1
- package/src/plugins/builtin/themes/headless.ts +8 -2
- package/src/plugins/builtin/themes/model.ts +43 -10
- package/src/plugins/builtin/themes/pane.tsx +8 -6
- package/src/plugins/builtin/ticker-detail/overview/model.ts +44 -10
- package/src/plugins/builtin/ticker-detail/overview/option-contract.ts +64 -0
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +82 -21
- package/src/plugins/builtin/ticker-detail/pane.tsx +21 -14
- package/src/plugins/builtin/ticker-detail/quote-footer.ts +5 -1
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +37 -8
- package/src/plugins/builtin/time-sales/pane.tsx +2 -2
- package/src/plugins/builtin/trace-bonds/client.ts +14 -3
- package/src/plugins/builtin/trace-bonds/headless.ts +1 -1
- package/src/plugins/builtin/vol-surface/client.ts +23 -3
- package/src/plugins/builtin/vol-surface/headless.ts +33 -14
- package/src/plugins/builtin/vol-surface/model.ts +30 -10
- package/src/plugins/builtin/vol-surface/pane.tsx +35 -15
- package/src/plugins/builtin/vol-surface/stored.ts +34 -3
- package/src/plugins/builtin/vol-surface/tables.ts +14 -0
- package/src/plugins/builtin-editorial.ts +1 -1
- package/src/plugins/compat.ts +3 -0
- package/src/plugins/external-runtime.ts +5 -0
- package/src/plugins/loader.ts +6 -0
- package/src/plugins/plugin-icon.ts +61 -0
- package/src/plugins/registry/host-actions.ts +2 -1
- package/src/plugins/registry/index.ts +9 -1
- package/src/plugins/runtime/context.tsx +5 -0
- package/src/plugins/runtime/index.tsx +3 -0
- package/src/portfolio/column-values.ts +13 -4
- package/src/portfolio/cost-fx.ts +5 -28
- package/src/public/__snapshots__/public-api.test.ts.snap +5 -0
- package/src/public/broker.ts +8 -0
- package/src/public/market-data.ts +5 -0
- package/src/renderers/dom/desktop/control-styles.ts +7 -1
- package/src/renderers/dom/desktop/controls.tsx +40 -8
- package/src/renderers/dom/desktop/icons.tsx +14 -0
- package/src/renderers/dom/desktop/list-view.tsx +51 -19
- package/src/renderers/dom/desktop/menu.tsx +10 -1
- package/src/renderers/dom/desktop/query-bar.tsx +2 -0
- package/src/renderers/dom/desktop/select-field.tsx +8 -6
- package/src/renderers/dom/host/style.ts +6 -1
- package/src/renderers/dom/host/tabs.tsx +22 -5
- package/src/renderers/dom/host/top-surface.ts +127 -0
- package/src/renderers/dom/styles.css +51 -5
- package/src/renderers/electrobun/bun/core-capabilities.ts +21 -1
- package/src/renderers/electrobun/bun/desktop/backend.ts +10 -0
- package/src/renderers/electrobun/bun/desktop/update.ts +210 -30
- package/src/renderers/electrobun/bun/external-plugins.ts +3 -0
- package/src/renderers/electrobun/shared/protocol.ts +2 -0
- package/src/renderers/electrobun/view/broker-remote-client.ts +16 -0
- package/src/renderers/electrobun/view/external-plugins.ts +1 -0
- package/src/renderers/electrobun/view/news-source.ts +4 -2
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +8 -1
- package/src/renderers/opentui/start.tsx +7 -0
- package/src/series/validate.ts +2 -2
- package/src/sources/gloomberb-cloud/index.ts +57 -17
- package/src/sources/gloomberb-cloud/normalizers.ts +4 -0
- package/src/sources/history-result.ts +3 -0
- package/src/sources/provider-errors.ts +3 -1
- package/src/sources/provider-router/history.ts +49 -6
- package/src/sources/provider-router/index.ts +18 -1
- package/src/state/app/activity.ts +13 -0
- package/src/sync/controller.ts +4 -0
- package/src/sync/core-contributors.ts +62 -11
- package/src/sync/local-only.ts +121 -0
- package/src/sync/react.ts +6 -0
- package/src/sync/types.ts +3 -0
- package/src/telemetry/crash-reports.ts +4 -0
- package/src/telemetry/update-failures-node.ts +59 -0
- package/src/telemetry/update-failures.ts +307 -0
- package/src/tickers/company-name-listing.ts +9 -7
- package/src/tickers/company-name.ts +43 -0
- package/src/tickers/listing-fate.ts +57 -8
- package/src/tickers/search/index.ts +24 -3
- package/src/time-series/price-comparison.ts +35 -0
- package/src/time-series/resolve.ts +52 -11
- package/src/time-series/spec.ts +1 -1
- package/src/time-series/types.ts +5 -0
- package/src/types/broker.ts +56 -1
- package/src/types/config.ts +6 -0
- package/src/types/data-provider.ts +11 -1
- package/src/types/financials.ts +23 -0
- package/src/types/headless.ts +19 -2
- package/src/types/instrument.ts +4 -0
- package/src/types/issuer-listings.ts +28 -0
- package/src/types/plugin.ts +24 -6
- package/src/types/price-history.ts +6 -1
- package/src/types/trading.ts +67 -0
- package/src/ui/host.tsx +4 -0
- package/src/updater/failure.ts +163 -0
- package/src/updater/index.ts +87 -23
- package/src/utils/base-currency.ts +108 -0
- package/src/utils/currency-names.ts +128 -0
- package/src/utils/currency-pair.ts +28 -1
- package/src/utils/currency-units.ts +32 -1
- package/src/utils/dom-screenshot.ts +22 -9
- package/src/utils/exchange-notation.generated.ts +360 -0
- package/src/utils/exchanges.ts +15 -322
- package/src/utils/format.ts +31 -1
- package/src/utils/instrument-identity.ts +38 -1
- package/src/utils/options.ts +46 -1
- package/src/utils/price-history.ts +4 -0
- package/src/utils/reported-money.ts +8 -4
- package/src/utils/sec.ts +68 -0
package/src/cli/glossary.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { cliStyles, cliTerminalWidth, renderDefinitions, renderSection, wrapText
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Plain-words meanings of the rates, auction, credit and bond yield, energy, perpetual-futures, portfolio,
|
|
5
|
-
* fund, bond fund (SEC yield, tax-equivalent yield, muni/Treasury ratio), short interest, quote-board, futures (basis, contango, roll yield), VIX curve (term structure, 3M/30D, VVIX) and economic-calendar terms the functions
|
|
5
|
+
* fund, bond fund (SEC yield, tax-equivalent yield, muni/Treasury ratio), short interest, quote-board, futures (basis, contango, roll yield), VIX curve (term structure, 3M/30D, VVIX), CFTC positioning (COT trader classes, net % of open interest) and economic-calendar terms the functions
|
|
6
6
|
* show in their rows, headers and footers.
|
|
7
7
|
* `catalog glossary` lists them, `catalog explain <term>` prints one, and
|
|
8
8
|
* `fn <function> --explain` and `portfolio show --explain` follow a report with
|
|
@@ -242,7 +242,7 @@ export const GLOSSARY: readonly GlossaryEntry[] = [
|
|
|
242
242
|
definition: "The first date the new rate level appears in the data, not necessarily the announcement or effective date.",
|
|
243
243
|
},
|
|
244
244
|
{
|
|
245
|
-
term: "Pctl 1Y", aliases: ["percentile", "1y percentile", "pctl"], functions: ["BTMM", "WIRP", "CBR", "CDX", "SOVR"],
|
|
245
|
+
term: "Pctl 1Y", aliases: ["percentile", "1y percentile", "1-year percentile", "pctl"], functions: ["BTMM", "WIRP", "CBR", "CDX", "SOVR", "COT"],
|
|
246
246
|
definition: "Where today's value ranks against the past year of the same series: 100 is the highest, 0 the lowest.",
|
|
247
247
|
},
|
|
248
248
|
{
|
|
@@ -360,8 +360,8 @@ export const GLOSSARY: readonly GlossaryEntry[] = [
|
|
|
360
360
|
+ "a simple annualisation of the rate now, not funding actually paid.",
|
|
361
361
|
},
|
|
362
362
|
{
|
|
363
|
-
term: "Open interest", short: "OI", aliases: ["open interest usd"], functions: ["PERP"],
|
|
364
|
-
definition: "The
|
|
363
|
+
term: "Open interest", short: "OI", aliases: ["open interest usd"], functions: ["PERP", "COT"],
|
|
364
|
+
definition: "The contracts that are open and not yet closed, counting each buyer and seller pair once: COT counts them, PERP gives their value, usually in dollars. "
|
|
365
365
|
+ "It rises as new positions open and falls as they close.",
|
|
366
366
|
},
|
|
367
367
|
{
|
|
@@ -631,6 +631,59 @@ export const GLOSSARY: readonly GlossaryEntry[] = [
|
|
|
631
631
|
definition: "A futures contract's official price for the day, set by its exchange from trading near the close. "
|
|
632
632
|
+ "The day's change and margin are measured from it, and it can differ from the last trade. FUT's PREV is the previous one.",
|
|
633
633
|
},
|
|
634
|
+
// CFTC positioning (COT): the legacy report's trader classes, then the disaggregated report's.
|
|
635
|
+
{
|
|
636
|
+
term: "Commitments of Traders", short: "COT", aliases: ["cot report", "commitment of traders", "cftc", "cftc report", "cftc positioning", "positioning"],
|
|
637
|
+
functions: ["COT"], shown: ["CFTC", "COT"],
|
|
638
|
+
definition: "The CFTC's weekly count of who holds each US futures market: open contracts split by type of trader, as of Tuesday and published that Friday. "
|
|
639
|
+
+ "It shows whether speculators or hedgers are net long or short, and how that moved since the week before.",
|
|
640
|
+
},
|
|
641
|
+
{
|
|
642
|
+
term: "Noncommercial", aliases: ["non-commercial", "noncommercials", "large speculators", "speculators", "large specs"], functions: ["COT"],
|
|
643
|
+
definition: "Large traders who do not hedge a business with the contract, such as funds and other speculators. "
|
|
644
|
+
+ "Their net position is the one most often read as the market's bet.",
|
|
645
|
+
},
|
|
646
|
+
{
|
|
647
|
+
term: "Commercial", aliases: ["commercials", "hedgers", "commercial hedgers"], functions: ["COT"],
|
|
648
|
+
definition: "Large traders who use the contract to hedge a business: producers, processors, merchants and dealers. "
|
|
649
|
+
+ "In a commodity they are usually net short, selling ahead what they will grow, mine or deliver.",
|
|
650
|
+
},
|
|
651
|
+
{
|
|
652
|
+
term: "Nonreportable", aliases: ["non-reportable", "nonreportables", "small traders", "small speculators"], functions: ["COT"],
|
|
653
|
+
definition: "Traders too small to report their positions to the CFTC, counted as open interest less every reported position. Mostly smaller speculators.",
|
|
654
|
+
},
|
|
655
|
+
{
|
|
656
|
+
term: "Net position", short: "Net", aliases: ["net long", "net short", "net positioning", "net spec"], functions: ["COT"], shown: ["Net"],
|
|
657
|
+
definition: "A group's long contracts less its short ones: positive is net long, negative net short.",
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
term: "Net % of open interest", short: "Net % OI", aliases: ["% of open interest", "percent of open interest", "net percent of open interest"], functions: ["COT"],
|
|
661
|
+
definition: "A group's net position as a share of all open contracts, so markets of different sizes compare: +8.3% means its longs exceed its shorts by 8.3% of open interest.",
|
|
662
|
+
},
|
|
663
|
+
{
|
|
664
|
+
term: "Weekly change", short: "1W Δ", aliases: ["1w change", "week change", "weekly net change"], functions: ["COT"],
|
|
665
|
+
definition: "How far a group's net position moved since the previous weekly report, in contracts.",
|
|
666
|
+
},
|
|
667
|
+
{
|
|
668
|
+
term: "Pctl 3Y", aliases: ["3y percentile", "3-year percentile", "three-year percentile"], functions: ["COT"],
|
|
669
|
+
definition: "Where this week's net position ranks against the past three years of weekly reports: 100 is the most net long it has been, 0 the most net short.",
|
|
670
|
+
},
|
|
671
|
+
{
|
|
672
|
+
term: "Managed money", aliases: ["money managers", "managed money traders", "hedge funds", "ctas"], functions: ["COT"], shown: ["Managed Money"],
|
|
673
|
+
definition: "The disaggregated report's funds that trade futures for clients, such as hedge funds and CTAs: the speculators most often watched.",
|
|
674
|
+
},
|
|
675
|
+
{
|
|
676
|
+
term: "Producer/merchant", aliases: ["producers", "merchants", "producer merchant", "processors"], functions: ["COT"], shown: ["Producer/Merchant"],
|
|
677
|
+
definition: "The disaggregated report's growers, miners, processors and merchants that hedge the physical commodity they produce or handle.",
|
|
678
|
+
},
|
|
679
|
+
{
|
|
680
|
+
term: "Swap dealers", aliases: ["swap dealer", "swaps dealers"], functions: ["COT"], shown: ["Swap Dealers"],
|
|
681
|
+
definition: "The disaggregated report's banks and dealers that hedge the commodity swaps they sell to clients, often index investors.",
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
term: "Other reportables", aliases: ["other reportable", "other reportable traders"], functions: ["COT"], shown: ["Other Reportables"],
|
|
685
|
+
definition: "The disaggregated report's large traders that fit none of its other classes, such as proprietary traders and family offices.",
|
|
686
|
+
},
|
|
634
687
|
// Futures basis and curve shape (CTM, FUT, PERP).
|
|
635
688
|
{
|
|
636
689
|
term: "Futures basis", aliases: ["basis", "basis trade", "cash and carry", "cash-and-carry", "vs spot", "spot spread"],
|
package/src/cli/help.ts
CHANGED
|
@@ -58,7 +58,7 @@ const GLOBAL_OPTIONS: Array<[string, string]> = [
|
|
|
58
58
|
|
|
59
59
|
const EXIT_CODES: Array<[string, string]> = [
|
|
60
60
|
[String(CLI_EXIT_CODES.ok), "Success"],
|
|
61
|
-
[String(CLI_EXIT_CODES.error), "Failed: bad input, no data found or a failed check"],
|
|
61
|
+
[String(CLI_EXIT_CODES.error), "Failed: bad input, no data found or a failed check. fn exits 0 on partial data with warnings; --json ok is false exactly when this is 1"],
|
|
62
62
|
[String(CLI_EXIT_CODES.unusableShot), "shot --strict saved an image of a pane with no usable data"],
|
|
63
63
|
];
|
|
64
64
|
|
package/src/cli/helpers.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
formatCompact,
|
|
3
3
|
formatCurrency,
|
|
4
|
+
formatCurrencyCode,
|
|
4
5
|
formatNumber,
|
|
5
6
|
formatPercentRaw,
|
|
6
7
|
} from "../utils/format";
|
|
7
|
-
import { formatMarketPriceWithCurrency, type MarketFormatOptions } from "../market-data/market/format";
|
|
8
|
+
import { formatMarketChangeWithCurrency, formatMarketPriceWithCurrency, type MarketFormatOptions } from "../market-data/market/format";
|
|
9
|
+
import { changeBasisLabel, changeBasisNote, quoteChangeBasis } from "../market-data/market/change-basis";
|
|
10
|
+
import type { FuturesContractTermsPayload } from "../api-client/futures-curve";
|
|
11
|
+
import type { ActiveQuoteDisplay } from "../market-data/market/status";
|
|
12
|
+
import type { Quote } from "../types/financials";
|
|
8
13
|
import { cliStyles, colorBySign } from "../utils/cli-output";
|
|
9
14
|
import type { AppConfig } from "../types/config";
|
|
10
15
|
import type { Watchlist, TickerRecord } from "../types/ticker";
|
|
@@ -12,8 +17,36 @@ import { isFiniteNumber } from "../utils/guards";
|
|
|
12
17
|
import { formatUtcTime } from "../utils/utc-time";
|
|
13
18
|
import { findNamedCollection } from "../portfolio/collection-name";
|
|
14
19
|
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
/** A signed amount with its sign ($), or with `code` its code (+12.50 CAD) as a report for another base currency writes it. */
|
|
21
|
+
export function formatSignedCurrency(value: number, currency: string, code = false): string {
|
|
22
|
+
const text = (code ? formatCurrencyCode : formatCurrency)(value, currency);
|
|
23
|
+
return value > 0 ? `+${text}` : text;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The Change line of `ticker` and of `quote`'s futures block: the regular
|
|
28
|
+
* session's move and its percent, colored by sign, and what the move is
|
|
29
|
+
* measured from, "-HK$0.10 (-1.05%) vs Fri 16 Oct close" (a future's from
|
|
30
|
+
* its terms, "vs Fri 16 Oct settle"), with the venue's holidays since that
|
|
31
|
+
* close on the line under it ("HKEX closed Mon 19 Oct, holiday").
|
|
32
|
+
*/
|
|
33
|
+
export function quoteChangeText(
|
|
34
|
+
quote: Quote,
|
|
35
|
+
session: Pick<ActiveQuoteDisplay, "price" | "change" | "changePercent">,
|
|
36
|
+
options: MarketFormatOptions,
|
|
37
|
+
terms?: Pick<FuturesContractTermsPayload, "settlement" | "spec"> | null,
|
|
38
|
+
now = Date.now(),
|
|
39
|
+
): string {
|
|
40
|
+
// A listing that no longer trades: its last close moves no more.
|
|
41
|
+
if (quote.delisting) return "—";
|
|
42
|
+
const move = colorBySign(
|
|
43
|
+
`${formatMarketChangeWithCurrency(session.change, quote.currency ?? "USD", options, session.price)} (${formatPercentRaw(session.changePercent)})`,
|
|
44
|
+
session.change,
|
|
45
|
+
);
|
|
46
|
+
const basis = quoteChangeBasis(quote, { terms });
|
|
47
|
+
if (!basis) return move;
|
|
48
|
+
const note = changeBasisNote(basis, now);
|
|
49
|
+
return `${move} ${cliStyles.muted(changeBasisLabel(basis, now))}${note ? `\n${cliStyles.muted(note)}` : ""}`;
|
|
17
50
|
}
|
|
18
51
|
|
|
19
52
|
// Text-table cell formats. They leave missing values blank; CSV and JSON keep the raw numbers.
|
package/src/cli/index.ts
CHANGED
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
runPaneScreenshot,
|
|
48
48
|
} from "./pane-functions";
|
|
49
49
|
import { catalogPointer, tickerPointer, type CatalogCommandHit } from "./unknown-command";
|
|
50
|
+
import { exportCommandPointer } from "./known-gaps";
|
|
50
51
|
import { catalogFredSeriesIds } from "./series-search";
|
|
51
52
|
import { primeBoardCoins } from "./board-coins";
|
|
52
53
|
|
|
@@ -189,8 +190,16 @@ export function createCoreCliCommands(
|
|
|
189
190
|
"fn WEI --csv --section europe > europe.csv",
|
|
190
191
|
"fn 13F AAPL --view=ticker-holdings",
|
|
191
192
|
"fn OVME --spot 100 --strike 100 --days 30 --volatility 25",
|
|
193
|
+
"fn HIVG SPY --event fomc --offset -6 --lookback ALL --csv",
|
|
192
194
|
"fn AUCT --explain",
|
|
193
195
|
],
|
|
196
|
+
sections: [{
|
|
197
|
+
title: "Exit status",
|
|
198
|
+
lines: [
|
|
199
|
+
"0 when the report has data for what was asked, partial data with warnings about the rest included; 1 when it has none (an empty report, or rows with no value for a listing that has nothing) or the input is bad. --json ok is false exactly when the exit status is 1.",
|
|
200
|
+
"CSV headers are the same for every symbol: a reason a figure is missing goes to the status column, never into a number cell.",
|
|
201
|
+
],
|
|
202
|
+
}],
|
|
194
203
|
},
|
|
195
204
|
execute: async (args, ctx) => {
|
|
196
205
|
requirePaneFunctionTarget(args, "fn", ctx);
|
|
@@ -382,7 +391,9 @@ function failUnknownCommand(token: string, commands: CliCommandDef[], pointers:
|
|
|
382
391
|
[`Run: ${pointers.nearFn.command}`, ticker].filter(Boolean).join("\n"),
|
|
383
392
|
);
|
|
384
393
|
}
|
|
385
|
-
|
|
394
|
+
// Exporting is a flag, not a command: `export LMT` says how, rather than listing functions that mention exports.
|
|
395
|
+
const exported = suggestion ? null : exportCommandPointer(token, pointers.args);
|
|
396
|
+
const catalog = suggestion ? null : exported ?? catalogPointer(token, pointers.hits, pointers.args);
|
|
386
397
|
const help = suggestion
|
|
387
398
|
? `Did you mean ${suggestion}? Run gloomberb help to see every command.`
|
|
388
399
|
: catalog ? `${catalog}\nRun gloomberb help to see every command.` : "Run gloomberb help to see every command.";
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { AppConfig } from "../types/config";
|
|
2
|
+
import type { DataProvider } from "../types/data-provider";
|
|
3
|
+
import type { TickerRecord } from "../types/ticker";
|
|
4
|
+
import { canonicalExchange, isUsListingExchange, parsePublicTickerKey } from "../utils/exchanges";
|
|
5
|
+
import { logFailure } from "../utils/log-failure";
|
|
6
|
+
import { savedListingName } from "./listing-arg";
|
|
7
|
+
|
|
8
|
+
/** A list holding the company: its name, and the other saved listing it holds the company as (null for the listing asked about). */
|
|
9
|
+
export interface ListMembership {
|
|
10
|
+
name: string;
|
|
11
|
+
/** RCI.B:TSX when the list holds Rogers as its Toronto line and the report is of RCI. */
|
|
12
|
+
via: string | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface CompanyMemberships {
|
|
16
|
+
portfolios: ListMembership[];
|
|
17
|
+
watchlists: ListMembership[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A listing as Gloom Cloud writes an issuer's listings: the bare ticker on a
|
|
22
|
+
* US venue or none (RCI), SYMBOL:EXCHANGE elsewhere (RCI.B:TSX), with a
|
|
23
|
+
* share class's dash or slash as a dot (BRK-B is BRK.B).
|
|
24
|
+
*/
|
|
25
|
+
export function issuerListingKey(symbol: string, exchange?: string): string {
|
|
26
|
+
const parsed = parsePublicTickerKey(symbol);
|
|
27
|
+
const venue = parsed.exchange ?? canonicalExchange(exchange);
|
|
28
|
+
const code = parsed.symbol.toUpperCase().replace(/[-/]/g, ".");
|
|
29
|
+
return venue && !isUsListingExchange(venue) ? `${code}:${venue}` : code;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function names(config: AppConfig, ids: readonly string[], kind: "portfolios" | "watchlists"): Map<string, string> {
|
|
33
|
+
const collections: ReadonlyArray<{ id: string; name: string }> = config[kind];
|
|
34
|
+
return new Map(ids.flatMap((id) => {
|
|
35
|
+
const name = collections.find((collection) => collection.id === id)?.name;
|
|
36
|
+
return name ? [[id, name] as const] : [];
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The portfolios and watchlists that hold a company, whichever of its
|
|
42
|
+
* listings they saved: the listing's own lists, then those holding another
|
|
43
|
+
* of `issuerListings` (its keys as `issuerListingKey` writes them), each
|
|
44
|
+
* once and saying which listing it holds. A restricted list holding RCI.B:TSX
|
|
45
|
+
* holds Rogers, which also trades as RCI in New York. Without the company's
|
|
46
|
+
* listings, only the listing's own lists.
|
|
47
|
+
*/
|
|
48
|
+
export function companyMemberships(
|
|
49
|
+
config: AppConfig,
|
|
50
|
+
own: TickerRecord | null,
|
|
51
|
+
saved: readonly TickerRecord[],
|
|
52
|
+
issuerListings: readonly string[] | null,
|
|
53
|
+
): CompanyMemberships {
|
|
54
|
+
const listings = new Set(issuerListings ?? []);
|
|
55
|
+
const ownKey = own ? savedListingName(own).key : null;
|
|
56
|
+
const others = listings.size === 0 ? [] : saved.filter((ticker) =>
|
|
57
|
+
savedListingName(ticker).key !== ownKey
|
|
58
|
+
&& listings.has(issuerListingKey(ticker.metadata.ticker, ticker.metadata.exchange)));
|
|
59
|
+
const collect = (kind: "portfolios" | "watchlists"): ListMembership[] => {
|
|
60
|
+
const held = new Map<string, ListMembership>();
|
|
61
|
+
for (const [id, name] of names(config, own?.metadata[kind] ?? [], kind)) held.set(id, { name, via: null });
|
|
62
|
+
for (const ticker of others) {
|
|
63
|
+
for (const [id, name] of names(config, ticker.metadata[kind], kind)) {
|
|
64
|
+
if (!held.has(id)) held.set(id, { name, via: savedListingName(ticker).key });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return [...held.values()];
|
|
68
|
+
};
|
|
69
|
+
return { portfolios: collect("portfolios"), watchlists: collect("watchlists") };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* `companyMemberships` for a listing, asking Gloom Cloud for the company's
|
|
74
|
+
* other listings only when another saved listing is in a list at all. A
|
|
75
|
+
* failed lookup leaves the listing's own lists.
|
|
76
|
+
*/
|
|
77
|
+
export async function loadCompanyMemberships({
|
|
78
|
+
config,
|
|
79
|
+
own,
|
|
80
|
+
symbol,
|
|
81
|
+
exchange,
|
|
82
|
+
loadTickers,
|
|
83
|
+
dataProvider,
|
|
84
|
+
}: {
|
|
85
|
+
config: AppConfig;
|
|
86
|
+
own: TickerRecord | null;
|
|
87
|
+
/** The listing the report is of, and its venue (RCI, NYSE). */
|
|
88
|
+
symbol: string;
|
|
89
|
+
exchange: string;
|
|
90
|
+
loadTickers: () => Promise<TickerRecord[]>;
|
|
91
|
+
dataProvider: Pick<DataProvider, "getIssuerListings">;
|
|
92
|
+
}): Promise<CompanyMemberships> {
|
|
93
|
+
const ownKey = own ? savedListingName(own).key : null;
|
|
94
|
+
const saved = await Promise.resolve().then(loadTickers)
|
|
95
|
+
.catch(logFailure("cli.issuer-membership", "Reading saved listings failed", [] as TickerRecord[]));
|
|
96
|
+
const listed = saved.filter((ticker) => savedListingName(ticker).key !== ownKey
|
|
97
|
+
&& (ticker.metadata.portfolios.length > 0 || ticker.metadata.watchlists.length > 0));
|
|
98
|
+
const { getIssuerListings } = dataProvider;
|
|
99
|
+
if (listed.length === 0 || !getIssuerListings) return companyMemberships(config, own, [], null);
|
|
100
|
+
const issuer = await Promise.resolve().then(() => getIssuerListings.call(dataProvider, symbol, exchange))
|
|
101
|
+
.catch(logFailure("cli.issuer-membership", "Reading the company's listings failed", null));
|
|
102
|
+
return companyMemberships(config, own, listed, issuer?.listings.map((listing) => issuerListingKey(listing.symbol, listing.exchange)) ?? null);
|
|
103
|
+
}
|
package/src/cli/known-gaps.ts
CHANGED
|
@@ -109,6 +109,23 @@ const BANK_FIGURES_TOPIC = {
|
|
|
109
109
|
closest: [["EQS", "NIM%, Pro: gloomberb fn EQS --metric kpiNimPercent"]],
|
|
110
110
|
} as const;
|
|
111
111
|
|
|
112
|
+
/**
|
|
113
|
+
* How to export: a flag on every command, which `export LMT`, `catalog export` and `catalog csv` look for as a
|
|
114
|
+
* command or a function. One example, writing a file.
|
|
115
|
+
*/
|
|
116
|
+
function exportLine(symbol = "LMT"): string {
|
|
117
|
+
return `Export: add --csv or --json to any command to print its result as CSV or JSON, e.g. gloomberb history ${symbol} --csv > ${
|
|
118
|
+
symbol.toLowerCase().replace(/[^a-z0-9]+/g, "-")}.csv`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const EXPORT_POINTER = {
|
|
122
|
+
names: ["export", "exporting", "csv", "json", "excel", "spreadsheet", "xlsx"],
|
|
123
|
+
words: ["data", "to", "as", "a", "an", "the", "in", "into", "file", "files", "table", "tables", "result", "results", "output",
|
|
124
|
+
"format", "save", "how", "can", "i", "my", "report", "reports", "command", "commands"],
|
|
125
|
+
line: exportLine(),
|
|
126
|
+
leads: true,
|
|
127
|
+
} as const;
|
|
128
|
+
|
|
112
129
|
/** "bank", "bank figures": beside the functions a bank's name finds (CBR), where its figures are. */
|
|
113
130
|
const BANK_FIGURES_POINTER = {
|
|
114
131
|
names: ["bank", "banks", "banking"],
|
|
@@ -193,8 +210,9 @@ export function topicPointer(query: string): { message: string; codes: string[]
|
|
|
193
210
|
* "dark pool"; "drip", "dividend income", but not "income statement" or "net income"; "tether", "depeg",
|
|
194
211
|
* "usdc peg", but not "peg ratio".
|
|
195
212
|
*/
|
|
196
|
-
const COMMAND_POINTERS: ReadonlyArray<{ names: readonly string[]; words: readonly string[]; line: string }> = [
|
|
213
|
+
const COMMAND_POINTERS: ReadonlyArray<{ names: readonly string[]; words: readonly string[]; line: string; leads?: true }> = [
|
|
197
214
|
BANK_FIGURES_POINTER,
|
|
215
|
+
EXPORT_POINTER,
|
|
198
216
|
{
|
|
199
217
|
names: ["theme", "themes", "light", "dark", "colorblind", "colourblind", "blind"],
|
|
200
218
|
words: ["mode", "color", "colour", "colors", "colours", "high", "contrast", "change", "switch", "set", "setting", "settings"],
|
|
@@ -218,6 +236,24 @@ export function commandPointer(query: string): string | null {
|
|
|
218
236
|
return findCommandPointer(query)?.line ?? null;
|
|
219
237
|
}
|
|
220
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Whether the query's command line answers it ahead of the functions its words find: "csv" is the flag, not
|
|
241
|
+
* CDS, whose description happens to mention it.
|
|
242
|
+
*/
|
|
243
|
+
export function commandPointerLeads(query: string): boolean {
|
|
244
|
+
return findCommandPointer(query)?.leads === true;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* The line for a command word typed as `gloomberb export LMT`: exporting is a flag every command takes, not a
|
|
249
|
+
* command, so the example runs on the symbol typed. Null for any other word.
|
|
250
|
+
*/
|
|
251
|
+
export function exportCommandPointer(token: string, args: readonly string[]): string | null {
|
|
252
|
+
if (findCommandPointer(token) !== EXPORT_POINTER) return null;
|
|
253
|
+
const symbol = args.find((arg) => /^\^?[A-Z0-9][A-Z0-9.=-]{0,11}(?::[A-Z0-9]{1,8})?$/.test(arg) && /[A-Z]/.test(arg));
|
|
254
|
+
return exportLine(symbol);
|
|
255
|
+
}
|
|
256
|
+
|
|
221
257
|
function findCommandPointer(query: string): (typeof COMMAND_POINTERS)[number] | null {
|
|
222
258
|
const asked = words(query);
|
|
223
259
|
if (asked.length === 0) return null;
|
package/src/cli/listing-arg.ts
CHANGED
|
@@ -42,6 +42,7 @@ import { classifyInstrumentType, kindFromListingSyntax } from "../tickers/instru
|
|
|
42
42
|
import type { InstrumentOfKind } from "../tickers/instrument-coverage";
|
|
43
43
|
import { brokerIndexCode, brokerIndexReadAs } from "./index-roots";
|
|
44
44
|
import { readTerminalListingCode, terminalCodeReadAs } from "../tickers/terminal-codes";
|
|
45
|
+
import { listingAbroadVenue } from "../utils/sec";
|
|
45
46
|
|
|
46
47
|
/** The `--exchange` option of every command that takes a ticker. */
|
|
47
48
|
export const EXCHANGE_OPTION = {
|
|
@@ -342,7 +343,7 @@ export function listingChoiceNote(
|
|
|
342
343
|
}
|
|
343
344
|
|
|
344
345
|
// Quotes of these never name a company's listing, so they are never a choice between companies.
|
|
345
|
-
const UNLISTED_TYPES = new Set(["FUTURE", "INDEX", "CURRENCY", "CRYPTOCURRENCY", "OPTION"]);
|
|
346
|
+
export const UNLISTED_TYPES = new Set(["FUTURE", "INDEX", "CURRENCY", "CRYPTOCURRENCY", "OPTION"]);
|
|
346
347
|
|
|
347
348
|
/** Whether the data service chose the listing: a bare symbol, with no venue named and none saved. */
|
|
348
349
|
function isBareListing(listing: Pick<CliListing, "exchange" | "saved">): boolean {
|
|
@@ -835,6 +836,13 @@ export async function loadSavedListing(store: ListingStore, listing: ListingArg)
|
|
|
835
836
|
return null;
|
|
836
837
|
}
|
|
837
838
|
|
|
839
|
+
/** A row saved under a vendor's suffixed key (RY.TO) for the listing it was read as: on that venue, or on none it names. */
|
|
840
|
+
async function loadSuffixedRow(store: ListingStore, key: string, exchange: string): Promise<TickerRecord | null> {
|
|
841
|
+
const ticker = await store.loadTicker(key);
|
|
842
|
+
const savedExchange = canonicalExchange(ticker?.metadata.exchange);
|
|
843
|
+
return ticker && (!savedExchange || savedExchange === exchange) ? ticker : null;
|
|
844
|
+
}
|
|
845
|
+
|
|
838
846
|
export interface CliListing extends ListingArg {
|
|
839
847
|
saved: TickerRecord | null;
|
|
840
848
|
/**
|
|
@@ -860,11 +868,47 @@ async function builderDexMarket(listing: ListingArg, deps: ListingDeps): Promise
|
|
|
860
868
|
: null;
|
|
861
869
|
}
|
|
862
870
|
|
|
871
|
+
/** A symbol written with a venue's suffix, as data vendors write a listing abroad: RY.TO, 7203.T, VOD.L, 0700.HK. */
|
|
872
|
+
const VENUE_SUFFIX = /^([A-Z0-9][A-Z0-9&-]*)\.([A-Z]{1,3})$/;
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* RY.TO, 7203.T, VOD.L: a listing abroad written with a data vendor's venue
|
|
876
|
+
* suffix, read as the listing its own quote names (RY:TSX, 7203:JPX,
|
|
877
|
+
* VOD:LSE), the way `quote` names it, so data that is read by venue (a
|
|
878
|
+
* company's SEC filings, data that covers US listings only) finds the same
|
|
879
|
+
* listing the quote is for. A US share class (BRK.B, quoted on NYSE), a
|
|
880
|
+
* suffix no quote answers and a named venue stay as typed.
|
|
881
|
+
*/
|
|
882
|
+
async function readVenueSuffix(listing: ListingArg, deps: Pick<ListingDeps, "dataProvider">): Promise<ListingArg | null> {
|
|
883
|
+
const match = listing.exchange ? null : VENUE_SUFFIX.exec(listing.symbol);
|
|
884
|
+
if (!match) return null;
|
|
885
|
+
let quote: Quote | null;
|
|
886
|
+
try {
|
|
887
|
+
quote = await deps.dataProvider.getQuote(listing.symbol, "");
|
|
888
|
+
} catch (error) {
|
|
889
|
+
// The command's own request then says what is wrong with the symbol.
|
|
890
|
+
if (!isNoProviderError(error)) logFailure("cli.listing-arg", "Quote venue suffix failed")(error);
|
|
891
|
+
return null;
|
|
892
|
+
}
|
|
893
|
+
const venue = canonicalExchange(quote?.listingExchangeName || quote?.exchangeName);
|
|
894
|
+
const key = `${match[1]}:${venue}`;
|
|
895
|
+
if (!venue || !isKnownExchangeCode(venue) || !listingAbroadVenue(key)) return null;
|
|
896
|
+
return { symbol: match[1]!, exchange: venue, key, readAs: `Read ${listing.symbol} as ${key}.` };
|
|
897
|
+
}
|
|
898
|
+
|
|
863
899
|
export async function resolveCliListing(
|
|
864
900
|
raw: string,
|
|
865
901
|
exchangeOption: string | null | undefined,
|
|
866
902
|
deps: ListingDeps,
|
|
867
|
-
options: {
|
|
903
|
+
options: {
|
|
904
|
+
ownExchangeWins?: boolean;
|
|
905
|
+
/**
|
|
906
|
+
* Read a venue suffix (RY.TO) as the listing its quote names (RY:TSX).
|
|
907
|
+
* Only pane functions ask for it (`applyListingArgument`, which `fn` and
|
|
908
|
+
* `shot` run through), as their data is read by venue.
|
|
909
|
+
*/
|
|
910
|
+
venueSuffix?: boolean;
|
|
911
|
+
} = {},
|
|
868
912
|
): Promise<CliListing> {
|
|
869
913
|
// "JPM US Equity" is Bloomberg's code for JPM; "Putnam US Equity", whose root is no US ticker, is a name.
|
|
870
914
|
const typed = stripStrayEdges(raw).text || raw;
|
|
@@ -879,6 +923,10 @@ export async function resolveCliListing(
|
|
|
879
923
|
// USD-NGN and USDNGN are the pair USDNGN=X unless a security is listed under those letters.
|
|
880
924
|
const pair = parsed.exchange ? null : await readAmbiguousCurrencyPair(parsed.symbol, deps);
|
|
881
925
|
if (pair) parsed = { symbol: pair, exchange: "", key: pair };
|
|
926
|
+
const suffixed = pair || named || !options.venueSuffix ? null : await readVenueSuffix(parsed, deps);
|
|
927
|
+
// The row may be saved under the suffixed key itself: a link or a layout's key is kept as it came.
|
|
928
|
+
const typedKey = suffixed ? parsed.symbol : null;
|
|
929
|
+
if (suffixed) parsed = parsed.readAs ? { ...suffixed, readAs: `${parsed.readAs} ${suffixed.readAs}` } : suffixed;
|
|
882
930
|
try {
|
|
883
931
|
await checkListingExchange(parsed, deps);
|
|
884
932
|
} catch (error) {
|
|
@@ -887,7 +935,7 @@ export async function resolveCliListing(
|
|
|
887
935
|
parsed = market;
|
|
888
936
|
}
|
|
889
937
|
let listing = await settleSharedCode(parsed, deps);
|
|
890
|
-
const saved = await loadSavedListing(deps.store, listing);
|
|
938
|
+
const saved = await loadSavedListing(deps.store, listing) ?? (typedKey ? await loadSuffixedRow(deps.store, typedKey, listing.exchange) : null);
|
|
891
939
|
// A code nothing could read stays the venue it is saved on.
|
|
892
940
|
const savedExchange = canonicalExchange(saved?.metadata.exchange);
|
|
893
941
|
if (listing.sharedCode && savedExchange) listing = { symbol: listing.symbol, exchange: savedExchange, key: `${listing.symbol}:${savedExchange}` };
|
package/src/cli/name-entries.ts
CHANGED
|
@@ -6,26 +6,65 @@ import { splitSymbolWords } from "./symbol-args";
|
|
|
6
6
|
import { isProviderBusy } from "../sources/provider-errors";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* The entries of a list (`splitSymbolArgs
|
|
10
|
-
* resolves. An entry with a space in it is a company's name when
|
|
11
|
-
* the company (`Whirlpool Corporation`),
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
9
|
+
* The entries of a list (`splitSymbolArgs`, or a file's lines) as the symbols
|
|
10
|
+
* a command resolves. An entry with a space in it is a company's name when
|
|
11
|
+
* search finds the company (`Whirlpool Corporation`, `philip morris intl`),
|
|
12
|
+
* and stays whole for its listing to say what it was read as. One search
|
|
13
|
+
* finds no company for is its words, each a symbol, when each is written as
|
|
14
|
+
* a symbol or has a quote (`AAPL MSFT`, `brk.b bf-b`, `aapl msft` on a
|
|
15
|
+
* pasted line), and otherwise stays whole, a name nothing lists: its words
|
|
16
|
+
* are not taken for other companies' symbols (INTL, a fund, from a misspelt
|
|
17
|
+
* `phillip morris intl`). Only those entries cost a search. One search was
|
|
18
|
+
* too busy to look up also stays whole, so its lookup says so instead of
|
|
19
|
+
* resolving its words as symbols of other companies.
|
|
16
20
|
*/
|
|
17
21
|
export async function readNameEntries(
|
|
18
22
|
entries: readonly string[],
|
|
19
|
-
dataProvider: Pick<DataProvider, "search"
|
|
23
|
+
dataProvider: Pick<DataProvider, "search"> & Partial<Pick<DataProvider, "getQuotesBatch" | "getQuote">>,
|
|
20
24
|
): Promise<string[]> {
|
|
21
|
-
const read = await Promise.all(entries.map(async (entry) =>
|
|
25
|
+
const read = await Promise.all(entries.map(async (entry) => {
|
|
22
26
|
// A terminal's code for a listing ("JPM US Equity") is one entry, like a company's name.
|
|
23
|
-
await readTerminalCodeArg(dataProvider, entry)
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
if (await readTerminalCodeArg(dataProvider, entry)) return [entry];
|
|
28
|
+
if (!isCompanyNameInput(entry)) return splitSymbolWords([entry]);
|
|
29
|
+
if (await findListingOfCompanyName(dataProvider, entry).catch(busyAsFound)) return [entry];
|
|
30
|
+
const words = splitSymbolWords([entry]);
|
|
31
|
+
return await wordsAreSymbols(words, dataProvider) ? words : [entry];
|
|
32
|
+
}));
|
|
26
33
|
return read.flat();
|
|
27
34
|
}
|
|
28
35
|
|
|
36
|
+
/** A word typed as a ticker is: in capitals (AAPL, 7203.T), with a venue or class mark (brk.b, bf-b, SAN:EPA), or after a $. */
|
|
37
|
+
function writtenAsSymbol(word: string): boolean {
|
|
38
|
+
return /^\$|[:.\-/=^]/.test(word) || /\d/.test(word) || (/\p{Lu}/u.test(word) && !/\p{Ll}/u.test(word));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Whether the words of an entry search found no company for are symbols:
|
|
43
|
+
* each written as one (2222, BRK.B) or else with a quote, the others asked in
|
|
44
|
+
* one batch (`2222 amd pltr`). A batch that fails says nothing, and the
|
|
45
|
+
* entry stays a name.
|
|
46
|
+
*/
|
|
47
|
+
async function wordsAreSymbols(
|
|
48
|
+
words: readonly string[],
|
|
49
|
+
dataProvider: Partial<Pick<DataProvider, "getQuotesBatch" | "getQuote">>,
|
|
50
|
+
): Promise<boolean> {
|
|
51
|
+
const symbols = words.filter((word) => !writtenAsSymbol(word)).map((word) => word.replace(/^\$/, "").toUpperCase());
|
|
52
|
+
if (symbols.length === 0) return true;
|
|
53
|
+
if (dataProvider.getQuotesBatch) {
|
|
54
|
+
const results = await dataProvider.getQuotesBatch(symbols.map((symbol) => ({ symbol, exchange: "" })))
|
|
55
|
+
.catch(logFailure("cli.name-entries", "Read quotes for a pasted line failed", []));
|
|
56
|
+
return results.length === symbols.length && results.every(({ quote }) => !!quote);
|
|
57
|
+
}
|
|
58
|
+
// A source without batches is asked a quote at a time: the few words not written as symbols.
|
|
59
|
+
const { getQuote } = dataProvider;
|
|
60
|
+
if (!getQuote) return false;
|
|
61
|
+
const quoted = await Promise.all(symbols.map((symbol) => getQuote(symbol, "").then(
|
|
62
|
+
(quote) => !!quote,
|
|
63
|
+
logFailure("cli.name-entries", "Read a quote for a pasted line failed", false),
|
|
64
|
+
)));
|
|
65
|
+
return quoted.every(Boolean);
|
|
66
|
+
}
|
|
67
|
+
|
|
29
68
|
/** `findListingOfCompanyName`'s busy answer as a name to keep whole, any other failure as it is. */
|
|
30
69
|
function busyAsFound(error: unknown): true {
|
|
31
70
|
if (isProviderBusy(error)) return true;
|
|
@@ -18,6 +18,8 @@ export interface PaneFunctionCapability {
|
|
|
18
18
|
botSafe: boolean;
|
|
19
19
|
tickerCardinality: PaneFunctionTickerCardinality;
|
|
20
20
|
aliases: string[];
|
|
21
|
+
/** Words that are no code but ask for this function's data: `fn` and `catalog` answer them with it. */
|
|
22
|
+
suggestFor?: string[];
|
|
21
23
|
intents: string[];
|
|
22
24
|
outputKind: string;
|
|
23
25
|
reportReadiness: PaneFunctionReadiness;
|
|
@@ -210,6 +210,21 @@ export function nearFunctionCodes(
|
|
|
210
210
|
.sort((left, right) => left.code.localeCompare(right.code));
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
+
/**
|
|
214
|
+
* The functions a word that is no code asks for (`IVOL`, `IV`: HIVG and
|
|
215
|
+
* OVDV), as their `discovery.suggestFor` lists it, each by its code.
|
|
216
|
+
*/
|
|
217
|
+
export function suggestedFunctionCodes(registry: PaneFunctionCatalog, name: string): NearFunctionCode[] {
|
|
218
|
+
const wanted = normalizeLookupToken(name);
|
|
219
|
+
if (!wanted) return [];
|
|
220
|
+
return [...registry.paneTemplates.values()].flatMap((template) => {
|
|
221
|
+
const pane = registry.panes.get(template.paneId);
|
|
222
|
+
const words = pane ? getHeadlessPaneDefinition(template, pane)?.discovery?.suggestFor ?? [] : [];
|
|
223
|
+
const code = template.shortcut?.prefix;
|
|
224
|
+
return code && words.some((word) => normalizeLookupToken(word) === wanted) ? [{ code: code.toUpperCase(), label: template.label }] : [];
|
|
225
|
+
}).sort((left, right) => left.code.localeCompare(right.code));
|
|
226
|
+
}
|
|
227
|
+
|
|
213
228
|
function sampleArgForTemplate(template: PaneTemplateDef): string {
|
|
214
229
|
switch (template.shortcut?.argKind) {
|
|
215
230
|
case "ticker":
|
|
@@ -391,6 +406,7 @@ function scorePaneCatalogEntry(entry: PaneCatalogEntry, query: string): CatalogM
|
|
|
391
406
|
entry.token,
|
|
392
407
|
entry.shortcut,
|
|
393
408
|
...entry.aliases,
|
|
409
|
+
...entry.capability.suggestFor ?? [],
|
|
394
410
|
entry.templateId,
|
|
395
411
|
entry.paneId,
|
|
396
412
|
].filter((value): value is string => !!value).map((value) => normalizeLookupToken(value));
|
|
@@ -694,13 +710,15 @@ export function renderPaneCatalogReport(
|
|
|
694
710
|
series: readonly SeriesMatch[] = [],
|
|
695
711
|
/** The `config` command a query names a setting of ("light theme"), printed last, beside the functions. */
|
|
696
712
|
setting: string | null = null,
|
|
713
|
+
/** The setting answers the query ahead of the functions its words find (`csv` is the flag, not CDS): printed first. */
|
|
714
|
+
settingFirst = false,
|
|
697
715
|
): string {
|
|
698
716
|
const query = args.query.trim().toLowerCase();
|
|
699
717
|
const exact = query
|
|
700
718
|
? entries.find((entry) => entry.token.toLowerCase() === query)
|
|
701
719
|
?? entries.find((entry) => entry.aliases.some((alias) => alias.toLowerCase() === query))
|
|
702
720
|
: undefined;
|
|
703
|
-
const withSetting = (text: string) => [text, setting ?? ""].filter(Boolean).join("\n\n");
|
|
721
|
+
const withSetting = (text: string) => (settingFirst ? [setting ?? "", text] : [text, setting ?? ""]).filter(Boolean).join("\n\n");
|
|
704
722
|
if (exact) return withSetting([renderCatalogEntry(exact), renderAlsoMatches(exact, entries, query)].filter(Boolean).join("\n\n"));
|
|
705
723
|
|
|
706
724
|
const width = Math.min(cliTerminalWidth() ?? CATALOG_TEXT_WIDTH, CATALOG_TEXT_WIDTH);
|