gloomberb 0.18.4 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/package.json +1 -1
- package/patches/electrobun@1.18.1.patch +169 -5
- package/src/account/auth-model.ts +7 -3
- package/src/api-client/auth.ts +9 -4
- package/src/api-client/catalysts.ts +2 -1
- package/src/api-client/cot.ts +6 -2
- package/src/api-client/credit-documents.ts +6 -0
- package/src/api-client/data.ts +31 -6
- package/src/api-client/equity-screener.ts +24 -0
- package/src/api-client/fund-facts.ts +45 -4
- package/src/api-client/index.ts +171 -11
- package/src/api-client/live-scan.ts +91 -0
- package/src/api-client/market-discovery.ts +10 -0
- package/src/api-client/market-movers.ts +7 -0
- package/src/api-client/members.ts +13 -1
- package/src/api-client/perps.ts +43 -0
- package/src/api-client/request.ts +222 -41
- package/src/api-client/research-activity.ts +6 -12
- package/src/api-client/types.ts +74 -0
- package/src/app/keybindings/index.ts +3 -0
- package/src/app/keybindings/labels.ts +18 -1
- package/src/app/keybindings/resolve.ts +14 -0
- package/src/app/pane-runtime/plugin-bindings.ts +9 -5
- package/src/app/runtime/broker-import.ts +42 -27
- package/src/app/runtime/plugin-bindings.ts +73 -56
- package/src/architecture/core-builtin-allowlist.json +1 -1
- package/src/architecture/pane-tabs-allowlist.json +3 -0
- package/src/architecture/ttl-caches-allowlist.json +19 -0
- package/src/brokers/sync-broker-instance.ts +2 -8
- package/src/capabilities/chart-series.ts +1 -1
- package/src/cli/commands/crypto-hints.ts +40 -24
- package/src/cli/commands/fred-series.ts +5 -0
- package/src/cli/commands/keybindings.ts +23 -0
- package/src/cli/commands/market.ts +138 -46
- package/src/cli/commands/options-chain.ts +107 -10
- package/src/cli/commands/options-leaps.ts +9 -3
- package/src/cli/commands/overview.ts +176 -39
- package/src/cli/commands/search.ts +39 -3
- package/src/cli/commands/themes.ts +11 -2
- package/src/cli/commands/ticker.ts +57 -35
- package/src/cli/company-name-hint.ts +41 -0
- package/src/cli/earnings-calendar.ts +1 -1
- package/src/cli/errors.ts +10 -2
- package/src/cli/export-source.ts +29 -1
- package/src/cli/glossary.ts +73 -1
- package/src/cli/history-rows.ts +87 -16
- package/src/cli/index.ts +2 -0
- package/src/cli/known-gaps.ts +5 -2
- package/src/cli/listing-arg.ts +195 -56
- package/src/cli/output-file.ts +68 -0
- package/src/cli/pane-functions/capabilities.ts +3 -0
- package/src/cli/pane-functions/catalog.ts +80 -7
- package/src/cli/pane-functions/dom.ts +13 -3
- package/src/cli/pane-functions/freshness.ts +111 -16
- package/src/cli/pane-functions/function-help.ts +23 -13
- package/src/cli/pane-functions/headless.ts +56 -12
- package/src/cli/pane-functions/index.ts +58 -16
- package/src/cli/pane-functions/market-session.ts +81 -9
- package/src/cli/pane-functions/options.ts +19 -1
- package/src/cli/pane-functions/report.ts +5 -1
- package/src/cli/pane-functions/resolver.ts +35 -8
- package/src/cli/pane-functions/screenshot-assessment.ts +6 -4
- package/src/cli/pane-functions/screenshot-types.ts +5 -0
- package/src/cli/quote-answer.ts +30 -13
- package/src/cli/report-tables.ts +18 -7
- package/src/cli/restore-plugins.ts +13 -1
- package/src/cli/result.ts +57 -5
- package/src/cli/ticker-resolution.ts +3 -2
- package/src/components/chart/composite/composite-chart.tsx +26 -4
- package/src/components/chart/composite/format.ts +27 -0
- package/src/components/chart/composite/interactions.ts +6 -0
- package/src/components/chart/composite/legend.tsx +45 -7
- package/src/components/chart/composite/levels.ts +2 -0
- package/src/components/chart/composite/panel-gestures.ts +33 -0
- package/src/components/chart/composite/panel-series.ts +1 -0
- package/src/components/chart/composite/panel-surface.tsx +61 -5
- package/src/components/chart/composite/range-statistics.ts +62 -0
- package/src/components/chart/composite/rasterizer.ts +24 -13
- package/src/components/chart/composite/scene.ts +46 -7
- package/src/components/chart/composite/series-axis-tags.tsx +16 -9
- package/src/components/chart/composite/series-cues.ts +14 -0
- package/src/components/chart/composite/text-renderer.ts +9 -2
- package/src/components/chart/composite/tool-catalog.ts +36 -0
- package/src/components/chart/composite/tools.ts +203 -44
- package/src/components/chart/composite/types.ts +4 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +11 -4
- package/src/components/command-bar/assist/inventory.ts +2 -1
- package/src/components/command-bar/commands/direct/index.ts +28 -13
- package/src/components/command-bar/pane-templates/items.ts +3 -2
- package/src/components/command-bar/panel/prompt-binding.ts +0 -8
- package/src/components/command-bar/workflow/alert.ts +1 -1
- package/src/components/command-bar/workflow/collection-actions.ts +3 -3
- package/src/components/layout/header.tsx +26 -40
- package/src/components/layout/pane/footer/index.tsx +1 -0
- package/src/components/layout/pane/footer/model.ts +27 -0
- package/src/components/onboarding/onboarding-frame.tsx +1 -1
- package/src/components/onboarding/onboarding-wizard.tsx +4 -1
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +14 -9
- package/src/components/onboarding/wizard-broker-sync.ts +0 -1
- package/src/components/onboarding/wizard-positions.ts +3 -3
- package/src/components/ticker/list-table-view.tsx +4 -1
- package/src/components/ui/choice-dialog.tsx +23 -18
- package/src/components/ui/choice-groups.ts +18 -0
- package/src/components/ui/data-table/opentui/index.tsx +9 -7
- package/src/components/ui/data-table/opentui/model.ts +26 -1
- package/src/components/ui/data-table/types.ts +2 -0
- package/src/components/ui/display.tsx +5 -1
- package/src/components/ui/list-view.tsx +8 -4
- package/src/components/ui/query-bar-keys.tsx +2 -0
- package/src/components/ui/query-bar.tsx +1 -0
- package/src/components/ui/select-button.tsx +5 -1
- package/src/components/ui/select-field.tsx +1 -0
- package/src/components/ui/table-layout.ts +8 -5
- package/src/core/app-runtime.ts +2 -0
- package/src/core/app-services.ts +2 -2
- package/src/core/state/app/layout.ts +2 -0
- package/src/core/state/app/state.ts +9 -0
- package/src/core/state/app/types.ts +3 -0
- package/src/data/config/chart-settings.ts +1 -1
- package/src/data/json-ticker-repository.ts +17 -8
- package/src/data/saved-copies.ts +55 -16
- package/src/data/ticker-repository.ts +16 -9
- package/src/data/ticker-writes.ts +81 -0
- package/src/data/ttl-cache.ts +165 -0
- package/src/docs/snapshot.json +427 -216
- package/src/i18n/es.ts +19 -3
- package/src/i18n/ja.ts +19 -3
- package/src/i18n/ko.ts +19 -3
- package/src/i18n/zh-cn.ts +19 -3
- package/src/i18n/zh-tw.ts +19 -3
- package/src/market-data/coordinator/financials.ts +10 -2
- package/src/market-data/coordinator/index.ts +3 -1
- package/src/market-data/coordinator/quotes.ts +4 -2
- package/src/market-data/depositary-pair.ts +2 -2
- package/src/market-data/fund-facts.ts +50 -0
- package/src/market-data/market/change-basis.ts +48 -7
- package/src/market-data/market/dated-previous-close.ts +203 -0
- package/src/market-data/market/format.ts +25 -0
- package/src/market-data/market/freshness.ts +2 -1
- package/src/market-data/market/futures-week.ts +68 -0
- package/src/market-data/market/status.ts +16 -4
- package/src/market-data/options-alternatives.ts +141 -4
- package/src/market-data/quotes/contributions.ts +20 -2
- package/src/market-data/quotes/resolution.ts +3 -0
- package/src/market-data/selectors.ts +3 -0
- package/src/news/aggregator.ts +113 -9
- package/src/news/cloud-session.ts +21 -0
- package/src/news/hooks.ts +1 -0
- package/src/news/news-model.ts +1 -0
- package/src/news/types.ts +11 -0
- package/src/notifications/notification-log.ts +6 -4
- package/src/plugins/builtin/alerts/alert-engine.ts +25 -2
- package/src/plugins/builtin/alerts/alert-log.ts +33 -0
- package/src/plugins/builtin/alerts/calendar-events.ts +57 -6
- package/src/plugins/builtin/alerts/cli-forms.ts +216 -0
- package/src/plugins/builtin/alerts/cli.ts +380 -82
- package/src/plugins/builtin/alerts/command.ts +31 -0
- package/src/plugins/builtin/alerts/constants.ts +1 -1
- package/src/plugins/builtin/alerts/events-pane.tsx +19 -4
- package/src/plugins/builtin/alerts/fired-log.ts +113 -8
- package/src/plugins/builtin/alerts/format.ts +80 -4
- package/src/plugins/builtin/alerts/headless.ts +30 -7
- package/src/plugins/builtin/alerts/history-rows.ts +7 -3
- package/src/plugins/builtin/alerts/history.ts +2 -0
- package/src/plugins/builtin/alerts/index.tsx +135 -22
- package/src/plugins/builtin/alerts/live.ts +3 -3
- package/src/plugins/builtin/alerts/metric-command.ts +134 -0
- package/src/plugins/builtin/alerts/metric-data.ts +111 -0
- package/src/plugins/builtin/alerts/metric-model.ts +324 -0
- package/src/plugins/builtin/alerts/metric-parity-fixture.json +725 -0
- package/src/plugins/builtin/alerts/pane.tsx +90 -39
- package/src/plugins/builtin/alerts/quotes.ts +6 -0
- package/src/plugins/builtin/alerts/storage.ts +37 -10
- package/src/plugins/builtin/alerts/types.ts +7 -0
- package/src/plugins/builtin/analytics/index.tsx +2 -1
- package/src/plugins/builtin/analytics/risk-client.ts +16 -5
- package/src/plugins/builtin/analytics/risk-fx.ts +70 -15
- package/src/plugins/builtin/analytics/risk-headless.ts +27 -0
- package/src/plugins/builtin/analytics/risk-model.ts +55 -9
- package/src/plugins/builtin/analytics/risk-pane.tsx +8 -2
- package/src/plugins/builtin/attention/index.tsx +2 -1
- package/src/plugins/builtin/attention/listing.ts +14 -0
- package/src/plugins/builtin/backtest/headless.ts +10 -5
- package/src/plugins/builtin/backtest/pane.tsx +9 -4
- package/src/plugins/builtin/backtest/presets.ts +29 -3
- package/src/plugins/builtin/broker-manager/index.tsx +10 -5
- package/src/plugins/builtin/broker-manager/model.ts +6 -1
- package/src/plugins/builtin/broker-trading/controller.ts +22 -12
- package/src/plugins/builtin/broker-trading/index.tsx +13 -1
- package/src/plugins/builtin/broker-trading/order-feed.ts +9 -4
- package/src/plugins/builtin/broker-trading/pane.tsx +1 -1
- package/src/plugins/builtin/buildout/cells.tsx +12 -4
- package/src/plugins/builtin/buildout/format.ts +38 -0
- package/src/plugins/builtin/buildout/model/normalizers.ts +36 -1
- package/src/plugins/builtin/buildout/pane/index.tsx +4 -1
- package/src/plugins/builtin/buildout/table-model.ts +23 -2
- package/src/plugins/builtin/builtin-plugin-meta.ts +7 -3
- package/src/plugins/builtin/catalysts/model.ts +2 -1
- package/src/plugins/builtin/changelog/index.tsx +9 -6
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +6 -1
- package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +1 -1
- package/src/plugins/builtin/chart-composer/cli-options.ts +9 -5
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +12 -2
- package/src/plugins/builtin/chart-composer/editor/controller.ts +4 -2
- package/src/plugins/builtin/chart-composer/editor/model.ts +2 -0
- package/src/plugins/builtin/chart-composer/editor.tsx +7 -5
- package/src/plugins/builtin/chart-composer/formula.ts +71 -18
- package/src/plugins/builtin/chart-composer/headless-schema.ts +21 -4
- package/src/plugins/builtin/chart-composer/headless.ts +19 -3
- package/src/plugins/builtin/chart-composer/index.tsx +1 -1
- package/src/plugins/builtin/chart-composer/pane.tsx +53 -9
- package/src/plugins/builtin/chart-composer/presets.ts +50 -15
- package/src/plugins/builtin/chart-composer/quick-add.tsx +40 -25
- package/src/plugins/builtin/chart-composer/session-history.ts +18 -9
- package/src/plugins/builtin/chart-composer/settings.ts +27 -0
- package/src/plugins/builtin/chart-composer/use-series-catalog.ts +40 -26
- package/src/plugins/builtin/chat/content/command-suggestions.ts +93 -0
- package/src/plugins/builtin/chat/content/composer.tsx +13 -6
- package/src/plugins/builtin/chat/content/footer.tsx +6 -3
- package/src/plugins/builtin/chat/content/index.tsx +50 -21
- package/src/plugins/builtin/chat/content/open-targets.ts +14 -3
- package/src/plugins/builtin/chat/controller/session-runtime.ts +4 -2
- package/src/plugins/builtin/chat/index.tsx +23 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +1 -0
- package/src/plugins/builtin/chat/message/inline-tokens.tsx +23 -0
- package/src/plugins/builtin/chat/message/pane-chip.tsx +50 -20
- package/src/plugins/builtin/chat/pane-links/commands.ts +271 -0
- package/src/plugins/builtin/chat/pane-links/model.ts +12 -3
- package/src/plugins/builtin/chat/pane-links/open.ts +8 -1
- package/src/plugins/builtin/chat/unread-inbox-pane.tsx +10 -1
- package/src/plugins/builtin/clinical-trials/model.ts +0 -9
- package/src/plugins/builtin/clinical-trials/pane.tsx +15 -22
- package/src/plugins/builtin/clinical-trials/sponsor-tickers.ts +8 -6
- package/src/plugins/builtin/cloud/askg/manifest.ts +2 -0
- package/src/plugins/builtin/cloud/plugin.tsx +1 -1
- package/src/plugins/builtin/company-attention/building.tsx +5 -1
- package/src/plugins/builtin/company-attention/client.ts +8 -9
- package/src/plugins/builtin/company-attention/evidence.ts +4 -1
- package/src/plugins/builtin/company-attention/moves.tsx +5 -1
- package/src/plugins/builtin/company-attention/pane.tsx +9 -2
- package/src/plugins/builtin/company-attention/signals.tsx +5 -1
- package/src/plugins/builtin/correlation/headless.ts +13 -5
- package/src/plugins/builtin/correlation/history.ts +22 -0
- package/src/plugins/builtin/cot/client.ts +22 -18
- package/src/plugins/builtin/cot/headless.ts +15 -10
- package/src/plugins/builtin/cot/model.ts +14 -1
- package/src/plugins/builtin/cot/pane.tsx +22 -14
- package/src/plugins/builtin/credit-boards/client.ts +6 -10
- package/src/plugins/builtin/credit-conditions/headless.ts +8 -2
- package/src/plugins/builtin/credit-conditions/index.tsx +5 -1
- package/src/plugins/builtin/credit-conditions/model.ts +4 -0
- package/src/plugins/builtin/credit-conditions/series.ts +3 -1
- package/src/plugins/builtin/credit-documents/detail.tsx +2 -2
- package/src/plugins/builtin/credit-documents/export.ts +173 -0
- package/src/plugins/builtin/credit-documents/headless.ts +7 -7
- package/src/plugins/builtin/credit-documents/model.ts +104 -14
- package/src/plugins/builtin/credit-documents/pane.tsx +12 -5
- package/src/plugins/builtin/custom-view/sources.ts +2 -0
- package/src/plugins/builtin/dividend-yield/client.ts +131 -23
- package/src/plugins/builtin/dividend-yield/headless.ts +44 -16
- package/src/plugins/builtin/dividend-yield/model.ts +8 -5
- package/src/plugins/builtin/dividend-yield/pane.tsx +38 -13
- package/src/plugins/builtin/dividend-yield/ranking.ts +37 -14
- package/src/plugins/builtin/dividend-yield/types.ts +20 -2
- package/src/plugins/builtin/dividend-yield/view.ts +30 -2
- package/src/plugins/builtin/docs/targets.ts +5 -1
- package/src/plugins/builtin/earnings/board-model.ts +16 -15
- package/src/plugins/builtin/earnings/board.tsx +62 -71
- package/src/plugins/builtin/earnings/headless.ts +40 -4
- package/src/plugins/builtin/earnings/scope.ts +31 -43
- package/src/plugins/builtin/earnings-calls/calendar.tsx +2 -2
- package/src/plugins/builtin/earnings-calls/format.ts +31 -2
- package/src/plugins/builtin/earnings-calls/headless.ts +7 -2
- package/src/plugins/builtin/earnings-calls/model.ts +6 -1
- package/src/plugins/builtin/earnings-calls/pane.tsx +5 -4
- package/src/plugins/builtin/econ/calendar-model.ts +14 -9
- package/src/plugins/builtin/econ/figures.ts +72 -0
- package/src/plugins/builtin/econ/index.tsx +33 -3
- package/src/plugins/builtin/econ/types.ts +4 -0
- package/src/plugins/builtin/econ-statistics/defs.ts +6 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +85 -35
- package/src/plugins/builtin/econ-statistics/stats.ts +37 -9
- package/src/plugins/builtin/econ-statistics/view.ts +3 -0
- package/src/plugins/builtin/equity-screener/categories.ts +179 -0
- package/src/plugins/builtin/equity-screener/client.ts +4 -2
- package/src/plugins/builtin/equity-screener/headless.ts +144 -13
- package/src/plugins/builtin/equity-screener/ideas.ts +49 -0
- package/src/plugins/builtin/equity-screener/model.ts +99 -10
- package/src/plugins/builtin/equity-screener/pane.tsx +70 -15
- package/src/plugins/builtin/exposure/charts.tsx +2 -2
- package/src/plugins/builtin/exposure/model.ts +13 -1
- package/src/plugins/builtin/exposure/pane.tsx +4 -4
- package/src/plugins/builtin/fixed-income/pane.tsx +2 -1
- package/src/plugins/builtin/futures/index.tsx +1 -0
- package/src/plugins/builtin/futures/model.ts +2 -1
- package/src/plugins/builtin/futures/table.tsx +2 -2
- package/src/plugins/builtin/futures/use-board-terms.ts +42 -28
- package/src/plugins/builtin/futures/use-front-returns.ts +45 -28
- package/src/plugins/builtin/fx-matrix/client.ts +11 -3
- package/src/plugins/builtin/fx-matrix/headless.ts +6 -3
- package/src/plugins/builtin/fx-matrix/index.tsx +16 -4
- package/src/plugins/builtin/fx-matrix/live-legs.ts +54 -3
- package/src/plugins/builtin/gpu/headless.ts +8 -2
- package/src/plugins/builtin/help/function-index.ts +4 -1
- package/src/plugins/builtin/help/index.tsx +1 -0
- package/src/plugins/builtin/help/keybindings-editor.tsx +18 -14
- package/src/plugins/builtin/help/shortcut-model.ts +1 -1
- package/src/plugins/builtin/holders/fund-holders.ts +51 -0
- package/src/plugins/builtin/holders/headless.ts +18 -1
- package/src/plugins/builtin/iv-history/client.ts +52 -11
- package/src/plugins/builtin/iv-history/format.ts +36 -23
- package/src/plugins/builtin/iv-history/headless.ts +36 -18
- package/src/plugins/builtin/iv-history/index.tsx +2 -2
- package/src/plugins/builtin/iv-history/model.ts +163 -27
- package/src/plugins/builtin/iv-history/pane.tsx +10 -6
- package/src/plugins/builtin/iv-history/screen-pane.tsx +22 -15
- package/src/plugins/builtin/iv-history/universe.ts +5 -1
- package/src/plugins/builtin/jobs/client.ts +25 -29
- package/src/plugins/builtin/kelly-sizer/model.ts +12 -8
- package/src/plugins/builtin/kelly-sizer/pane.tsx +9 -9
- package/src/plugins/builtin/kelly-sizer/sections.tsx +19 -10
- package/src/plugins/builtin/kelly-sizer/types.ts +10 -4
- package/src/plugins/builtin/macro-day/pane.tsx +7 -5
- package/src/plugins/builtin/macro-day/release-table.ts +2 -2
- package/src/plugins/builtin/market-heatmap/data.ts +8 -33
- package/src/plugins/builtin/market-movers/client.ts +25 -7
- package/src/plugins/builtin/market-movers/footer.ts +2 -2
- package/src/plugins/builtin/market-movers/headless.ts +32 -12
- package/src/plugins/builtin/market-movers/index.tsx +26 -14
- package/src/plugins/builtin/market-movers/min-float.ts +74 -0
- package/src/plugins/builtin/market-movers/model.ts +4 -1
- package/src/plugins/builtin/market-movers/screener.ts +14 -0
- package/src/plugins/builtin/market-movers/session-body.tsx +13 -8
- package/src/plugins/builtin/market-movers/session-table.ts +4 -3
- package/src/plugins/builtin/market-movers/table.ts +17 -5
- package/src/plugins/builtin/members/breadth-pane.tsx +82 -0
- package/src/plugins/builtin/members/client.ts +19 -4
- package/src/plugins/builtin/members/headless.ts +20 -7
- package/src/plugins/builtin/members/index.tsx +9 -9
- package/src/plugins/builtin/members/model.ts +23 -4
- package/src/plugins/builtin/members/pane.tsx +25 -15
- package/src/plugins/builtin/news/index.tsx +1 -0
- package/src/plugins/builtin/news/wire/categories.ts +19 -3
- package/src/plugins/builtin/news/wire/industry-pane.tsx +1 -0
- package/src/plugins/builtin/news/wire/news/footer.ts +31 -5
- package/src/plugins/builtin/news/wire/news/preset-pane.tsx +6 -1
- package/src/plugins/builtin/news/wire/news/table.tsx +2 -2
- package/src/plugins/builtin/openfda/client.ts +14 -2
- package/src/plugins/builtin/openfda/index.tsx +3 -2
- package/src/plugins/builtin/openfda/model.ts +9 -0
- package/src/plugins/builtin/openfda/pane.tsx +42 -6
- package/src/plugins/builtin/options/analytics.ts +54 -6
- package/src/plugins/builtin/options/enrichment.ts +17 -5
- package/src/plugins/builtin/options/model-spot.ts +5 -2
- package/src/plugins/builtin/options/strike-window.ts +2 -1
- package/src/plugins/builtin/options/table.ts +6 -9
- package/src/plugins/builtin/options/types.ts +2 -0
- package/src/plugins/builtin/options/view.tsx +42 -12
- package/src/plugins/builtin/options-positioning/client.ts +30 -0
- package/src/plugins/builtin/options-positioning/headless.ts +74 -21
- package/src/plugins/builtin/options-positioning/index.tsx +4 -4
- package/src/plugins/builtin/options-positioning/model.ts +122 -14
- package/src/plugins/builtin/options-positioning/pane.tsx +87 -42
- package/src/plugins/builtin/options-scenario/client.ts +116 -47
- package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +142 -10
- package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +206 -55
- package/src/plugins/builtin/options-scenario/csp-screen.ts +63 -23
- package/src/plugins/builtin/options-scenario/csp.ts +8 -2
- package/src/plugins/builtin/options-scenario/index.tsx +9 -7
- package/src/plugins/builtin/options-scenario/strategy-screen.ts +532 -0
- package/src/plugins/builtin/pe-band/model.ts +12 -49
- package/src/plugins/builtin/perps/cascade-tabs.tsx +161 -0
- package/src/plugins/builtin/perps/cascade.ts +236 -0
- package/src/plugins/builtin/perps/client.ts +56 -2
- package/src/plugins/builtin/perps/freshness.ts +12 -10
- package/src/plugins/builtin/perps/headless.ts +65 -9
- package/src/plugins/builtin/perps/index.tsx +7 -5
- package/src/plugins/builtin/perps/live-rows.ts +10 -3
- package/src/plugins/builtin/perps/model.ts +18 -4
- package/src/plugins/builtin/perps/pane.tsx +32 -31
- package/src/plugins/builtin/perps/status-line.ts +25 -0
- package/src/plugins/builtin/plugin-module.ts +5 -1
- package/src/plugins/builtin/portfolio-list/cached-account.ts +3 -1
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +2 -8
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +4 -4
- package/src/plugins/builtin/portfolio-list/cli/render.ts +12 -7
- package/src/plugins/builtin/portfolio-list/headless.ts +1 -1
- package/src/plugins/builtin/portfolio-list/pane/futures-front.ts +40 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +4 -1
- package/src/plugins/builtin/portfolio-list/pane/streaming.ts +5 -2
- package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +3 -2
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +3 -1
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +11 -8
- package/src/plugins/builtin/portfolio-list/table.tsx +11 -3
- package/src/plugins/builtin/primary-dealers/client.ts +13 -38
- package/src/plugins/builtin/rate-path/pane.tsx +2 -2
- package/src/plugins/builtin/realized-vol/index.tsx +2 -2
- package/src/plugins/builtin/realized-vol/pane.tsx +3 -3
- package/src/plugins/builtin/relative-rotation/client.ts +18 -4
- package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
- package/src/plugins/builtin/relative-rotation/index.tsx +2 -1
- package/src/plugins/builtin/relative-rotation/model.ts +16 -40
- package/src/plugins/builtin/relative-rotation/pane.tsx +3 -2
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +3 -2
- package/src/plugins/builtin/research/event-model.ts +10 -8
- package/src/plugins/builtin/research/headless.ts +1 -1
- package/src/plugins/builtin/research/relative-valuation-headless.ts +5 -1
- package/src/plugins/builtin/research/relative-valuation-model.ts +31 -3
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +11 -9
- package/src/plugins/builtin/reverse-dcf/headless.ts +5 -3
- package/src/plugins/builtin/reverse-dcf/model.ts +61 -6
- package/src/plugins/builtin/reverse-dcf/pane.tsx +7 -4
- package/src/plugins/builtin/scanner/feed.ts +2 -2
- package/src/plugins/builtin/scanner/flow-model.ts +50 -4
- package/src/plugins/builtin/scanner/flow-pane.tsx +367 -65
- package/src/plugins/builtin/scanner/flow-session.ts +146 -0
- package/src/plugins/builtin/scanner/headless.ts +204 -35
- package/src/plugins/builtin/scanner/index.ts +40 -6
- package/src/plugins/builtin/scanner/live-condition-editor.tsx +222 -0
- package/src/plugins/builtin/scanner/live-feed.ts +168 -0
- package/src/plugins/builtin/scanner/live-headless.ts +138 -0
- package/src/plugins/builtin/scanner/live-model.ts +362 -0
- package/src/plugins/builtin/scanner/live-pane.tsx +677 -0
- package/src/plugins/builtin/scanner/live-track.ts +186 -0
- package/src/plugins/builtin/scanner/lock-note.ts +3 -2
- package/src/plugins/builtin/seasonality/headless.ts +10 -1
- package/src/plugins/builtin/sec/fund-facts-view.tsx +5 -2
- package/src/plugins/builtin/sec/fund-facts.ts +116 -34
- package/src/plugins/builtin/sec/headless.ts +2 -1
- package/src/plugins/builtin/series-inventory.ts +3 -0
- package/src/plugins/builtin/shared/cloud-resource.ts +3 -2
- package/src/plugins/builtin/shared/cloud-upgrade.ts +4 -3
- package/src/plugins/builtin/shared/earnings-calendar.ts +6 -2
- package/src/plugins/builtin/shared/earnings-report.ts +2 -2
- package/src/plugins/builtin/shared/job-posting.ts +1 -0
- package/src/plugins/builtin/shared/macro-releases.ts +65 -0
- package/src/plugins/builtin/shared/members-menu.tsx +3 -2
- package/src/plugins/builtin/shared/pro-lock-note.ts +12 -12
- package/src/plugins/builtin/shared/report-freshness.ts +3 -2
- package/src/plugins/builtin/shared/scanner-capture.ts +3 -0
- package/src/plugins/builtin/shared/ticker-choice.tsx +2 -1
- package/src/plugins/builtin/shared/ticker-company.ts +77 -0
- package/src/plugins/builtin/shared/use-quote-board.ts +10 -3
- package/src/plugins/builtin/shared/volatility/live-session.ts +34 -8
- package/src/plugins/builtin/shared/volatility/pricing.ts +26 -1
- package/src/plugins/builtin/shared/wall-view-lifecycle.ts +3 -1
- package/src/plugins/builtin/themes/headless.ts +6 -4
- package/src/plugins/builtin/themes/model.ts +17 -8
- package/src/plugins/builtin/themes/pane.tsx +7 -7
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +43 -18
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +3 -2
- package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +62 -0
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +83 -46
- package/src/plugins/builtin/ticker-detail/headless.ts +31 -16
- package/src/plugins/builtin/ticker-detail/overview/model.ts +1 -1
- package/src/plugins/builtin/ticker-detail/pane.tsx +3 -2
- package/src/plugins/builtin/ticker-detail/quote-footer.ts +6 -1
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -1
- package/src/plugins/builtin/ticker-detail/settings.ts +1 -0
- package/src/plugins/builtin/time-sales/pane.tsx +31 -19
- package/src/plugins/builtin/treasury-daily/client.ts +41 -5
- package/src/plugins/builtin/treasury-daily/headless.ts +2 -2
- package/src/plugins/builtin/treasury-daily/index.tsx +1 -1
- package/src/plugins/builtin/treasury-daily/model.ts +50 -3
- package/src/plugins/builtin/treasury-daily/pane.tsx +81 -2
- package/src/plugins/builtin/vol-surface/charts.tsx +9 -4
- package/src/plugins/builtin/vol-surface/client.ts +9 -17
- package/src/plugins/builtin/vol-surface/headless.ts +63 -14
- package/src/plugins/builtin/vol-surface/index.tsx +2 -2
- package/src/plugins/builtin/vol-surface/model.ts +22 -7
- package/src/plugins/builtin/vol-surface/pane.tsx +48 -9
- package/src/plugins/builtin/vol-surface/tables.ts +31 -3
- package/src/plugins/builtin/volatility/dvol.ts +46 -0
- package/src/plugins/builtin/volatility/index.tsx +2 -2
- package/src/plugins/builtin/volatility/pane.tsx +4 -4
- package/src/plugins/builtin/volatility/series.ts +26 -0
- package/src/plugins/builtin/world-indices/footer.ts +1 -1
- package/src/plugins/builtin/world-venue-map/headless.ts +3 -3
- package/src/plugins/catalog-browser.ts +13 -8
- package/src/plugins/catalog-manifest.ts +2 -1
- package/src/plugins/marketplace/model.ts +18 -5
- package/src/portfolio/column-values.ts +5 -5
- package/src/portfolio/futures-positions.ts +6 -3
- package/src/portfolio/position-quantity.ts +15 -9
- package/src/public/__snapshots__/public-api.test.ts.snap +1 -0
- package/src/remote/resources.ts +2 -1
- package/src/renderers/browser/app-services.ts +1 -7
- package/src/renderers/browser/config-host.ts +2 -55
- package/src/renderers/browser/main.tsx +7 -57
- package/src/renderers/dom/data-table/row.tsx +26 -0
- package/src/renderers/dom/desktop/list-view.tsx +13 -10
- package/src/renderers/dom/desktop/query-bar.tsx +4 -2
- package/src/renderers/dom/desktop/select-field.tsx +4 -2
- package/src/renderers/dom/host/chart-surface.tsx +21 -0
- package/src/renderers/electrobun/bun/desktop/app-name.ts +222 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +29 -7
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +7 -0
- package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -0
- package/src/renderers/electrobun/bun/desktop/relaunch.ts +74 -25
- package/src/renderers/electrobun/bun/desktop/state-broadcaster.ts +1 -0
- package/src/renderers/electrobun/bun/desktop/update.ts +173 -5
- package/src/renderers/electrobun/bun/desktop/view-ids.ts +52 -0
- package/src/renderers/electrobun/bun/desktop/workspace/index.ts +2 -0
- package/src/renderers/electrobun/bun/index.ts +25 -1
- package/src/renderers/electrobun/shared/app-name.ts +30 -0
- package/src/renderers/electrobun/shared/protocol.ts +10 -0
- package/src/renderers/electrobun/view/backend-rpc.ts +6 -0
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +3 -3
- package/src/renderers/electrobun/view/desktop/window/snapshot.ts +1 -0
- package/src/renderers/electrobun/view/main.tsx +24 -1
- package/src/renderers/electrobun/view/news-source.ts +3 -1
- package/src/renderers/electrobun/view/remote/ticker-repository.ts +14 -7
- package/src/renderers/electrobun/view/view-ids.ts +85 -0
- package/src/renderers/opentui/start.tsx +5 -0
- package/src/renderers/opentui/toast-host.tsx +71 -43
- package/src/series/registry.ts +1 -0
- package/src/series/types.ts +6 -0
- package/src/series/validate.ts +1 -0
- package/src/sources/gloomberb-cloud/index.ts +1 -0
- package/src/sources/gloomberb-cloud/news.ts +47 -7
- package/src/sources/gloomberb-cloud/normalizers.ts +2 -0
- package/src/sources/provider-router/batches.ts +10 -2
- package/src/sources/provider-router/financial-routes.ts +3 -3
- package/src/sources/provider-router/financials.ts +15 -3
- package/src/sources/provider-router/history.ts +28 -7
- package/src/sources/provider-router/index.ts +149 -10
- package/src/sources/provider-router/search.ts +13 -2
- package/src/state/app/context/index.tsx +3 -0
- package/src/state/ticker-cleanup.ts +50 -0
- package/src/sync/auth-transition.ts +19 -9
- package/src/sync/baseline.ts +10 -4
- package/src/sync/controller.ts +70 -19
- package/src/sync/core-contributors.ts +90 -31
- package/src/sync/react.ts +4 -1
- package/src/sync/types.ts +3 -0
- package/src/telemetry/stall-reports-dom.ts +38 -0
- package/src/telemetry/stall-reports-node.ts +75 -0
- package/src/telemetry/stall-reports.ts +214 -0
- package/src/telemetry/usage-counts.ts +0 -18
- package/src/test-support/preload.ts +14 -0
- package/src/theme/colors.ts +8 -0
- package/src/theme/themes.ts +10 -0
- package/src/tickers/company-name.ts +103 -3
- package/src/tickers/listing-venues.ts +38 -3
- package/src/tickers/search/bare-symbol.ts +36 -0
- package/src/tickers/search/index.ts +36 -7
- package/src/tickers/search/ranking.ts +10 -1
- package/src/tickers/search/types.ts +5 -0
- package/src/tickers/terminal-codes.ts +19 -0
- package/src/time-series/alignment.ts +1 -1
- package/src/time-series/base-series.ts +13 -5
- package/src/time-series/daily-valuation.ts +62 -0
- package/src/time-series/economic.ts +18 -4
- package/src/time-series/field-catalog.ts +2 -4
- package/src/time-series/filed-trailing-eps.ts +197 -0
- package/src/time-series/forward-valuation.ts +32 -0
- package/src/time-series/fundamentals.ts +198 -7
- package/src/time-series/hooks.ts +1 -0
- package/src/time-series/ice-credit.ts +3 -0
- package/src/time-series/price-comparison.ts +30 -2
- package/src/time-series/price-units.ts +72 -2
- package/src/time-series/resolve-context.ts +7 -1
- package/src/time-series/resolve.ts +116 -15
- package/src/time-series/series-presentation.ts +40 -6
- package/src/time-series/session-bar.ts +11 -0
- package/src/time-series/spec.ts +5 -3
- package/src/time-series/studies.ts +278 -74
- package/src/time-series/total-return.ts +160 -0
- package/src/time-series/transforms.ts +3 -3
- package/src/time-series/types.ts +27 -1
- package/src/time-series/valuation-releases.ts +39 -0
- package/src/types/data-provider.ts +9 -1
- package/src/types/desktop-window.ts +2 -0
- package/src/types/financials.ts +73 -2
- package/src/types/headless.ts +61 -5
- package/src/types/instrument.ts +3 -0
- package/src/types/news-source.ts +1 -0
- package/src/types/plugin.ts +10 -1
- package/src/ui/host.tsx +3 -0
- package/src/updater/command-names.ts +12 -7
- package/src/updater/failure.ts +4 -1
- package/src/utils/cli-output.ts +42 -1
- package/src/utils/crypto-pair.ts +44 -0
- package/src/utils/financial-statements.ts +6 -1
- package/src/utils/forward-dividend.ts +2 -0
- package/src/utils/fundamentals.ts +24 -3
- package/src/utils/fx-market-hours.ts +26 -3
- package/src/utils/main-thread-stall.ts +35 -2
- package/src/utils/market-capitalization.ts +24 -1
- package/src/utils/network-failure.ts +9 -6
- package/src/utils/option-expiry.ts +48 -1
- package/src/utils/options.ts +10 -0
- package/src/utils/plugin-proxy-hosts.json +1 -0
- package/src/utils/price-history.ts +12 -1
- package/src/utils/shell-word.ts +8 -0
- package/src/utils/trailing-dividend.ts +53 -4
- package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +0 -17
- package/src/renderers/browser/first-screen.ts +0 -193
|
@@ -86,6 +86,7 @@ const STREAM_QUOTE_MAX_SILENCE_MS = 75_000;
|
|
|
86
86
|
const uncertainPlacement = "Outcome unknown. Check open orders before placing it again.";
|
|
87
87
|
/** A change or cancel whose answer was lost: the views ask the broker until it says. */
|
|
88
88
|
const uncertainChange = "Outcome unknown. Checking with the broker.";
|
|
89
|
+
const orderReadFailed = "Order status could not be read. Showing the last known order.";
|
|
89
90
|
/** The broker's own words come first: they say more than "outcome unknown". */
|
|
90
91
|
const uncertainAfter = (error: unknown) => error instanceof Error && error.message && !error.message.includes(uncertainPlacement) ? `${error.message.trim().replace(/\.?$/, ".")} ${uncertainPlacement}` : uncertainPlacement;
|
|
91
92
|
/** The broker answered no, or nothing was sent (see BrokerAdapter.placeOrder): its one-line reason, else undefined. */
|
|
@@ -639,7 +640,7 @@ export class BrokerTradingController {
|
|
|
639
640
|
&& value.contract.symbol === order.contract.symbol && (value.orderId === order.orderId || sameOrder(value, order)));
|
|
640
641
|
} catch (error) {
|
|
641
642
|
logFailure("broker-trading.controller", "Look up broker order failed")(error);
|
|
642
|
-
|
|
643
|
+
throw new Error(orderReadFailed);
|
|
643
644
|
}
|
|
644
645
|
}
|
|
645
646
|
|
|
@@ -651,7 +652,10 @@ export class BrokerTradingController {
|
|
|
651
652
|
*/
|
|
652
653
|
private async settleRefusal(order: BrokerOrder, reason: string, action: "modify" | "cancel"): Promise<void> {
|
|
653
654
|
const brokerName = this.context(false).context.adapter.name;
|
|
654
|
-
|
|
655
|
+
let current: BrokerOrder | undefined;
|
|
656
|
+
let readFailed = false;
|
|
657
|
+
try { current = await this.lookup(order); }
|
|
658
|
+
catch { readFailed = true; reason = `${reason}. ${orderReadFailed}`; }
|
|
655
659
|
if (this.disposed) return;
|
|
656
660
|
const now = current ?? order;
|
|
657
661
|
const label = brokerOrderStatus(now.status);
|
|
@@ -662,7 +666,7 @@ export class BrokerTradingController {
|
|
|
662
666
|
this.publish({ phase: "editing", review: undefined, receipt: undefined, error: reason });
|
|
663
667
|
return;
|
|
664
668
|
}
|
|
665
|
-
this.publish({ phase: "result", cancelOrder: undefined, review: undefined, result: copy(now), resultQuantities: current ? "confirmed" : "last-known", error: undefined });
|
|
669
|
+
this.publish({ phase: "result", cancelOrder: undefined, review: undefined, result: copy(now), resultQuantities: current ? "confirmed" : "last-known", error: readFailed ? reason : undefined });
|
|
666
670
|
const title = ended ? label === "Rejected" ? reason : `Already ${label.toLowerCase()}` : changed ? `Order changed in ${brokerName}, refreshed` : reason;
|
|
667
671
|
this.options.onOutcome?.({ title, type: ended || changed ? "info" : "error", order: copy(now) });
|
|
668
672
|
}
|
|
@@ -677,16 +681,22 @@ export class BrokerTradingController {
|
|
|
677
681
|
async refreshResult(): Promise<void> {
|
|
678
682
|
const result = this.snapshot.result;
|
|
679
683
|
if (!result) return;
|
|
680
|
-
const { context } = this.context(false);
|
|
681
|
-
if (!context.adapter.listOpenOrders && !context.adapter.getOrderStatus) throw new Error("Refresh this order in your broker.");
|
|
682
684
|
const fingerprint = this.key();
|
|
683
|
-
const
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
685
|
+
const stillCurrent = () => !this.disposed && fingerprint === this.key() && this.snapshot.result === result;
|
|
686
|
+
try {
|
|
687
|
+
const { context } = this.context(false);
|
|
688
|
+
if (!context.adapter.listOpenOrders && !context.adapter.getOrderStatus) throw new Error("Refresh this order in your broker.");
|
|
689
|
+
const orders = context.adapter.getOrderStatus && result.orderId !== 0
|
|
690
|
+
? [await context.adapter.getOrderStatus(context.instance, result.orderId)].filter((order): order is BrokerOrder => order !== null)
|
|
691
|
+
: await context.adapter.listOpenOrders?.(context.instance) ?? [];
|
|
692
|
+
if (!stillCurrent()) return;
|
|
693
|
+
const current = orders.find((order) => order.accountId === result.accountId && order.contract.symbol === result.contract.symbol && sameOrder(order, result));
|
|
694
|
+
if (current) this.publish({ result: copy(current), resultQuantities: "confirmed", error: current.status === "UNKNOWN" ? uncertainChange : undefined });
|
|
695
|
+
// Absence from open orders does not prove a fill, rejection or cancellation, or clear a read failure.
|
|
696
|
+
} catch {
|
|
697
|
+
if (stillCurrent()) this.publish({ error: orderReadFailed, resultQuantities: this.snapshot.resultQuantities === "unconfirmed" ? "unconfirmed" : "last-known" });
|
|
698
|
+
throw new Error(orderReadFailed);
|
|
699
|
+
}
|
|
690
700
|
}
|
|
691
701
|
|
|
692
702
|
/**
|
|
@@ -32,7 +32,19 @@ export const brokerTradingModule: PluginModule = {
|
|
|
32
32
|
}],
|
|
33
33
|
setup(ctx) {
|
|
34
34
|
brokerOrderFeed.setNotifier((notification) => { ctx.notify(notification); });
|
|
35
|
-
brokerOrderFeed.setPositionSync((instanceId) =>
|
|
35
|
+
brokerOrderFeed.setPositionSync(async (instanceId) => {
|
|
36
|
+
try {
|
|
37
|
+
await ctx.syncBrokerInstance(instanceId);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
ctx.notify({
|
|
40
|
+
title: "Position sync failed",
|
|
41
|
+
body: "The fill was received, but positions could not be synced. Use Sync in Brokers to retry.",
|
|
42
|
+
type: "error",
|
|
43
|
+
action: { label: "Brokers", onClick: () => ctx.showPane("brokers") },
|
|
44
|
+
});
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
36
48
|
let held = new Map<string, { key: string; release(): void }>();
|
|
37
49
|
// A broker registered by a later plugin, or a profile added or edited, is held from then on.
|
|
38
50
|
const holdProfiles = () => {
|
|
@@ -225,20 +225,24 @@ class ProfileOrderFeed {
|
|
|
225
225
|
}
|
|
226
226
|
// A working order missing from the list ended somehow; only the broker can say how.
|
|
227
227
|
const missing = [...this.orders].filter(([key, order]) => !listed.has(key) && !brokerOrderDone(order.status));
|
|
228
|
+
let failed = false;
|
|
228
229
|
for (const [key, order] of missing) {
|
|
229
230
|
// A broker with no status read says nothing beyond its open list.
|
|
230
231
|
if (!this.broker.getOrderStatus) { this.orders.delete(key); continue; }
|
|
231
|
-
const status = await this.broker.getOrderStatus(this.instance, order.orderId).catch(
|
|
232
|
+
const status = await this.broker.getOrderStatus(this.instance, order.orderId).catch((error) => {
|
|
233
|
+
logFailure("broker-trading.order-feed", "Read missing broker order status failed")(error);
|
|
234
|
+
failed = true;
|
|
235
|
+
});
|
|
232
236
|
if (generation !== this.generation) return;
|
|
233
237
|
if (status) this.apply(status, baseline ? "baseline" : "poll", false);
|
|
234
238
|
// Null is the broker unable to confirm it, not an end: keep it, unconfirmed, at its last report's time,
|
|
235
239
|
// so the next read that lists it or a status that answers replaces it.
|
|
236
240
|
else if (status === null && brokerOrderStatus(order.status) !== "UNKNOWN") this.apply({ ...order, status: "UNKNOWN" }, baseline ? "baseline" : "poll", false);
|
|
237
241
|
}
|
|
238
|
-
this.failures = 0;
|
|
242
|
+
this.failures = failed ? this.failures + 1 : 0;
|
|
239
243
|
this.baselined = true;
|
|
240
244
|
this.prune();
|
|
241
|
-
this.publish({ failed
|
|
245
|
+
this.publish({ failed, loaded: true });
|
|
242
246
|
} catch {
|
|
243
247
|
if (generation === this.generation) { this.failures++; this.publish({ failed: true, loaded: true }); }
|
|
244
248
|
} finally {
|
|
@@ -275,7 +279,8 @@ class ProfileOrderFeed {
|
|
|
275
279
|
|
|
276
280
|
private publish(changes: Partial<BrokerOrderFeedState> = {}): void {
|
|
277
281
|
const orders = [...this.orders.values()].sort((a, b) => b.updatedAt - a.updatedAt);
|
|
278
|
-
|
|
282
|
+
const failed = changes.failed ?? this.state.failed;
|
|
283
|
+
this.state = Object.freeze({ ...this.state, ...changes, orders, live: this.live, updatedAt: failed ? this.state.updatedAt : Date.now(), fills: this.feed.fillCount(this.instance.id) });
|
|
279
284
|
this.feed.changed();
|
|
280
285
|
}
|
|
281
286
|
}
|
|
@@ -480,7 +480,7 @@ function ProfileTicket({ broker, instance, contract, width, height, focused, ord
|
|
|
480
480
|
accountType: accounts.find((account) => account.accountId === accountId)?.accountType,
|
|
481
481
|
quote: state.quote?.quote, quoteStale: state.quote?.stale, legQuotes: state.quote?.legs, quoteData: connection?.quoteData,
|
|
482
482
|
phase: page === "enable" ? "enable" : state.phase, draft: receipt?.request ?? draft, preview: state.review?.preview ?? receipt?.preview, warnings: state.review?.warnings ?? [], result: state.result, resultQuantities: state.resultQuantities,
|
|
483
|
-
error: connection?.state === "error" && connection.message ? connection.message : error ?? state.error, reconnecting,
|
|
483
|
+
error: connection?.state === "error" && connection.message ? connection.message : error ?? state.error ?? (orderFeed.failed ? "Order status could not be read. Showing the last known orders." : undefined), reconnecting,
|
|
484
484
|
position: position?.quantity, avgCost: position?.avgCost, positionPnl: position?.pnl, tradingEnabled: caps?.enabled === true,
|
|
485
485
|
typedConfirmation: typed, connected, capabilities: caps, modifying: state.modifying, original: state.modifying ? controller.modifyingOrder() : undefined, defaultPriceLabel, confirmOrders: state.confirmOrders,
|
|
486
486
|
initialFocus: focusReview ? "review" : state.modifying ? draft?.orderType === "STP" ? "stopPrice" : draft?.orderType === "TRAIL" ? "trailing" : "limitPrice" : focusRevision ? "review" : undefined,
|
|
@@ -12,11 +12,19 @@ import {
|
|
|
12
12
|
activityLabel,
|
|
13
13
|
criticalityColor,
|
|
14
14
|
metricColor,
|
|
15
|
+
moneyAmount,
|
|
16
|
+
moneyText,
|
|
15
17
|
text,
|
|
16
18
|
tickerSymbol,
|
|
17
19
|
} from "./format";
|
|
18
20
|
import { favoriteKey } from "./table-model";
|
|
19
21
|
|
|
22
|
+
/** A dollar figure in the compact form, with its whole number for an export. */
|
|
23
|
+
function moneyCell(value: string | null | undefined, color: string): DataTableCell {
|
|
24
|
+
const amount = moneyAmount(value);
|
|
25
|
+
return { text: moneyText(value), ...(amount == null ? {} : { value: amount }), color };
|
|
26
|
+
}
|
|
27
|
+
|
|
20
28
|
interface BuildoutCellContext {
|
|
21
29
|
favoriteBusyKey: string | null;
|
|
22
30
|
/** The row's last star did not take. */
|
|
@@ -40,7 +48,7 @@ export function renderBuildoutCell(
|
|
|
40
48
|
case "companyCount":
|
|
41
49
|
return { text: list.companyCount == null ? "-" : String(list.companyCount), color: colors.textDim };
|
|
42
50
|
case "totalMarketCap":
|
|
43
|
-
return
|
|
51
|
+
return moneyCell(list.totalMarketCap, colors.textDim);
|
|
44
52
|
case "avgSectorGrowth":
|
|
45
53
|
return { text: text(list.avgSectorGrowth), color: metricColor(list.avgSectorGrowth) };
|
|
46
54
|
case "avgReturn1y":
|
|
@@ -87,16 +95,16 @@ export function renderBuildoutCell(
|
|
|
87
95
|
case "criticality":
|
|
88
96
|
return { text: text(company.aiCriticality), color: criticalityColor(company.aiCriticality), attributes: TextAttributes.BOLD };
|
|
89
97
|
case "marketCap":
|
|
90
|
-
return
|
|
98
|
+
return moneyCell(company.marketCap, colors.textDim);
|
|
91
99
|
case "revenue":
|
|
92
|
-
return
|
|
100
|
+
return moneyCell(company.revenue, colors.textDim);
|
|
93
101
|
case "revenueGrowth":
|
|
94
102
|
return {
|
|
95
103
|
text: text(company.revenueGrowthYoy ?? company.lastQuarterGrowth),
|
|
96
104
|
color: metricColor(company.revenueGrowthYoy ?? company.lastQuarterGrowth),
|
|
97
105
|
};
|
|
98
106
|
case "netIncome":
|
|
99
|
-
return
|
|
107
|
+
return moneyCell(company.netIncome, metricColor(company.netIncome));
|
|
100
108
|
case "margin":
|
|
101
109
|
return { text: text(company.profitMargins), color: metricColor(company.profitMargins) };
|
|
102
110
|
case "forwardPE":
|
|
@@ -44,6 +44,44 @@ export function metricNumber(value: unknown): number | null {
|
|
|
44
44
|
return (negative ? -parsed : parsed) * multiplier;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/** A dollar figure as the service prints it ("$5094.1B", "$-4.9B"); anything else is not money to reformat. */
|
|
48
|
+
const DOLLAR_STRING = /^-?\$-?[\d,]*\.?\d+\s*[KMBT]?$/i;
|
|
49
|
+
|
|
50
|
+
/** The dollars in a string the service prints as money, or null for anything else. */
|
|
51
|
+
export function moneyAmount(value: unknown): number | null {
|
|
52
|
+
return typeof value === "string" && DOLLAR_STRING.test(value.trim()) ? metricNumber(value) : null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const MONEY_UNITS = [
|
|
56
|
+
{ divisor: 1e12, suffix: "T" },
|
|
57
|
+
{ divisor: 1e9, suffix: "B" },
|
|
58
|
+
{ divisor: 1e6, suffix: "M" },
|
|
59
|
+
{ divisor: 1e3, suffix: "K" },
|
|
60
|
+
] as const;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Dollars in the one compact form every TheBuildout table uses: "$5.1T",
|
|
64
|
+
* "$356.4B", "-$4.9B". The unit is picked after rounding, so $999.96B is
|
|
65
|
+
* "$1.0T" and not "$1000.0B".
|
|
66
|
+
*/
|
|
67
|
+
export function formatCompactMoney(amount: number): string {
|
|
68
|
+
const abs = Math.abs(amount);
|
|
69
|
+
let index = MONEY_UNITS.findIndex((unit) => abs >= unit.divisor);
|
|
70
|
+
let digits = index < 0 ? abs.toFixed(0) : (abs / MONEY_UNITS[index]!.divisor).toFixed(1);
|
|
71
|
+
if (index > 0 && Number(digits) >= 1000) {
|
|
72
|
+
index -= 1;
|
|
73
|
+
digits = (abs / MONEY_UNITS[index]!.divisor).toFixed(1);
|
|
74
|
+
}
|
|
75
|
+
const sign = amount < 0 && /[1-9]/.test(digits) ? "-" : "";
|
|
76
|
+
return `${sign}$${digits}${index < 0 ? "" : MONEY_UNITS[index]!.suffix}`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** A table cell's text for a dollar figure: compact when it is money, the service's own text otherwise, "-" when absent. */
|
|
80
|
+
export function moneyText(value: string | null | undefined): string {
|
|
81
|
+
const amount = moneyAmount(value);
|
|
82
|
+
return amount == null ? text(value) : formatCompactMoney(amount);
|
|
83
|
+
}
|
|
84
|
+
|
|
47
85
|
export function dateShort(value: string | null | undefined) {
|
|
48
86
|
const date = parseDisplayDate(value);
|
|
49
87
|
if (!date) return "-";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { metricNumber, textOrNull, tickerSymbol, uniqueStrings } from "../format";
|
|
1
|
+
import { metricNumber, moneyAmount, textOrNull, tickerSymbol, uniqueStrings } from "../format";
|
|
2
2
|
import type {
|
|
3
3
|
BuildoutCompany,
|
|
4
4
|
BuildoutList,
|
|
@@ -124,7 +124,42 @@ export function normalizeList(raw: RawObject): BuildoutList {
|
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
/**
|
|
128
|
+
* The statement figures a depositary receipt can carry in the issuer's
|
|
129
|
+
* reporting currency under a "$" and the receipt's USD currency: the service
|
|
130
|
+
* converts a foreign listing's figures and keeps the local ones as "...Original",
|
|
131
|
+
* but for an ADR it prints the local amounts as they are and names no currency
|
|
132
|
+
* (SK hynix's receipt shows the won revenue of its Korean listing as dollars).
|
|
133
|
+
*/
|
|
134
|
+
const STATEMENT_FIELDS = ["revenue", "netIncome", "freeCashFlow", "operatingCashFlow", "totalCash", "totalDebt", "dilutedEps"] as const;
|
|
135
|
+
|
|
136
|
+
/** A yearly figure this many times the company's whole market value is not dollars. */
|
|
137
|
+
const IMPLAUSIBLE_MULTIPLE_OF_MARKET_CAP = 10;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* A USD row with nothing converted whose revenue or net income dwarfs its own
|
|
141
|
+
* market cap has statements in another currency, and the row does not say
|
|
142
|
+
* which: the figures are left out rather than shown as wrong dollars. The
|
|
143
|
+
* ordinary range of revenue to market cap is a few times; the rows this
|
|
144
|
+
* catches sit at 15 to 4,000.
|
|
145
|
+
*/
|
|
146
|
+
function withoutUnconvertedStatements(company: BuildoutCompany): BuildoutCompany {
|
|
147
|
+
const converted = [company.revenueOriginal, company.netIncomeOriginal].some((value) => textOrNull(value) != null);
|
|
148
|
+
const usd = (company.currency?.trim().toUpperCase() || "USD") === "USD";
|
|
149
|
+
const cap = moneyAmount(company.marketCap);
|
|
150
|
+
if (converted || !usd || cap == null || cap <= 0) return company;
|
|
151
|
+
const revenue = moneyAmount(company.revenue);
|
|
152
|
+
const income = moneyAmount(company.netIncome);
|
|
153
|
+
const limit = cap * IMPLAUSIBLE_MULTIPLE_OF_MARKET_CAP;
|
|
154
|
+
if ((revenue == null || Math.abs(revenue) <= limit) && (income == null || Math.abs(income) <= limit)) return company;
|
|
155
|
+
return { ...company, ...Object.fromEntries(STATEMENT_FIELDS.map((field) => [field, null])) };
|
|
156
|
+
}
|
|
157
|
+
|
|
127
158
|
export function normalizeCompany(raw: RawObject): BuildoutCompany {
|
|
159
|
+
return withoutUnconvertedStatements(readCompany(raw));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function readCompany(raw: RawObject): BuildoutCompany {
|
|
128
163
|
const ticker = tickerSymbol(stringField(raw, "ticker"));
|
|
129
164
|
const name = stringField(raw, "name") ?? ticker ?? "Company";
|
|
130
165
|
const supplyChain = objectField(raw, "supplyChain", "supply_chain");
|
|
@@ -160,7 +160,10 @@ export function BuildoutPane({ focused, width, height }: PaneProps) {
|
|
|
160
160
|
const favoriteNotes = useRowNotes<BuildoutRow, string>(rows, { key: favoriteNoteKey });
|
|
161
161
|
const { setNote: setFavoriteNote, noteFor: favoriteNoteFor } = favoriteNotes;
|
|
162
162
|
clearFavoriteNotesRef.current = favoriteNotes.clearNotes;
|
|
163
|
-
const columns = useMemo(
|
|
163
|
+
const columns = useMemo(
|
|
164
|
+
() => columnsForTab(activeTab, selectedList, canFavorite, width),
|
|
165
|
+
[activeTab, canFavorite, selectedList, width],
|
|
166
|
+
);
|
|
164
167
|
const selectedRow = rows[selectedIndex] ?? rows[0] ?? null;
|
|
165
168
|
// The table's cells carry their own badges; this catalog only serves the open
|
|
166
169
|
// detail: its row's tickers, plus the loaded rows' tickers its text mentions.
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
BuildoutTabId,
|
|
9
9
|
SortComparable,
|
|
10
10
|
} from "./model/types";
|
|
11
|
+
import { dropColumnsToFit } from "../../../components/ui/table-layout";
|
|
11
12
|
import type { SortDirection } from "../../../utils/sort-values";
|
|
12
13
|
import { metricNumber, sourceDetailEntries, textOrNull, tickerSymbol } from "./format";
|
|
13
14
|
|
|
@@ -171,9 +172,29 @@ export function activeRows(
|
|
|
171
172
|
return state.intel.items.map((item) => ({ kind: "intel", item }));
|
|
172
173
|
}
|
|
173
174
|
|
|
174
|
-
|
|
175
|
+
/**
|
|
176
|
+
* What the Companies tab gives up when the pane is too narrow for its figures,
|
|
177
|
+
* least needed first: the descriptions, then the columns that only add to a
|
|
178
|
+
* figure already shown, instead of the right edge cutting Market Cap or a
|
|
179
|
+
* median. The star and the names stay at every width.
|
|
180
|
+
*/
|
|
181
|
+
const LIST_DROP_ORDER: readonly BuildoutColumnId[] = ["listDescription", "avgMargin", "avgReturn1y", "avgSectorGrowth"];
|
|
182
|
+
const COMPANY_DROP_ORDER: readonly BuildoutColumnId[] = [
|
|
183
|
+
"description", "employees", "dividendYield", "forwardPE", "netIncome", "margin", "sectorTech", "criticality",
|
|
184
|
+
];
|
|
185
|
+
|
|
186
|
+
/** The columns of a tab for a pane `width` cells wide; the table's scrollbar keeps its cell. */
|
|
187
|
+
export function columnsForTab(
|
|
188
|
+
activeTab: BuildoutTabId,
|
|
189
|
+
selectedList: BuildoutList | null,
|
|
190
|
+
canFavorite: boolean,
|
|
191
|
+
width: number,
|
|
192
|
+
): BuildoutColumn[] {
|
|
175
193
|
if (activeTab === "companies") {
|
|
176
|
-
|
|
194
|
+
const columns = selectedList
|
|
195
|
+
? canFavorite ? [favoriteColumn, ...companyColumns] : companyColumns
|
|
196
|
+
: listColumns;
|
|
197
|
+
return dropColumnsToFit(columns, width - 1, selectedList ? COMPANY_DROP_ORDER : LIST_DROP_ORDER);
|
|
177
198
|
}
|
|
178
199
|
if (activeTab === "sites") return canFavorite ? [favoriteColumn, ...siteColumns] : siteColumns;
|
|
179
200
|
return intelColumns;
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
// Identity of the built-in composite plugins, shared by the native catalog and
|
|
2
2
|
// the browser catalog (catalog-browser.ts). Keep this file import-free so the
|
|
3
|
-
// browser catalog can read it without pulling in native-only modules
|
|
3
|
+
// browser catalog can read it without pulling in native-only modules; the
|
|
4
|
+
// one import, ATTN's listing flag, has none of its own.
|
|
4
5
|
//
|
|
5
|
-
// Screeners & Movers
|
|
6
|
+
// Screeners & Movers and Ownership & Insiders ship fewer panes on
|
|
6
7
|
// the web, so each catalog gives them their own description rather than
|
|
7
8
|
// advertising panes they lack.
|
|
8
9
|
|
|
10
|
+
import { ATTENTION_LISTED } from "./attention/listing";
|
|
11
|
+
|
|
9
12
|
export const applicationPluginMeta = {
|
|
10
13
|
id: "application",
|
|
11
14
|
name: "Application",
|
|
@@ -116,7 +119,8 @@ export const altDataPluginMeta = {
|
|
|
116
119
|
stateId: "ticker-research",
|
|
117
120
|
name: "Supply Chain & Alt Data",
|
|
118
121
|
version: "1.0.0",
|
|
119
|
-
|
|
122
|
+
// Research attention joins once ATTN is listed again (attention/listing.ts).
|
|
123
|
+
description: `Supply chains and exposure, government awards, hiring, apps and job postings, social mentions, ${ATTENTION_LISTED ? "research attention, " : ""}GPU prices, and power queues.`,
|
|
120
124
|
toggleable: true,
|
|
121
125
|
};
|
|
122
126
|
|
|
@@ -122,11 +122,12 @@ export function catalystStatusTone(status: string): StateTone {
|
|
|
122
122
|
return STATUS_TONES.find(([pattern]) => pattern.test(text))?.[1] ?? "text";
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
/** Event types: the adverse ones amber, the binary decisions in the accent, routine rulemaking quiet. */
|
|
125
|
+
/** Event types: the adverse ones amber, the binary decisions in the accent, routine rulemaking quiet, a company's own dates plain. */
|
|
126
126
|
const TYPE_TONES: Record<CatalystType, StateTone> = {
|
|
127
127
|
litigation: "warning", antitrust: "warning", recall: "warning", sanctions: "warning", export_control: "warning", tariff: "warning",
|
|
128
128
|
pdufa: "accent", advisory: "accent", approval: "accent", clinical: "text",
|
|
129
129
|
regulatory: "muted", rulemaking: "muted",
|
|
130
|
+
results: "text", shareholder_meeting: "text", merger_vote: "text", deal_closing: "text", investor_day: "text",
|
|
130
131
|
};
|
|
131
132
|
export const catalystTypeTone = (type: CatalystType): StateTone => TYPE_TONES[type] ?? "text";
|
|
132
133
|
function changeValue(value: unknown): string {
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from "../../../components";
|
|
12
12
|
import { DetailReader } from "../../../components/reader/detail-reader";
|
|
13
13
|
import { loadingErrorFooterInfo, usePaneRefreshKey } from "../../../components/data-table/table-pane";
|
|
14
|
+
import { createTtlCache } from "../../../data/ttl-cache";
|
|
14
15
|
import { fetchChangelogReleases, type ChangelogRelease } from "../../../updater/github-releases";
|
|
15
16
|
import { colors } from "../../../theme/colors";
|
|
16
17
|
import type { PaneProps } from "../../../types/plugin";
|
|
@@ -32,7 +33,8 @@ const CHANGELOG_CACHE_TTL_MS = 10 * 60 * 1000;
|
|
|
32
33
|
|
|
33
34
|
// Process-lifetime cache. Move it into the updater module if other
|
|
34
35
|
// surfaces start reading releases too.
|
|
35
|
-
|
|
36
|
+
const releaseCache = createTtlCache<ChangelogRelease[]>({ ttlMs: CHANGELOG_CACHE_TTL_MS });
|
|
37
|
+
const RELEASES = "releases";
|
|
36
38
|
|
|
37
39
|
type ChangelogColumn = DataTableColumn & { id: ChangelogColumnId };
|
|
38
40
|
type LoadStatus = "loading" | "loaded" | "error";
|
|
@@ -83,10 +85,10 @@ function ChangelogDetail({
|
|
|
83
85
|
function ChangelogPane({ focused, width, height }: PaneProps) {
|
|
84
86
|
const paneInstance = usePaneInstance();
|
|
85
87
|
const requestedVersion = paneInstance?.params?.version ?? null;
|
|
86
|
-
const [releases, setReleases] = useState<ChangelogRelease[]>(() =>
|
|
88
|
+
const [releases, setReleases] = useState<ChangelogRelease[]>(() => releaseCache.peek(RELEASES, { stale: true }) ?? []);
|
|
87
89
|
// The mount effect starts the request immediately, so the first paint is a
|
|
88
90
|
// spinner and never "No changelog entries found".
|
|
89
|
-
const [status, setStatus] = useState<LoadStatus>(() => (
|
|
91
|
+
const [status, setStatus] = useState<LoadStatus>(() => (releaseCache.peek(RELEASES, { stale: true }) ? "loaded" : "loading"));
|
|
90
92
|
const [error, setError] = useState<string | null>(null);
|
|
91
93
|
// The selected row and the open release are pane state, so a reload or a
|
|
92
94
|
// shared layout comes back to the same release.
|
|
@@ -98,8 +100,9 @@ function ChangelogPane({ focused, width, height }: PaneProps) {
|
|
|
98
100
|
const requestedVersionOpenedRef = useRef(false);
|
|
99
101
|
|
|
100
102
|
const loadReleases = useCallback(async (force = false) => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
+
const fresh = force ? undefined : releaseCache.peek(RELEASES);
|
|
104
|
+
if (fresh) {
|
|
105
|
+
setReleases(fresh);
|
|
103
106
|
setError(null);
|
|
104
107
|
setStatus("loaded");
|
|
105
108
|
return;
|
|
@@ -118,7 +121,7 @@ function ChangelogPane({ focused, width, height }: PaneProps) {
|
|
|
118
121
|
|
|
119
122
|
try {
|
|
120
123
|
const nextReleases = await fetchChangelogReleases(CHANGELOG_LIMIT, controller.signal);
|
|
121
|
-
|
|
124
|
+
releaseCache.set(RELEASES, nextReleases);
|
|
122
125
|
setReleases(nextReleases);
|
|
123
126
|
setStatus("loaded");
|
|
124
127
|
} catch (loadError) {
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
import type { SeriesCatalogEntry, SeriesFrequency, SeriesInput, SeriesPlacement } from "../../../series/types";
|
|
7
7
|
import { parseOptionSymbol } from "../../../utils/options";
|
|
8
8
|
import type { SeriesCatalogInstrument } from "./series-catalog";
|
|
9
|
+
import { macroReleaseTopic } from "../shared/macro-releases";
|
|
9
10
|
|
|
10
11
|
export const CHART_COMPOSER_TEMPLATE_ID = "chart-composer-pane";
|
|
11
12
|
export const DATA_CATALOG_PANE_ID = "data-catalog";
|
|
@@ -30,6 +31,8 @@ export interface CatalogSeriesRow {
|
|
|
30
31
|
/** The registered expression, `{ticker}` where a symbol goes. */
|
|
31
32
|
template: string;
|
|
32
33
|
url?: string;
|
|
34
|
+
/** A limit the publisher sets on the series' data, such as how far back its history goes. */
|
|
35
|
+
limitation?: string;
|
|
33
36
|
/** Asks for a symbol before charting. */
|
|
34
37
|
input?: SeriesInput;
|
|
35
38
|
/** The symbol a row filled in for a typed ticker charts. */
|
|
@@ -119,6 +122,7 @@ function rowFromEntry(entry: SeriesCatalogEntry): Omit<CatalogSeriesRow, "order"
|
|
|
119
122
|
expression,
|
|
120
123
|
template: entry.expression,
|
|
121
124
|
...(entry.url ? { url: entry.url } : {}),
|
|
125
|
+
...(entry.limitation ? { limitation: entry.limitation } : {}),
|
|
122
126
|
...(entry.input ? { input: entry.input } : {}),
|
|
123
127
|
...(entry.placement || entry.lines?.length ? {
|
|
124
128
|
seriesName: entry.name,
|
|
@@ -358,6 +362,7 @@ export function catalogEmptyCopy(
|
|
|
358
362
|
): { title: string; hint?: string } {
|
|
359
363
|
if (loading) return { title: "Loading catalog…" };
|
|
360
364
|
const query = searchQuery.trim();
|
|
361
|
-
|
|
365
|
+
// A PMI or a nowcast is a calendar release, not a series: say where it is rather than search again.
|
|
366
|
+
if (query) return { title: `No series matching "${query}"`, hint: macroReleaseTopic(query)?.paneHint ?? "Press / to search." };
|
|
362
367
|
return { title: "No series", hint: "Press / to search." };
|
|
363
368
|
}
|
|
@@ -210,7 +210,7 @@ function effectiveSeriesUnitGroup(series: ChartSeriesSpec): string {
|
|
|
210
210
|
: getTimeSeriesField(series.source.fieldId)?.unitGroup ?? series.source.fieldId;
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
function nextGeneratedPanelId(
|
|
213
|
+
export function nextGeneratedPanelId(
|
|
214
214
|
spec: Pick<ChartSpec, "panels" | "series" | "studies">,
|
|
215
215
|
prefix = "panel",
|
|
216
216
|
): string {
|
|
@@ -39,8 +39,8 @@ function chartResolution(options: HeadlessPaneOptionValues): ChartResolution | n
|
|
|
39
39
|
return parseChartResolution(options.chartResolution ?? options.resolution);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
function financialPeriod(value: unknown): SeriesPeriod | null {
|
|
43
|
-
return value === "annual" || value === "quarterly" || value === "ttm" ? value : null;
|
|
42
|
+
function financialPeriod(value: unknown, valuation: boolean): SeriesPeriod | null {
|
|
43
|
+
return value === "annual" || value === "quarterly" || value === "ttm" || (valuation && value === "daily") ? value : null;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
function mapSecuritySeries(
|
|
@@ -81,6 +81,10 @@ export function applyChartComposerCapabilityOptions(
|
|
|
81
81
|
next = { ...next, viewport: { ...next.viewport, extendedHours: true } };
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
if (capabilityId === "price-comparison" && options.totalReturn === true) {
|
|
85
|
+
next = { ...next, viewport: { ...next.viewport, totalReturn: true } };
|
|
86
|
+
}
|
|
87
|
+
|
|
84
88
|
if (PRICE_CAPABILITIES.has(capabilityId) && options.axisMode) {
|
|
85
89
|
const transform = options.axisMode === "percent" ? "percent" : "raw";
|
|
86
90
|
next = {
|
|
@@ -95,15 +99,15 @@ export function applyChartComposerCapabilityOptions(
|
|
|
95
99
|
const graphKind = capabilityId === "fundamental-series"
|
|
96
100
|
? "fundamental"
|
|
97
101
|
: capabilityId === "valuation-series" ? "valuation" : null;
|
|
98
|
-
if (graphKind
|
|
99
|
-
const period = financialPeriod(options.period);
|
|
102
|
+
if (graphKind) {
|
|
103
|
+
const period = financialPeriod(options.period, graphKind === "valuation");
|
|
100
104
|
next = {
|
|
101
105
|
...next,
|
|
102
106
|
series: mapSecuritySeries(next.series, (entry) => ({
|
|
103
107
|
...entry,
|
|
104
108
|
source: entry.source.kind === "security" ? {
|
|
105
109
|
...entry.source,
|
|
106
|
-
fieldId: `${graphKind}.${options.metric}
|
|
110
|
+
...(typeof options.metric === "string" ? { fieldId: `${graphKind}.${options.metric}` } : {}),
|
|
107
111
|
...(period ? { period } : {}),
|
|
108
112
|
} : entry.source,
|
|
109
113
|
})),
|
|
@@ -4,6 +4,7 @@ import { Box } from "../../../ui";
|
|
|
4
4
|
import {
|
|
5
5
|
DataTableView,
|
|
6
6
|
QueryBar,
|
|
7
|
+
usePaneNoticeFooter,
|
|
7
8
|
usePaneTabs,
|
|
8
9
|
useQueryBarSearch,
|
|
9
10
|
type DataTableCell,
|
|
@@ -11,6 +12,7 @@ import {
|
|
|
11
12
|
type DataTableKeyEvent,
|
|
12
13
|
type DataTableRootKeyContext,
|
|
13
14
|
} from "../../../components";
|
|
15
|
+
import { usePaneRefreshKey } from "../../../components/data-table/table-pane";
|
|
14
16
|
import type { PaneProps } from "../../../types/plugin";
|
|
15
17
|
import { colors } from "../../../theme/colors";
|
|
16
18
|
import { nextHeaderSort, type SortDirection } from "../../../utils/sort-values";
|
|
@@ -118,14 +120,15 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
|
|
|
118
120
|
const [sortPreference, setSortPreference] = useState<CatalogSortPreference>(DEFAULT_SORT);
|
|
119
121
|
const { active: searchFocused, focus: focusSearch, searchProps } = useQueryBarSearch();
|
|
120
122
|
|
|
121
|
-
const entries = useRegisteredSeries();
|
|
123
|
+
const { entries, loading: catalogLoading, error: catalogError, retry } = useRegisteredSeries();
|
|
124
|
+
usePaneRefreshKey(() => { void retry(); }, { focused, enabled: !searchFocused });
|
|
122
125
|
const catalogRows = useMemo(() => catalogRowsFromEntries(entries), [entries]);
|
|
123
126
|
const filter = normalizeCatalogFilter(savedFilter, catalogRows);
|
|
124
127
|
const tickerQuery = looksLikeCatalogTickerQuery(searchQuery);
|
|
125
128
|
const { instruments, loading: universeLoading } = useCatalogUniverse(
|
|
126
129
|
tickerQuery ? searchQuery : "",
|
|
127
130
|
);
|
|
128
|
-
const loading = tickerQuery && universeLoading;
|
|
131
|
+
const loading = catalogLoading || (tickerQuery && universeLoading);
|
|
129
132
|
const emptyCopy = catalogEmptyCopy(loading, searchQuery);
|
|
130
133
|
|
|
131
134
|
const listedCrypto = useMemo(
|
|
@@ -240,6 +243,12 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
|
|
|
240
243
|
}
|
|
241
244
|
}, []);
|
|
242
245
|
|
|
246
|
+
usePaneNoticeFooter({
|
|
247
|
+
registrationId: `${DATA_CATALOG_PANE_ID}:notices`,
|
|
248
|
+
focused,
|
|
249
|
+
notices: selectedRow?.limitation ? [`${selectedRow.label}: ${selectedRow.limitation}`] : [],
|
|
250
|
+
});
|
|
251
|
+
|
|
243
252
|
usePaneStatusLinkFooter({
|
|
244
253
|
registrationId: DATA_CATALOG_PANE_ID,
|
|
245
254
|
focused,
|
|
@@ -247,6 +256,7 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
|
|
|
247
256
|
source: selectedUrl ? selectedRow?.publisher : null,
|
|
248
257
|
label: "source",
|
|
249
258
|
loading,
|
|
259
|
+
error: catalogError,
|
|
250
260
|
hints: [
|
|
251
261
|
{ id: "graph", key: "g", label: "raph", onPress: () => chartSelected(selectedRow), disabled: !selectedRow },
|
|
252
262
|
{ id: "search", key: "/", label: "search", onPress: focusSearch },
|
|
@@ -10,7 +10,7 @@ import type {
|
|
|
10
10
|
SeriesTimestampMode,
|
|
11
11
|
SeriesTransform,
|
|
12
12
|
} from "../../../../time-series/types";
|
|
13
|
-
import { hasStudyInputCount, validateChartSpec } from "../../../../time-series/spec";
|
|
13
|
+
import { hasStudyInputCount, isOhlcSeriesStyle, validateChartSpec } from "../../../../time-series/spec";
|
|
14
14
|
import { isPlainKey } from "../../../../utils/keyboard";
|
|
15
15
|
import { getSharedRegistry } from "../../../registry";
|
|
16
16
|
import {
|
|
@@ -190,6 +190,7 @@ export function useSeriesEditorController({
|
|
|
190
190
|
suggestions: quickAddSuggestions,
|
|
191
191
|
loading: quickAddLoading,
|
|
192
192
|
error: quickAddError,
|
|
193
|
+
retry: retryQuickAdd,
|
|
193
194
|
} = useSeriesCatalogSuggestions({
|
|
194
195
|
query: quickAddQuery,
|
|
195
196
|
defaultInstrument,
|
|
@@ -414,7 +415,7 @@ export function useSeriesEditorController({
|
|
|
414
415
|
: current.panels,
|
|
415
416
|
series: replaceAt(current.series, selectedIndex, (() => {
|
|
416
417
|
const currentSeries = current.series[selectedIndex]!;
|
|
417
|
-
const ohlcStyle = currentSeries.style
|
|
418
|
+
const ohlcStyle = isOhlcSeriesStyle(currentSeries.style);
|
|
418
419
|
return {
|
|
419
420
|
...currentSeries,
|
|
420
421
|
style: transform !== "raw" && ohlcStyle
|
|
@@ -638,6 +639,7 @@ export function useSeriesEditorController({
|
|
|
638
639
|
quickAddItems,
|
|
639
640
|
quickAddLoading,
|
|
640
641
|
quickAddError,
|
|
642
|
+
retryQuickAdd,
|
|
641
643
|
quickAddQuery,
|
|
642
644
|
quickAddRef,
|
|
643
645
|
quickAddSelection,
|
|
@@ -74,12 +74,14 @@ function seriesFieldId(series: ChartSeriesSpec): string {
|
|
|
74
74
|
|
|
75
75
|
function compatiblePeriods(series: ChartSeriesSpec): SeriesPeriod[] {
|
|
76
76
|
if (series.source.kind !== "security") return [];
|
|
77
|
+
if (series.source.fieldId.startsWith("valuation.") && series.source.fieldId !== "valuation.realizedNtmPE") return ["daily", ...FINANCIAL_PERIODS];
|
|
77
78
|
return series.source.fieldId.startsWith("market.") ? MARKET_PERIODS : FINANCIAL_PERIODS;
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
export function supportsSeriesTimestampMode(series: ChartSeriesSpec | null): boolean {
|
|
81
82
|
return !!series
|
|
82
83
|
&& series.source.kind === "security"
|
|
84
|
+
&& series.source.period !== "daily"
|
|
83
85
|
&& isFundamentalFieldId(series.source.fieldId);
|
|
84
86
|
}
|
|
85
87
|
|