gloomberb 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
|
@@ -15,6 +15,10 @@ import type { DataProvider } from "../../../../types/data-provider";
|
|
|
15
15
|
import type { PricePoint } from "../../../../types/financials";
|
|
16
16
|
import { isRoundTheClockCoin } from "../../../../utils/crypto-pair";
|
|
17
17
|
import { isCurrencyPairListing } from "../../../../utils/fx-market-hours";
|
|
18
|
+
import { latestRegularSessionClose } from "../../../../market-data/market/freshness";
|
|
19
|
+
import { futuresSessionOpenMinute } from "../../../../market-data/market/trading-sessions";
|
|
20
|
+
import { calendarBarStart } from "../../../../time-series/chart-data";
|
|
21
|
+
import { newestClosedSession, newestSessionClose, withOfficialCloses } from "../../../../time-series/official-close";
|
|
18
22
|
import {
|
|
19
23
|
effectiveReturnResolution,
|
|
20
24
|
endsAtLatestBar,
|
|
@@ -39,6 +43,8 @@ export interface ReturnSeries {
|
|
|
39
43
|
lastSession?: string;
|
|
40
44
|
/** The venue whose sessions the window follows; empty when none is known. */
|
|
41
45
|
venue: string;
|
|
46
|
+
/** The local date of the newest session, closed but without its official close yet: its last bar ends on the last trade. */
|
|
47
|
+
closingPrintPending?: string;
|
|
42
48
|
}
|
|
43
49
|
|
|
44
50
|
export interface ReturnSeriesRequest {
|
|
@@ -66,20 +72,76 @@ function historyErrorMessage(error: unknown, resolution: ManualChartResolution):
|
|
|
66
72
|
/**
|
|
67
73
|
* The venue whose sessions set where the window ends: the one the ticker
|
|
68
74
|
* names, else the listing its quote names, so a bare VTI ends at the NYSE
|
|
69
|
-
* Arca close on a weekend
|
|
75
|
+
* Arca close on a weekend, with the listing's currency when that was read.
|
|
76
|
+
* Coins and currency pairs need none.
|
|
70
77
|
*/
|
|
71
|
-
async function sessionVenue(provider: DataProvider, symbol: string, exchange: string): Promise<string> {
|
|
72
|
-
if (exchange || isRoundTheClockCoin(symbol) || isCurrencyPairListing(symbol, exchange)) return exchange;
|
|
78
|
+
async function sessionVenue(provider: DataProvider, symbol: string, exchange: string): Promise<{ venue: string; currency?: string }> {
|
|
79
|
+
if (exchange || isRoundTheClockCoin(symbol) || isCurrencyPairListing(symbol, exchange)) return { venue: exchange };
|
|
73
80
|
try {
|
|
74
81
|
const metadata = provider.getQuoteMetadata
|
|
75
82
|
? await provider.getQuoteMetadata(symbol, exchange)
|
|
76
83
|
: await provider.getQuote(symbol, exchange);
|
|
77
|
-
return metadata?.listingExchangeName ?? "";
|
|
84
|
+
return { venue: metadata?.listingExchangeName ?? "", ...(metadata?.currency ? { currency: metadata.currency } : {}) };
|
|
78
85
|
} catch (error) {
|
|
79
|
-
return logFailure("ticker-detail.data-panes.returns-history", "Read return session venue failed", "")(error);
|
|
86
|
+
return { venue: logFailure("ticker-detail.data-panes.returns-history", "Read return session venue failed", "")(error) };
|
|
80
87
|
}
|
|
81
88
|
}
|
|
82
89
|
|
|
90
|
+
const DAY_MS = 86_400_000;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Intraday bars with each closed session's last bar on its official close
|
|
94
|
+
* (withOfficialCloses), so every total and the base they are measured from
|
|
95
|
+
* are the closes `history` and CMP give, not the last trade before the
|
|
96
|
+
* closing auction. Earlier sessions take their daily bar's close, dated by
|
|
97
|
+
* the venue's local date; the newest closed session the close
|
|
98
|
+
* newestSessionClose picks from the quote and its daily bar, or the note
|
|
99
|
+
* that its print is to come. Daily and longer bars, futures (which settle
|
|
100
|
+
* rather than close on a print) and listings without sessions are returned
|
|
101
|
+
* as loaded.
|
|
102
|
+
*/
|
|
103
|
+
async function withSessionCloses(
|
|
104
|
+
provider: DataProvider,
|
|
105
|
+
target: { symbol: string; exchange: string; venue: string; currency?: string },
|
|
106
|
+
interval: ManualChartResolution,
|
|
107
|
+
points: PricePoint[],
|
|
108
|
+
now: number,
|
|
109
|
+
context: { cacheMode: "refresh" } | undefined,
|
|
110
|
+
): Promise<{ points: PricePoint[]; closingPrintPending?: string }> {
|
|
111
|
+
const venue = target.venue || undefined;
|
|
112
|
+
if (!isIntradayResolution(interval) || !points.length || futuresSessionOpenMinute(target.symbol, target.venue || target.exchange) != null
|
|
113
|
+
|| !latestRegularSessionClose(venue, now)) return { points };
|
|
114
|
+
const newest = newestClosedSession(points, { venue, now });
|
|
115
|
+
// Whole UTC days, so the same window asks the same read (and its cached copy) all day.
|
|
116
|
+
const first = Math.floor(new Date(points[0]!.date).getTime() / DAY_MS) * DAY_MS - 2 * DAY_MS;
|
|
117
|
+
const end = Math.floor(Math.min(now, new Date(points.at(-1)!.date).getTime() + DAY_MS) / DAY_MS) * DAY_MS + DAY_MS - 1;
|
|
118
|
+
const [daily, quote] = await Promise.all([
|
|
119
|
+
fetchHistoryResult(provider, target.symbol, target.exchange, { kind: "detail", start: new Date(first), end: new Date(end), interval: "1d" }, context)
|
|
120
|
+
.catch(logFailure("ticker-detail.data-panes.returns-history", "Read the daily closes of a return window failed", null)),
|
|
121
|
+
// Only the newest closed session needs the quote's word on its close.
|
|
122
|
+
newest
|
|
123
|
+
? Promise.resolve(provider.getQuote(target.symbol, target.exchange, context))
|
|
124
|
+
.catch(logFailure("ticker-detail.data-panes.returns-history", "Read the official close of a return window failed", null))
|
|
125
|
+
: null,
|
|
126
|
+
]);
|
|
127
|
+
const dailyCloses = new Map<string, number>();
|
|
128
|
+
for (const bar of daily?.points ?? []) {
|
|
129
|
+
const time = new Date(bar.date).getTime();
|
|
130
|
+
if (!bar.partial && Number.isFinite(time) && Number.isFinite(bar.close) && bar.close > 0) {
|
|
131
|
+
dailyCloses.set(calendarBarStart(time, "1d", venue), bar.close);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const closes = new Map([...dailyCloses].filter(([date]) => date !== newest?.date));
|
|
135
|
+
const decided = newest
|
|
136
|
+
? newestSessionClose(quote, { ...newest, venue, currency: target.currency ?? null, dailyClose: dailyCloses.get(newest.date) ?? null })
|
|
137
|
+
: null;
|
|
138
|
+
if (newest && decided && "close" in decided) closes.set(newest.date, decided.close);
|
|
139
|
+
return {
|
|
140
|
+
points: withOfficialCloses(points, closes, { venue, now }),
|
|
141
|
+
...(newest && decided && "pending" in decided ? { closingPrintPending: newest.date } : {}),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
83
145
|
/**
|
|
84
146
|
* The bars of a return window and where it starts and ends, as RETURN, its
|
|
85
147
|
* report and its capture all load them: the window ends now while the
|
|
@@ -91,7 +153,7 @@ export async function loadReturnSeries(provider: DataProvider, request: ReturnSe
|
|
|
91
153
|
if (request.window) return loadReturnWindow(provider, request, request.window);
|
|
92
154
|
const { symbol, exchange, range, support, now } = request;
|
|
93
155
|
const interval = effectiveReturnResolution(range, request.resolution, support);
|
|
94
|
-
const venue = await sessionVenue(provider, symbol, exchange);
|
|
156
|
+
const { venue, currency } = await sessionVenue(provider, symbol, exchange);
|
|
95
157
|
const windowEnd = returnWindowEnd({ symbol, exchange: venue }, now);
|
|
96
158
|
const visibleFrom = returnVisibleFrom(range, interval, windowEnd.end, venue || undefined);
|
|
97
159
|
const start = new Date(visibleFrom - returnLookbackMs(range, interval, support));
|
|
@@ -100,18 +162,24 @@ export async function loadReturnSeries(provider: DataProvider, request: ReturnSe
|
|
|
100
162
|
let result;
|
|
101
163
|
try {
|
|
102
164
|
// Exact bounds first, then the interval's range history, as charts do
|
|
103
|
-
// when a source keeps no bars for the exact window
|
|
104
|
-
|
|
165
|
+
// when a source keeps no bars for the exact window or failed to load it
|
|
166
|
+
// (the range history may answer from a saved copy); the failure stands when that has none either.
|
|
167
|
+
let detailFailure: unknown = null;
|
|
168
|
+
result = await fetchHistoryResult(provider, symbol, exchange, { kind: "detail", start, end, interval }, context)
|
|
169
|
+
.catch((error: unknown) => { detailFailure = error; return null; });
|
|
105
170
|
if (!result?.points.length) {
|
|
106
171
|
result = await fetchHistoryResult(provider, symbol, exchange, { kind: "resolution", range: returnSupportRange(range), resolution: interval }, context) ?? result;
|
|
107
172
|
}
|
|
173
|
+
if (!result?.points.length && detailFailure) throw detailFailure;
|
|
108
174
|
} catch (error) {
|
|
109
175
|
throw historyErrorMessage(error, interval);
|
|
110
176
|
}
|
|
111
177
|
if (!result) throw new Error("Price history unavailable");
|
|
112
178
|
const latest = latestBarTime(result.points);
|
|
179
|
+
const closed = await withSessionCloses(provider, { symbol, exchange, venue, currency }, interval, result.points, now, context);
|
|
113
180
|
return {
|
|
114
|
-
points:
|
|
181
|
+
points: closed.points,
|
|
182
|
+
...(closed.closingPrintPending ? { closingPrintPending: closed.closingPrintPending } : {}),
|
|
115
183
|
// A 1W to 5Y window's rows start after its base close, found among the bars by their session days.
|
|
116
184
|
visibleFrom: endsAtLatestBar(range) && latest !== null && latest < windowEnd.end
|
|
117
185
|
? returnVisibleFrom(range, interval, latest, venue || undefined)
|
|
@@ -142,7 +210,7 @@ async function loadReturnWindow(provider: DataProvider, request: ReturnSeriesReq
|
|
|
142
210
|
const step = CHART_RESOLUTION_STEP_MS[request.resolution];
|
|
143
211
|
let interval = available.includes(request.resolution) ? request.resolution
|
|
144
212
|
: available.find((candidate) => CHART_RESOLUTION_STEP_MS[candidate] >= step) ?? available.at(-1) ?? "1d";
|
|
145
|
-
const venue = await sessionVenue(provider, symbol, exchange);
|
|
213
|
+
const { venue, currency } = await sessionVenue(provider, symbol, exchange);
|
|
146
214
|
const context = request.forceRefresh ? { cacheMode: "refresh" as const } : undefined;
|
|
147
215
|
const load = async (resolution: ManualChartResolution) => {
|
|
148
216
|
// A daily or longer bar is stamped at midnight UTC, so the window takes every bar from its first date's day, week or month on.
|
|
@@ -167,8 +235,10 @@ async function loadReturnWindow(provider: DataProvider, request: ReturnSeriesReq
|
|
|
167
235
|
}
|
|
168
236
|
}
|
|
169
237
|
if (!loaded?.result) throw new Error("Price history unavailable");
|
|
238
|
+
const closed = await withSessionCloses(provider, { symbol, exchange, venue, currency }, interval, loaded.result.points, now, context);
|
|
170
239
|
return {
|
|
171
|
-
points:
|
|
240
|
+
points: closed.points,
|
|
241
|
+
...(closed.closingPrintPending ? { closingPrintPending: closed.closingPrintPending } : {}),
|
|
172
242
|
visibleFrom: loaded.visibleFrom,
|
|
173
243
|
visibleTo: Math.min(last, now),
|
|
174
244
|
...(loaded.result.coverageStart ? { coverageStart: loaded.result.coverageStart } : {}),
|
|
@@ -505,13 +505,46 @@ function coversLatestYear(ttm: FinancialTableStatement, latestYear: FinancialSta
|
|
|
505
505
|
return days <= 7;
|
|
506
506
|
}
|
|
507
507
|
|
|
508
|
+
/** Counts of the shares a company has issued or has outstanding, which are never zero; treasury shares can be. */
|
|
509
|
+
const OUTSTANDING_COUNT_FIELDS = ["basicShares", "dilutedShares", "shareIssued", "ordinarySharesNumber"] as const;
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Share counts that cannot be the company's: zero, or under a thousandth of its
|
|
513
|
+
* typical count (IAG's 4,642 for Q3 2025, millions read as shares, which shows
|
|
514
|
+
* as 0.00 bn and a fall of 100%). They are missing, not a value to grow from.
|
|
515
|
+
*/
|
|
516
|
+
function withoutImpossibleShareCounts(
|
|
517
|
+
annualStatements: FinancialStatement[],
|
|
518
|
+
quarterlyStatements: FinancialStatement[],
|
|
519
|
+
): { annualStatements: FinancialStatement[]; quarterlyStatements: FinancialStatement[] } {
|
|
520
|
+
const all = [...annualStatements, ...quarterlyStatements];
|
|
521
|
+
const floors = new Map<string, number>();
|
|
522
|
+
for (const field of OUTSTANDING_COUNT_FIELDS) {
|
|
523
|
+
const counts = all.map((row) => row[field]).filter((value): value is number => typeof value === "number" && value > 0).sort((a, b) => a - b);
|
|
524
|
+
floors.set(field, counts.length ? counts[Math.floor(counts.length / 2)]! / 1000 : 0);
|
|
525
|
+
}
|
|
526
|
+
const impossible = (row: FinancialStatement, field: typeof OUTSTANDING_COUNT_FIELDS[number]) => {
|
|
527
|
+
const value = row[field];
|
|
528
|
+
return typeof value === "number" && (value <= 0 || value < floors.get(field)!);
|
|
529
|
+
};
|
|
530
|
+
const clean = (rows: FinancialStatement[]) => rows.map((row) => {
|
|
531
|
+
const drop = OUTSTANDING_COUNT_FIELDS.filter((field) => impossible(row, field));
|
|
532
|
+
if (!drop.length) return row;
|
|
533
|
+
const next = { ...row };
|
|
534
|
+
for (const field of drop) delete next[field];
|
|
535
|
+
return next;
|
|
536
|
+
});
|
|
537
|
+
return { annualStatements: clean(annualStatements), quarterlyStatements: clean(quarterlyStatements) };
|
|
538
|
+
}
|
|
539
|
+
|
|
508
540
|
export function selectFinancialStatements(
|
|
509
541
|
period: FinancialPeriod,
|
|
510
542
|
statement: string,
|
|
511
|
-
|
|
512
|
-
|
|
543
|
+
servedAnnual: FinancialStatement[],
|
|
544
|
+
servedQuarterly: FinancialStatement[],
|
|
513
545
|
limit = period === "annual" ? 5 : 6,
|
|
514
546
|
) {
|
|
547
|
+
const { annualStatements, quarterlyStatements } = withoutImpossibleShareCounts(servedAnnual, servedQuarterly);
|
|
515
548
|
// A period with nothing on this statement (a fiscal year-end balance point on
|
|
516
549
|
// the income statement) would render as an all-dash column.
|
|
517
550
|
const tabRows = FINANCIAL_SUB_TABS.find((tab) => tab.key === statement)?.rows;
|
|
@@ -4,6 +4,7 @@ import { formatNumber, pickUnit } from "../../../../utils/format";
|
|
|
4
4
|
import { pricePointIntegrity } from "../../../../utils/price-history-integrity";
|
|
5
5
|
import { formatPerShareNumber } from "../../../../utils/reported-money";
|
|
6
6
|
import { hasStatementGap } from "../../../../utils/statement-gaps";
|
|
7
|
+
import { debtAndLeases, leaseBasis, type LeaseBasis } from "../../../../utils/lease-liabilities";
|
|
7
8
|
import { cashAndShortTermInvestments, excludesCashRunway, formatRunwayMonths, SHORT_RUNWAY_HISTORY, monthlyOperatingBurn, QUARTER_MONTHS, reportsShortTermTotal, runwayMonths, YEAR_MONTHS } from "../../../../utils/cash-runway";
|
|
8
9
|
import {
|
|
9
10
|
buildPreviousStatementMap,
|
|
@@ -58,6 +59,8 @@ export interface RatioPeriod {
|
|
|
58
59
|
price: RatioAmount;
|
|
59
60
|
/** The filer reports cash and short-term investments as a total in some period on file (utils/cash-runway). */
|
|
60
61
|
shortTermTotalOnFile?: boolean;
|
|
62
|
+
/** How net debt treats the lease liabilities the listing's balance sheets report; absent when none do. */
|
|
63
|
+
leaseBasis?: LeaseBasis;
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
interface RatioInputDef {
|
|
@@ -75,6 +78,13 @@ interface RatioInputDef {
|
|
|
75
78
|
trailing?: boolean;
|
|
76
79
|
/** A shorter name for quarterly columns, so the label, TTM and its unit fit the label column. */
|
|
77
80
|
trailingLabel?: string;
|
|
81
|
+
/** Debt net of cash: where the listing reports lease liabilities, a row naming them follows it (withLeaseRow). */
|
|
82
|
+
netDebt?: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Not an operand: a line the input before it includes or leaves out, shown under it. Neither its value nor
|
|
85
|
+
* its gap enters the ratio.
|
|
86
|
+
*/
|
|
87
|
+
memo?: boolean;
|
|
78
88
|
value: (period: RatioPeriod) => RatioAmount;
|
|
79
89
|
}
|
|
80
90
|
|
|
@@ -245,12 +255,41 @@ function marketCap(period: RatioPeriod): RatioAmount {
|
|
|
245
255
|
return period.price * shares;
|
|
246
256
|
}
|
|
247
257
|
|
|
258
|
+
/**
|
|
259
|
+
* Total debt less cash and short-term investments, with the balance sheet's lease liabilities where the listing's
|
|
260
|
+
* are included (utils/lease-liabilities). A balance sheet without its lease line then has no net debt.
|
|
261
|
+
*/
|
|
262
|
+
function netDebt({ statement, leaseBasis: basis }: RatioPeriod): RatioAmount {
|
|
263
|
+
const cash = cashAndShortTerm(statement);
|
|
264
|
+
if (basis === "included") {
|
|
265
|
+
const lines = debtAndLeases(statement);
|
|
266
|
+
return lines === undefined || cash === undefined ? "not-reported" : lines.totalDebt + lines.leases - cash;
|
|
267
|
+
}
|
|
268
|
+
const debt = finite(statement.totalDebt);
|
|
269
|
+
return debt === undefined || cash === undefined ? "not-reported" : debt - cash;
|
|
270
|
+
}
|
|
271
|
+
|
|
248
272
|
function enterpriseValue(period: RatioPeriod): RatioAmount {
|
|
249
|
-
const debt =
|
|
250
|
-
|
|
251
|
-
if (debt === undefined || cash === undefined) return "not-reported";
|
|
273
|
+
const debt = netDebt(period);
|
|
274
|
+
if (isGap(debt)) return debt;
|
|
252
275
|
const cap = marketCap(period);
|
|
253
|
-
return isGap(cap) ? cap : cap + debt
|
|
276
|
+
return isGap(cap) ? cap : cap + debt;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/** The lease liabilities net debt includes, or a US GAAP filer's operating leases it leaves out. */
|
|
280
|
+
const LEASE_ROW_LABEL: Record<LeaseBasis, string> = { included: "incl. leases", excluded: "excl. op. leases" };
|
|
281
|
+
|
|
282
|
+
/** The ratio with a row naming the listing's lease liabilities under its net debt, when it reports any. */
|
|
283
|
+
function withLeaseRow(def: RatioDef, basis: LeaseBasis | undefined): RatioDef {
|
|
284
|
+
const at = def.inputs.findIndex((input) => input.netDebt);
|
|
285
|
+
if (!basis || at < 0) return def;
|
|
286
|
+
const row: RatioInputDef = {
|
|
287
|
+
label: LEASE_ROW_LABEL[basis],
|
|
288
|
+
format: "money",
|
|
289
|
+
memo: true,
|
|
290
|
+
value: ({ statement }) => reported(finite(statement.capitalLeaseObligations)),
|
|
291
|
+
};
|
|
292
|
+
return { ...def, inputs: [...def.inputs.slice(0, at + 1), row, ...def.inputs.slice(at + 1)] };
|
|
254
293
|
}
|
|
255
294
|
|
|
256
295
|
const DSO: RatioDef = {
|
|
@@ -378,15 +417,7 @@ export const RATIO_TABS: RatioTabDef[] = [
|
|
|
378
417
|
label: "Net Debt / EBITDA",
|
|
379
418
|
format: "multiple",
|
|
380
419
|
inputs: [
|
|
381
|
-
{
|
|
382
|
-
label: "Net Debt",
|
|
383
|
-
format: "money",
|
|
384
|
-
value: ({ statement }) => {
|
|
385
|
-
const debt = finite(statement.totalDebt);
|
|
386
|
-
const cash = cashAndShortTerm(statement);
|
|
387
|
-
return debt === undefined || cash === undefined ? "not-reported" : debt - cash;
|
|
388
|
-
},
|
|
389
|
-
},
|
|
420
|
+
{ label: "Net Debt", format: "money", netDebt: true, value: netDebt },
|
|
390
421
|
trailingFlow("EBITDA", line("ebitda"), "÷"),
|
|
391
422
|
],
|
|
392
423
|
compute: ([debt, ebitda]) => over(debt!, ebitda!),
|
|
@@ -517,7 +548,7 @@ export const RATIO_TABS: RatioTabDef[] = [
|
|
|
517
548
|
label: "EV / EBITDA",
|
|
518
549
|
format: "multiple",
|
|
519
550
|
inputs: [
|
|
520
|
-
{ label: "Enterprise Value", format: "money", value: enterpriseValue },
|
|
551
|
+
{ label: "Enterprise Value", format: "money", netDebt: true, value: enterpriseValue },
|
|
521
552
|
trailingFlow("EBITDA", line("ebitda"), "÷"),
|
|
522
553
|
],
|
|
523
554
|
// A negative enterprise value makes the multiple meaningless too.
|
|
@@ -568,10 +599,11 @@ function inputAmount(input: RatioInputDef, period: RatioPeriod): RatioAmount {
|
|
|
568
599
|
|
|
569
600
|
export function evaluateRatio(def: RatioDef, period: RatioPeriod): RatioCell {
|
|
570
601
|
const inputs = def.inputs.map((input) => inputAmount(input, period));
|
|
571
|
-
const
|
|
602
|
+
const operands = inputs.filter((_, index) => !def.inputs[index]!.memo);
|
|
603
|
+
const gap = GAP_ORDER.find((candidate) => operands.includes(candidate));
|
|
572
604
|
if (gap) return { value: gap, inputs };
|
|
573
|
-
const values = inputs.
|
|
574
|
-
|
|
605
|
+
const values = def.inputs.flatMap((input, index) => (
|
|
606
|
+
input.memo ? [] : [input.annualized && period.quarterly ? (inputs[index] as number) * QUARTERS_PER_YEAR : inputs[index] as number]
|
|
575
607
|
));
|
|
576
608
|
const value = def.compute(values, period);
|
|
577
609
|
return { value: isGap(value) || Number.isFinite(value) ? value : "not-meaningful", inputs };
|
|
@@ -702,6 +734,7 @@ export function ratioPeriods(
|
|
|
702
734
|
onFile: { annual: readonly FinancialStatement[]; quarterly: readonly FinancialStatement[] } = { annual: [], quarterly: [] },
|
|
703
735
|
): RatioPeriod[] {
|
|
704
736
|
const shortTermTotalOnFile = reportsShortTermTotal([...onFile.annual, ...onFile.quarterly, ...statements]);
|
|
737
|
+
const leases = leaseBasis([...onFile.annual, ...onFile.quarterly, ...statements]);
|
|
705
738
|
return statements.map((statement) => {
|
|
706
739
|
const quarterly = period === "quarterly" && statement.date !== "TTM";
|
|
707
740
|
return {
|
|
@@ -711,6 +744,7 @@ export function ratioPeriods(
|
|
|
711
744
|
...(quarterly ? { trailing: trailingYear(statement, onFile.annual, onFile.quarterly) } : {}),
|
|
712
745
|
price: price(statement),
|
|
713
746
|
shortTermTotalOnFile,
|
|
747
|
+
...(leases ? { leaseBasis: leases } : {}),
|
|
714
748
|
};
|
|
715
749
|
});
|
|
716
750
|
}
|
|
@@ -758,11 +792,12 @@ export function buildRatioTableModel(
|
|
|
758
792
|
): RatioTableModel {
|
|
759
793
|
const quarterly = periods.some((period) => period.quarterly);
|
|
760
794
|
const totalOnFile = periods.some((period) => period.shortTermTotalOnFile);
|
|
795
|
+
const leases = periods.find((period) => period.leaseBasis)?.leaseBasis;
|
|
761
796
|
const ratios = visibleRatios(tab, quarterly)
|
|
762
797
|
.filter((def) => def.format !== "months" || !excludesCashRunway(profile))
|
|
763
798
|
.map((def) => def.format === "months" && !totalOnFile
|
|
764
799
|
? { ...def, inputs: def.inputs.map((input, index) => index === 0 ? { ...input, label: "Cash" } : input) }
|
|
765
|
-
: def);
|
|
800
|
+
: withLeaseRow(def, leases));
|
|
766
801
|
const cells = new Map(ratios.map((def) => [def.id, periods.map((period) => evaluateRatio(def, period))]));
|
|
767
802
|
const inputs = ratios.flatMap((def) => def.inputs.map((input, index) => {
|
|
768
803
|
const values = cells.get(def.id)!.map((cell) => cell.inputs[index]).filter((value) => typeof value === "number");
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
FINANCIAL_VINTAGE_NOTICE, filledPeriodsNote, hasOlderStatements, reportsHalfYearly, stalePeriodNote, statementHistoryNotes,
|
|
3
|
+
} from "../../../utils/financial-statements";
|
|
4
|
+
import { canonicalExchange } from "../../../utils/exchanges";
|
|
2
5
|
import { hasValidQuoteObservationTime } from "../../../market-data/quotes/freshness";
|
|
3
6
|
import { EXTENDED_SESSION_LABELS, getQuoteSessionFields, quoteHeadlineTime, type ExtendedSession } from "../../../market-data/market/status";
|
|
4
7
|
import type { HeadlessPaneColumn, HeadlessPaneDefinition, HeadlessPaneFreshness, HeadlessPaneOptionValues } from "../../../types/headless";
|
|
@@ -6,7 +9,8 @@ import type { TimeRange } from "../../../time-series/range";
|
|
|
6
9
|
import { formatNumber, formatPercentRaw } from "../../../utils/format";
|
|
7
10
|
import { formatMarketPrice, formatMarketPriceWithCurrency, formatPriceObservation, penceFigure, quoteFormatOptions, withCurrencyMinorDigits, type MarketFormatOptions } from "../../../market-data/market/format";
|
|
8
11
|
import {
|
|
9
|
-
MISSING_VOLUME_TEXT, missingVolumeCount, missingVolumeNotice, pricePointValues, priceHistoryIntegrityNotice,
|
|
12
|
+
MISSING_VOLUME_TEXT, missingVolumeCount, missingVolumeNotice, pricePointValues, pricePointWickFlags, priceHistoryIntegrityNotice,
|
|
13
|
+
priceHistoryWickNotice,
|
|
10
14
|
} from "../../../utils/price-history-integrity";
|
|
11
15
|
import {
|
|
12
16
|
buildFinancialTableModel, financialStatementCurrency, financialStatementDateNotice, financialStatementLimitations,
|
|
@@ -48,6 +52,7 @@ import { DAY_SO_FAR_TEXT, withSessionBar } from "../../../time-series/session-ba
|
|
|
48
52
|
import { buildReturnRows, closedMarketNote, isTodayReturnRow, returnBaseCloseDay, type ReturnRange } from "./data-panes/returns-model";
|
|
49
53
|
import { periodBaseText } from "../../../market-data/market/period-return";
|
|
50
54
|
import { loadReturnSeries } from "./data-panes/returns-history";
|
|
55
|
+
import { CLOSING_PRINT_PENDING_TEXT } from "../../../time-series/official-close";
|
|
51
56
|
import {
|
|
52
57
|
closedHistoryBarDay, formingHistoryBar, HISTORY_DEFAULT_RANGE, historyBarDate, historyBarSize, historyBarSizeWord, historyDateHeader, isDailyOrLongerBar,
|
|
53
58
|
type HistoryBarSize,
|
|
@@ -151,18 +156,23 @@ export const financialStatementsHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
|
151
156
|
const stale = table ? stalePeriodNote(financialStatementPeriods(table.statements, table.subTab)) : null;
|
|
152
157
|
// Years filled from the listing's exchange, with the lines this table shows.
|
|
153
158
|
const filled = table ? filledPeriodsNote(table.statements, financialSubTabFields(table.subTab)) : null;
|
|
159
|
+
const periodDates = dates.map(({ date }) => date);
|
|
160
|
+
const missing = rows.length ? null : await missingPeriodsError(ctx, symbol, financials, requestedPeriod, hasRequestedStatements, options.statement);
|
|
154
161
|
return {
|
|
155
162
|
rows, columns, unavailableSymbols: rows.length ? [] : [symbol],
|
|
156
|
-
...(
|
|
163
|
+
...(missing ? { errors: [missing] } : {}),
|
|
157
164
|
// The report closes with how old its latest period is, how far back its periods go, and how to read further.
|
|
158
|
-
notes: [...stale ? [stale] : [], ...filled ? [filled] : [], ...offering ? [offering] : [],
|
|
165
|
+
notes: [...stale ? [stale] : [], ...filled ? [filled] : [], ...offering ? [offering] : [],
|
|
166
|
+
...statementHistoryNotes(requestedPeriod, periodDates, symbol, await reportOlderStatements(ctx, symbol, requestedPeriod, periodDates))],
|
|
159
167
|
metadata: {
|
|
160
168
|
symbol, name: financials.quote?.name ?? symbol, currency: statementCurrency ?? null, unit: table?.unit ?? null, quoteCurrency: financials.quote?.currency ?? null,
|
|
161
169
|
statement: table?.subTab.key ?? options.statement, statementLabel: table?.subTab.name ?? null,
|
|
162
170
|
period: requestedPeriod, growthBasis: requestedPeriod === "quarterly" ? "QoQ" : "YoY", columns: dates,
|
|
163
171
|
shareBasis: shareBases.size === 1 ? [...shareBases][0] ?? null : null,
|
|
164
172
|
...(receiptPeriods.length > 0 ? { adrRatio: financials.fundamentals?.adrRatio ?? financials.quote?.adrRatio ?? null } : {}),
|
|
165
|
-
|
|
173
|
+
// A quarter's change is against the quarter before it, which a reader of a table of quarters must be told.
|
|
174
|
+
notices: rows.length ? [FINANCIAL_VINTAGE_NOTICE, ...requestedPeriod === "quarterly" ? [QUARTERLY_GROWTH_NOTICE] : [],
|
|
175
|
+
...(shareBasisNotice ? [shareBasisNotice] : [])] : [],
|
|
166
176
|
limitations: financialStatementLimitations(financials),
|
|
167
177
|
dateProvenance: financialStatementDateNotice(table?.statements ?? []),
|
|
168
178
|
},
|
|
@@ -172,6 +182,44 @@ export const financialStatementsHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
|
172
182
|
|
|
173
183
|
const reportAmount = (amount: RatioAmount) => (typeof amount === "number" ? amount : null);
|
|
174
184
|
|
|
185
|
+
/** What a table of quarters says its growth is measured against. */
|
|
186
|
+
const QUARTERLY_GROWTH_NOTICE = "Growth is vs prior quarter.";
|
|
187
|
+
|
|
188
|
+
type HeadlessContext = Parameters<typeof financialStatementsHeadless.load>[1];
|
|
189
|
+
|
|
190
|
+
/** Whether GF, reading the listing's extended statement history, goes back further than the report (statementHistoryNotes). */
|
|
191
|
+
function reportOlderStatements(ctx: HeadlessContext, symbol: string, period: "annual" | "quarterly", dates: readonly string[]) {
|
|
192
|
+
return hasOlderStatements(async () => {
|
|
193
|
+
const { symbol: bare, exchange } = await resolveHeadlessInstrument(ctx, symbol);
|
|
194
|
+
return ctx.marketData.getTickerFinancials(bare, exchange ?? "", { statementHistory: "extended" });
|
|
195
|
+
}, period, dates);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Why a statements report has no rows, and what to read instead: a listing
|
|
200
|
+
* with years but no quarters names its years, and says so of a company that
|
|
201
|
+
* reports half-yearly (Qantas on ASX). Null when it has years and quarters,
|
|
202
|
+
* whatever this table lacks.
|
|
203
|
+
*/
|
|
204
|
+
async function missingPeriodsError(
|
|
205
|
+
ctx: HeadlessContext,
|
|
206
|
+
symbol: string,
|
|
207
|
+
financials: Awaited<ReturnType<typeof loadHeadlessFinancials>>,
|
|
208
|
+
period: "annual" | "quarterly",
|
|
209
|
+
hasRequestedStatements: boolean,
|
|
210
|
+
statement: unknown,
|
|
211
|
+
): Promise<string | null> {
|
|
212
|
+
const hasYears = financials.annualStatements.length > 0;
|
|
213
|
+
if (period === "annual" || !hasYears) return hasRequestedStatements ? null : `${symbol}: No ${period} financial statement coverage.`;
|
|
214
|
+
const exchange = await resolveHeadlessInstrument(ctx, symbol).then(({ exchange }) => canonicalExchange(exchange ?? ""))
|
|
215
|
+
.catch(logFailure("ticker-detail.headless", "Resolving the listing of a statements report failed", ""));
|
|
216
|
+
const halfYearly = reportsHalfYearly(exchange, financials.quarterlyStatements);
|
|
217
|
+
if (hasRequestedStatements && !halfYearly) return null;
|
|
218
|
+
const tab = typeof statement === "string" && statement && statement !== "income" ? ` --statement ${statement}` : "";
|
|
219
|
+
const years = `For its years: gloom fn FA ${symbol} --period annual${tab}`;
|
|
220
|
+
return halfYearly ? `${symbol} reports half-yearly, not quarterly. ${years}` : `${symbol}: No quarterly financial statement coverage. ${years}`;
|
|
221
|
+
}
|
|
222
|
+
|
|
175
223
|
/** The note that an offering filed after the latest balance sheet is not in its cash yet; a failed read leaves it out. */
|
|
176
224
|
async function reportOfferingNote(
|
|
177
225
|
ctx: Parameters<typeof financialStatementsHeadless.load>[1],
|
|
@@ -240,16 +288,18 @@ async function loadRatioReport(
|
|
|
240
288
|
const runwayShown = liquidity && table.ratios.some((def) => def.format === "months"
|
|
241
289
|
&& table.cells.get(def.id)!.some((cell) => typeof cell.value === "number"));
|
|
242
290
|
const offering = liquidity ? await reportOfferingNote(ctx, symbol, financials) : null;
|
|
291
|
+
const periodDates = dates.map(({ date }) => date);
|
|
292
|
+
const missing = rows.length ? null : await missingPeriodsError(ctx, symbol, financials, period, hasRequestedStatements, tab.key);
|
|
243
293
|
return {
|
|
244
294
|
rows, columns, unavailableSymbols: rows.length ? [] : [symbol],
|
|
245
|
-
...(
|
|
295
|
+
...(missing ? { errors: [missing] } : {}),
|
|
246
296
|
...(tab.key === "valuation" && hasRequestedStatements && !history?.length ? { complete: false } : {}),
|
|
247
297
|
notes: [
|
|
248
298
|
...[stalePeriodNote(dates.map(({ periodEnd }) => ({ date: periodEnd, lead: true })))].filter((note): note is string => !!note),
|
|
249
299
|
...[filledPeriodsNote(table?.periods.map(({ statement }) => statement) ?? [])].filter((note): note is string => !!note),
|
|
250
300
|
...offering ? [offering] : [],
|
|
251
301
|
...runwayShown ? [runwayMethod(reportsShortTermTotal([...financials.quarterlyStatements, ...financials.annualStatements]))] : [],
|
|
252
|
-
...statementHistoryNotes(period,
|
|
302
|
+
...statementHistoryNotes(period, periodDates, symbol, await reportOlderStatements(ctx, symbol, period, periodDates)),
|
|
253
303
|
],
|
|
254
304
|
metadata: {
|
|
255
305
|
symbol, name: financials.quote?.name ?? symbol, currency: statementCurrency ?? null,
|
|
@@ -453,7 +503,9 @@ export const historicalPricesHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
|
453
503
|
const drawdown = maxDrawdown(shown);
|
|
454
504
|
const drawdownLine = drawdown ? maxDrawdownText(drawdown, { basis: `${historyBarSizeWord(size)} closes`, price: (value) => formatBarPrice(value, decimals),
|
|
455
505
|
date: (value) => isDailyOrLongerBar(size) ? value.slice(0, 10) : formatUtcTime(value) }) : null;
|
|
456
|
-
|
|
506
|
+
// A wick left out of the range is said, though the bar's close still counts.
|
|
507
|
+
const wickNotice = priceHistoryWickNotice(points.filter((point) => pricePointWickFlags(point).length > 0).length);
|
|
508
|
+
const reportNotices = [drawdownLine, notice, wickNotice].filter((line): line is string => line != null);
|
|
457
509
|
return {
|
|
458
510
|
rows: shown,
|
|
459
511
|
columns: historyColumns(size, marked, false, false, decimals),
|
|
@@ -545,7 +597,10 @@ export const returnsHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
|
545
597
|
...figures,
|
|
546
598
|
...forming || dayToDate ? [{ key: "partial", header: "Partial", format: (value: unknown) => value === true ? "true" : "" }] : [],
|
|
547
599
|
];
|
|
548
|
-
|
|
600
|
+
// A narrow table drops the dollar moves, the interval's first, rather than putting Total % on a line under every row.
|
|
601
|
+
const textFigures = figures.map((column) => column.key === "intervalChange" ? { ...column, optional: true, dropPriority: 2 }
|
|
602
|
+
: column.key === "totalChange" ? { ...column, optional: true, dropPriority: 1 } : column);
|
|
603
|
+
const textColumns: HeadlessPaneColumn[] = [timeColumn(true), ...textFigures];
|
|
549
604
|
// An interval the range is too long for is served in the nearest longer bar; say so rather than switch silently.
|
|
550
605
|
const notices = [
|
|
551
606
|
maxDrawdownLine,
|
|
@@ -568,8 +623,12 @@ export const returnsHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
|
568
623
|
oldest: null,
|
|
569
624
|
...(forming ? { periodToDate: forming } : closedDay ? { asOf: closedDay } : {}),
|
|
570
625
|
...(series.venue ? { cadenceExchange: series.venue } : {}),
|
|
571
|
-
// The window ends at the last session while the market is shut, which the status line says
|
|
572
|
-
|
|
626
|
+
// The window ends at the last session while the market is shut, which the status line says, and whether its
|
|
627
|
+
// last bar ends on the official close yet.
|
|
628
|
+
...(series.lastSession || series.closingPrintPending ? { note: [
|
|
629
|
+
series.lastSession ? closedMarketNote(series.lastSession, series.visibleTo) : null,
|
|
630
|
+
series.closingPrintPending ? CLOSING_PRINT_PENDING_TEXT : null,
|
|
631
|
+
].filter(Boolean).join(", ") } : {}),
|
|
573
632
|
...(dayToDate ? { basis: "daily bars", note: `the newest bar is ${DAY_SO_FAR_TEXT}` } : {}),
|
|
574
633
|
},
|
|
575
634
|
metadata: {
|
|
@@ -4,14 +4,9 @@ import { holdsActiveTicker } from "../../../shares/pane-image";
|
|
|
4
4
|
import { TICKER_RESEARCH_PANE_ID } from "../../../types/config";
|
|
5
5
|
import { normalizeTickerInput } from "../../../tickers/search";
|
|
6
6
|
import { createTickerSurfacePaneTemplate } from "../shared/ticker-surface";
|
|
7
|
-
import { FinancialAnalysisPane } from "./financials/pane";
|
|
8
|
-
import { HistoricalPricesPane } from "./data-panes/historical-prices";
|
|
9
|
-
import { ReturnsPane } from "./data-panes/returns-pane";
|
|
10
|
-
import { TickerResearchPane } from "./pane";
|
|
11
7
|
import { futuresContractCache } from "./overview/futures-contract";
|
|
12
8
|
import { offeringFilingsCache } from "./financials/offerings";
|
|
13
9
|
import { TICKER_RESEARCH_BUILTIN_TABS } from "./research-tabs";
|
|
14
|
-
import { QuoteMonitorPane } from "./quote-monitor";
|
|
15
10
|
import { financialStatementsHeadless, historicalPricesHeadless, quoteComparisonHeadless, returnsHeadless } from "./headless";
|
|
16
11
|
import {
|
|
17
12
|
buildQuoteMonitorSettingsDef,
|
|
@@ -47,7 +42,7 @@ export const tickerDetailModule: PluginModule = {
|
|
|
47
42
|
id: TICKER_RESEARCH_PANE_ID,
|
|
48
43
|
name: "Research",
|
|
49
44
|
icon: "D",
|
|
50
|
-
component: TickerResearchPane,
|
|
45
|
+
get component(): typeof import("./pane").TickerResearchPane { const { TickerResearchPane } = require("./pane"); return TickerResearchPane; },
|
|
51
46
|
defaultPosition: "right",
|
|
52
47
|
tickerFollower: true,
|
|
53
48
|
// DES and ADR open this pane; ADR's window is named by its params (the tab it asked for), so settings never say whose a window is.
|
|
@@ -70,7 +65,7 @@ export const tickerDetailModule: PluginModule = {
|
|
|
70
65
|
id: "financial-analysis",
|
|
71
66
|
name: "Financials",
|
|
72
67
|
icon: "F",
|
|
73
|
-
component: FinancialAnalysisPane,
|
|
68
|
+
get component(): typeof import("./financials/pane").FinancialAnalysisPane { const { FinancialAnalysisPane } = require("./financials/pane"); return FinancialAnalysisPane; },
|
|
74
69
|
headless: financialStatementsHeadless,
|
|
75
70
|
defaultPosition: "right",
|
|
76
71
|
tickerFollower: true,
|
|
@@ -82,7 +77,7 @@ export const tickerDetailModule: PluginModule = {
|
|
|
82
77
|
id: "quote-monitor",
|
|
83
78
|
name: "Quote Monitor",
|
|
84
79
|
icon: "Q",
|
|
85
|
-
component: QuoteMonitorPane,
|
|
80
|
+
get component(): typeof import("./quote-monitor").QuoteMonitorPane { const { QuoteMonitorPane } = require("./quote-monitor"); return QuoteMonitorPane; },
|
|
86
81
|
headless: quoteComparisonHeadless,
|
|
87
82
|
defaultPosition: "right",
|
|
88
83
|
defaultMode: "floating",
|
|
@@ -97,7 +92,7 @@ export const tickerDetailModule: PluginModule = {
|
|
|
97
92
|
id: "historical-prices",
|
|
98
93
|
name: "Historical Prices",
|
|
99
94
|
icon: "H",
|
|
100
|
-
component: HistoricalPricesPane,
|
|
95
|
+
get component(): typeof import("./data-panes/historical-prices").HistoricalPricesPane { const { HistoricalPricesPane } = require("./data-panes/historical-prices"); return HistoricalPricesPane; },
|
|
101
96
|
headless: historicalPricesHeadless,
|
|
102
97
|
defaultPosition: "right",
|
|
103
98
|
tickerFollower: true,
|
|
@@ -110,7 +105,7 @@ export const tickerDetailModule: PluginModule = {
|
|
|
110
105
|
reportFreshness: { status: "not-a-feed", basis: "price history" },
|
|
111
106
|
name: "Returns",
|
|
112
107
|
icon: "R",
|
|
113
|
-
component: ReturnsPane,
|
|
108
|
+
get component(): typeof import("./data-panes/returns-pane").ReturnsPane { const { ReturnsPane } = require("./data-panes/returns-pane"); return ReturnsPane; },
|
|
114
109
|
headless: returnsHeadless,
|
|
115
110
|
defaultPosition: "right",
|
|
116
111
|
tickerFollower: true,
|