@gloom-sh/terminal 0.18.5 → 0.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/package.json +1 -1
- package/patches/electrobun@1.18.1.patch +163 -8
- package/src/api-client/app-attention.ts +3 -0
- package/src/api-client/beneficial-owners.ts +3 -0
- package/src/api-client/company-kpis.ts +3 -0
- package/src/api-client/cot.ts +6 -2
- package/src/api-client/credit-documents.ts +6 -0
- package/src/api-client/data.ts +19 -7
- package/src/api-client/equity-screener.ts +24 -0
- package/src/api-client/fund-facts.ts +45 -4
- package/src/api-client/hiring.ts +3 -0
- package/src/api-client/index.ts +15 -0
- package/src/api-client/ipo.ts +24 -1
- package/src/api-client/market-discovery.ts +10 -0
- package/src/api-client/market-movers.ts +7 -0
- package/src/api-client/members.ts +1 -1
- package/src/api-client/mna.ts +3 -0
- package/src/api-client/paths.ts +9 -1
- package/src/api-client/perps.ts +43 -0
- package/src/api-client/research-activity.ts +3 -2
- package/src/api-client/roadmap.ts +85 -0
- package/src/api-client/types.ts +82 -2
- package/src/app/pane-runtime/plugin-bindings.ts +9 -5
- package/src/app/runtime/broker-import.ts +0 -2
- package/src/app/runtime/plugin-bindings.ts +73 -56
- package/src/architecture/core-builtin-allowlist.json +2 -2
- package/src/architecture/pane-tabs-allowlist.json +3 -0
- package/src/architecture/ttl-caches-allowlist.json +19 -0
- package/src/brokers/sync-broker-instance.ts +2 -8
- package/src/capabilities/chart-series.ts +1 -1
- package/src/cli/commands/crypto-hints.ts +40 -24
- package/src/cli/commands/market.ts +107 -38
- package/src/cli/commands/news-search.ts +22 -0
- package/src/cli/commands/options-chain.ts +48 -7
- package/src/cli/commands/options-leaps.ts +9 -3
- package/src/cli/commands/overview.ts +147 -32
- package/src/cli/commands/search.ts +21 -1
- package/src/cli/commands/themes.ts +11 -2
- package/src/cli/commands/ticker.ts +87 -36
- package/src/cli/company-name-hint.ts +41 -0
- package/src/cli/earnings-calendar.ts +1 -1
- package/src/cli/errors.ts +25 -2
- package/src/cli/glossary.ts +31 -2
- package/src/cli/history-rows.ts +57 -9
- package/src/cli/index-roots.ts +0 -7
- package/src/cli/index.ts +2 -0
- package/src/cli/listing-arg.ts +235 -60
- package/src/cli/output-file.ts +68 -0
- package/src/cli/pane-functions/capabilities.ts +4 -0
- package/src/cli/pane-functions/catalog.ts +80 -7
- package/src/cli/pane-functions/discovery.ts +21 -1
- package/src/cli/pane-functions/dom.ts +13 -3
- package/src/cli/pane-functions/freshness.ts +93 -4
- package/src/cli/pane-functions/function-help.ts +20 -10
- package/src/cli/pane-functions/headless.ts +17 -7
- package/src/cli/pane-functions/index.ts +54 -16
- package/src/cli/pane-functions/market-session.ts +66 -4
- package/src/cli/pane-functions/options.ts +19 -1
- package/src/cli/pane-functions/resolver.ts +19 -8
- package/src/cli/pane-functions/screenshot-assessment.ts +6 -4
- package/src/cli/pane-functions/screenshot-types.ts +5 -0
- package/src/cli/quote-answer.ts +22 -11
- package/src/cli/saved-copy-persistence.ts +88 -0
- package/src/cli/ticker-resolution.ts +3 -2
- package/src/components/chart/composite/composite-chart.tsx +4 -0
- package/src/components/chart/composite/interactions.ts +6 -0
- package/src/components/chart/composite/legend.tsx +45 -7
- package/src/components/chart/composite/panel-gestures.ts +33 -0
- package/src/components/chart/composite/panel-surface.tsx +52 -3
- package/src/components/chart/composite/rasterizer.ts +24 -13
- package/src/components/chart/composite/scene.ts +39 -4
- package/src/components/chart/composite/series-cues.ts +14 -0
- package/src/components/chart/composite/text-renderer.ts +9 -2
- package/src/components/chart/composite/tool-catalog.ts +36 -0
- package/src/components/chart/composite/tools.ts +203 -44
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +11 -4
- package/src/components/command-bar/assist/inventory.ts +2 -1
- package/src/components/command-bar/commands/direct/index.ts +28 -13
- package/src/components/command-bar/list/model.ts +5 -0
- package/src/components/command-bar/pane-templates/items.ts +3 -2
- package/src/components/command-bar/routes/root/runtime.ts +6 -7
- package/src/components/command-bar/selection-runtime.ts +52 -3
- package/src/components/command-bar/surface/index.tsx +2 -0
- package/src/components/command-bar/workflow/collection-actions.ts +3 -3
- package/src/components/layout/pane/capture-stamp.ts +2 -2
- package/src/components/layout/pane/footer/index.tsx +22 -6
- package/src/components/layout/pane/footer/model.ts +83 -15
- package/src/components/layout/pane/status-footer.ts +35 -2
- package/src/components/layout/status-widget-space.ts +9 -0
- package/src/components/onboarding/onboarding-wizard.tsx +4 -1
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +12 -7
- package/src/components/onboarding/wizard-broker-sync.ts +0 -1
- package/src/components/onboarding/wizard-positions.ts +3 -3
- package/src/components/ticker/list-table-view.tsx +8 -21
- package/src/components/ui/choice-dialog.tsx +23 -18
- package/src/components/ui/choice-groups.ts +18 -0
- package/src/components/ui/data-table/opentui/index.tsx +9 -7
- package/src/components/ui/data-table/opentui/model.ts +26 -1
- package/src/components/ui/data-table/types.ts +2 -0
- package/src/components/ui/display.tsx +18 -3
- package/src/components/ui/icon.tsx +4 -1
- package/src/components/ui/list-view.tsx +8 -4
- package/src/components/ui/query-bar-keys.tsx +2 -0
- package/src/components/ui/query-bar.tsx +1 -0
- package/src/components/ui/select-button.tsx +5 -1
- package/src/components/ui/select-field.tsx +1 -0
- package/src/components/ui/table-layout.ts +8 -5
- package/src/core/app-runtime.ts +2 -0
- package/src/core/app-services.ts +2 -2
- package/src/data/config/chart-settings.ts +1 -1
- package/src/data/json-ticker-repository.ts +17 -8
- package/src/data/plugin-cache.ts +5 -3
- package/src/data/saved-copies.ts +8 -0
- package/src/data/ticker-repository.ts +16 -9
- package/src/data/ticker-writes.ts +81 -0
- package/src/data/ttl-cache.ts +165 -0
- package/src/docs/snapshot.json +103 -142
- package/src/i18n/es.ts +20 -6
- package/src/i18n/ja.ts +20 -6
- package/src/i18n/ko.ts +20 -6
- package/src/i18n/zh-cn.ts +20 -6
- package/src/i18n/zh-tw.ts +20 -6
- package/src/market-data/depositary-pair.ts +27 -3
- package/src/market-data/fund-facts.ts +50 -0
- package/src/market-data/market/change-basis.ts +16 -3
- package/src/market-data/market/format.ts +25 -0
- package/src/market-data/market/freshness.ts +2 -1
- package/src/market-data/options-alternatives.ts +81 -4
- package/src/market-data/quotes/metadata.ts +7 -0
- package/src/news/aggregator.ts +119 -9
- package/src/news/cloud-session.ts +21 -0
- package/src/news/hooks.ts +1 -0
- package/src/news/news-model.ts +1 -0
- package/src/news/types.ts +17 -0
- package/src/plugins/builtin/alerts/alert-engine.ts +20 -1
- package/src/plugins/builtin/alerts/alert-log.ts +33 -0
- package/src/plugins/builtin/alerts/calendar-events.ts +10 -4
- package/src/plugins/builtin/alerts/cli-forms.ts +216 -0
- package/src/plugins/builtin/alerts/cli.ts +362 -80
- package/src/plugins/builtin/alerts/command.ts +25 -1
- package/src/plugins/builtin/alerts/event-rows.ts +24 -3
- package/src/plugins/builtin/alerts/events-pane.tsx +34 -10
- package/src/plugins/builtin/alerts/fired-log.ts +73 -9
- package/src/plugins/builtin/alerts/format.ts +75 -5
- package/src/plugins/builtin/alerts/headless.ts +34 -12
- package/src/plugins/builtin/alerts/history-rows.ts +3 -2
- package/src/plugins/builtin/alerts/history.ts +1 -1
- package/src/plugins/builtin/alerts/index.tsx +79 -16
- package/src/plugins/builtin/alerts/metric-command.ts +77 -4
- package/src/plugins/builtin/alerts/metric-data.ts +54 -13
- package/src/plugins/builtin/alerts/metric-model.ts +163 -14
- package/src/plugins/builtin/alerts/metric-parity-fixture.json +1 -1
- package/src/plugins/builtin/alerts/pane.tsx +61 -23
- package/src/plugins/builtin/alerts/quotes.ts +6 -0
- package/src/plugins/builtin/alerts/storage.ts +12 -8
- package/src/plugins/builtin/alerts/types.ts +4 -0
- package/src/plugins/builtin/analytics/index.tsx +2 -1
- package/src/plugins/builtin/analytics/risk-client.ts +16 -5
- package/src/plugins/builtin/analytics/risk-fx.ts +70 -15
- package/src/plugins/builtin/analytics/risk-headless.ts +27 -0
- package/src/plugins/builtin/analytics/risk-model.ts +55 -9
- package/src/plugins/builtin/analytics/risk-pane.tsx +8 -2
- package/src/plugins/builtin/attention/index.tsx +2 -1
- package/src/plugins/builtin/attention/listing.ts +14 -0
- package/src/plugins/builtin/broker-manager/index.tsx +7 -3
- package/src/plugins/builtin/buildout/cells.tsx +12 -4
- package/src/plugins/builtin/buildout/format.ts +38 -0
- package/src/plugins/builtin/buildout/model/normalizers.ts +36 -1
- package/src/plugins/builtin/buildout/pane/index.tsx +4 -1
- package/src/plugins/builtin/buildout/table-model.ts +23 -2
- package/src/plugins/builtin/builtin-plugin-meta.ts +6 -2
- package/src/plugins/builtin/cds/client.ts +142 -30
- package/src/plugins/builtin/cds/headless.ts +35 -8
- package/src/plugins/builtin/cds/model.ts +145 -18
- package/src/plugins/builtin/cds/pane.tsx +16 -5
- package/src/plugins/builtin/changelog/index.tsx +9 -6
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +3 -0
- package/src/plugins/builtin/chart-composer/cli-options.ts +4 -0
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +7 -0
- package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -2
- package/src/plugins/builtin/chart-composer/follow-binding.ts +14 -2
- package/src/plugins/builtin/chart-composer/headless-schema.ts +7 -1
- package/src/plugins/builtin/chart-composer/headless.ts +6 -1
- package/src/plugins/builtin/chart-composer/index.tsx +5 -6
- package/src/plugins/builtin/chart-composer/pane.tsx +37 -8
- package/src/plugins/builtin/chart-composer/settings.ts +27 -0
- package/src/plugins/builtin/chat/content/command-suggestions.ts +1 -0
- package/src/plugins/builtin/chat/controller/index.ts +5 -1
- package/src/plugins/builtin/chat/controller/notifications.ts +33 -3
- package/src/plugins/builtin/chat/controller/state.ts +25 -2
- package/src/plugins/builtin/chat/controller/unread-people.ts +89 -23
- package/src/plugins/builtin/chat/controller/utils.ts +7 -2
- package/src/plugins/builtin/chat/pane-links/commands.ts +7 -1
- package/src/plugins/builtin/chat/status-preview.ts +79 -0
- package/src/plugins/builtin/chat/status-widget.tsx +147 -10
- package/src/plugins/builtin/chat/unread-badge.ts +51 -10
- package/src/plugins/builtin/clinical-trials/client.ts +49 -4
- package/src/plugins/builtin/clinical-trials/model.ts +86 -31
- package/src/plugins/builtin/clinical-trials/pane.tsx +61 -49
- package/src/plugins/builtin/clinical-trials/sponsor-listing.ts +90 -0
- package/src/plugins/builtin/clinical-trials/sponsor-tickers.ts +95 -15
- package/src/plugins/builtin/clinical-trials/trial-pages.ts +50 -0
- package/src/plugins/builtin/cloud/askg/manifest.ts +2 -0
- package/src/plugins/builtin/company-attention/building.tsx +5 -1
- package/src/plugins/builtin/company-attention/client.ts +8 -9
- package/src/plugins/builtin/company-attention/evidence.ts +4 -1
- package/src/plugins/builtin/company-attention/headless.ts +2 -1
- package/src/plugins/builtin/company-attention/moves.tsx +5 -1
- package/src/plugins/builtin/company-attention/pane.tsx +12 -2
- package/src/plugins/builtin/company-attention/signals.tsx +5 -1
- package/src/plugins/builtin/company-kpis/headless.ts +8 -3
- package/src/plugins/builtin/company-kpis/model.ts +73 -5
- package/src/plugins/builtin/company-kpis/pane.tsx +15 -7
- package/src/plugins/builtin/composite-plugins.ts +2 -1
- package/src/plugins/builtin/correlation/headless.ts +13 -5
- package/src/plugins/builtin/correlation/history.ts +22 -0
- package/src/plugins/builtin/cot/client.ts +22 -18
- package/src/plugins/builtin/cot/headless.ts +15 -10
- package/src/plugins/builtin/cot/model.ts +14 -1
- package/src/plugins/builtin/cot/pane.tsx +22 -14
- package/src/plugins/builtin/credit-boards/client.ts +6 -10
- package/src/plugins/builtin/credit-conditions/headless.ts +8 -2
- package/src/plugins/builtin/credit-conditions/index.tsx +5 -1
- package/src/plugins/builtin/credit-conditions/model.ts +4 -0
- package/src/plugins/builtin/credit-conditions/series.ts +3 -1
- package/src/plugins/builtin/credit-documents/detail.tsx +2 -2
- package/src/plugins/builtin/credit-documents/export.ts +173 -0
- package/src/plugins/builtin/credit-documents/headless.ts +10 -10
- package/src/plugins/builtin/credit-documents/model.ts +104 -14
- package/src/plugins/builtin/credit-documents/pane.tsx +12 -5
- package/src/plugins/builtin/custom-view/sources.ts +2 -0
- package/src/plugins/builtin/dividend-yield/client.ts +131 -23
- package/src/plugins/builtin/dividend-yield/headless.ts +44 -16
- package/src/plugins/builtin/dividend-yield/model.ts +8 -5
- package/src/plugins/builtin/dividend-yield/pane.tsx +38 -13
- package/src/plugins/builtin/dividend-yield/ranking.ts +37 -14
- package/src/plugins/builtin/dividend-yield/types.ts +20 -2
- package/src/plugins/builtin/dividend-yield/view.ts +30 -2
- package/src/plugins/builtin/docs/targets.ts +5 -1
- package/src/plugins/builtin/doe/headless.ts +3 -2
- package/src/plugins/builtin/doe/pane.tsx +13 -3
- package/src/plugins/builtin/earnings/board-model.ts +16 -15
- package/src/plugins/builtin/earnings/board.tsx +62 -71
- package/src/plugins/builtin/earnings/headless.ts +40 -4
- package/src/plugins/builtin/earnings/scope.ts +31 -43
- package/src/plugins/builtin/earnings-calls/calendar.tsx +2 -2
- package/src/plugins/builtin/earnings-calls/data.ts +18 -6
- package/src/plugins/builtin/earnings-calls/format.ts +31 -2
- package/src/plugins/builtin/earnings-calls/headless.ts +20 -5
- package/src/plugins/builtin/earnings-calls/model.ts +6 -1
- package/src/plugins/builtin/earnings-calls/pane.tsx +12 -4
- package/src/plugins/builtin/econ/calendar-model.ts +48 -1
- package/src/plugins/builtin/econ/calendar-source.ts +4 -2
- package/src/plugins/builtin/econ/detail-view.tsx +2 -2
- package/src/plugins/builtin/econ/figures.ts +48 -0
- package/src/plugins/builtin/econ/index.tsx +14 -5
- package/src/plugins/builtin/econ/print-watch.ts +3 -1
- package/src/plugins/builtin/econ/types.ts +2 -0
- package/src/plugins/builtin/econ-statistics/client.ts +11 -0
- package/src/plugins/builtin/econ-statistics/defs.ts +6 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +16 -6
- package/src/plugins/builtin/econ-statistics/pane.tsx +8 -4
- package/src/plugins/builtin/econ-statistics/stats.ts +39 -9
- package/src/plugins/builtin/equity-screener/categories.ts +179 -0
- package/src/plugins/builtin/equity-screener/client.ts +4 -2
- package/src/plugins/builtin/equity-screener/headless.ts +144 -13
- package/src/plugins/builtin/equity-screener/ideas.ts +49 -0
- package/src/plugins/builtin/equity-screener/model.ts +99 -10
- package/src/plugins/builtin/equity-screener/pane.tsx +68 -13
- package/src/plugins/builtin/fixed-income/pane.tsx +2 -1
- package/src/plugins/builtin/futures/use-board-terms.ts +42 -28
- package/src/plugins/builtin/futures/use-front-returns.ts +45 -28
- package/src/plugins/builtin/fx-matrix/client.ts +6 -3
- package/src/plugins/builtin/fx-matrix/headless.ts +1 -1
- package/src/plugins/builtin/fx-matrix/index.tsx +4 -2
- package/src/plugins/builtin/fx-matrix/live-legs.ts +42 -3
- package/src/plugins/builtin/gpu/headless.ts +8 -2
- package/src/plugins/builtin/help/function-index.ts +4 -1
- package/src/plugins/builtin/help/index.tsx +62 -59
- package/src/plugins/builtin/help/shortcut-model.ts +1 -1
- package/src/plugins/builtin/help/shortcut-table.tsx +5 -6
- package/src/plugins/builtin/help/table-cells.tsx +13 -2
- package/src/plugins/builtin/holders/beneficial-client.ts +5 -1
- package/src/plugins/builtin/holders/beneficial-view.tsx +3 -0
- package/src/plugins/builtin/holders/fund-holders.ts +51 -0
- package/src/plugins/builtin/holders/headless.ts +22 -3
- package/src/plugins/builtin/holders/pane.tsx +3 -0
- package/src/plugins/builtin/holders/report-rows.ts +4 -1
- package/src/plugins/builtin/insider/headless.ts +2 -2
- package/src/plugins/builtin/ipo-calendar/client.ts +18 -2
- package/src/plugins/builtin/ipo-calendar/headless.ts +75 -11
- package/src/plugins/builtin/ipo-calendar/listing-ipo.ts +160 -0
- package/src/plugins/builtin/ipo-calendar/model.ts +98 -2
- package/src/plugins/builtin/iv-history/client.ts +52 -11
- package/src/plugins/builtin/iv-history/format.ts +36 -23
- package/src/plugins/builtin/iv-history/headless.ts +33 -18
- package/src/plugins/builtin/iv-history/index.tsx +2 -2
- package/src/plugins/builtin/iv-history/model.ts +163 -27
- package/src/plugins/builtin/iv-history/pane.tsx +10 -6
- package/src/plugins/builtin/iv-history/screen-pane.tsx +22 -15
- package/src/plugins/builtin/iv-history/universe.ts +5 -1
- package/src/plugins/builtin/jobs/client.ts +25 -29
- package/src/plugins/builtin/kelly-sizer/model.ts +12 -8
- package/src/plugins/builtin/kelly-sizer/pane.tsx +9 -9
- package/src/plugins/builtin/kelly-sizer/sections.tsx +19 -10
- package/src/plugins/builtin/kelly-sizer/types.ts +10 -4
- package/src/plugins/builtin/macro-day/headless.ts +12 -5
- package/src/plugins/builtin/macro-day/index.tsx +1 -1
- package/src/plugins/builtin/macro-day/model.ts +39 -5
- package/src/plugins/builtin/macro-day/pane.tsx +27 -19
- package/src/plugins/builtin/macro-day/release-table.ts +2 -2
- package/src/plugins/builtin/market-heatmap/data.ts +8 -33
- package/src/plugins/builtin/market-movers/client.ts +27 -7
- package/src/plugins/builtin/market-movers/headless.ts +34 -12
- package/src/plugins/builtin/market-movers/index.tsx +26 -14
- package/src/plugins/builtin/market-movers/min-float.ts +74 -0
- package/src/plugins/builtin/market-movers/model.ts +4 -1
- package/src/plugins/builtin/market-movers/screener.ts +22 -4
- package/src/plugins/builtin/market-movers/session-body.tsx +13 -8
- package/src/plugins/builtin/market-movers/session-table.ts +4 -3
- package/src/plugins/builtin/market-movers/table.ts +17 -5
- package/src/plugins/builtin/members/breadth-pane.tsx +2 -1
- package/src/plugins/builtin/mna/headless.ts +2 -0
- package/src/plugins/builtin/mna/pane.tsx +3 -1
- package/src/plugins/builtin/news/headless.ts +3 -1
- package/src/plugins/builtin/news/index.tsx +4 -0
- package/src/plugins/builtin/news/wire/categories.ts +19 -3
- package/src/plugins/builtin/news/wire/industry-pane.tsx +1 -0
- package/src/plugins/builtin/news/wire/news/footer.ts +31 -5
- package/src/plugins/builtin/news/wire/news/preset-pane.tsx +6 -1
- package/src/plugins/builtin/news/wire/news/table.tsx +2 -2
- package/src/plugins/builtin/openfda/client.ts +14 -2
- package/src/plugins/builtin/openfda/index.tsx +3 -2
- package/src/plugins/builtin/openfda/model.ts +9 -0
- package/src/plugins/builtin/openfda/pane.tsx +42 -6
- package/src/plugins/builtin/options/analytics.ts +29 -5
- package/src/plugins/builtin/options/enrichment.ts +17 -5
- package/src/plugins/builtin/options/table.ts +5 -2
- package/src/plugins/builtin/options/types.ts +2 -0
- package/src/plugins/builtin/options/view.tsx +17 -4
- package/src/plugins/builtin/options-positioning/client.ts +11 -0
- package/src/plugins/builtin/options-positioning/headless.ts +21 -8
- package/src/plugins/builtin/options-positioning/index.tsx +1 -1
- package/src/plugins/builtin/options-positioning/model.ts +78 -9
- package/src/plugins/builtin/options-positioning/pane.tsx +21 -6
- package/src/plugins/builtin/options-scenario/client.ts +116 -47
- package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +142 -10
- package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +206 -55
- package/src/plugins/builtin/options-scenario/csp-screen.ts +63 -23
- package/src/plugins/builtin/options-scenario/csp.ts +8 -2
- package/src/plugins/builtin/options-scenario/index.tsx +9 -7
- package/src/plugins/builtin/options-scenario/strategy-screen.ts +532 -0
- package/src/plugins/builtin/pe-band/model.ts +12 -49
- package/src/plugins/builtin/perps/cascade-tabs.tsx +161 -0
- package/src/plugins/builtin/perps/cascade.ts +236 -0
- package/src/plugins/builtin/perps/client.ts +56 -2
- package/src/plugins/builtin/perps/headless.ts +65 -9
- package/src/plugins/builtin/perps/index.tsx +7 -5
- package/src/plugins/builtin/perps/model.ts +18 -4
- package/src/plugins/builtin/perps/pane.tsx +19 -22
- package/src/plugins/builtin/perps/status-line.ts +25 -0
- package/src/plugins/builtin/plugin-module.ts +5 -1
- package/src/plugins/builtin/portfolio-list/cached-account.ts +3 -1
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +2 -8
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +4 -4
- package/src/plugins/builtin/portfolio-list/cli/render.ts +7 -5
- package/src/plugins/builtin/portfolio-list/pane/futures-front.ts +40 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +6 -7
- package/src/plugins/builtin/portfolio-list/pane/streaming.ts +5 -2
- package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +3 -2
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +0 -14
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +5 -2
- package/src/plugins/builtin/portfolio-list/table.tsx +15 -9
- package/src/plugins/builtin/primary-dealers/client.ts +13 -38
- package/src/plugins/builtin/realized-vol/client.ts +13 -5
- package/src/plugins/builtin/realized-vol/evidence.ts +29 -4
- package/src/plugins/builtin/realized-vol/headless.ts +8 -4
- package/src/plugins/builtin/realized-vol/index.tsx +2 -2
- package/src/plugins/builtin/realized-vol/model.ts +37 -6
- package/src/plugins/builtin/realized-vol/pane.tsx +11 -9
- package/src/plugins/builtin/relative-rotation/client.ts +18 -4
- package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
- package/src/plugins/builtin/relative-rotation/index.tsx +2 -1
- package/src/plugins/builtin/relative-rotation/model.ts +16 -40
- package/src/plugins/builtin/relative-rotation/pane.tsx +3 -2
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +3 -2
- package/src/plugins/builtin/research/event-model.ts +40 -12
- package/src/plugins/builtin/research/headless.ts +1 -1
- package/src/plugins/builtin/research/index.tsx +7 -3
- package/src/plugins/builtin/research/relative-valuation-headless.ts +13 -26
- package/src/plugins/builtin/research/relative-valuation-model.ts +31 -3
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +59 -20
- package/src/plugins/builtin/research/relative-valuation-peers.ts +217 -20
- package/src/plugins/builtin/research/relative-valuation-settings.ts +44 -0
- package/src/plugins/builtin/reverse-dcf/headless.ts +5 -3
- package/src/plugins/builtin/reverse-dcf/model.ts +61 -6
- package/src/plugins/builtin/reverse-dcf/pane.tsx +7 -4
- package/src/plugins/builtin/risk-factors/data.ts +4 -2
- package/src/plugins/builtin/risk-factors/headless.ts +5 -2
- package/src/plugins/builtin/roadmap/index.tsx +28 -0
- package/src/plugins/builtin/roadmap/model.ts +67 -0
- package/src/plugins/builtin/roadmap/pane.tsx +244 -0
- package/src/plugins/builtin/scanner/flow-model.ts +50 -4
- package/src/plugins/builtin/scanner/flow-pane.tsx +367 -65
- package/src/plugins/builtin/scanner/flow-session.ts +146 -0
- package/src/plugins/builtin/scanner/headless.ts +204 -35
- package/src/plugins/builtin/scanner/index.ts +16 -5
- package/src/plugins/builtin/scanner/live-headless.ts +48 -5
- package/src/plugins/builtin/scanner/live-model.ts +11 -0
- package/src/plugins/builtin/scanner/live-pane.tsx +3 -3
- package/src/plugins/builtin/scanner/lock-note.ts +3 -2
- package/src/plugins/builtin/seasonality/headless.ts +10 -1
- package/src/plugins/builtin/sec/fund-facts-view.tsx +5 -2
- package/src/plugins/builtin/sec/fund-facts.ts +116 -34
- package/src/plugins/builtin/sec/headless.ts +4 -2
- package/src/plugins/builtin/sec/index.tsx +3 -0
- package/src/plugins/builtin/series-inventory.ts +2 -0
- package/src/plugins/builtin/shared/cloud-resource.ts +16 -7
- package/src/plugins/builtin/shared/cloud-upgrade.ts +4 -3
- package/src/plugins/builtin/shared/earnings-calendar.ts +6 -2
- package/src/plugins/builtin/shared/earnings-report.ts +2 -2
- package/src/plugins/builtin/shared/headless-market-data.ts +2 -2
- package/src/plugins/builtin/shared/job-posting.ts +1 -0
- package/src/plugins/builtin/shared/members-menu.tsx +3 -2
- package/src/plugins/builtin/shared/pro-lock-note.ts +12 -12
- package/src/plugins/builtin/shared/report-freshness.ts +11 -2
- package/src/plugins/builtin/shared/research-cells.tsx +1 -1
- package/src/plugins/builtin/shared/series-cache.ts +4 -4
- package/src/plugins/builtin/shared/ticker-choice.tsx +2 -1
- package/src/plugins/builtin/shared/ticker-company.ts +77 -0
- package/src/plugins/builtin/shared/use-quote-board.ts +2 -1
- package/src/plugins/builtin/shared/volatility/live-session.ts +34 -8
- package/src/plugins/builtin/shared/volatility/pricing.ts +19 -0
- package/src/plugins/builtin/shared/wall-view-lifecycle.ts +3 -1
- package/src/plugins/builtin/themes/model.ts +16 -7
- package/src/plugins/builtin/themes/pane.tsx +5 -5
- package/src/plugins/builtin/thirteenf/api.ts +12 -1
- package/src/plugins/builtin/thirteenf/data.ts +7 -7
- package/src/plugins/builtin/thirteenf/headless.ts +31 -4
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +43 -18
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +3 -2
- package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +62 -0
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +83 -46
- package/src/plugins/builtin/ticker-detail/headless.ts +31 -16
- package/src/plugins/builtin/ticker-detail/overview/model.ts +11 -3
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +2 -1
- package/src/plugins/builtin/ticker-detail/pane.tsx +14 -8
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -1
- package/src/plugins/builtin/ticker-detail/settings.ts +1 -0
- package/src/plugins/builtin/time-sales/pane.tsx +31 -19
- package/src/plugins/builtin/treasury-auctions/headless.ts +21 -12
- package/src/plugins/builtin/treasury-auctions/pane.tsx +9 -3
- package/src/plugins/builtin/treasury-daily/client.ts +41 -5
- package/src/plugins/builtin/treasury-daily/headless.ts +2 -2
- package/src/plugins/builtin/treasury-daily/index.tsx +1 -1
- package/src/plugins/builtin/treasury-daily/model.ts +50 -3
- package/src/plugins/builtin/treasury-daily/pane.tsx +81 -2
- package/src/plugins/builtin/vol-surface/client.ts +3 -13
- package/src/plugins/builtin/vol-surface/headless.ts +3 -3
- package/src/plugins/builtin/vol-surface/index.tsx +1 -1
- package/src/plugins/builtin/vol-surface/pane.tsx +7 -5
- package/src/plugins/builtin/volatility/index.tsx +2 -2
- package/src/plugins/builtin/volatility/pane.tsx +7 -4
- package/src/plugins/builtin/world-venue-map/headless.ts +3 -3
- package/src/plugins/builtin/yield-curve/client.ts +61 -1
- package/src/plugins/builtin/yield-curve/headless.ts +9 -6
- package/src/plugins/builtin/yield-curve/index.tsx +34 -10
- package/src/plugins/builtin/yield-curve/swaps.tsx +9 -5
- package/src/plugins/catalog-browser.ts +2 -1
- package/src/plugins/catalog-manifest.ts +2 -1
- package/src/plugins/host-link.ts +1 -1
- package/src/plugins/marketplace/model.ts +18 -5
- package/src/portfolio/column-values.ts +11 -7
- package/src/portfolio/futures-positions.ts +6 -3
- package/src/portfolio/position-quantity.ts +15 -9
- package/src/remote/resources.ts +2 -1
- package/src/renderers/dom/data-table/row.tsx +26 -0
- package/src/renderers/dom/desktop/icons.tsx +7 -0
- package/src/renderers/dom/desktop/list-view.tsx +13 -10
- package/src/renderers/dom/desktop/query-bar.tsx +4 -2
- package/src/renderers/dom/desktop/select-field.tsx +4 -2
- package/src/renderers/dom/host/chart-surface.tsx +21 -0
- package/src/renderers/electrobun/bun/desktop/app-name.ts +3 -3
- package/src/renderers/electrobun/bun/desktop/backend.ts +21 -10
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +15 -0
- package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -0
- package/src/renderers/electrobun/bun/desktop/installer-folder.ts +731 -0
- package/src/renderers/electrobun/bun/desktop/relaunch.ts +102 -10
- package/src/renderers/electrobun/bun/desktop/update.ts +115 -14
- package/src/renderers/electrobun/bun/desktop/view-ids.ts +52 -0
- package/src/renderers/electrobun/bun/desktop/windows-script.ts +92 -0
- package/src/renderers/electrobun/bun/index.ts +26 -2
- package/src/renderers/electrobun/bun/window/create.ts +43 -4
- package/src/renderers/electrobun/bun/window/events.ts +20 -0
- package/src/renderers/electrobun/bun/window/windows-custom-chrome.ts +9 -2
- package/src/renderers/electrobun/bun/window/windows-native.ts +78 -0
- package/src/renderers/electrobun/bun/window/windows-quit.ts +57 -0
- package/src/renderers/electrobun/shared/app-name.ts +13 -0
- package/src/renderers/electrobun/shared/protocol.ts +12 -0
- package/src/renderers/electrobun/view/backend-rpc.ts +6 -0
- package/src/renderers/electrobun/view/main.tsx +24 -1
- package/src/renderers/electrobun/view/news-source.ts +5 -1
- package/src/renderers/electrobun/view/remote/ticker-repository.ts +14 -7
- package/src/renderers/electrobun/view/ui-host.tsx +8 -0
- package/src/renderers/electrobun/view/view-ids.ts +85 -0
- package/src/renderers/opentui/start.tsx +5 -0
- package/src/series/registry.ts +1 -0
- package/src/series/types.ts +6 -0
- package/src/series/validate.ts +1 -0
- package/src/sources/gloomberb-cloud/fred-series.ts +3 -1
- package/src/sources/gloomberb-cloud/index.ts +43 -8
- package/src/sources/gloomberb-cloud/news.ts +47 -7
- package/src/sources/provider-router/financials.ts +15 -3
- package/src/sources/provider-router/index.ts +8 -5
- package/src/state/ticker-cleanup.ts +50 -0
- package/src/sync/controller.ts +4 -3
- package/src/sync/core-contributors.ts +90 -31
- package/src/telemetry/stall-reports-dom.ts +38 -0
- package/src/telemetry/stall-reports-node.ts +75 -0
- package/src/telemetry/stall-reports.ts +214 -0
- package/src/test-support/preload.ts +14 -0
- package/src/theme/themes.ts +10 -0
- package/src/tickers/company-name-listing.ts +53 -13
- package/src/tickers/company-name.ts +50 -4
- package/src/tickers/index-roots.ts +7 -0
- package/src/tickers/listing-fate.ts +2 -2
- package/src/tickers/listing-venues.ts +15 -3
- package/src/tickers/search/index.ts +6 -2
- package/src/tickers/search/ranking.ts +5 -1
- package/src/tickers/search/upsert.ts +13 -0
- package/src/tickers/terminal-codes.ts +19 -0
- package/src/tickers/ticker-changes.ts +8 -4
- package/src/time-series/alignment.ts +1 -1
- package/src/time-series/economic.ts +18 -4
- package/src/time-series/field-catalog.ts +1 -1
- package/src/time-series/filed-trailing-eps.ts +197 -0
- package/src/time-series/fundamentals.ts +44 -1
- package/src/time-series/ice-credit.ts +3 -0
- package/src/time-series/price-comparison.ts +30 -2
- package/src/time-series/resolve-context.ts +3 -1
- package/src/time-series/resolve.ts +56 -4
- package/src/time-series/session-bar.ts +11 -0
- package/src/time-series/spec.ts +3 -2
- package/src/time-series/studies.ts +8 -2
- package/src/time-series/total-return.ts +160 -0
- package/src/time-series/transforms.ts +2 -3
- package/src/time-series/types.ts +22 -1
- package/src/types/company-from.ts +40 -0
- package/src/types/data-provider.ts +7 -0
- package/src/types/financials.ts +59 -1
- package/src/types/headless.ts +27 -3
- package/src/types/news-source.ts +1 -0
- package/src/types/plugin.ts +9 -0
- package/src/ui/host.tsx +3 -0
- package/src/updater/failure.ts +4 -1
- package/src/utils/cli-output.ts +42 -1
- package/src/utils/crypto-pair.ts +165 -7
- package/src/utils/declared-dividends.ts +1 -1
- package/src/utils/forward-dividend.ts +2 -0
- package/src/utils/fundamentals.ts +60 -8
- package/src/utils/fx-market-hours.ts +26 -3
- package/src/utils/main-thread-stall.ts +35 -2
- package/src/utils/market-capitalization.ts +24 -1
- package/src/utils/price-history.ts +7 -1
- package/src/utils/shell-word.ts +8 -0
- package/src/utils/trailing-dividend.ts +53 -4
- package/src/version.ts +2 -2
- package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +0 -17
|
@@ -42,7 +42,7 @@ import { appTtmRate, enterpriseValueReconciliationNote, ttmAtAppRate, ttmConvers
|
|
|
42
42
|
import { atRegularSessionPrice } from "../../../market-data/quotes/regular-session-valuation";
|
|
43
43
|
import { zonedDateKey } from "../../../utils/zoned-date-time";
|
|
44
44
|
import { sharesOutstandingInReceipts } from "../../../utils/depositary-receipt";
|
|
45
|
-
import { isReceiptSide, listingDepositaryPair } from "../../../market-data/depositary-pair";
|
|
45
|
+
import { isReceiptSide, listingCedearRatio, listingDepositaryPair } from "../../../market-data/depositary-pair";
|
|
46
46
|
import {
|
|
47
47
|
CompactRangeBar,
|
|
48
48
|
FundamentalsGrid,
|
|
@@ -335,6 +335,7 @@ function ResolvedOverviewTab({ width, height, focused = false, ticker, financial
|
|
|
335
335
|
nextEarnings: financials?.nextEarnings,
|
|
336
336
|
depositaryReceipt: sharesOutstandingInReceipts(quote, fundamentals, description),
|
|
337
337
|
depositaryPair: depositaryPair ? { pair: depositaryPair, receiptSide: isReceiptSide(financials) } : null,
|
|
338
|
+
cedearRatio: listingCedearRatio(financials),
|
|
338
339
|
// Report and ex-dividend dates are the listing's calendar days.
|
|
339
340
|
today: zonedDateKey(Date.now(), chartTimeZone ?? "America/New_York"),
|
|
340
341
|
dividend,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logFailure } from "../../../utils/log-failure";
|
|
1
2
|
import { Box } from "../../../ui";
|
|
2
3
|
import { getCurrentPluginTarget } from "../../current-target";
|
|
3
4
|
import { recordResearchActivity, recordResearchTabView } from "../../../api-client/research-activity";
|
|
@@ -283,7 +284,7 @@ export function TickerResearchPane({ focused, width, height }: PaneProps) {
|
|
|
283
284
|
choices={choices.map((item) => ({ ...item, label: t(item.label) }))} />,
|
|
284
285
|
}).then((templateId) => {
|
|
285
286
|
if (templateId && choices.some((item) => item.id === templateId)) createPaneFromTemplate(templateId, { symbol: companySymbol });
|
|
286
|
-
}).catch((
|
|
287
|
+
}).catch(logFailure("ticker-detail.pane", "Open company research choices failed"));
|
|
287
288
|
} }];
|
|
288
289
|
}, [companySymbol, createPaneFromTemplate, dialog, disabledPlugins, registry, tickerResearchTabsSnapshot]);
|
|
289
290
|
usePaneMenuItems("ticker-research:go-to-tab", () => {
|
|
@@ -304,7 +305,7 @@ export function TickerResearchPane({ focused, width, height }: PaneProps) {
|
|
|
304
305
|
),
|
|
305
306
|
}).then((tabId) => {
|
|
306
307
|
if (tabId) selectResearchTab(tabId);
|
|
307
|
-
}).catch((
|
|
308
|
+
}).catch(logFailure("ticker-detail.pane", "Open research tab choices failed"));
|
|
308
309
|
},
|
|
309
310
|
}];
|
|
310
311
|
}, [dialog, resolvedTabId, selectResearchTab, showTabs, tabItems]);
|
|
@@ -325,16 +326,21 @@ export function TickerResearchPane({ focused, width, height }: PaneProps) {
|
|
|
325
326
|
selectResearchTab(tabId);
|
|
326
327
|
return true;
|
|
327
328
|
}, [selectResearchTab, visibleTabIds]);
|
|
329
|
+
// Without a ticker the pane draws only its empty state, and the tab list has
|
|
330
|
+
// no Overview, so the fallback above lands on the first tab that needs no
|
|
331
|
+
// ticker. Nobody opened it, and keeping it mounted would load its data on
|
|
332
|
+
// every ticker switch.
|
|
333
|
+
const shownTabId = ticker && visibleTabIds.has(resolvedTabId) ? resolvedTabId : null;
|
|
328
334
|
const renderedTabIds = useMemo(() => {
|
|
329
335
|
const next = new Set<string>();
|
|
330
336
|
for (const tabId of mountedTabIds) {
|
|
331
337
|
if (visibleTabIds.has(tabId)) next.add(tabId);
|
|
332
338
|
}
|
|
333
|
-
if (
|
|
334
|
-
next.add(
|
|
339
|
+
if (shownTabId) {
|
|
340
|
+
next.add(shownTabId);
|
|
335
341
|
}
|
|
336
342
|
return next;
|
|
337
|
-
}, [mountedTabIds,
|
|
343
|
+
}, [mountedTabIds, shownTabId, visibleTabIds]);
|
|
338
344
|
|
|
339
345
|
const handlePluginCapture = useCallback((capturing: boolean) => {
|
|
340
346
|
setPluginCaptured(capturing);
|
|
@@ -353,12 +359,12 @@ export function TickerResearchPane({ focused, width, height }: PaneProps) {
|
|
|
353
359
|
for (const tabId of current) {
|
|
354
360
|
if (visibleTabIds.has(tabId)) next.add(tabId);
|
|
355
361
|
}
|
|
356
|
-
if (
|
|
357
|
-
next.add(
|
|
362
|
+
if (shownTabId) {
|
|
363
|
+
next.add(shownTabId);
|
|
358
364
|
}
|
|
359
365
|
return sameStringSet(current, next) ? current : next;
|
|
360
366
|
});
|
|
361
|
-
}, [
|
|
367
|
+
}, [shownTabId, visibleTabIds]);
|
|
362
368
|
|
|
363
369
|
if (!ticker) {
|
|
364
370
|
const isEmptyFollowCollection = paneInstance?.binding?.kind === "follow" && !!collectionId && collectionTickerCount === 0;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logFailure } from "../../../../utils/log-failure";
|
|
1
2
|
import { PerpEquityRow } from "../../perps/equity-row";
|
|
2
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
4
|
import { Box, useUiCapabilities } from "../../../../ui";
|
|
@@ -173,7 +174,7 @@ export function QuoteMonitorPane({ paneId, focused, width, height }: PaneProps)
|
|
|
173
174
|
useEffect(() => {
|
|
174
175
|
const coordinator = getSharedMarketDataCoordinator();
|
|
175
176
|
if (!coordinator || !liveStreaming || boardInstruments.length === 0) return;
|
|
176
|
-
void coordinator.loadQuotesBatch(boardInstruments).catch((
|
|
177
|
+
void coordinator.loadQuotesBatch(boardInstruments).catch(logFailure("ticker-detail.quote-monitor", "Warm quote monitor board failed"));
|
|
177
178
|
}, [boardInstrumentKey, liveStreaming]);
|
|
178
179
|
const { pinTicker } = usePluginTickerActions();
|
|
179
180
|
const { openPaneSettings } = usePluginAppActions();
|
|
@@ -119,6 +119,7 @@ export function getQuoteMonitorPaneSettings(
|
|
|
119
119
|
try {
|
|
120
120
|
symbols = parseTickerListInput(storedText, MAX_TICKER_LIST_SIZE);
|
|
121
121
|
} catch {
|
|
122
|
+
// Intentional ignore: unparseable saved ticker text falls back to the legacy symbol or the pane's ticker.
|
|
122
123
|
symbols = [];
|
|
123
124
|
}
|
|
124
125
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { Box } from "../../../ui";
|
|
3
3
|
import { usePaneSettingValue, useShortcut } from "../../../public/react";
|
|
4
|
-
import {
|
|
4
|
+
import { createDataTableCsv } from "../../../components/data-table/export";
|
|
5
|
+
import { dropColumnsToFit } from "../../../components/ui/table-layout";
|
|
6
|
+
import { splitDelayedStatus, DataTableStackView, KeyValueRow, PaneStatusBody, StatGrid, usePaneFooter, usePaneNoticeFooter, usePaneStatusFooter, usePaneTabs, usePaneTicker, type DataTableCell, type DataTableColumn } from "../../../components";
|
|
5
7
|
import { useThemeColors } from "../../../theme/theme-context";
|
|
6
8
|
import type { PaneProps } from "../../../types/plugin";
|
|
7
9
|
import type { TapeQuote, TapeSnapshot, TapeTrade } from "../../../api-client/tape";
|
|
@@ -32,6 +34,12 @@ const QUOTES: DataTableColumn[] = [
|
|
|
32
34
|
{ id: "askExchange", label: "VENUE", width: 9, align: "left" },
|
|
33
35
|
{ id: "spread", label: "SPREAD BP", width: 10, align: "right" },
|
|
34
36
|
];
|
|
37
|
+
/**
|
|
38
|
+
* A narrow pane gives up the venues, then the lots, before the right edge cuts
|
|
39
|
+
* the spread: each pair together, since one side's alone would not say which
|
|
40
|
+
* side it is. The scrollbar keeps one cell, and exports keep every column.
|
|
41
|
+
*/
|
|
42
|
+
const QUOTE_DROP_ORDER = [["bidExchange", "askExchange"], ["bidSize", "askSize"]];
|
|
35
43
|
const rank = (value: number | null) => value == null ? "pctl --" : `${value.toFixed(0)} pctl`;
|
|
36
44
|
type TapeRow = { id: string; trade?: TapeTrade; quote?: TapeQuote };
|
|
37
45
|
|
|
@@ -112,13 +120,32 @@ function TimeSalesView({ width, height, focused, symbol, exchange }: PaneProps &
|
|
|
112
120
|
info: data ? [...splitDelayedStatus({ id: "feed", quoteStatus: true, parts: [{ text: `${data.feed === "sip" ? "real-time" : "15m delayed"} · ${tapeStampNewYork(data.asOf)}`, tone: "muted" }] }),
|
|
113
121
|
...(frozen ? [{ id: "paused", parts: [{ text: "paused", tone: "warning" as const }] }] : []),
|
|
114
122
|
...(!data.connected || resource.snapshotOnly ? [{ id: "snapshot", parts: [{ text: "snapshot", tone: "warning" as const }] }] : [])] : [] });
|
|
123
|
+
const quoteColumns = useMemo(() => dropColumnsToFit(QUOTES, width - 1, QUOTE_DROP_ORDER), [width]);
|
|
124
|
+
const columns = tab === "quotes" ? quoteColumns : TRADES;
|
|
115
125
|
const selectTab = (value: string) => { setTab(value); setDetail(null); setSelected(null); };
|
|
116
126
|
const { strip: tabStrip, rows: tabRows } = usePaneTabs({ tabs: TABS, activeValue: tab, onSelect: selectTab, focused: focused && !detail, dense: true });
|
|
127
|
+
const renderCell = (row: TapeRow, column: DataTableColumn): DataTableCell => {
|
|
128
|
+
if (row.trade) {
|
|
129
|
+
const trade = row.trade;
|
|
130
|
+
const tick = ticks.get(trade);
|
|
131
|
+
return { text: column.id === "time" ? tapeClockNewYork(trade.timestamp) : column.id === "price" ? tapePrice(trade.price, tradeDigits)
|
|
132
|
+
: column.id === "size" ? tapeQuantity(trade.size) : column.id === "venue" ? tapeVenue(trade.exchange)
|
|
133
|
+
: column.id === "conditions" ? tapeConditionWords(trade.conditions) : trade.tape,
|
|
134
|
+
// Price by tick, as on a tape; a block print lights the rest of its row.
|
|
135
|
+
color: laterThanPin(row) ? colors.textMuted : column.id === "price" ? tick === "up" ? colors.positive : tick === "down" ? colors.negative : colors.text
|
|
136
|
+
: trade.size >= 10_000 ? colors.warning : colors.textMuted };
|
|
137
|
+
}
|
|
138
|
+
const quote = row.quote!, spread = quoteSpread(quote);
|
|
139
|
+
return { text: column.id === "time" ? tapeClockNewYork(quote.timestamp) : column.id === "bid" ? tapePrice(quote.bid, quoteDigits) : column.id === "ask" ? tapePrice(quote.ask, quoteDigits)
|
|
140
|
+
: column.id === "bidSize" ? tapeQuantity(quote.bidSize) : column.id === "askSize" ? tapeQuantity(quote.askSize)
|
|
141
|
+
: column.id === "bidExchange" ? tapeVenue(quote.bidExchange) : column.id === "askExchange" ? tapeVenue(quote.askExchange)
|
|
142
|
+
: spread.bps == null ? "--" : spread.bps.toFixed(2), color: laterThanPin(row) ? colors.textMuted : spread.state === "normal" ? colors.text : colors.warning };
|
|
143
|
+
};
|
|
117
144
|
if (!data && isCloudSessionRequired(resource.error)) return <SignInWall placement="time-sales-signin" action="view time and sales" needsVerification={session.needsVerification} />;
|
|
118
145
|
return <Box width={width} height={height} flexDirection="column">
|
|
119
146
|
{tabStrip}
|
|
120
147
|
<PaneStatusBody loading={resource.loading && !data} error={!data ? resource.error : null} empty={!!data && !rows.length} subject={tab === "quotes" ? "NBBO observations" : "trade observations"}>
|
|
121
|
-
{data && stats ? <DataTableStackView<TapeRow> columns={
|
|
148
|
+
{data && stats ? <DataTableStackView<TapeRow> columns={columns} items={rows}
|
|
122
149
|
focused={focused} rootWidth={width} rootHeight={Math.max(3, height - tabRows)}
|
|
123
150
|
selection={{ kind: "id", selectedId: selected, getId: (row) => row.id, onChange: setSelected }}
|
|
124
151
|
onActivate={(row) => { setPaused({ data, epoch: resource.epoch }); setDetail({ row, epoch: resource.epoch }); }} getItemKey={(row) => row.id}
|
|
@@ -136,23 +163,8 @@ function TimeSalesView({ width, height, focused, symbol, exchange }: PaneProps &
|
|
|
136
163
|
]),
|
|
137
164
|
...(data.session.high != null && data.session.low != null ? [{ id: "session", label: "Session", value: `${tapePrice(data.session.low, sessionDigits)} to ${tapePrice(data.session.high, sessionDigits)}` }] : []),
|
|
138
165
|
]} />}
|
|
139
|
-
renderCell={(
|
|
140
|
-
|
|
141
|
-
const trade = row.trade;
|
|
142
|
-
const tick = ticks.get(trade);
|
|
143
|
-
return { text: column.id === "time" ? tapeClockNewYork(trade.timestamp) : column.id === "price" ? tapePrice(trade.price, tradeDigits)
|
|
144
|
-
: column.id === "size" ? tapeQuantity(trade.size) : column.id === "venue" ? tapeVenue(trade.exchange)
|
|
145
|
-
: column.id === "conditions" ? tapeConditionWords(trade.conditions) : trade.tape,
|
|
146
|
-
// Price by tick, as on a tape; a block print lights the rest of its row.
|
|
147
|
-
color: laterThanPin(row) ? colors.textMuted : column.id === "price" ? tick === "up" ? colors.positive : tick === "down" ? colors.negative : colors.text
|
|
148
|
-
: trade.size >= 10_000 ? colors.warning : colors.textMuted };
|
|
149
|
-
}
|
|
150
|
-
const quote = row.quote!, spread = quoteSpread(quote);
|
|
151
|
-
return { text: column.id === "time" ? tapeClockNewYork(quote.timestamp) : column.id === "bid" ? tapePrice(quote.bid, quoteDigits) : column.id === "ask" ? tapePrice(quote.ask, quoteDigits)
|
|
152
|
-
: column.id === "bidSize" ? tapeQuantity(quote.bidSize) : column.id === "askSize" ? tapeQuantity(quote.askSize)
|
|
153
|
-
: column.id === "bidExchange" ? tapeVenue(quote.bidExchange) : column.id === "askExchange" ? tapeVenue(quote.askExchange)
|
|
154
|
-
: spread.bps == null ? "--" : spread.bps.toFixed(2), color: laterThanPin(row) ? colors.textMuted : spread.state === "normal" ? colors.text : colors.warning };
|
|
155
|
-
}} emptyStateTitle="No observations in this window." /> : null}
|
|
166
|
+
renderCell={renderCell} exportCsv={() => createDataTableCsv({ columns: tab === "quotes" ? QUOTES : TRADES, items: rows, renderCell })}
|
|
167
|
+
emptyStateTitle="No observations in this window." /> : null}
|
|
156
168
|
</PaneStatusBody>
|
|
157
169
|
</Box>;
|
|
158
170
|
}
|
|
@@ -28,27 +28,34 @@ import {
|
|
|
28
28
|
} from "./model";
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
* A
|
|
32
|
-
*
|
|
33
|
-
*
|
|
31
|
+
* A missing bid-to-cover or bidder split is a blank cell: the source has
|
|
32
|
+
* bid-to-cover regularly from late 1999 and the split only from 2008-04-07,
|
|
33
|
+
* and an announced auction has no results to fill them; its Rate says so.
|
|
34
34
|
*/
|
|
35
|
-
const
|
|
36
|
-
|
|
35
|
+
const formatPercent = (value: unknown) => value == null ? "" : `${Number(value).toFixed(1)}%`;
|
|
36
|
+
|
|
37
|
+
/** What an announced auction's Rate reads until the source publishes its results. */
|
|
38
|
+
const RESULTS_NOT_PUBLISHED = "results not published";
|
|
39
|
+
const pending = (row: Record<string, unknown>) => isPendingAuction(row as unknown as TreasuryAuction);
|
|
37
40
|
|
|
38
41
|
/** Why the stop-out column is not a tail; the docs page says the same at length. */
|
|
39
42
|
const STOP_OUT_NOTE = "Stop-out vs avg is the high yield minus the average/median yield, in bp (bills: discount rates). "
|
|
40
43
|
+ "A true tail, the stop-out against the 1 pm when-issued yield, needs the when-issued yield, which the source does not carry.";
|
|
41
44
|
|
|
42
45
|
const MISSING_METRICS_NOTE = "A blank B/C or bidder share is one the source does not have for that auction: "
|
|
43
|
-
+ "bid-to-cover is regular from late 1999, the indirect, direct and dealer split from 2008-04-07.
|
|
46
|
+
+ "bid-to-cover is regular from late 1999, the indirect, direct and dealer split from 2008-04-07.";
|
|
44
47
|
|
|
45
48
|
/** A completed auction the source gives no bid-to-cover or no bidder split for. */
|
|
46
49
|
const lacksMetrics = (auction: TreasuryAuction) => !isPendingAuction(auction)
|
|
47
50
|
&& (auction.bidToCoverRatio == null || indirectPct(auction) == null || directPct(auction) == null || dealerPct(auction) == null);
|
|
48
51
|
|
|
49
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* The rate as the table prints it; a TIPS or FRN row says what its number is
|
|
54
|
+
* (`2.653% real`, `4.0bp spread`), and an announced auction that its results
|
|
55
|
+
* are not published yet.
|
|
56
|
+
*/
|
|
50
57
|
const rateCell = (value: unknown, row: Record<string, unknown>) => {
|
|
51
|
-
const text = formatAuctionRate(row as unknown as TreasuryAuction, value == null ? null : Number(value), "-");
|
|
58
|
+
const text = formatAuctionRate(row as unknown as TreasuryAuction, value == null ? null : Number(value), pending(row) ? RESULTS_NOT_PUBLISHED : "-");
|
|
52
59
|
const qualifier = value == null ? null : rateQualifier(row as unknown as TreasuryAuction);
|
|
53
60
|
return qualifier ? `${text} ${qualifier}` : text;
|
|
54
61
|
};
|
|
@@ -61,14 +68,16 @@ const COLUMNS = [
|
|
|
61
68
|
key: "rate",
|
|
62
69
|
header: "Rate",
|
|
63
70
|
align: "right" as const,
|
|
64
|
-
format: (value: unknown, row: Record<string, unknown>) => formatAuctionRate(
|
|
71
|
+
format: (value: unknown, row: Record<string, unknown>) => formatAuctionRate(
|
|
72
|
+
row as unknown as TreasuryAuction, value == null ? null : Number(value), pending(row) ? RESULTS_NOT_PUBLISHED : "-",
|
|
73
|
+
),
|
|
65
74
|
textFormat: rateCell,
|
|
66
75
|
},
|
|
67
|
-
{ key: "stopOutVsAvgBp", header: "Stop-out vs avg (bp)", align: "right" as const, format: (value: unknown) => value == null ? "-" : Number(value).toFixed(1) },
|
|
68
76
|
{
|
|
69
|
-
key: "
|
|
70
|
-
format: (value: unknown, row: Record<string, unknown>) => value == null ?
|
|
77
|
+
key: "stopOutVsAvgBp", header: "Stop-out vs avg (bp)", align: "right" as const,
|
|
78
|
+
format: (value: unknown, row: Record<string, unknown>) => value == null ? pending(row) ? "" : "-" : Number(value).toFixed(1),
|
|
71
79
|
},
|
|
80
|
+
{ key: "bidToCoverRatio", header: "B/C", align: "right" as const, format: (value: unknown) => value == null ? "" : Number(value).toFixed(2) },
|
|
72
81
|
{ key: "indirectPercent", header: "Indirect", align: "right" as const, format: formatPercent },
|
|
73
82
|
{ key: "directPercent", header: "Direct", align: "right" as const, format: formatPercent },
|
|
74
83
|
{ key: "dealerPercent", header: "Dealer", align: "right" as const, format: formatPercent },
|
|
@@ -105,6 +105,9 @@ function secTypeColor(secType: string, selected: boolean): string {
|
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
/** An announced auction's Rate in the table, the word other panes use for a figure not out yet (KPI's Later actual). */
|
|
109
|
+
const RESULTS_PENDING = "Pending";
|
|
110
|
+
|
|
108
111
|
// Stable table adapter so memoized rows survive pane re-renders.
|
|
109
112
|
const auctionKey = (auction: TreasuryAuction) => auction.id;
|
|
110
113
|
|
|
@@ -119,8 +122,8 @@ function renderAuctionCell(
|
|
|
119
122
|
|
|
120
123
|
switch (column.id) {
|
|
121
124
|
case "date":
|
|
122
|
-
// Announced auctions have no results yet
|
|
123
|
-
//
|
|
125
|
+
// Announced auctions have no results yet: Rate reads Pending, the other
|
|
126
|
+
// metric cells "—", and the date is bright.
|
|
124
127
|
return {
|
|
125
128
|
text: showYear ? auction.auctionDate : formatShortDate(auction.auctionDate, { year: false, utc: true, fallback: "\u2014" }),
|
|
126
129
|
color: rowState.selected ? colors.selectedText : isPendingAuction(auction) ? colors.textBright : colors.textDim,
|
|
@@ -134,7 +137,10 @@ function renderAuctionCell(
|
|
|
134
137
|
case "term":
|
|
135
138
|
return { text: auction.securityTerm, color: selected ?? colors.text };
|
|
136
139
|
case "rate":
|
|
137
|
-
|
|
140
|
+
// An announced auction says its results are pending, as its detail does; other metric cells stay "—".
|
|
141
|
+
return isPendingAuction(auction)
|
|
142
|
+
? { text: RESULTS_PENDING, color: dimmed }
|
|
143
|
+
: { text: formatAuctionRate(auction, rateValue(auction), "—"), color: selected ?? colors.textBright };
|
|
138
144
|
case "stopOut":
|
|
139
145
|
return { text: formatBp(stopOutVsAverageBp(auction)), color: selected ?? colors.text };
|
|
140
146
|
case "btc":
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { httpFetch } from "../../../utils/http-transport";
|
|
2
2
|
import { numericOrNull, scalarTextOrNull } from "../../../utils/guards";
|
|
3
|
-
import type
|
|
3
|
+
import { cashLineLabel, type CashAccount, type DebtDay, type OperatingCash, type TgaClose } from "./model";
|
|
4
4
|
|
|
5
5
|
const CASH_URL = "https://api.fiscaldata.treasury.gov/services/api/fiscal_service/v1/accounting/dts/operating_cash_balance?sort=-record_date&page[size]=40";
|
|
6
|
+
// One line of the statement, every day since it took its present form in 2022: about a thousand closes.
|
|
7
|
+
const TGA_CLOSING_ACCOUNT = "Treasury General Account (TGA) Closing Balance";
|
|
8
|
+
const TGA_HISTORY_URL = `https://api.fiscaldata.treasury.gov/services/api/fiscal_service/v1/accounting/dts/operating_cash_balance?${new URLSearchParams({
|
|
9
|
+
filter: `account_type:eq:${TGA_CLOSING_ACCOUNT}`,
|
|
10
|
+
fields: "record_date,open_today_bal",
|
|
11
|
+
sort: "-record_date",
|
|
12
|
+
"page[size]": "3000",
|
|
13
|
+
})}`;
|
|
6
14
|
const DEBT_URL = "https://api.fiscaldata.treasury.gov/services/api/fiscal_service/v2/accounting/od/debt_to_penny?sort=-record_date&page[size]=20";
|
|
7
15
|
const FETCH_TIMEOUT_MS = 15_000;
|
|
8
16
|
const DEBT_DAYS = 20;
|
|
@@ -10,6 +18,9 @@ const DEBT_DAYS = 20;
|
|
|
10
18
|
export interface TreasuryDaily {
|
|
11
19
|
cash: OperatingCash;
|
|
12
20
|
debt: DebtDay[];
|
|
21
|
+
/** The Treasury General Account's closing balance each day, oldest first. Empty when it could not be read, with the reason. */
|
|
22
|
+
tga: TgaClose[];
|
|
23
|
+
tgaError?: string;
|
|
13
24
|
}
|
|
14
25
|
|
|
15
26
|
function recordDate(value: unknown): string | null {
|
|
@@ -39,7 +50,7 @@ function parseOperatingCash(payload: unknown): OperatingCash {
|
|
|
39
50
|
parsed.push({
|
|
40
51
|
id: `${date}:${line ?? account}`,
|
|
41
52
|
date,
|
|
42
|
-
account,
|
|
53
|
+
account: cashLineLabel(account),
|
|
43
54
|
// Since the 2022 statement format the day's figures are in open_today_bal
|
|
44
55
|
// and close_today_bal is always "null".
|
|
45
56
|
today: numericOrNull(row.open_today_bal),
|
|
@@ -60,6 +71,17 @@ function parseOperatingCash(payload: unknown): OperatingCash {
|
|
|
60
71
|
};
|
|
61
72
|
}
|
|
62
73
|
|
|
74
|
+
function parseTgaHistory(payload: unknown): TgaClose[] {
|
|
75
|
+
const byDate = new Map<string, number>();
|
|
76
|
+
for (const row of rowsOf(payload)) {
|
|
77
|
+
const date = recordDate(row.record_date);
|
|
78
|
+
// The closing balance is sent in open_today_bal, as the statement's other lines are.
|
|
79
|
+
const millions = numericOrNull(row.open_today_bal);
|
|
80
|
+
if (date && millions != null && !byDate.has(date)) byDate.set(date, millions);
|
|
81
|
+
}
|
|
82
|
+
return [...byDate].map(([date, millions]) => ({ date, millions })).sort((a, b) => a.date.localeCompare(b.date));
|
|
83
|
+
}
|
|
84
|
+
|
|
63
85
|
function parseDebtToPenny(payload: unknown): DebtDay[] {
|
|
64
86
|
const byDate = new Map<string, DebtDay>();
|
|
65
87
|
for (const row of rowsOf(payload)) {
|
|
@@ -87,10 +109,24 @@ async function readJson(url: string, label: string, signal?: AbortSignal): Promi
|
|
|
87
109
|
return response.json() as Promise<unknown>;
|
|
88
110
|
}
|
|
89
111
|
|
|
90
|
-
|
|
91
|
-
|
|
112
|
+
/**
|
|
113
|
+
* The latest day's cash lines and the last 20 days of debt, with the account's
|
|
114
|
+
* closing balance history unless `history` is off (a report that does not draw it).
|
|
115
|
+
* A history that cannot be read leaves the figures as they are.
|
|
116
|
+
*/
|
|
117
|
+
export async function fetchTreasuryDaily(signal?: AbortSignal, { history = true }: { history?: boolean } = {}): Promise<TreasuryDaily> {
|
|
118
|
+
const [cash, debt, tga] = await Promise.all([
|
|
92
119
|
readJson(CASH_URL, "Treasury cash", signal),
|
|
93
120
|
readJson(DEBT_URL, "Treasury debt", signal),
|
|
121
|
+
history ? readJson(TGA_HISTORY_URL, "Treasury account history", signal).then(parseTgaHistory).then(
|
|
122
|
+
(closes) => ({ closes }),
|
|
123
|
+
(error: unknown) => ({ closes: [] as TgaClose[], error: error instanceof Error ? error.message : String(error) }),
|
|
124
|
+
) : { closes: [] as TgaClose[] },
|
|
94
125
|
]);
|
|
95
|
-
return {
|
|
126
|
+
return {
|
|
127
|
+
cash: parseOperatingCash(cash),
|
|
128
|
+
debt: parseDebtToPenny(debt),
|
|
129
|
+
tga: tga.closes,
|
|
130
|
+
...("error" in tga ? { tgaError: tga.error } : {}),
|
|
131
|
+
};
|
|
96
132
|
}
|
|
@@ -3,7 +3,7 @@ import { fetchTreasuryDaily } from "./client";
|
|
|
3
3
|
import { formatBillions, formatTrillions } from "./model";
|
|
4
4
|
|
|
5
5
|
const CASH_COLUMNS: HeadlessPaneColumn[] = [
|
|
6
|
-
{ key: "account", header: "Account" },
|
|
6
|
+
{ key: "account", header: "Treasury General Account" },
|
|
7
7
|
{ key: "today", header: "Today $bn", align: "right", description: "The day's figure, billions of dollars", format: formatBillions },
|
|
8
8
|
{ key: "month", header: "This month $bn", align: "right", description: "Month to date, billions of dollars", format: formatBillions },
|
|
9
9
|
];
|
|
@@ -32,7 +32,7 @@ export const treasuryDailyHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
32
32
|
describe: "Treasury operating cash and public debt",
|
|
33
33
|
freshness: { source: "US Treasury", status: "not-a-feed", basis: "daily statement" },
|
|
34
34
|
async load(_args, ctx) {
|
|
35
|
-
const { cash, debt } = await fetchTreasuryDaily(ctx.signal);
|
|
35
|
+
const { cash, debt } = await fetchTreasuryDaily(ctx.signal, { history: false });
|
|
36
36
|
return {
|
|
37
37
|
complete: cash.rows.length > 0 && debt.length > 0,
|
|
38
38
|
sections: [
|
|
@@ -8,7 +8,7 @@ export const treasuryDailyModule: PluginModule = {
|
|
|
8
8
|
id: "treasury-daily-pane",
|
|
9
9
|
paneId: TREASURY_DAILY_PANE_ID,
|
|
10
10
|
label: "Treasury Cash and Debt",
|
|
11
|
-
description: "Treasury operating cash for the latest day, and debt held by the public for the last 20 business days.",
|
|
11
|
+
description: "Treasury operating cash for the latest day with the Treasury General Account's closing balance history, and debt held by the public for the last 20 business days.",
|
|
12
12
|
keywords: ["treasury", "dts", "debt", "cash", "tga", "debt to the penny", "operating cash"],
|
|
13
13
|
shortcut: { prefix: "DTS" },
|
|
14
14
|
headless: treasuryDailyHeadless,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DataTableColumn } from "../../../components";
|
|
2
|
+
import { formatNumber } from "../../../utils/format";
|
|
2
3
|
|
|
3
4
|
export const TREASURY_DAILY_PANE_ID = "treasury-daily";
|
|
4
5
|
|
|
@@ -23,6 +24,51 @@ export interface OperatingCash {
|
|
|
23
24
|
rows: CashAccount[];
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
/** One day's Treasury General Account closing balance, millions of dollars. */
|
|
28
|
+
export interface TgaClose {
|
|
29
|
+
date: string;
|
|
30
|
+
millions: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The longest stretch of closing balances the Cash tab charts, and the ranges it offers. */
|
|
34
|
+
export type TgaRange = "3M" | "6M" | "1Y" | "ALL";
|
|
35
|
+
export const TGA_RANGES: ReadonlyArray<{ value: TgaRange; label: string; hint: string; months: number | null }> = [
|
|
36
|
+
{ value: "3M", label: "3M", hint: "1", months: 3 },
|
|
37
|
+
{ value: "6M", label: "6M", hint: "2", months: 6 },
|
|
38
|
+
{ value: "1Y", label: "1Y", hint: "3", months: 12 },
|
|
39
|
+
{ value: "ALL", label: "All", hint: "4", months: null },
|
|
40
|
+
];
|
|
41
|
+
const DEFAULT_TGA_RANGE: TgaRange = "1Y";
|
|
42
|
+
|
|
43
|
+
export function tgaRange(value: unknown): TgaRange {
|
|
44
|
+
return TGA_RANGES.find((range) => range.value === value)?.value ?? DEFAULT_TGA_RANGE;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** The closes of the last `range`, counted back from the newest one, oldest first. */
|
|
48
|
+
export function tgaClosesInRange(closes: readonly TgaClose[], range: TgaRange): TgaClose[] {
|
|
49
|
+
const months = TGA_RANGES.find((entry) => entry.value === range)?.months ?? null;
|
|
50
|
+
const last = closes.at(-1);
|
|
51
|
+
if (months == null || !last) return [...closes];
|
|
52
|
+
const start = new Date(`${last.date}T00:00:00Z`);
|
|
53
|
+
start.setUTCMonth(start.getUTCMonth() - months);
|
|
54
|
+
const from = start.toISOString().slice(0, 10);
|
|
55
|
+
return closes.filter((close) => close.date >= from);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* What the Treasury's statement calls a line of the Treasury General Account,
|
|
60
|
+
* said plainly: `Treasury General Account (TGA) Opening Balance` is the
|
|
61
|
+
* opening balance, `Total TGA Withdrawals (Table II) (-)` the withdrawals. A
|
|
62
|
+
* line the statement adds later keeps its own words, less the table reference.
|
|
63
|
+
*/
|
|
64
|
+
export function cashLineLabel(account: string): string {
|
|
65
|
+
if (/^Treasury General Account \(TGA\) Opening Balance$/i.test(account)) return "Opening balance";
|
|
66
|
+
if (/^Treasury General Account \(TGA\) Closing Balance$/i.test(account)) return "Closing balance";
|
|
67
|
+
if (/^Total TGA Deposits\b/i.test(account)) return "Deposits";
|
|
68
|
+
if (/^Total TGA Withdrawals\b/i.test(account)) return "Withdrawals";
|
|
69
|
+
return account.replace(/\s*\(Table [IVX]+\)/g, "").replace(/\s*\(-\)$/, "").trim();
|
|
70
|
+
}
|
|
71
|
+
|
|
26
72
|
export interface DebtDay {
|
|
27
73
|
id: string;
|
|
28
74
|
date: string;
|
|
@@ -40,7 +86,7 @@ export type CashColumn = DataTableColumn & { id: CashColumnId };
|
|
|
40
86
|
export type DebtColumn = DataTableColumn & { id: DebtColumnId };
|
|
41
87
|
|
|
42
88
|
export const CASH_COLUMNS: CashColumn[] = [
|
|
43
|
-
{ id: "account", label: "Account", width:
|
|
89
|
+
{ id: "account", label: "Treasury General Account", width: 26, align: "left", flexGrow: 1 },
|
|
44
90
|
{ id: "today", label: "Today $bn", width: 12, align: "right" },
|
|
45
91
|
{ id: "month", label: "This month $bn", width: 15, align: "right" },
|
|
46
92
|
];
|
|
@@ -52,10 +98,11 @@ export const DEBT_COLUMNS: DebtColumn[] = [
|
|
|
52
98
|
{ id: "total", label: "Total $tn", width: 12, align: "right" },
|
|
53
99
|
];
|
|
54
100
|
|
|
101
|
+
/** Two decimals with thousands separators, as every money table writes a large figure: `2,594.63`. */
|
|
55
102
|
function scaled(value: unknown, divisor: number): string {
|
|
56
103
|
if (typeof value !== "number" || !Number.isFinite(value)) return "--";
|
|
57
|
-
const
|
|
58
|
-
return
|
|
104
|
+
const rounded = Number((value / divisor).toFixed(2));
|
|
105
|
+
return formatNumber(rounded === 0 ? 0 : rounded, 2);
|
|
59
106
|
}
|
|
60
107
|
|
|
61
108
|
/** Millions of dollars, drawn as billions. */
|
|
@@ -1,33 +1,52 @@
|
|
|
1
1
|
import { useCallback, useMemo, useState } from "react";
|
|
2
2
|
import {
|
|
3
|
+
ChartTableHeader,
|
|
3
4
|
DataTableView,
|
|
4
5
|
PaneStatusBody,
|
|
6
|
+
QueryBar,
|
|
7
|
+
usePaneNoticeFooter,
|
|
5
8
|
usePaneStatusFooter,
|
|
6
9
|
usePaneTabs,
|
|
10
|
+
type ChartTableChart,
|
|
7
11
|
type DataTableCell,
|
|
12
|
+
type DataTableKeyEvent,
|
|
8
13
|
} from "../../../components";
|
|
9
|
-
import {
|
|
14
|
+
import { spanAxisFormatter } from "../../../components/chart-table";
|
|
15
|
+
import { useChartViewReset } from "../../../components/chart/core/view-reset";
|
|
16
|
+
import { scalarPoint, staticSeries } from "../../../components/chart/static/series";
|
|
17
|
+
import { handleRefreshKey, usePaneRefreshKey } from "../../../components/data-table/table-pane";
|
|
10
18
|
import { useAsyncResource, useAutoRefresh, usePluginPaneState } from "../../../public/react";
|
|
11
19
|
import { useThemeColors } from "../../../theme/theme-context";
|
|
12
20
|
import type { PaneProps } from "../../../types/plugin";
|
|
13
21
|
import { Box } from "../../../ui";
|
|
22
|
+
import { formatNumber } from "../../../utils/format";
|
|
23
|
+
import { isPlainKeyboardEvent } from "../../../utils/keyboard";
|
|
14
24
|
import { fetchTreasuryDaily } from "./client";
|
|
15
25
|
import {
|
|
16
26
|
CASH_COLUMNS,
|
|
17
27
|
DEBT_COLUMNS,
|
|
28
|
+
TGA_RANGES,
|
|
18
29
|
TREASURY_DAILY_PANE_ID,
|
|
19
30
|
TREASURY_TABS,
|
|
20
31
|
formatBillions,
|
|
21
32
|
formatTrillions,
|
|
33
|
+
tgaClosesInRange,
|
|
34
|
+
tgaRange,
|
|
22
35
|
type CashAccount,
|
|
23
36
|
type CashColumn,
|
|
24
37
|
type DebtColumn,
|
|
25
38
|
type DebtDay,
|
|
39
|
+
type TgaRange,
|
|
26
40
|
type TreasuryTab,
|
|
27
41
|
} from "./model";
|
|
28
42
|
|
|
29
43
|
const EMPTY_CASH: CashAccount[] = [];
|
|
30
44
|
const EMPTY_DEBT: DebtDay[] = [];
|
|
45
|
+
const RANGE_OPTIONS = TGA_RANGES.map(({ value, label, hint }) => ({ value, label, hint }));
|
|
46
|
+
const TGA_SERIES_LABEL = "TGA closing balance $bn";
|
|
47
|
+
/** Ticks in billions, with thousands separators and the decimals the plotted range needs. */
|
|
48
|
+
const formatBillionsAxis = spanAxisFormatter((value, digits) => formatNumber(value, digits));
|
|
49
|
+
const formatBillionsLevel = (value: number) => formatNumber(value, 2);
|
|
31
50
|
|
|
32
51
|
function scaledCell(value: number | null, text: string, muted: string): DataTableCell {
|
|
33
52
|
return value == null ? { text, value, color: muted } : { text, value };
|
|
@@ -44,6 +63,9 @@ export function TreasuryDailyPane({ width, height, focused }: PaneProps) {
|
|
|
44
63
|
const debtRows = data?.debt ?? EMPTY_DEBT;
|
|
45
64
|
const activeRows = tab === "cash" ? cashRows : debtRows;
|
|
46
65
|
const recordDate = tab === "cash" ? data?.cash.recordDate ?? null : debtRows[0]?.date ?? null;
|
|
66
|
+
const [storedRange, setStoredRange] = usePluginPaneState<string>("range", "1Y");
|
|
67
|
+
const range = tgaRange(storedRange);
|
|
68
|
+
const resetChartView = useChartViewReset();
|
|
47
69
|
const [selectedId, setSelectedId] = useState<string | null>(null);
|
|
48
70
|
const resolvedId = activeRows.some((row) => row.id === selectedId) ? selectedId : activeRows[0]?.id ?? null;
|
|
49
71
|
const info = useMemo(
|
|
@@ -58,13 +80,46 @@ export function TreasuryDailyPane({ width, height, focused }: PaneProps) {
|
|
|
58
80
|
dense: true,
|
|
59
81
|
});
|
|
60
82
|
useAutoRefresh(resource.updatedAt, resource.load);
|
|
61
|
-
|
|
83
|
+
const refresh = useCallback(() => void resource.reload(), [resource.reload]);
|
|
84
|
+
usePaneRefreshKey(refresh, { focused });
|
|
62
85
|
usePaneStatusFooter({
|
|
63
86
|
registrationId: TREASURY_DAILY_PANE_ID,
|
|
64
87
|
loading: resource.loading,
|
|
65
88
|
error: resource.error,
|
|
66
89
|
info,
|
|
67
90
|
});
|
|
91
|
+
usePaneNoticeFooter({
|
|
92
|
+
registrationId: `${TREASURY_DAILY_PANE_ID}:history`,
|
|
93
|
+
focused: focused && tab === "cash",
|
|
94
|
+
notices: data?.tgaError ? [`Closing balance history is unavailable: ${data.tgaError}`] : [],
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// The closing balance the table's last line states for the day, drawn over the range chosen.
|
|
98
|
+
const series = useMemo(() => {
|
|
99
|
+
const closes = tgaClosesInRange(data?.tga ?? [], range);
|
|
100
|
+
return closes.length < 2 ? [] : [staticSeries(
|
|
101
|
+
closes.map((close) => scalarPoint(new Date(`${close.date}T00:00:00Z`), close.millions / 1_000)),
|
|
102
|
+
{ id: "tga-closing-balance", label: TGA_SERIES_LABEL, color: colors.positive, calendarSpaced: true },
|
|
103
|
+
)];
|
|
104
|
+
}, [colors.positive, data?.tga, range]);
|
|
105
|
+
const chart: ChartTableChart | null = data?.tgaError ? null : {
|
|
106
|
+
series,
|
|
107
|
+
formatValue: formatBillionsLevel,
|
|
108
|
+
formatAxisValue: formatBillionsAxis,
|
|
109
|
+
remoteKind: "treasury-general-account",
|
|
110
|
+
empty: "No closing balance history.",
|
|
111
|
+
};
|
|
112
|
+
// The number keys pick the range, as the bar's hints say; picking the one showing sends the chart back to it.
|
|
113
|
+
const handleKeyDown = useCallback((event: DataTableKeyEvent) => {
|
|
114
|
+
if (handleRefreshKey(event, refresh, { stopPropagation: true })) return true;
|
|
115
|
+
if (!isPlainKeyboardEvent(event)) return false;
|
|
116
|
+
const picked = TGA_RANGES.find((option) => option.hint === event.name);
|
|
117
|
+
if (!picked) return false;
|
|
118
|
+
event.preventDefault?.();
|
|
119
|
+
if (picked.value === range) resetChartView();
|
|
120
|
+
else setStoredRange(picked.value);
|
|
121
|
+
return true;
|
|
122
|
+
}, [range, refresh, resetChartView, setStoredRange]);
|
|
68
123
|
|
|
69
124
|
const bodyHeight = Math.max(1, height - tabRows);
|
|
70
125
|
const renderCash = useCallback((row: CashAccount, column: CashColumn): DataTableCell => {
|
|
@@ -91,6 +146,30 @@ export function TreasuryDailyPane({ width, height, focused }: PaneProps) {
|
|
|
91
146
|
focused={focused}
|
|
92
147
|
rootWidth={width}
|
|
93
148
|
rootHeight={bodyHeight}
|
|
149
|
+
rootBefore={chart ? (
|
|
150
|
+
<ChartTableHeader
|
|
151
|
+
width={width}
|
|
152
|
+
height={bodyHeight}
|
|
153
|
+
tableRows={cashRows.length}
|
|
154
|
+
tableColumns={CASH_COLUMNS}
|
|
155
|
+
query={(
|
|
156
|
+
<QueryBar
|
|
157
|
+
width={width}
|
|
158
|
+
filters={[{
|
|
159
|
+
id: "range",
|
|
160
|
+
label: "Range",
|
|
161
|
+
inline: true,
|
|
162
|
+
chartRange: true,
|
|
163
|
+
value: range,
|
|
164
|
+
options: RANGE_OPTIONS,
|
|
165
|
+
onChange: (value: string) => setStoredRange(tgaRange(value) satisfies TgaRange),
|
|
166
|
+
}]}
|
|
167
|
+
/>
|
|
168
|
+
)}
|
|
169
|
+
chart={chart}
|
|
170
|
+
/>
|
|
171
|
+
) : undefined}
|
|
172
|
+
onRootKeyDown={handleKeyDown}
|
|
94
173
|
columns={CASH_COLUMNS}
|
|
95
174
|
items={cashRows}
|
|
96
175
|
sortColumnId={null}
|