@gloom-sh/terminal 0.19.1 → 0.19.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/README.md +7 -1
- package/package.json +2 -1
- package/patches/electrobun@1.18.1.patch +108 -1
- package/src/account/upgrade-dialog.tsx +4 -23
- package/src/api-client/coalesce.ts +118 -0
- package/src/api-client/credit-boards.ts +13 -0
- package/src/api-client/crypto-etf-flows.ts +6 -0
- package/src/api-client/crypto-markets.ts +40 -0
- package/src/api-client/data.ts +201 -14
- package/src/api-client/equity-screener.ts +10 -0
- package/src/api-client/errors.ts +58 -0
- package/src/api-client/gpu.ts +29 -0
- package/src/api-client/index.ts +5 -2
- package/src/api-client/plan-access.ts +10 -1
- package/src/api-client/plan-rules.ts +35 -0
- package/src/api-client/research-activity.ts +1 -32
- package/src/api-client/types.ts +21 -1
- package/src/app/attention-notice.tsx +94 -0
- package/src/app/runtime/startup.ts +3 -1
- package/src/app.tsx +23 -1
- package/src/architecture/core-builtin-allowlist.json +2 -1
- package/src/capabilities/chart-series.ts +2 -1
- package/src/capabilities/factories.ts +1 -0
- package/src/cli/ascii-output.ts +42 -0
- package/src/cli/base-converter.ts +10 -2
- package/src/cli/command-options.ts +16 -1
- package/src/cli/commands/crypto-hints.ts +23 -4
- package/src/cli/commands/market.ts +101 -27
- package/src/cli/commands/news-search.ts +24 -5
- package/src/cli/commands/overview.ts +14 -10
- package/src/cli/commands/search.ts +84 -25
- package/src/cli/commands/system.ts +22 -30
- package/src/cli/commands/ticker.ts +49 -9
- package/src/cli/commands/version.ts +33 -0
- package/src/cli/context.ts +6 -9
- package/src/cli/data-dir.ts +7 -0
- package/src/cli/desktop-pane-shot-api-policy.ts +85 -0
- package/src/cli/desktop-pane-shot-browser.ts +320 -0
- package/src/cli/desktop-pane-shot-routes.ts +26 -1
- package/src/cli/desktop-pane-shot.ts +196 -256
- package/src/cli/early-command.ts +42 -0
- package/src/cli/earnings-calendar.ts +9 -0
- package/src/cli/entry.ts +19 -13
- package/src/cli/errors.ts +12 -2
- package/src/cli/glossary.ts +2 -1
- package/src/cli/help.ts +1 -1
- package/src/cli/history-export.ts +22 -2
- package/src/cli/history-rows.ts +189 -11
- package/src/cli/index.ts +18 -1
- package/src/cli/known-gaps.ts +51 -5
- package/src/cli/listing-arg.ts +63 -10
- package/src/cli/options.ts +1 -1
- package/src/cli/output-file.ts +60 -13
- package/src/cli/pane-functions/catalog.ts +14 -3
- package/src/cli/pane-functions/data.ts +1 -1
- package/src/cli/pane-functions/dom.ts +45 -0
- package/src/cli/pane-functions/freshness.ts +46 -9
- package/src/cli/pane-functions/function-help.ts +17 -9
- package/src/cli/pane-functions/headless.ts +22 -14
- package/src/cli/pane-functions/index.ts +6 -2
- package/src/cli/pane-functions/options.ts +6 -2
- package/src/cli/pane-functions/resolver.ts +27 -5
- package/src/cli/pane-functions/screenshot-assessment.ts +33 -0
- package/src/cli/pane-functions/screenshot-bridge.ts +94 -13
- package/src/cli/pane-functions/screenshot-http.ts +70 -0
- package/src/cli/pane-functions/screenshot-render.ts +19 -5
- package/src/cli/quote-answer.ts +49 -6
- package/src/cli/registry.ts +41 -13
- package/src/cli/result.ts +12 -6
- package/src/cli/ticker-resolution.ts +2 -1
- package/src/cli/types.ts +2 -0
- package/src/components/chart/composite/format.ts +3 -0
- package/src/components/chart-table/header.tsx +1 -1
- package/src/components/chart-table/layout.ts +28 -11
- package/src/components/command-bar/action-runtime.ts +4 -0
- package/src/components/command-bar/commands/direct/index.ts +18 -33
- package/src/components/command-bar/commands/direct/runtime.ts +5 -0
- package/src/components/command-bar/commands/registry.ts +10 -1
- package/src/components/command-bar/routes/root/command-items.ts +9 -4
- package/src/components/command-bar/routes/root/runtime.ts +51 -6
- package/src/components/command-bar/selection-runtime.ts +12 -29
- package/src/components/command-bar/surface/index.tsx +9 -3
- package/src/components/company-logo.tsx +2 -1
- package/src/components/layout/detached-pane-shell.tsx +2 -2
- package/src/components/layout/header.tsx +10 -5
- package/src/components/layout/market-summary.ts +25 -7
- package/src/components/layout/pane/footer/index.tsx +8 -2
- package/src/components/layout/pane/footer/model.ts +73 -6
- package/src/components/layout/pane/header.tsx +2 -2
- package/src/components/layout/pane/status-footer.ts +2 -1
- package/src/components/market-board/index.tsx +3 -2
- package/src/components/onboarding/desks-step.tsx +12 -4
- package/src/components/onboarding/first-run-workspace.ts +81 -4
- package/src/components/onboarding/onboarding-frame.tsx +4 -2
- package/src/components/onboarding/onboarding-keyboard.ts +8 -5
- package/src/components/onboarding/onboarding-wizard.tsx +60 -26
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +7 -2
- package/src/components/onboarding/run-setup-again.ts +24 -0
- package/src/components/onboarding/use-onboarding-progress.ts +33 -15
- package/src/components/onboarding/use-onboarding-upgrade.ts +2 -6
- package/src/components/onboarding/wizard-model.ts +57 -3
- package/src/components/onboarding/wizard-positions.ts +1 -1
- package/src/components/ui/delayed-mark.tsx +56 -0
- package/src/components/ui/display.tsx +16 -5
- package/src/components/ui/external-link.tsx +3 -6
- package/src/components/ui/icon.tsx +16 -3
- package/src/components/ui/logo-mark.tsx +8 -5
- package/src/components/ui/stat-grid.tsx +263 -19
- package/src/core/app-services.ts +11 -2
- package/src/data/app-persistence.ts +9 -7
- package/src/data/config/store/node.ts +11 -5
- package/src/data/config/store/normalize.ts +16 -3
- package/src/data/plugin-cache.ts +15 -0
- package/src/data/plugin-state-store.ts +81 -24
- package/src/data/profile-permissions.ts +47 -0
- package/src/data/resource-store.ts +165 -90
- package/src/data/session-store.ts +31 -8
- package/src/data/sqlite/access.ts +324 -0
- package/src/data/sqlite/checkpointer.ts +285 -0
- package/src/data/sqlite/database.ts +80 -4
- package/src/data/sqlite/retry.ts +50 -9
- package/src/data/ticker-store.ts +57 -23
- package/src/docs/snapshot.json +191 -78
- package/src/i18n/es.ts +18 -2
- package/src/i18n/ja.ts +18 -2
- package/src/i18n/ko.ts +18 -2
- package/src/i18n/zh-cn.ts +18 -2
- package/src/i18n/zh-tw.ts +18 -2
- package/src/layout/desk-keys.ts +4 -1
- package/src/layout/desks.ts +38 -5
- package/src/layout-marketplace/gallery-desktop.tsx +45 -16
- package/src/market-data/batched-reads.ts +16 -0
- package/src/market-data/coordinator/auxiliary.ts +4 -2
- package/src/market-data/coordinator/index.ts +11 -2
- package/src/market-data/futures-board.ts +1 -1
- package/src/market-data/futures-contract.ts +3 -1
- package/src/market-data/market/index-level.ts +6 -4
- package/src/market-data/published-apac-sessions.ts +6 -0
- package/src/market-data/realized-volatility.ts +4 -2
- package/src/news/aggregator.ts +7 -4
- package/src/news/news-model.ts +11 -0
- package/src/news/story-id.ts +22 -0
- package/src/news/ticker-symbols.ts +17 -1
- package/src/notifications/app-notifier.ts +35 -14
- package/src/plugins/auto-update-node.ts +10 -6
- package/src/plugins/builtin/account-management/form-components.tsx +1 -1
- package/src/plugins/builtin/account-management/index.tsx +2 -3
- package/src/plugins/builtin/account-management/model.ts +1 -1
- package/src/plugins/builtin/alerts/cli-forms.ts +15 -1
- package/src/plugins/builtin/alerts/events-pane.tsx +7 -5
- package/src/plugins/builtin/alerts/events.ts +10 -2
- package/src/plugins/builtin/alerts/index.tsx +5 -5
- package/src/plugins/builtin/alerts/research-builder.ts +5 -1
- package/src/plugins/builtin/alerts/research-rules.ts +18 -0
- package/src/plugins/builtin/alerts/targets.ts +4 -1
- package/src/plugins/builtin/attention/headless.ts +1 -1
- package/src/plugins/builtin/attention/index.tsx +2 -4
- package/src/plugins/builtin/attention/listing.ts +1 -1
- package/src/plugins/builtin/attention/series.ts +1 -1
- package/src/plugins/builtin/awards/index.tsx +1 -2
- package/src/plugins/builtin/backtest/client.ts +1 -0
- package/src/plugins/builtin/backtest/index.tsx +1 -2
- package/src/plugins/builtin/backtest/rules.ts +3 -1
- package/src/plugins/builtin/backtest/window.ts +8 -7
- package/src/plugins/builtin/broker-manager/detail.tsx +16 -3
- package/src/plugins/builtin/broker-manager/index.tsx +1 -1
- package/src/plugins/builtin/buildout/cells.tsx +5 -0
- package/src/plugins/builtin/buildout/company/flow.tsx +367 -0
- package/src/plugins/builtin/buildout/company/id.ts +2 -0
- package/src/plugins/builtin/buildout/company/model.ts +247 -0
- package/src/plugins/builtin/buildout/company/pane.tsx +317 -0
- package/src/plugins/builtin/buildout/data-runtime.ts +31 -10
- package/src/plugins/builtin/buildout/facilities.ts +309 -0
- package/src/plugins/builtin/buildout/format.ts +9 -0
- package/src/plugins/builtin/buildout/index.tsx +51 -5
- package/src/plugins/builtin/buildout/model/index.ts +62 -10
- package/src/plugins/builtin/buildout/model/normalizers.ts +5 -0
- package/src/plugins/builtin/buildout/model/types.ts +11 -2
- package/src/plugins/builtin/buildout/pane/index.tsx +91 -20
- package/src/plugins/builtin/buildout/pane/status.tsx +1 -1
- package/src/plugins/builtin/buildout/pane/themes.tsx +110 -0
- package/src/plugins/builtin/buildout/table-model.ts +26 -2
- package/src/plugins/builtin/builtin-plugin-meta.ts +16 -0
- package/src/plugins/builtin/cds/headless.ts +10 -2
- package/src/plugins/builtin/cds/model.ts +7 -3
- package/src/plugins/builtin/central-bank-rates/index.tsx +1 -2
- package/src/plugins/builtin/central-bank-rates/pane.tsx +2 -1
- package/src/plugins/builtin/central-bank-rates/series.ts +2 -3
- package/src/plugins/builtin/changelog/index.tsx +3 -2
- package/src/plugins/builtin/chart-composer/cli-options.ts +16 -0
- package/src/plugins/builtin/chart-composer/headless-schema.ts +10 -0
- package/src/plugins/builtin/chart-composer/headless.ts +88 -21
- package/src/plugins/builtin/chart-composer/index.tsx +2 -3
- package/src/plugins/builtin/chart-composer/pane.tsx +30 -2
- package/src/plugins/builtin/chart-composer/series-expression.ts +3 -2
- package/src/plugins/builtin/chart-composer/session-range.ts +5 -2
- package/src/plugins/builtin/chart-composer/studies.ts +1 -1
- package/src/plugins/builtin/chat/controller/index.ts +1 -1
- package/src/plugins/builtin/chat/controller/messages.ts +15 -4
- package/src/plugins/builtin/chat/ghost-user.ts +8 -0
- package/src/plugins/builtin/chat/index.tsx +5 -5
- package/src/plugins/builtin/clinical-trials/index.tsx +1 -2
- package/src/plugins/builtin/cloud/company-picker.tsx +1 -1
- package/src/plugins/builtin/cloud/index.tsx +1 -2
- package/src/plugins/builtin/cloud/plugin.tsx +6 -4
- package/src/plugins/builtin/cloud/team/module.tsx +1 -1
- package/src/plugins/builtin/cloud/thesis/module.tsx +1 -1
- package/src/plugins/builtin/cloud/trial-offer-status-widget.tsx +24 -1
- package/src/plugins/builtin/cloud/upgrade-status-widget.tsx +39 -15
- package/src/plugins/builtin/comment-letters/index.tsx +1 -2
- package/src/plugins/builtin/commodity-balances/client.ts +4 -1
- package/src/plugins/builtin/commodity-balances/index.tsx +3 -3
- package/src/plugins/builtin/commodity-balances/pane.tsx +2 -2
- package/src/plugins/builtin/congress-trades/aggregates.ts +13 -2
- package/src/plugins/builtin/congress-trades/detail.tsx +20 -4
- package/src/plugins/builtin/congress-trades/headless.ts +2 -0
- package/src/plugins/builtin/congress-trades/model.ts +92 -64
- package/src/plugins/builtin/congress-trades/table.tsx +14 -2
- package/src/plugins/builtin/connections/index.ts +2 -3
- package/src/plugins/builtin/cot/client.ts +28 -2
- package/src/plugins/builtin/cot/headless.ts +4 -1
- package/src/plugins/builtin/cot/index.tsx +5 -4
- package/src/plugins/builtin/cot/model.ts +58 -7
- package/src/plugins/builtin/cot/pane.tsx +6 -2
- package/src/plugins/builtin/cpi/client.ts +6 -5
- package/src/plugins/builtin/cpi/index.tsx +1 -2
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +2 -1
- package/src/plugins/builtin/credit-boards/client.ts +7 -2
- package/src/plugins/builtin/credit-boards/headless.ts +25 -12
- package/src/plugins/builtin/credit-boards/model.ts +29 -0
- package/src/plugins/builtin/credit-boards/series.ts +3 -4
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +9 -4
- package/src/plugins/builtin/credit-conditions/client.ts +22 -14
- package/src/plugins/builtin/crypto-board/bitcoin-network.ts +143 -0
- package/src/plugins/builtin/crypto-board/client.ts +5 -5
- package/src/plugins/builtin/crypto-board/headless.ts +4 -3
- package/src/plugins/builtin/crypto-board/index.tsx +4 -2
- package/src/plugins/builtin/crypto-board/series.ts +6 -4
- package/src/plugins/builtin/crypto-etf-flows/client.ts +9 -2
- package/src/plugins/builtin/crypto-etf-flows/headless.ts +61 -6
- package/src/plugins/builtin/crypto-etf-flows/index.tsx +1 -2
- package/src/plugins/builtin/crypto-etf-flows/model.ts +14 -1
- package/src/plugins/builtin/crypto-etf-flows/pane.tsx +8 -5
- package/src/plugins/builtin/debt-maturities/headless.ts +4 -3
- package/src/plugins/builtin/debt-maturities/model.ts +17 -1
- package/src/plugins/builtin/debt-maturities/pane.tsx +18 -4
- package/src/plugins/builtin/debt-maturities/series.ts +3 -3
- package/src/plugins/builtin/debug/index.tsx +1 -1
- package/src/plugins/builtin/dividend-yield/client.ts +32 -2
- package/src/plugins/builtin/dividend-yield/headless.ts +58 -33
- package/src/plugins/builtin/dividend-yield/index.tsx +37 -2
- package/src/plugins/builtin/dividend-yield/pane.tsx +32 -13
- package/src/plugins/builtin/dividend-yield/ranking-reads.ts +73 -0
- package/src/plugins/builtin/dividend-yield/ranking-view.tsx +163 -0
- package/src/plugins/builtin/dividend-yield/ranking.ts +1 -1
- package/src/plugins/builtin/dividend-yield/view.ts +21 -0
- package/src/plugins/builtin/docs/index.tsx +2 -3
- package/src/plugins/builtin/doe/client.ts +6 -5
- package/src/plugins/builtin/doe/headless.ts +16 -3
- package/src/plugins/builtin/doe/index.tsx +5 -4
- package/src/plugins/builtin/doe/prices.ts +2 -3
- package/src/plugins/builtin/doe/series.ts +4 -4
- package/src/plugins/builtin/earnings/board.tsx +2 -1
- package/src/plugins/builtin/earnings/history.tsx +2 -1
- package/src/plugins/builtin/earnings-calls/calendar.tsx +10 -2
- package/src/plugins/builtin/earnings-calls/data.ts +19 -11
- package/src/plugins/builtin/earnings-calls/pane.tsx +27 -14
- package/src/plugins/builtin/earnings-ripple/client.ts +32 -7
- package/src/plugins/builtin/earnings-ripple/index.tsx +1 -2
- package/src/plugins/builtin/econ/calendar-model.ts +29 -6
- package/src/plugins/builtin/econ/detail-view.tsx +16 -2
- package/src/plugins/builtin/econ-statistics/index.tsx +1 -2
- package/src/plugins/builtin/equity-screener/client.ts +1 -1
- package/src/plugins/builtin/equity-screener/headless.ts +1 -0
- package/src/plugins/builtin/equity-screener/ideas.ts +30 -1
- package/src/plugins/builtin/equity-screener/index.tsx +1 -2
- package/src/plugins/builtin/equity-screener/model.ts +28 -4
- package/src/plugins/builtin/equity-screener/pane.tsx +5 -0
- package/src/plugins/builtin/equity-screener/screen-check.ts +23 -1
- package/src/plugins/builtin/estimate-revisions/index.tsx +1 -2
- package/src/plugins/builtin/executives/data.ts +6 -1
- package/src/plugins/builtin/executives/pane.tsx +9 -21
- package/src/plugins/builtin/exposure/holdings.ts +35 -13
- package/src/plugins/builtin/exposure/index.tsx +1 -2
- package/src/plugins/builtin/fear-greed/cache.ts +4 -0
- package/src/plugins/builtin/fear-greed/cli.ts +44 -0
- package/src/plugins/builtin/fear-greed/index.tsx +5 -53
- package/src/plugins/builtin/fear-greed/pane.tsx +2 -1
- package/src/plugins/builtin/fear-greed/series.ts +6 -4
- package/src/plugins/builtin/fixed-income/index.tsx +1 -2
- package/src/plugins/builtin/futures/board-reads.ts +25 -0
- package/src/plugins/builtin/futures/coalesced-bump.ts +44 -0
- package/src/plugins/builtin/futures/index.tsx +15 -0
- package/src/plugins/builtin/futures/model.ts +14 -0
- package/src/plugins/builtin/futures/use-board-terms.ts +22 -15
- package/src/plugins/builtin/futures/use-front-returns.ts +20 -14
- package/src/plugins/builtin/futures-curve/headless.ts +6 -1
- package/src/plugins/builtin/futures-curve/index.tsx +1 -2
- package/src/plugins/builtin/fx-matrix/index.tsx +2 -2
- package/src/plugins/builtin/gpu/board.tsx +51 -12
- package/src/plugins/builtin/gpu/client.ts +19 -3
- package/src/plugins/builtin/gpu/equities.tsx +5 -2
- package/src/plugins/builtin/gpu/headless.ts +14 -2
- package/src/plugins/builtin/gpu/index.tsx +1 -2
- package/src/plugins/builtin/gpu/model.ts +20 -2
- package/src/plugins/builtin/gpu/pane.tsx +1 -1
- package/src/plugins/builtin/gpu/series.ts +2 -3
- package/src/plugins/builtin/help/index.tsx +1 -1
- package/src/plugins/builtin/holders/beneficial-view.tsx +1 -2
- package/src/plugins/builtin/holders/index-holders.ts +24 -12
- package/src/plugins/builtin/holders/index.tsx +2 -3
- package/src/plugins/builtin/ipo-calendar/index.tsx +1 -2
- package/src/plugins/builtin/iv-history/index.tsx +1 -2
- package/src/plugins/builtin/jodi/client.ts +4 -1
- package/src/plugins/builtin/jodi/index.tsx +1 -2
- package/src/plugins/builtin/kelly-sizer/index.tsx +1 -2
- package/src/plugins/builtin/layout-manager/index.tsx +9 -8
- package/src/plugins/builtin/macro-day/pane.tsx +4 -2
- package/src/plugins/builtin/market-halts/index.tsx +1 -2
- package/src/plugins/builtin/market-heatmap/index.tsx +11 -2
- package/src/plugins/builtin/market-movers/client.ts +1 -0
- package/src/plugins/builtin/market-movers/index.tsx +16 -5
- package/src/plugins/builtin/market-movers/screener.ts +23 -6
- package/src/plugins/builtin/market-movers/session-body.tsx +6 -2
- package/src/plugins/builtin/market-valuation/index.tsx +1 -2
- package/src/plugins/builtin/members/index.tsx +1 -2
- package/src/plugins/builtin/money-markets/index.tsx +1 -2
- package/src/plugins/builtin/money-markets/pane.tsx +2 -1
- package/src/plugins/builtin/money-markets/series.ts +3 -5
- package/src/plugins/builtin/news/headless.ts +7 -0
- package/src/plugins/builtin/news/wire/index.tsx +1 -1
- package/src/plugins/builtin/news/wire/news/pop-out.tsx +9 -3
- package/src/plugins/builtin/notes/index.tsx +3 -6
- package/src/plugins/builtin/openfda/index.tsx +1 -2
- package/src/plugins/builtin/options/view.tsx +6 -5
- package/src/plugins/builtin/options-calculator/index.tsx +1 -2
- package/src/plugins/builtin/options-positioning/index.tsx +1 -2
- package/src/plugins/builtin/options-scenario/index.tsx +2 -4
- package/src/plugins/builtin/perps/index.tsx +1 -2
- package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -3
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +2 -1
- package/src/plugins/builtin/plugin-module.ts +16 -2
- package/src/plugins/builtin/portfolio-list/cli/render.ts +53 -3
- package/src/plugins/builtin/portfolio-list/index.tsx +1 -2
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +11 -0
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +2 -2
- package/src/plugins/builtin/power/gas-client.ts +2 -1
- package/src/plugins/builtin/power/index.tsx +1 -2
- package/src/plugins/builtin/power/prices-client.ts +3 -2
- package/src/plugins/builtin/rate-path/index.tsx +1 -2
- package/src/plugins/builtin/realized-vol/headless.ts +2 -0
- package/src/plugins/builtin/realized-vol/index.tsx +1 -2
- package/src/plugins/builtin/realized-vol/model.ts +16 -2
- package/src/plugins/builtin/realized-vol/pane.tsx +3 -3
- package/src/plugins/builtin/relative-rotation/index.tsx +1 -2
- package/src/plugins/builtin/research/analyst-headless.ts +33 -6
- package/src/plugins/builtin/research/analyst-model.ts +37 -2
- package/src/plugins/builtin/research/analyst-pane.tsx +25 -5
- package/src/plugins/builtin/research/index.tsx +5 -8
- package/src/plugins/builtin/research-search/index.tsx +1 -2
- package/src/plugins/builtin/revenue-breakdown/headless.ts +22 -8
- package/src/plugins/builtin/revenue-breakdown/model.ts +23 -0
- package/src/plugins/builtin/reverse-dcf/pane.tsx +4 -2
- package/src/plugins/builtin/risk-factors/data.ts +8 -4
- package/src/plugins/builtin/risk-factors/index.tsx +3 -1
- package/src/plugins/builtin/risk-factors/pane.tsx +5 -8
- package/src/plugins/builtin/roadmap/index.tsx +2 -3
- package/src/plugins/builtin/roadmap/pane.tsx +49 -2
- package/src/plugins/builtin/scanner/hilo-model.ts +18 -1
- package/src/plugins/builtin/scanner/hilo-pane.tsx +12 -2
- package/src/plugins/builtin/scanner/live-pane.tsx +7 -4
- package/src/plugins/builtin/scanner/lock-note.ts +26 -3
- package/src/plugins/builtin/sec/filing-content.ts +38 -6
- package/src/plugins/builtin/sec/headless.ts +5 -1
- package/src/plugins/builtin/sec/index.tsx +4 -2
- package/src/plugins/builtin/sec/model.ts +2 -0
- package/src/plugins/builtin/sectors/index.tsx +11 -5
- package/src/plugins/builtin/series-inventory.ts +2 -0
- package/src/plugins/builtin/shared/cloud-resource.ts +73 -8
- package/src/plugins/builtin/shared/cloud-upgrade.ts +24 -1
- package/src/plugins/builtin/shared/forming-bars.ts +29 -0
- package/src/plugins/builtin/shared/fred-points.ts +6 -1
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +17 -0
- package/src/plugins/builtin/shared/pro-lock-note.ts +23 -8
- package/src/plugins/builtin/shared/series-detail-chart.tsx +4 -2
- package/src/plugins/builtin/shared/series-warning.ts +13 -4
- package/src/plugins/builtin/shared/use-quote-board.ts +5 -0
- package/src/plugins/builtin/short-interest/publications-pane.tsx +2 -1
- package/src/plugins/builtin/short-volume/pane.tsx +2 -1
- package/src/plugins/builtin/short-volume/series.ts +2 -3
- package/src/plugins/builtin/social-mentions/client.ts +15 -10
- package/src/plugins/builtin/social-mentions/index.tsx +1 -2
- package/src/plugins/builtin/social-mentions/pane.tsx +2 -1
- package/src/plugins/builtin/social-mentions/series.ts +2 -3
- package/src/plugins/builtin/supply-chain/client.ts +22 -1
- package/src/plugins/builtin/supply-chain/graph-client.ts +22 -1
- package/src/plugins/builtin/supply-chain/index.tsx +1 -2
- package/src/plugins/builtin/thirteenf/api.ts +127 -29
- package/src/plugins/builtin/thirteenf/data.ts +165 -35
- package/src/plugins/builtin/thirteenf/index.tsx +2 -4
- package/src/plugins/builtin/thirteenf/model.ts +2 -0
- package/src/plugins/builtin/thirteenf/overlap-pane.tsx +5 -1
- package/src/plugins/builtin/thirteenf/pane.tsx +41 -16
- package/src/plugins/builtin/thirteenf/types.ts +14 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +22 -6
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +81 -11
- package/src/plugins/builtin/ticker-detail/financials/model.ts +35 -2
- package/src/plugins/builtin/ticker-detail/financials/ratios.ts +53 -18
- package/src/plugins/builtin/ticker-detail/headless.ts +70 -11
- package/src/plugins/builtin/ticker-detail/index.tsx +5 -10
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +16 -6
- package/src/plugins/builtin/time-sales/index.tsx +1 -2
- package/src/plugins/builtin/time-sales/pane.tsx +3 -1
- package/src/plugins/builtin/trace-bonds/headless.ts +11 -2
- package/src/plugins/builtin/trace-bonds/model.ts +44 -10
- package/src/plugins/builtin/trace-bonds/pane.tsx +12 -7
- package/src/plugins/builtin/treasury-auctions/cache.ts +20 -8
- package/src/plugins/builtin/treasury-auctions/client.ts +3 -3
- package/src/plugins/builtin/treasury-auctions/headless.ts +3 -1
- package/src/plugins/builtin/treasury-auctions/pane.tsx +10 -4
- package/src/plugins/builtin/vol-surface/client.ts +18 -3
- package/src/plugins/builtin/vol-surface/index.tsx +1 -2
- package/src/plugins/builtin/volatility/client.ts +43 -16
- package/src/plugins/builtin/volatility/headless.ts +5 -2
- package/src/plugins/builtin/volatility/index.tsx +1 -2
- package/src/plugins/builtin/volatility/model.ts +17 -6
- package/src/plugins/builtin/volatility/pane.tsx +6 -2
- package/src/plugins/builtin/volatility/series.ts +2 -1
- package/src/plugins/builtin/world-indices/footer.ts +6 -1
- package/src/plugins/builtin/world-venue-map/client.ts +10 -1
- package/src/plugins/builtin/world-venue-map/index.ts +6 -2
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +48 -7
- package/src/plugins/builtin/world-venue-map/layers.ts +17 -0
- package/src/plugins/builtin/world-venue-map/local-layers.ts +141 -0
- package/src/plugins/builtin/world-venue-map/map-symbols.ts +18 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +4 -2
- package/src/plugins/builtin/world-venue-map/scope.ts +63 -0
- package/src/plugins/builtin/yield-curve/client.ts +4 -6
- package/src/plugins/builtin/yield-curve/curves.ts +16 -2
- package/src/plugins/builtin/yield-curve/headless.ts +3 -3
- package/src/plugins/bundle.ts +52 -2
- package/src/plugins/catalog-browser.ts +2 -2
- package/src/plugins/catalog-cli.ts +20 -0
- package/src/plugins/host-link.ts +13 -1
- package/src/plugins/installer.ts +64 -42
- package/src/plugins/loader.ts +43 -11
- package/src/plugins/peer-imports.ts +201 -0
- package/src/plugins/peer-retry.ts +26 -29
- package/src/plugins/plugin-process.ts +128 -0
- package/src/plugins/redirection-guard.ts +45 -0
- package/src/remote/endpoint.ts +16 -3
- package/src/renderers/browser/main.tsx +3 -2
- package/src/renderers/cloudflare/http-proxy.ts +7 -123
- package/src/renderers/dom/desktop/icons.tsx +5 -2
- package/src/renderers/dom/host/image-surface.tsx +46 -21
- package/src/renderers/dom/styles.css +7 -0
- package/src/renderers/dom/toast-host.tsx +2 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +7 -1
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +23 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +12 -3
- package/src/renderers/electrobun/bun/desktop/rpc-timing.ts +88 -0
- package/src/renderers/electrobun/bun/desktop/update.ts +20 -4
- package/src/renderers/electrobun/bun/desktop/view-ids.ts +8 -4
- package/src/renderers/electrobun/bun/external-plugins.ts +4 -0
- package/src/renderers/electrobun/bun/window/attention.ts +54 -0
- package/src/renderers/electrobun/bun/window/create.ts +6 -2
- package/src/renderers/electrobun/bun/window/native-timing.ts +48 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +82 -4
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +13 -5
- package/src/renderers/electrobun/view/desktop/window/snapshot.ts +3 -0
- package/src/renderers/electrobun/view/main.tsx +7 -2
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -0
- package/src/renderers/electrobun/view/ui-host.tsx +9 -2
- package/src/renderers/opentui/browser-open.ts +10 -4
- package/src/renderers/opentui/image/surface.tsx +1 -1
- package/src/renderers/opentui/start.tsx +12 -6
- package/src/renderers/opentui/toast-host.tsx +2 -1
- package/src/series/registry.ts +18 -0
- package/src/series/resolve.ts +2 -1
- package/src/series/standalone.ts +10 -1
- package/src/series/types.ts +12 -0
- package/src/series/validate.ts +11 -2
- package/src/sources/gloomberb-cloud/fred-series.ts +5 -3
- package/src/sources/gloomberb-cloud/index.ts +28 -5
- package/src/sources/gloomberb-cloud/news.ts +24 -3
- package/src/sources/gloomberb-cloud/normalizers.ts +17 -2
- package/src/sources/provider-errors.ts +26 -3
- package/src/sources/provider-router/history.ts +5 -0
- package/src/sources/provider-router/index.ts +13 -0
- package/src/sync/core-contributors.ts +32 -0
- package/src/telemetry/attention-counts.ts +64 -6
- package/src/telemetry/attention-setting.ts +33 -0
- package/src/telemetry/crash-reports-node.ts +3 -1
- package/src/telemetry/stall-clocks.ts +93 -0
- package/src/telemetry/stall-reports-node.ts +25 -9
- package/src/telemetry/stall-reports.ts +218 -13
- package/src/test-support/outage.ts +8 -0
- package/src/test-support/preload.ts +9 -0
- package/src/tickers/company-name-listing.ts +59 -29
- package/src/tickers/company-name.ts +84 -1
- package/src/tickers/listing-fate.ts +14 -3
- package/src/tickers/saved-instrument.ts +17 -0
- package/src/tickers/search/home-listing.ts +104 -8
- package/src/tickers/search/index.ts +5 -2
- package/src/tickers/search/types.ts +6 -1
- package/src/time-series/bar-aggregation.ts +7 -1
- package/src/time-series/base-series.ts +3 -3
- package/src/time-series/chart-bounds.ts +1 -1
- package/src/time-series/chart-data.ts +5 -2
- package/src/time-series/chart-seed.ts +1 -1
- package/src/time-series/coin-session-close.ts +211 -0
- package/src/time-series/live-bars.ts +13 -2
- package/src/time-series/live-quotes.ts +1 -1
- package/src/time-series/market.ts +5 -3
- package/src/time-series/official-close.ts +159 -0
- package/src/time-series/price-comparison.ts +75 -8
- package/src/time-series/resolve.ts +32 -4
- package/src/time-series/series-presentation.ts +1 -1
- package/src/time-series/studies/formula.ts +205 -0
- package/src/time-series/studies/indicators.ts +299 -0
- package/src/time-series/studies/leverage.ts +75 -0
- package/src/time-series/studies/pair.ts +138 -0
- package/src/time-series/studies/resolve.ts +333 -0
- package/src/time-series/studies/shared.ts +141 -0
- package/src/time-series/studies/units.ts +243 -0
- package/src/time-series/studies/vwap.ts +274 -0
- package/src/time-series/types.ts +7 -0
- package/src/types/config.ts +18 -2
- package/src/types/data-provider.ts +23 -0
- package/src/types/financials.ts +40 -3
- package/src/types/headless.ts +42 -3
- package/src/types/plugin.ts +32 -3
- package/src/ui/host.tsx +17 -1
- package/src/ui/toast.tsx +26 -1
- package/src/utils/ascii-text.ts +140 -0
- package/src/utils/cli-output.ts +91 -18
- package/src/utils/concurrency.ts +24 -0
- package/src/utils/exchanges.ts +6 -0
- package/src/utils/external-url.ts +20 -7
- package/src/utils/financial-statements.ts +73 -16
- package/src/utils/fundamentals.ts +17 -5
- package/src/utils/futures-generic.ts +4 -4
- package/src/utils/http-proxy-upstream.ts +124 -0
- package/src/utils/lease-liabilities.ts +54 -0
- package/src/utils/main-thread-stall.ts +122 -5
- package/src/utils/perf-marks.ts +58 -12
- package/src/utils/price-history-integrity.ts +47 -1
- package/src/utils/private-files.ts +141 -0
- package/src/utils/public-address.ts +99 -0
- package/src/account/upgrade-personalization.ts +0 -57
- package/src/account/upgrade-tickers.ts +0 -124
- package/src/api-client/upgrade-experiment.ts +0 -91
- package/src/plugins/builtin/cloud/browser.tsx +0 -3
- package/src/time-series/studies.ts +0 -1628
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { InstrumentSearchResult } from "../types/instrument";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Company names as venues spell them, compared and shortened for sentences.
|
|
3
5
|
* One company's listings carry its name with different legal forms and share
|
|
@@ -9,7 +11,7 @@
|
|
|
9
11
|
const NAME_NOISE = new Set([
|
|
10
12
|
"co", "company", "corp", "corporation", "inc", "incorporated", "ltd", "limited", "llc", "lp", "plc", "sa", "ag", "nv", "se",
|
|
11
13
|
"spa", "ab", "as", "asa", "oyj", "bv", "gmbh", "kgaa", "bhd", "berhad", "pcl", "the", "adr", "ads", "cedear", "cedears",
|
|
12
|
-
"sponsored", "unsponsored", "cdr", "cdi",
|
|
14
|
+
"sponsored", "unsponsored", "cdr", "cdi", "aktiengesellschaft", "aktiebolag",
|
|
13
15
|
]);
|
|
14
16
|
// Words a venue adds to the share it lists ("Microsoft Corporation Common Stock"), never part of whose it is.
|
|
15
17
|
const SHARE_NOISE = new Set(["common", "ordinary", "stock", "shares"]);
|
|
@@ -43,6 +45,56 @@ export function sameCompany(left: string | null | undefined, right: string | nul
|
|
|
43
45
|
return [...fewer].every((word) => more.has(word));
|
|
44
46
|
}
|
|
45
47
|
|
|
48
|
+
// Words that tell one class of a company's shares from another ("Berkshire Hathaway Inc. Class B"), never its business.
|
|
49
|
+
const SHARE_CLASS_WORD = /^(?:class|series|[a-z]|\d+)$/;
|
|
50
|
+
|
|
51
|
+
/** Whether two names differ only in how they name a class of shares, so they are one company's whatever the venue. */
|
|
52
|
+
function sameBusinessWords(left: Set<string>, right: Set<string>): boolean {
|
|
53
|
+
const differ = [...left].filter((word) => !right.has(word)).concat([...right].filter((word) => !left.has(word)));
|
|
54
|
+
return differ.every((word) => SHARE_CLASS_WORD.test(word));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** A company line as `companyLines` weighs it. */
|
|
58
|
+
export interface CompanyLineFacts {
|
|
59
|
+
name: string | null | undefined;
|
|
60
|
+
/** The line's canonical venue. */
|
|
61
|
+
exchange: string;
|
|
62
|
+
/** A depositary receipt, whose name says whose shares it holds rather than whose it is. */
|
|
63
|
+
receipt: boolean;
|
|
64
|
+
/** The service marks it as its company's home line (`homeListing`). */
|
|
65
|
+
home: boolean;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The lines among `lines` that are `lead`'s company's own (`sameCompany`),
|
|
70
|
+
* less those under a name that adds words for another business, though one
|
|
71
|
+
* name's words are all in the other's: Siemens Energy AG and Siemens
|
|
72
|
+
* Healthineers AG are not Siemens AG, nor Sony Financial Group Sony Group. A
|
|
73
|
+
* name is another business's where a venue lists a line under it beside a
|
|
74
|
+
* line under the lead's own name (both on XETRA, both in Tokyo), or where it
|
|
75
|
+
* and a line under the lead's name are each marked as a home line, since a
|
|
76
|
+
* company has one (Siemens Ltd. on NSE beside Siemens AG on XETRA). Receipts
|
|
77
|
+
* are named for the shares they hold, so they never tell two businesses
|
|
78
|
+
* apart, and nor do words that name a class of shares (Class B). A name with
|
|
79
|
+
* more words on no shared venue stays the company's (Deutsche Lufthansa AG on
|
|
80
|
+
* XETRA for LUFTHANSA on Budapest). `lead` is always one of them.
|
|
81
|
+
*/
|
|
82
|
+
export function companyLines<T>(lead: T, lines: readonly T[], facts: (line: T) => CompanyLineFacts): T[] {
|
|
83
|
+
const own = facts(lead);
|
|
84
|
+
const ownWords = companyWords(own.name);
|
|
85
|
+
const ownName = (line: CompanyLineFacts) => sameBusinessWords(companyWords(line.name), ownWords);
|
|
86
|
+
const candidates = lines.filter((line) => line === lead || sameCompany(own.name, facts(line).name));
|
|
87
|
+
const read = candidates.map((line) => ({ line, facts: facts(line), words: companyWords(facts(line).name) }));
|
|
88
|
+
const ownShares = read.filter((entry) => !entry.facts.receipt && ownName(entry.facts));
|
|
89
|
+
const ownVenues = new Set(ownShares.map((entry) => entry.facts.exchange).filter(Boolean));
|
|
90
|
+
const ownHome = ownShares.some((entry) => entry.facts.home);
|
|
91
|
+
// A name another business goes by, once one of its share lines gives it away: all its lines are that business's.
|
|
92
|
+
const others = read.filter((entry) => !entry.facts.receipt && !ownName(entry.facts)
|
|
93
|
+
&& ((!!entry.facts.exchange && ownVenues.has(entry.facts.exchange)) || (entry.facts.home && ownHome)));
|
|
94
|
+
const otherBusiness = (words: Set<string>) => others.some((other) => sameBusinessWords(other.words, words));
|
|
95
|
+
return read.filter((entry) => entry.line === lead || ownName(entry.facts) || !otherBusiness(entry.words)).map((entry) => entry.line);
|
|
96
|
+
}
|
|
97
|
+
|
|
46
98
|
/**
|
|
47
99
|
* How many words a listing's name has beyond a company name typed for it,
|
|
48
100
|
* which it must have every word of: 0 for the same name however each spells
|
|
@@ -152,6 +204,25 @@ export function groupByCompany<T>(
|
|
|
152
204
|
return groups;
|
|
153
205
|
}
|
|
154
206
|
|
|
207
|
+
/**
|
|
208
|
+
* A one-letter code a venue pads onto the end of a name after a run of
|
|
209
|
+
* spaces: the `R` of "Americold Realty Trust Inc. R". A longer word there
|
|
210
|
+
* (`AG`, `ASA`) is the name's own.
|
|
211
|
+
*/
|
|
212
|
+
const STRAY_NAME_TAIL = /\s{2,}[A-Za-z0-9]$/;
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* A listing's name as a venue's file writes it, without the stray fragment a
|
|
216
|
+
* fixed-width file leaves after a run of spaces ("Americold Realty Trust
|
|
217
|
+
* Inc. R" on Hanover is "Americold Realty Trust Inc."), and with its spaces
|
|
218
|
+
* single. A name that is only the fragment keeps it.
|
|
219
|
+
*/
|
|
220
|
+
export function cleanListingName(name: string): string {
|
|
221
|
+
const trimmed = name.trim();
|
|
222
|
+
const cut = trimmed.replace(STRAY_NAME_TAIL, "");
|
|
223
|
+
return (cut || trimmed).replace(/\s+/g, " ");
|
|
224
|
+
}
|
|
225
|
+
|
|
155
226
|
/** A company's name without its legal form, for sentences: "Avis Budget Group, Inc." is "Avis Budget Group". */
|
|
156
227
|
export function shortCompanyName(name: string): string {
|
|
157
228
|
const words = name.trim().split(/\s+/).filter(Boolean);
|
|
@@ -234,3 +305,15 @@ export function companyNameCase(name: string): string {
|
|
|
234
305
|
}).join("");
|
|
235
306
|
});
|
|
236
307
|
}
|
|
308
|
+
|
|
309
|
+
/** Letters and digits only, in capitals: "JP Morgan" and "JPMorgan" are JPMORGAN. */
|
|
310
|
+
export function runTogether(text: string): string {
|
|
311
|
+
return text.normalize("NFKD").replace(/\p{M}/gu, "").toUpperCase().replace(/[^\p{L}\p{N}]/gu, "");
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/** Whether the service marked the row with the name as typed: the company it means by it. */
|
|
315
|
+
export function namedByService(typed: string, result: Pick<InstrumentSearchResult, "searchAliases">): boolean {
|
|
316
|
+
const wanted = runTogether(typed);
|
|
317
|
+
return !!wanted && Array.isArray(result.searchAliases)
|
|
318
|
+
&& result.searchAliases.some((alias) => typeof alias === "string" && runTogether(alias) === wanted);
|
|
319
|
+
}
|
|
@@ -132,6 +132,12 @@ export function listingChangeLine(fate: Pick<ListingFate, "change" | "formerIssu
|
|
|
132
132
|
export const NO_FATE: ListingFate = { endedOn: null, change: null, note: null, moved: null, formerIssuer: null };
|
|
133
133
|
/** How long a fate waits for a change lookup it started late, or for a stopped line's. */
|
|
134
134
|
export const LATE_CHANGE_WAIT_MS = 2_000;
|
|
135
|
+
/**
|
|
136
|
+
* How long a command that says what became of a symbol's company (GOGL's merger) waits for the lookup it started
|
|
137
|
+
* beside its own request, once that is in: the lookup takes about a third of a second, and a cached request answers
|
|
138
|
+
* at once. A lookup that hangs costs a symbol that trades no more than this.
|
|
139
|
+
*/
|
|
140
|
+
export const SUCCESSOR_CHANGE_WAIT_MS = 750;
|
|
135
141
|
|
|
136
142
|
// The zones of the US exchanges; a venue in another is abroad.
|
|
137
143
|
const US_TIME_ZONES = new Set(["America/New_York", "America/Chicago"]);
|
|
@@ -195,7 +201,11 @@ export function lineMayHaveMoved(quote: Quote | null, now = Date.now()): boolean
|
|
|
195
201
|
export async function loadListingFate(
|
|
196
202
|
listing: { symbol: string; exchange?: string | null; request?: { symbol: string; exchange: string } },
|
|
197
203
|
dataProvider: Pick<DataProvider, "getQuote" | "getTickerChanges">,
|
|
198
|
-
|
|
204
|
+
/**
|
|
205
|
+
* `graceMs`: how long a lookup the command started waits once the quote is in, for a command that says what
|
|
206
|
+
* became of the company beside what it serves (GOGL's merger), not only whether it moved. A short grace by default.
|
|
207
|
+
*/
|
|
208
|
+
options: { quote?: Quote | null | Promise<Quote | null>; changes?: TickerChangeLookup; graceMs?: number } = {},
|
|
199
209
|
): Promise<ListingFate> {
|
|
200
210
|
const request = listing.request ?? { symbol: listing.symbol, exchange: listing.exchange ?? "" };
|
|
201
211
|
const lookup = options.changes ?? startTickerChangeLookup(dataProvider, listing.symbol, listing.exchange);
|
|
@@ -206,7 +216,7 @@ export async function loadListingFate(
|
|
|
206
216
|
// A lookup started beside the command's request gets a short grace once that is ready, so a slow
|
|
207
217
|
// one never holds a symbol that trades. A line that stopped is waited for: only its company can
|
|
208
218
|
// have moved, and then the answer decides whether the command serves anything at all.
|
|
209
|
-
const changes = await lookup.settle(!options.changes || lineMayHaveMoved(quote) ? LATE_CHANGE_WAIT_MS :
|
|
219
|
+
const changes = await lookup.settle(!options.changes || lineMayHaveMoved(quote) ? LATE_CHANGE_WAIT_MS : options.graceMs);
|
|
210
220
|
return describeListingFate(listing, quote, changes);
|
|
211
221
|
} catch (error) {
|
|
212
222
|
logFailure("tickers-listing-fate", "Could not resolve listing fate")(error);
|
|
@@ -230,7 +240,8 @@ export function listingFateNotes(fate: ListingFate, served: { served: boolean; f
|
|
|
230
240
|
return [
|
|
231
241
|
// What it served ends on the listing's last session, and says so.
|
|
232
242
|
fate.delisted ?? null,
|
|
233
|
-
|
|
243
|
+
// A company that left the symbol, else one that merged away from it (GOGL), as `quote` says it.
|
|
244
|
+
listingChangeLine(fate),
|
|
234
245
|
earlier.length > 0 ? `Includes ${earlier.join("- and ")}-era bars: ${change!.note}` : null,
|
|
235
246
|
].filter((line): line is string => !!line);
|
|
236
247
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { TickerRecord } from "../types/ticker";
|
|
2
|
+
import { parsePublicTickerKey } from "../utils/exchanges";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The listing a typed key stands for in a report (`resolveInstrument`): the
|
|
6
|
+
* venue it names (`SBK:JSE`), else the venue of the ticker saved under the key
|
|
7
|
+
* or under its bare symbol, so a saved `S32` held on the JSE is read there.
|
|
8
|
+
* `fn`, `shot` and the panes that read as they do resolve keys this way.
|
|
9
|
+
*/
|
|
10
|
+
export async function resolveSavedInstrument(
|
|
11
|
+
key: string,
|
|
12
|
+
loadTicker: (key: string) => Promise<TickerRecord | null | undefined> | TickerRecord | null | undefined,
|
|
13
|
+
): Promise<{ symbol: string; exchange?: string }> {
|
|
14
|
+
const parsed = parsePublicTickerKey(key);
|
|
15
|
+
const ticker = await loadTicker(key) ?? (key !== parsed.symbol ? await loadTicker(parsed.symbol) : null);
|
|
16
|
+
return { symbol: parsed.symbol, exchange: parsed.exchange ?? ticker?.metadata.exchange };
|
|
17
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { canonicalExchange } from "../../utils/exchanges";
|
|
2
|
-
import { companyNameExtraWords,
|
|
1
|
+
import { canonicalExchange, isUsListingExchange } from "../../utils/exchanges";
|
|
2
|
+
import { companyLines, companyNameExtraWords, namedByService, type CompanyLineFacts } from "../company-name";
|
|
3
3
|
import { answersOnlyByKeyword, isQualifiedTickerQuery } from "./ranking";
|
|
4
4
|
import type { TickerSearchCandidate } from "./types";
|
|
5
5
|
|
|
@@ -29,6 +29,69 @@ export function lineDistance(type: string, exchange: string, symbol: string): 0
|
|
|
29
29
|
return SECONDARY_VENUES.has(exchange) || /\d/.test(symbol) && /[A-Za-z]/.test(symbol) ? 1 : 0;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
/** How the primary-listing choice weighs one of a company's lines. */
|
|
33
|
+
export interface WeighedCompanyLine {
|
|
34
|
+
/** `listingDistance`: 0 its own line, 1 a line quoting shares listed elsewhere, 2 a receipt. */
|
|
35
|
+
distance: number;
|
|
36
|
+
/** The search score the service gives the listings people look up most; null when it gives none. */
|
|
37
|
+
score: number | null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The line a company's search lists as its primary listing instead of `lead`,
|
|
42
|
+
* the line search put first, often the one-off cross-listing whose short name
|
|
43
|
+
* matched the query (LUFTHANSA on Budapest): its lines go by how far each is
|
|
44
|
+
* from being its own line, then by the search score. The lead gives way only
|
|
45
|
+
* to a closer line, or to one searched at least twice as often, or any scored
|
|
46
|
+
* line when it has no score. With `named` (the service marked the lead with
|
|
47
|
+
* the name as typed) no score outweighs the mark: only a closer line does.
|
|
48
|
+
* `lines` holds the lead. `search` and a company's name typed for a listing
|
|
49
|
+
* (`findListingOfCompanyName`) choose by this one rule, so both open the same
|
|
50
|
+
* listing.
|
|
51
|
+
*/
|
|
52
|
+
export function primaryCompanyLine<T>(
|
|
53
|
+
lead: T,
|
|
54
|
+
lines: readonly T[],
|
|
55
|
+
weigh: (line: T) => WeighedCompanyLine,
|
|
56
|
+
options: { named?: boolean } = {},
|
|
57
|
+
): T {
|
|
58
|
+
const order = (line: T) => lines.indexOf(line);
|
|
59
|
+
const [home] = [...lines].sort((a, b) => weigh(a).distance - weigh(b).distance
|
|
60
|
+
|| (weigh(b).score ?? -1) - (weigh(a).score ?? -1) || order(a) - order(b));
|
|
61
|
+
if (!home || home === lead) return lead;
|
|
62
|
+
const [best, first] = [weigh(home), weigh(lead)];
|
|
63
|
+
const closer = best.distance < first.distance;
|
|
64
|
+
const moreSearched = !options.named && best.distance === first.distance && best.score != null
|
|
65
|
+
&& (first.score == null || best.score >= first.score * 2);
|
|
66
|
+
return closer || moreSearched ? home : lead;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** A row as `companyLines` weighs it. */
|
|
70
|
+
function lineFacts(candidate: TickerSearchCandidate): CompanyLineFacts {
|
|
71
|
+
return {
|
|
72
|
+
name: candidateName(candidate),
|
|
73
|
+
exchange: candidateExchange(candidate),
|
|
74
|
+
receipt: listingDistance(candidate) === 2,
|
|
75
|
+
home: candidate.result?.homeListing === true,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** The rows of `lead`'s company among `items` (`companyLines`): never a line of another business its name is in (Siemens Energy for Siemens). */
|
|
80
|
+
function companyRows<T extends TickerSearchCandidate>(lead: T, items: readonly T[]): T[] {
|
|
81
|
+
return companyLines(lead, items.filter((item) => item === lead || isListedEquity(item)), lineFacts);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** `primaryCompanyLine` among `items` of `start`'s company, for the command bar's rows. */
|
|
85
|
+
function primaryLineOf<T extends TickerSearchCandidate>(start: T, items: readonly T[], query: string): T {
|
|
86
|
+
const name = candidateName(start);
|
|
87
|
+
const named = !!start.result && namedByService(query, start.result);
|
|
88
|
+
const lines = companyRows(start, items).filter((item) => item === start
|
|
89
|
+
|| !named || companyNameExtraWords(candidateName(item), name) != null);
|
|
90
|
+
return primaryCompanyLine(start, lines, (item) => ({
|
|
91
|
+
distance: listingDistance(item), score: item.result?.popularity ?? item.popularity ?? null,
|
|
92
|
+
}), { named });
|
|
93
|
+
}
|
|
94
|
+
|
|
32
95
|
function candidateName(candidate: TickerSearchCandidate): string {
|
|
33
96
|
return candidate.result?.name || candidate.detail.split(" | ")[0] || "";
|
|
34
97
|
}
|
|
@@ -51,24 +114,57 @@ function isListedEquity(candidate: TickerSearchCandidate): boolean {
|
|
|
51
114
|
* service marks as the company's home (`homeListing`) takes the lead from
|
|
52
115
|
* the company's first row. Without that mark, a receipt in the lead gives
|
|
53
116
|
* way to the company's own shares on an exchange (`listingDistance` 0, not
|
|
54
|
-
* an OTC or regional line), the name nearest the receipt's first.
|
|
55
|
-
*
|
|
117
|
+
* an OTC or regional line), the name nearest the receipt's first. Then the
|
|
118
|
+
* line `search` calls the company's primary listing (`primaryCompanyLine`)
|
|
119
|
+
* takes the lead, so a name opens what `search` lists first: LHA on XETRA
|
|
120
|
+
* for "lufthansa", not LUFTHANSA on Budapest. A company's lines are never
|
|
121
|
+
* another business's its name is in (`companyLines`: Siemens Energy AG for
|
|
122
|
+
* Siemens AG). The row the service marks with the word as typed is the
|
|
123
|
+
* company the word means, ahead of a line abroad whose symbol is the word:
|
|
124
|
+
* "siemens" is SIE on XETRA, not SIEMENS on NSE (Siemens Ltd.); a US line
|
|
125
|
+
* keeps its ticker. A symbol typed whose first row is another company's
|
|
126
|
+
* regional line abroad leads with the line the service marks as a home under
|
|
127
|
+
* that symbol (YAR is Yara on OSL, not Americold on Hanover). A query that
|
|
128
|
+
* names a venue (LVMH:TSX, 7203.T) asked for that line, and a saved row keeps
|
|
129
|
+
* the lead.
|
|
56
130
|
*/
|
|
57
131
|
export function withHomeListingLead<T extends TickerSearchCandidate>(items: T[], query: string): T[] {
|
|
58
132
|
if (isQualifiedTickerQuery(query)) return items;
|
|
59
133
|
const lead = items.find((item) => item.instrumentClass !== "fund" && item.instrumentClass !== "derivative"
|
|
60
134
|
&& !answersOnlyByKeyword(item, query));
|
|
61
135
|
if (!lead || !isListedEquity(lead)) return items;
|
|
136
|
+
const typedSymbol = lead.symbol.toUpperCase() === query.trim().toUpperCase();
|
|
137
|
+
const meant = typedSymbol && !isUsListingExchange(candidateExchange(lead)) && !(lead.result && namedByService(query, lead.result))
|
|
138
|
+
// A company's shares under another symbol: an index the code also names (SPX) or the word's own line elsewhere (SAP) is not it.
|
|
139
|
+
? items.find((item) => item !== lead && isListedEquity(item) && item.instrumentClass === "equity" && !!item.result
|
|
140
|
+
&& item.symbol.toUpperCase() !== lead.symbol.toUpperCase() && namedByService(query, item.result))
|
|
141
|
+
: undefined;
|
|
142
|
+
if (meant) return moveAhead(items, meant, lead);
|
|
143
|
+
// A line abroad that only quotes shares listed elsewhere (a German regional venue) gives way to the line the
|
|
144
|
+
// service marks as a company's home under the same symbol: YAR is Yara on Oslo, not Americold on Hanover.
|
|
145
|
+
const homeOfSymbol = typedSymbol && lead.result?.homeListing !== true && listingDistance(lead) === 1
|
|
146
|
+
&& !isUsListingExchange(candidateExchange(lead))
|
|
147
|
+
? items.find((item) => item !== lead && isListedEquity(item) && item.result?.homeListing === true
|
|
148
|
+
&& item.symbol.toUpperCase() === lead.symbol.toUpperCase())
|
|
149
|
+
: undefined;
|
|
150
|
+
if (homeOfSymbol) return moveAhead(items, homeOfSymbol, lead);
|
|
62
151
|
const name = candidateName(lead);
|
|
63
|
-
const lines = items.filter((item) => item !== lead
|
|
152
|
+
const lines = companyRows(lead, items).filter((item) => item !== lead);
|
|
64
153
|
const nearest = (candidates: T[]) => [...candidates].sort((a, b) => nameGap(name, candidateName(a)) - nameGap(name, candidateName(b))
|
|
65
154
|
|| items.indexOf(a) - items.indexOf(b))[0];
|
|
66
155
|
const marked = lines.filter((item) => item.result?.homeListing === true);
|
|
156
|
+
const own = listingDistance(lead) === 2 ? nearest(lines.filter((item) => listingDistance(item) === 0)) : undefined;
|
|
67
157
|
const home = lead.result?.homeListing === true ? undefined
|
|
68
158
|
: marked.length ? nearest(marked)
|
|
69
|
-
|
|
70
|
-
:
|
|
71
|
-
|
|
159
|
+
// A listing searched by its own symbol is that listing, as `search` keeps it.
|
|
160
|
+
: typedSymbol ? own
|
|
161
|
+
: primaryLineOf(own ?? lead, [lead, ...lines], query);
|
|
162
|
+
if (!home || home === lead) return items;
|
|
163
|
+
return moveAhead(items, home, lead);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** `items` with `home` moved just ahead of `lead`. */
|
|
167
|
+
function moveAhead<T>(items: readonly T[], home: T, lead: T): T[] {
|
|
72
168
|
const rest = items.filter((item) => item !== home);
|
|
73
169
|
const at = rest.indexOf(lead);
|
|
74
170
|
return [...rest.slice(0, at), home, ...rest.slice(at)];
|
|
@@ -54,7 +54,7 @@ export {
|
|
|
54
54
|
rankTickerSearchItems,
|
|
55
55
|
} from "./ranking";
|
|
56
56
|
export { upsertTickerFromSearchResult } from "./upsert";
|
|
57
|
-
export { candidateExchange, listingDistance } from "./home-listing";
|
|
57
|
+
export { candidateExchange, listingDistance, primaryCompanyLine } from "./home-listing";
|
|
58
58
|
|
|
59
59
|
const MAX_NAMED_LISTINGS = 6;
|
|
60
60
|
|
|
@@ -507,7 +507,10 @@ async function resolveTickerSymbol(
|
|
|
507
507
|
throw new AmbiguousContractError(symbol, matches.map((item) => tickerInstrumentLabel(item.symbol, item.result?.brokerContract)));
|
|
508
508
|
}
|
|
509
509
|
const listings = new Set(matches.map((item) => publicTickerKey(item.symbol, listingExchange(item.result!))));
|
|
510
|
-
|
|
510
|
+
// A line the service marks as a company's home leads the choices: YAR is Yara on Oslo before Americold's German lines.
|
|
511
|
+
const homeFirst = [...matches.filter((item) => item.result?.homeListing === true), ...matches.filter((item) => item.result?.homeListing !== true)];
|
|
512
|
+
const choices = new Set(homeFirst.map((item) => publicTickerKey(item.symbol, listingExchange(item.result!))));
|
|
513
|
+
const ambiguity = (query: string) => new AmbiguousTickerError(query, [...choices], Object.fromEntries(matches.map((item) => [
|
|
511
514
|
publicTickerKey(item.symbol, listingExchange(item.result!)), listingChoiceName(item.result!),
|
|
512
515
|
])));
|
|
513
516
|
if (pickerQuery && listings.size > 1) throw ambiguity(pickerQuery);
|
|
@@ -3,7 +3,12 @@ import type { Quote } from "../../types/financials";
|
|
|
3
3
|
import type { TickerRecord } from "../../types/ticker";
|
|
4
4
|
|
|
5
5
|
export type TickerSearchInstrumentClass = "equity" | "fund" | "derivative" | "other";
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* `Other Matches`: rows `gloom search` finds for the query that are not a listing
|
|
8
|
+
* of the primary listing's company (another company's DK, a line search names
|
|
9
|
+
* no company for), kept apart from its Other Listings.
|
|
10
|
+
*/
|
|
11
|
+
type TickerSearchCategory = "Saved" | "Primary Listing" | "Other Listings" | "Other Matches" | "Funds & Derivatives" | "Related";
|
|
7
12
|
|
|
8
13
|
export interface TickerSearchRankableItem {
|
|
9
14
|
id: string;
|
|
@@ -182,6 +182,8 @@ function buildBar(bucket: Bucket, intraday: boolean): AggregatedPricePoint {
|
|
|
182
182
|
let low = Number.POSITIVE_INFINITY;
|
|
183
183
|
let volume: number | undefined;
|
|
184
184
|
let venueVolume: PricePoint["venueVolume"] | null | undefined;
|
|
185
|
+
// What the volume counts carries over while every bar counts the same way.
|
|
186
|
+
let volumeBasis: string | null | undefined;
|
|
185
187
|
let partial = false;
|
|
186
188
|
let filled = false;
|
|
187
189
|
const integrity: PriceHistoryIntegrity[] = [];
|
|
@@ -189,7 +191,10 @@ function buildBar(bucket: Bucket, intraday: boolean): AggregatedPricePoint {
|
|
|
189
191
|
const close = bar.close;
|
|
190
192
|
high = Math.max(high, isFiniteNumber(bar.high) ? bar.high : close);
|
|
191
193
|
low = Math.min(low, isFiniteNumber(bar.low) ? bar.low : close);
|
|
192
|
-
if (isFiniteNumber(bar.volume))
|
|
194
|
+
if (isFiniteNumber(bar.volume)) {
|
|
195
|
+
volume = (volume ?? 0) + bar.volume;
|
|
196
|
+
volumeBasis = volumeBasis === undefined || volumeBasis === bar.volumeBasis ? bar.volumeBasis ?? null : null;
|
|
197
|
+
}
|
|
193
198
|
// One venue's trades add up only while every bar counts the same venue.
|
|
194
199
|
if (bar.venueVolume && venueVolume !== null) {
|
|
195
200
|
venueVolume = venueVolume === undefined || venueVolume.venue === bar.venueVolume.venue
|
|
@@ -207,6 +212,7 @@ function buildBar(bucket: Bucket, intraday: boolean): AggregatedPricePoint {
|
|
|
207
212
|
low,
|
|
208
213
|
close: last.close,
|
|
209
214
|
...(volume !== undefined ? { volume } : {}),
|
|
215
|
+
...(volume !== undefined && volumeBasis ? { volumeBasis } : {}),
|
|
210
216
|
...(volume === undefined && venueVolume ? { venueVolume } : {}),
|
|
211
217
|
...(partial ? { partial: true } : {}),
|
|
212
218
|
...(filled ? { filled: true } : {}),
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
valuationPriceIssues,
|
|
16
16
|
} from "./fundamentals";
|
|
17
17
|
import { extractSecuritySeries } from "./market";
|
|
18
|
-
import { activeStudyInputSeriesIds } from "./studies";
|
|
18
|
+
import { activeStudyInputSeriesIds } from "./studies/resolve";
|
|
19
19
|
import { reportingCurrencySeries } from "./reporting-currency";
|
|
20
20
|
import { compareChartQuoteRecency } from "./live-quotes";
|
|
21
21
|
import { marketSeriesFrequency } from "./market";
|
|
@@ -138,8 +138,8 @@ export function baseSecuritySeries(
|
|
|
138
138
|
: field.unit;
|
|
139
139
|
const generic = field.unitGroup === "price"
|
|
140
140
|
? futuresGenericListing(spec.source.instrument.symbol, spec.source.instrument.exchange) : null;
|
|
141
|
-
//
|
|
142
|
-
//
|
|
141
|
+
// Index and Treasury futures read in points or 32nds across generics,
|
|
142
|
+
// continuous symbols and listed contracts, as their quotes do.
|
|
143
143
|
const genericBasis = field.unitGroup === "price" && isMarketFieldId(field.id)
|
|
144
144
|
? futuresListingPriceBasis(spec.source.instrument.symbol, spec.source.instrument.exchange) : null;
|
|
145
145
|
// An index's level is points too, never the currency its members trade in.
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
type ManualChartResolution,
|
|
16
16
|
} from "./resolution";
|
|
17
17
|
import { TIME_RANGES, type TimeRange } from "./range";
|
|
18
|
-
import { maxStudyWarmupPoints } from "./studies";
|
|
18
|
+
import { maxStudyWarmupPoints } from "./studies/resolve";
|
|
19
19
|
import type { PriceComparison } from "./price-comparison";
|
|
20
20
|
import { resolutionForExplicitMarketPeriods } from "./market-resolution";
|
|
21
21
|
import { latestSessionStart, latestTradingSessionOpen, priorSessionClose } from "../market-data/market/trading-sessions";
|
|
@@ -103,8 +103,11 @@ function finiteOrFallback(value: number | undefined, fallback: number): number {
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
function mergeQuoteIntoLatestBar(latest: PricePoint, quotePrice: number, range?: QuoteSessionRange | null): PricePoint {
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
if (pricePointIntegrity(latest)) {
|
|
107
|
+
// A later quote cannot establish which reported OHLC field was wrong, unless it names the bar's whole session: its
|
|
108
|
+
// open, range and price are the bar (GOGL's 2026-10-30 daily bar, served with a high under its open).
|
|
109
|
+
return range?.open === undefined ? latest : { ...latest, open: range.open, high: range.high, low: range.low, close: quotePrice };
|
|
110
|
+
}
|
|
108
111
|
const open = finiteOrFallback(latest.open, latest.close);
|
|
109
112
|
const high = finiteOrFallback(latest.high, Math.max(open, latest.close));
|
|
110
113
|
const low = finiteOrFallback(latest.low, Math.min(open, latest.close));
|
|
@@ -10,7 +10,7 @@ import { aggregatePriceBars, futuresOpenMinuteOf, withBuiltBarSize } from "./bar
|
|
|
10
10
|
import type { TickerFinancials } from "../types/financials";
|
|
11
11
|
import { isMarketFieldId } from "./field-catalog";
|
|
12
12
|
import { chartPriceHistoryIntegrityNotices } from "./market";
|
|
13
|
-
import { resolveStudies } from "./studies";
|
|
13
|
+
import { resolveStudies } from "./studies/resolve";
|
|
14
14
|
import { clipSeriesToWindow } from "./alignment";
|
|
15
15
|
import { bufferPriceComparison, clipPriceComparison, priceComparisonBoundsForSeries, resolvePriceComparison } from "./price-comparison";
|
|
16
16
|
import { readSeedListingFacts } from "./parsed-history-cache";
|