gloomberb 0.19.2 → 0.19.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/package.json +1 -1
- package/patches/electrobun@1.18.1.patch +108 -1
- package/src/account/upgrade-dialog.tsx +4 -23
- package/src/api-client/coalesce.ts +118 -0
- package/src/api-client/credit-boards.ts +13 -0
- package/src/api-client/crypto-etf-flows.ts +6 -0
- package/src/api-client/crypto-markets.ts +40 -0
- package/src/api-client/data.ts +201 -14
- package/src/api-client/equity-screener.ts +10 -0
- package/src/api-client/errors.ts +20 -0
- package/src/api-client/gpu.ts +29 -0
- package/src/api-client/index.ts +5 -2
- package/src/api-client/plan-access.ts +10 -1
- package/src/api-client/plan-rules.ts +35 -0
- package/src/api-client/research-activity.ts +1 -32
- package/src/api-client/types.ts +21 -1
- package/src/app/attention-notice.tsx +94 -0
- package/src/app.tsx +23 -1
- package/src/architecture/core-builtin-allowlist.json +2 -1
- package/src/capabilities/factories.ts +1 -0
- package/src/cli/ascii-output.ts +42 -0
- package/src/cli/base-converter.ts +10 -2
- package/src/cli/command-options.ts +16 -1
- package/src/cli/commands/crypto-hints.ts +23 -4
- package/src/cli/commands/market.ts +92 -23
- package/src/cli/commands/news-search.ts +24 -5
- package/src/cli/commands/overview.ts +9 -4
- package/src/cli/commands/search.ts +71 -12
- package/src/cli/commands/system.ts +22 -30
- package/src/cli/commands/ticker.ts +49 -9
- package/src/cli/commands/version.ts +33 -0
- package/src/cli/context.ts +5 -9
- package/src/cli/data-dir.ts +7 -0
- package/src/cli/desktop-pane-shot-api-policy.ts +85 -0
- package/src/cli/desktop-pane-shot-browser.ts +320 -0
- package/src/cli/desktop-pane-shot-routes.ts +26 -1
- package/src/cli/desktop-pane-shot.ts +196 -256
- package/src/cli/early-command.ts +42 -0
- package/src/cli/earnings-calendar.ts +9 -0
- package/src/cli/entry.ts +19 -13
- package/src/cli/errors.ts +12 -2
- package/src/cli/help.ts +1 -1
- package/src/cli/history-export.ts +22 -2
- package/src/cli/history-rows.ts +154 -4
- package/src/cli/index.ts +18 -1
- package/src/cli/known-gaps.ts +40 -5
- package/src/cli/listing-arg.ts +46 -9
- package/src/cli/options.ts +1 -1
- package/src/cli/output-file.ts +60 -13
- package/src/cli/pane-functions/catalog.ts +14 -3
- package/src/cli/pane-functions/data.ts +1 -1
- package/src/cli/pane-functions/dom.ts +45 -0
- package/src/cli/pane-functions/freshness.ts +46 -9
- package/src/cli/pane-functions/function-help.ts +17 -9
- package/src/cli/pane-functions/headless.ts +22 -14
- package/src/cli/pane-functions/index.ts +6 -2
- package/src/cli/pane-functions/options.ts +6 -2
- package/src/cli/pane-functions/resolver.ts +27 -5
- package/src/cli/pane-functions/screenshot-assessment.ts +33 -0
- package/src/cli/pane-functions/screenshot-bridge.ts +94 -13
- package/src/cli/pane-functions/screenshot-http.ts +70 -0
- package/src/cli/pane-functions/screenshot-render.ts +19 -5
- package/src/cli/quote-answer.ts +20 -0
- package/src/cli/registry.ts +41 -13
- package/src/cli/result.ts +12 -6
- package/src/cli/ticker-resolution.ts +2 -1
- package/src/cli/types.ts +2 -0
- package/src/components/chart/composite/format.ts +3 -0
- package/src/components/chart-table/header.tsx +1 -1
- package/src/components/chart-table/layout.ts +28 -11
- package/src/components/command-bar/action-runtime.ts +4 -0
- package/src/components/command-bar/commands/direct/index.ts +18 -33
- package/src/components/command-bar/commands/direct/runtime.ts +5 -0
- package/src/components/command-bar/commands/registry.ts +10 -1
- package/src/components/command-bar/routes/root/command-items.ts +9 -4
- package/src/components/command-bar/routes/root/runtime.ts +24 -1
- package/src/components/command-bar/surface/index.tsx +9 -3
- package/src/components/company-logo.tsx +2 -1
- package/src/components/layout/header.tsx +8 -3
- package/src/components/layout/market-summary.ts +25 -7
- package/src/components/layout/pane/footer/index.tsx +7 -2
- package/src/components/layout/pane/footer/model.ts +40 -5
- package/src/components/market-board/index.tsx +3 -2
- package/src/components/onboarding/desks-step.tsx +12 -4
- package/src/components/onboarding/first-run-workspace.ts +81 -4
- package/src/components/onboarding/onboarding-frame.tsx +2 -1
- package/src/components/onboarding/onboarding-keyboard.ts +8 -5
- package/src/components/onboarding/onboarding-wizard.tsx +54 -23
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +7 -2
- package/src/components/onboarding/run-setup-again.ts +24 -0
- package/src/components/onboarding/use-onboarding-progress.ts +33 -15
- package/src/components/onboarding/use-onboarding-upgrade.ts +2 -6
- package/src/components/onboarding/wizard-model.ts +57 -3
- package/src/components/onboarding/wizard-positions.ts +1 -1
- package/src/components/ui/delayed-mark.tsx +56 -0
- package/src/components/ui/external-link.tsx +3 -6
- package/src/components/ui/icon.tsx +8 -1
- package/src/components/ui/logo-mark.tsx +8 -5
- package/src/components/ui/stat-grid.tsx +263 -19
- package/src/data/config/store/node.ts +11 -5
- package/src/data/config/store/normalize.ts +16 -3
- package/src/data/profile-permissions.ts +47 -0
- package/src/data/resource-store.ts +34 -31
- package/src/data/sqlite/access.ts +19 -8
- package/src/data/sqlite/checkpointer.ts +95 -8
- package/src/data/sqlite/database.ts +40 -7
- package/src/docs/snapshot.json +191 -78
- package/src/i18n/es.ts +18 -2
- package/src/i18n/ja.ts +18 -2
- package/src/i18n/ko.ts +18 -2
- package/src/i18n/zh-cn.ts +18 -2
- package/src/i18n/zh-tw.ts +18 -2
- package/src/layout/desk-keys.ts +4 -1
- package/src/layout/desks.ts +38 -5
- package/src/layout-marketplace/gallery-desktop.tsx +45 -16
- package/src/market-data/batched-reads.ts +16 -0
- package/src/market-data/coordinator/auxiliary.ts +4 -2
- package/src/market-data/coordinator/index.ts +11 -2
- package/src/market-data/futures-board.ts +1 -1
- package/src/market-data/futures-contract.ts +3 -1
- package/src/market-data/market/index-level.ts +6 -4
- package/src/market-data/published-apac-sessions.ts +6 -0
- package/src/news/aggregator.ts +7 -4
- package/src/news/news-model.ts +11 -0
- package/src/news/story-id.ts +22 -0
- package/src/news/ticker-symbols.ts +17 -1
- package/src/notifications/app-notifier.ts +35 -14
- package/src/plugins/builtin/account-management/form-components.tsx +1 -1
- package/src/plugins/builtin/account-management/index.tsx +2 -3
- package/src/plugins/builtin/account-management/model.ts +1 -1
- package/src/plugins/builtin/alerts/cli-forms.ts +15 -1
- package/src/plugins/builtin/alerts/events-pane.tsx +7 -5
- package/src/plugins/builtin/alerts/events.ts +10 -2
- package/src/plugins/builtin/alerts/index.tsx +5 -5
- package/src/plugins/builtin/alerts/research-builder.ts +5 -1
- package/src/plugins/builtin/alerts/research-rules.ts +18 -0
- package/src/plugins/builtin/alerts/targets.ts +4 -1
- package/src/plugins/builtin/attention/headless.ts +1 -1
- package/src/plugins/builtin/attention/index.tsx +2 -4
- package/src/plugins/builtin/attention/listing.ts +1 -1
- package/src/plugins/builtin/attention/series.ts +1 -1
- package/src/plugins/builtin/awards/index.tsx +1 -2
- package/src/plugins/builtin/backtest/client.ts +1 -0
- package/src/plugins/builtin/backtest/index.tsx +1 -2
- package/src/plugins/builtin/backtest/rules.ts +3 -1
- package/src/plugins/builtin/backtest/window.ts +8 -7
- package/src/plugins/builtin/broker-manager/detail.tsx +16 -3
- package/src/plugins/builtin/broker-manager/index.tsx +1 -1
- package/src/plugins/builtin/buildout/cells.tsx +5 -0
- package/src/plugins/builtin/buildout/company/flow.tsx +367 -0
- package/src/plugins/builtin/buildout/company/id.ts +2 -0
- package/src/plugins/builtin/buildout/company/model.ts +247 -0
- package/src/plugins/builtin/buildout/company/pane.tsx +317 -0
- package/src/plugins/builtin/buildout/data-runtime.ts +31 -10
- package/src/plugins/builtin/buildout/facilities.ts +309 -0
- package/src/plugins/builtin/buildout/format.ts +9 -0
- package/src/plugins/builtin/buildout/index.tsx +51 -5
- package/src/plugins/builtin/buildout/model/index.ts +62 -10
- package/src/plugins/builtin/buildout/model/normalizers.ts +5 -0
- package/src/plugins/builtin/buildout/model/types.ts +11 -2
- package/src/plugins/builtin/buildout/pane/index.tsx +91 -20
- package/src/plugins/builtin/buildout/pane/status.tsx +1 -1
- package/src/plugins/builtin/buildout/pane/themes.tsx +110 -0
- package/src/plugins/builtin/buildout/table-model.ts +26 -2
- package/src/plugins/builtin/builtin-plugin-meta.ts +16 -0
- package/src/plugins/builtin/cds/headless.ts +10 -2
- package/src/plugins/builtin/cds/model.ts +7 -3
- package/src/plugins/builtin/central-bank-rates/index.tsx +1 -2
- package/src/plugins/builtin/central-bank-rates/pane.tsx +2 -1
- package/src/plugins/builtin/changelog/index.tsx +3 -2
- package/src/plugins/builtin/chart-composer/headless-schema.ts +7 -2
- package/src/plugins/builtin/chart-composer/headless.ts +88 -21
- package/src/plugins/builtin/chart-composer/index.tsx +2 -3
- package/src/plugins/builtin/chart-composer/pane.tsx +26 -2
- package/src/plugins/builtin/chart-composer/series-expression.ts +3 -2
- package/src/plugins/builtin/chart-composer/studies.ts +1 -1
- package/src/plugins/builtin/chat/controller/index.ts +1 -1
- package/src/plugins/builtin/chat/controller/messages.ts +15 -4
- package/src/plugins/builtin/chat/ghost-user.ts +8 -0
- package/src/plugins/builtin/chat/index.tsx +5 -5
- package/src/plugins/builtin/clinical-trials/index.tsx +1 -2
- package/src/plugins/builtin/cloud/company-picker.tsx +1 -1
- package/src/plugins/builtin/cloud/index.tsx +1 -2
- package/src/plugins/builtin/cloud/plugin.tsx +6 -4
- package/src/plugins/builtin/cloud/team/module.tsx +1 -1
- package/src/plugins/builtin/cloud/thesis/module.tsx +1 -1
- package/src/plugins/builtin/cloud/trial-offer-status-widget.tsx +24 -1
- package/src/plugins/builtin/cloud/upgrade-status-widget.tsx +39 -15
- package/src/plugins/builtin/comment-letters/index.tsx +1 -2
- package/src/plugins/builtin/commodity-balances/index.tsx +3 -3
- package/src/plugins/builtin/commodity-balances/pane.tsx +2 -2
- package/src/plugins/builtin/congress-trades/aggregates.ts +13 -2
- package/src/plugins/builtin/congress-trades/detail.tsx +20 -4
- package/src/plugins/builtin/congress-trades/headless.ts +2 -0
- package/src/plugins/builtin/congress-trades/model.ts +92 -64
- package/src/plugins/builtin/congress-trades/table.tsx +14 -2
- package/src/plugins/builtin/connections/index.ts +2 -3
- package/src/plugins/builtin/cot/index.tsx +1 -2
- package/src/plugins/builtin/cpi/index.tsx +1 -2
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +2 -1
- package/src/plugins/builtin/credit-boards/client.ts +7 -2
- package/src/plugins/builtin/credit-boards/headless.ts +25 -12
- package/src/plugins/builtin/credit-boards/model.ts +29 -0
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +9 -4
- package/src/plugins/builtin/crypto-board/bitcoin-network.ts +143 -0
- package/src/plugins/builtin/crypto-board/headless.ts +4 -3
- package/src/plugins/builtin/crypto-board/index.tsx +4 -2
- package/src/plugins/builtin/crypto-board/series.ts +2 -0
- package/src/plugins/builtin/crypto-etf-flows/client.ts +9 -2
- package/src/plugins/builtin/crypto-etf-flows/headless.ts +61 -6
- package/src/plugins/builtin/crypto-etf-flows/index.tsx +1 -2
- package/src/plugins/builtin/crypto-etf-flows/model.ts +14 -1
- package/src/plugins/builtin/crypto-etf-flows/pane.tsx +8 -5
- package/src/plugins/builtin/debt-maturities/headless.ts +4 -3
- package/src/plugins/builtin/debt-maturities/model.ts +17 -1
- package/src/plugins/builtin/debt-maturities/pane.tsx +18 -4
- package/src/plugins/builtin/debug/index.tsx +1 -1
- package/src/plugins/builtin/dividend-yield/client.ts +32 -2
- package/src/plugins/builtin/dividend-yield/headless.ts +58 -33
- package/src/plugins/builtin/dividend-yield/index.tsx +37 -2
- package/src/plugins/builtin/dividend-yield/pane.tsx +32 -13
- package/src/plugins/builtin/dividend-yield/ranking-reads.ts +73 -0
- package/src/plugins/builtin/dividend-yield/ranking-view.tsx +163 -0
- package/src/plugins/builtin/dividend-yield/ranking.ts +1 -1
- package/src/plugins/builtin/dividend-yield/view.ts +21 -0
- package/src/plugins/builtin/docs/index.tsx +2 -3
- package/src/plugins/builtin/doe/headless.ts +16 -3
- package/src/plugins/builtin/doe/index.tsx +5 -4
- package/src/plugins/builtin/earnings/board.tsx +2 -1
- package/src/plugins/builtin/earnings/history.tsx +2 -1
- package/src/plugins/builtin/earnings-ripple/client.ts +32 -7
- package/src/plugins/builtin/earnings-ripple/index.tsx +1 -2
- package/src/plugins/builtin/econ/calendar-model.ts +29 -6
- package/src/plugins/builtin/econ-statistics/index.tsx +1 -2
- package/src/plugins/builtin/equity-screener/client.ts +1 -1
- package/src/plugins/builtin/equity-screener/headless.ts +1 -0
- package/src/plugins/builtin/equity-screener/ideas.ts +30 -1
- package/src/plugins/builtin/equity-screener/index.tsx +1 -2
- package/src/plugins/builtin/equity-screener/model.ts +28 -4
- package/src/plugins/builtin/equity-screener/pane.tsx +5 -0
- package/src/plugins/builtin/equity-screener/screen-check.ts +23 -1
- package/src/plugins/builtin/estimate-revisions/index.tsx +1 -2
- package/src/plugins/builtin/exposure/holdings.ts +35 -13
- package/src/plugins/builtin/exposure/index.tsx +1 -2
- package/src/plugins/builtin/fear-greed/cli.ts +44 -0
- package/src/plugins/builtin/fear-greed/index.tsx +5 -53
- package/src/plugins/builtin/fear-greed/pane.tsx +2 -1
- package/src/plugins/builtin/fixed-income/index.tsx +1 -2
- package/src/plugins/builtin/futures/board-reads.ts +25 -0
- package/src/plugins/builtin/futures/coalesced-bump.ts +44 -0
- package/src/plugins/builtin/futures/index.tsx +15 -0
- package/src/plugins/builtin/futures/model.ts +14 -0
- package/src/plugins/builtin/futures/use-board-terms.ts +22 -15
- package/src/plugins/builtin/futures/use-front-returns.ts +20 -14
- package/src/plugins/builtin/futures-curve/headless.ts +6 -1
- package/src/plugins/builtin/futures-curve/index.tsx +1 -2
- package/src/plugins/builtin/fx-matrix/index.tsx +2 -2
- package/src/plugins/builtin/gpu/board.tsx +51 -12
- package/src/plugins/builtin/gpu/client.ts +15 -2
- package/src/plugins/builtin/gpu/equities.tsx +5 -2
- package/src/plugins/builtin/gpu/headless.ts +14 -2
- package/src/plugins/builtin/gpu/index.tsx +1 -2
- package/src/plugins/builtin/gpu/model.ts +20 -2
- package/src/plugins/builtin/gpu/pane.tsx +1 -1
- package/src/plugins/builtin/help/index.tsx +1 -1
- package/src/plugins/builtin/holders/index-holders.ts +24 -12
- package/src/plugins/builtin/holders/index.tsx +2 -3
- package/src/plugins/builtin/ipo-calendar/index.tsx +1 -2
- package/src/plugins/builtin/iv-history/index.tsx +1 -2
- package/src/plugins/builtin/jodi/index.tsx +1 -2
- package/src/plugins/builtin/kelly-sizer/index.tsx +1 -2
- package/src/plugins/builtin/layout-manager/index.tsx +9 -8
- package/src/plugins/builtin/macro-day/pane.tsx +4 -2
- package/src/plugins/builtin/market-halts/index.tsx +1 -2
- package/src/plugins/builtin/market-heatmap/index.tsx +11 -2
- package/src/plugins/builtin/market-movers/index.tsx +7 -1
- package/src/plugins/builtin/market-movers/session-body.tsx +4 -1
- package/src/plugins/builtin/market-valuation/index.tsx +1 -2
- package/src/plugins/builtin/members/index.tsx +1 -2
- package/src/plugins/builtin/money-markets/index.tsx +1 -2
- package/src/plugins/builtin/money-markets/pane.tsx +2 -1
- package/src/plugins/builtin/news/headless.ts +7 -0
- package/src/plugins/builtin/news/wire/index.tsx +1 -1
- package/src/plugins/builtin/news/wire/news/pop-out.tsx +9 -3
- package/src/plugins/builtin/notes/index.tsx +3 -6
- package/src/plugins/builtin/openfda/index.tsx +1 -2
- package/src/plugins/builtin/options/view.tsx +6 -5
- package/src/plugins/builtin/options-calculator/index.tsx +1 -2
- package/src/plugins/builtin/options-positioning/index.tsx +1 -2
- package/src/plugins/builtin/options-scenario/index.tsx +2 -4
- package/src/plugins/builtin/perps/index.tsx +1 -2
- package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -3
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +2 -1
- package/src/plugins/builtin/plugin-module.ts +16 -2
- package/src/plugins/builtin/portfolio-list/cli/render.ts +53 -3
- package/src/plugins/builtin/portfolio-list/index.tsx +1 -2
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +11 -0
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +2 -2
- package/src/plugins/builtin/power/index.tsx +1 -2
- package/src/plugins/builtin/rate-path/index.tsx +1 -2
- package/src/plugins/builtin/realized-vol/headless.ts +2 -0
- package/src/plugins/builtin/realized-vol/index.tsx +1 -2
- package/src/plugins/builtin/realized-vol/model.ts +16 -2
- package/src/plugins/builtin/realized-vol/pane.tsx +3 -3
- package/src/plugins/builtin/relative-rotation/index.tsx +1 -2
- package/src/plugins/builtin/research/analyst-headless.ts +33 -6
- package/src/plugins/builtin/research/analyst-model.ts +37 -2
- package/src/plugins/builtin/research/analyst-pane.tsx +25 -5
- package/src/plugins/builtin/research/index.tsx +5 -8
- package/src/plugins/builtin/research-search/index.tsx +1 -2
- package/src/plugins/builtin/revenue-breakdown/headless.ts +22 -8
- package/src/plugins/builtin/revenue-breakdown/model.ts +23 -0
- package/src/plugins/builtin/reverse-dcf/pane.tsx +4 -2
- package/src/plugins/builtin/roadmap/index.tsx +2 -3
- package/src/plugins/builtin/roadmap/pane.tsx +49 -2
- package/src/plugins/builtin/scanner/hilo-model.ts +18 -1
- package/src/plugins/builtin/scanner/hilo-pane.tsx +12 -2
- package/src/plugins/builtin/scanner/live-pane.tsx +7 -4
- package/src/plugins/builtin/sec/filing-content.ts +38 -6
- package/src/plugins/builtin/sec/headless.ts +5 -1
- package/src/plugins/builtin/sec/index.tsx +4 -2
- package/src/plugins/builtin/sec/model.ts +2 -0
- package/src/plugins/builtin/sectors/index.tsx +11 -5
- package/src/plugins/builtin/series-inventory.ts +2 -0
- package/src/plugins/builtin/shared/cloud-resource.ts +60 -0
- package/src/plugins/builtin/shared/cloud-upgrade.ts +24 -1
- package/src/plugins/builtin/shared/forming-bars.ts +29 -0
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +17 -0
- package/src/plugins/builtin/shared/series-detail-chart.tsx +4 -2
- package/src/plugins/builtin/shared/use-quote-board.ts +5 -0
- package/src/plugins/builtin/short-interest/publications-pane.tsx +2 -1
- package/src/plugins/builtin/short-volume/pane.tsx +2 -1
- package/src/plugins/builtin/social-mentions/index.tsx +1 -2
- package/src/plugins/builtin/social-mentions/pane.tsx +2 -1
- package/src/plugins/builtin/supply-chain/client.ts +22 -1
- package/src/plugins/builtin/supply-chain/graph-client.ts +22 -1
- package/src/plugins/builtin/supply-chain/index.tsx +1 -2
- package/src/plugins/builtin/thirteenf/api.ts +116 -13
- package/src/plugins/builtin/thirteenf/data.ts +132 -30
- package/src/plugins/builtin/thirteenf/index.tsx +2 -4
- package/src/plugins/builtin/thirteenf/model.ts +2 -0
- package/src/plugins/builtin/thirteenf/pane.tsx +20 -11
- package/src/plugins/builtin/thirteenf/types.ts +12 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +17 -4
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +81 -11
- package/src/plugins/builtin/ticker-detail/headless.ts +11 -3
- package/src/plugins/builtin/ticker-detail/index.tsx +5 -10
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +16 -6
- package/src/plugins/builtin/time-sales/index.tsx +1 -2
- package/src/plugins/builtin/time-sales/pane.tsx +3 -1
- package/src/plugins/builtin/trace-bonds/headless.ts +11 -2
- package/src/plugins/builtin/trace-bonds/model.ts +44 -10
- package/src/plugins/builtin/trace-bonds/pane.tsx +12 -7
- package/src/plugins/builtin/treasury-auctions/pane.tsx +2 -2
- package/src/plugins/builtin/vol-surface/client.ts +18 -3
- package/src/plugins/builtin/vol-surface/index.tsx +1 -2
- package/src/plugins/builtin/volatility/index.tsx +1 -2
- package/src/plugins/builtin/world-indices/footer.ts +6 -1
- package/src/plugins/builtin/world-venue-map/client.ts +10 -1
- package/src/plugins/builtin/world-venue-map/index.ts +6 -2
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +48 -7
- package/src/plugins/builtin/world-venue-map/layers.ts +17 -0
- package/src/plugins/builtin/world-venue-map/local-layers.ts +141 -0
- package/src/plugins/builtin/world-venue-map/map-symbols.ts +18 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +4 -2
- package/src/plugins/builtin/world-venue-map/scope.ts +63 -0
- package/src/plugins/builtin/yield-curve/curves.ts +16 -2
- package/src/plugins/builtin/yield-curve/headless.ts +3 -3
- package/src/plugins/bundle.ts +52 -2
- package/src/plugins/catalog-browser.ts +2 -2
- package/src/plugins/catalog-cli.ts +20 -0
- package/src/plugins/host-link.ts +13 -1
- package/src/plugins/installer.ts +15 -4
- package/src/plugins/loader.ts +43 -11
- package/src/plugins/peer-imports.ts +201 -0
- package/src/plugins/peer-retry.ts +26 -29
- package/src/plugins/plugin-process.ts +128 -0
- package/src/plugins/redirection-guard.ts +45 -0
- package/src/remote/endpoint.ts +16 -3
- package/src/renderers/browser/main.tsx +3 -2
- package/src/renderers/cloudflare/http-proxy.ts +7 -123
- package/src/renderers/dom/desktop/icons.tsx +2 -0
- package/src/renderers/dom/host/image-surface.tsx +46 -21
- package/src/renderers/dom/styles.css +7 -0
- package/src/renderers/dom/toast-host.tsx +2 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +7 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +3 -2
- package/src/renderers/electrobun/bun/desktop/rpc-timing.ts +88 -0
- package/src/renderers/electrobun/bun/desktop/update.ts +20 -4
- package/src/renderers/electrobun/bun/desktop/view-ids.ts +8 -4
- package/src/renderers/electrobun/bun/external-plugins.ts +4 -0
- package/src/renderers/electrobun/bun/window/create.ts +4 -2
- package/src/renderers/electrobun/bun/window/native-timing.ts +48 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +82 -4
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +13 -5
- package/src/renderers/electrobun/view/desktop/window/snapshot.ts +3 -0
- package/src/renderers/electrobun/view/main.tsx +7 -2
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -0
- package/src/renderers/opentui/browser-open.ts +10 -4
- package/src/renderers/opentui/image/surface.tsx +1 -1
- package/src/renderers/opentui/start.tsx +12 -6
- package/src/renderers/opentui/toast-host.tsx +2 -1
- package/src/series/registry.ts +18 -0
- package/src/series/standalone.ts +10 -1
- package/src/series/types.ts +7 -0
- package/src/series/validate.ts +11 -2
- package/src/sources/gloomberb-cloud/index.ts +28 -5
- package/src/sources/gloomberb-cloud/news.ts +24 -3
- package/src/sources/gloomberb-cloud/normalizers.ts +17 -2
- package/src/sources/provider-errors.ts +26 -3
- package/src/sources/provider-router/history.ts +5 -0
- package/src/sources/provider-router/index.ts +13 -0
- package/src/sync/core-contributors.ts +32 -0
- package/src/telemetry/attention-counts.ts +64 -6
- package/src/telemetry/attention-setting.ts +33 -0
- package/src/telemetry/crash-reports-node.ts +3 -1
- package/src/telemetry/stall-clocks.ts +93 -0
- package/src/telemetry/stall-reports-node.ts +12 -7
- package/src/telemetry/stall-reports.ts +34 -5
- package/src/test-support/preload.ts +9 -0
- package/src/tickers/company-name.ts +19 -0
- package/src/tickers/listing-fate.ts +14 -3
- package/src/tickers/saved-instrument.ts +17 -0
- package/src/tickers/search/home-listing.ts +13 -2
- package/src/tickers/search/index.ts +4 -1
- package/src/tickers/search/types.ts +6 -1
- package/src/time-series/bar-aggregation.ts +7 -1
- package/src/time-series/base-series.ts +3 -3
- package/src/time-series/chart-bounds.ts +1 -1
- package/src/time-series/chart-data.ts +5 -2
- package/src/time-series/chart-seed.ts +1 -1
- package/src/time-series/coin-session-close.ts +211 -0
- package/src/time-series/live-bars.ts +13 -2
- package/src/time-series/live-quotes.ts +1 -1
- package/src/time-series/official-close.ts +159 -0
- package/src/time-series/price-comparison.ts +55 -6
- package/src/time-series/resolve.ts +12 -3
- package/src/time-series/series-presentation.ts +1 -1
- package/src/time-series/studies/formula.ts +205 -0
- package/src/time-series/studies/indicators.ts +299 -0
- package/src/time-series/studies/leverage.ts +75 -0
- package/src/time-series/studies/pair.ts +138 -0
- package/src/time-series/studies/resolve.ts +333 -0
- package/src/time-series/studies/shared.ts +141 -0
- package/src/time-series/studies/units.ts +243 -0
- package/src/time-series/studies/vwap.ts +274 -0
- package/src/types/config.ts +18 -2
- package/src/types/data-provider.ts +23 -0
- package/src/types/financials.ts +22 -0
- package/src/types/headless.ts +42 -3
- package/src/types/plugin.ts +32 -3
- package/src/ui/host.tsx +11 -0
- package/src/ui/toast.tsx +26 -1
- package/src/utils/ascii-text.ts +140 -0
- package/src/utils/cli-output.ts +91 -18
- package/src/utils/concurrency.ts +24 -0
- package/src/utils/exchanges.ts +6 -0
- package/src/utils/external-url.ts +20 -7
- package/src/utils/futures-generic.ts +4 -4
- package/src/utils/http-proxy-upstream.ts +124 -0
- package/src/utils/main-thread-stall.ts +75 -3
- package/src/utils/perf-marks.ts +36 -2
- package/src/utils/private-files.ts +141 -0
- package/src/utils/public-address.ts +99 -0
- package/src/account/upgrade-personalization.ts +0 -57
- package/src/account/upgrade-tickers.ts +0 -124
- package/src/api-client/upgrade-experiment.ts +0 -91
- package/src/plugins/builtin/cloud/browser.tsx +0 -3
- package/src/renderers/electrobun/launcher/preload.ts +0 -13
- package/src/renderers/electrobun/launcher/windows-emulation.ts +0 -50
- package/src/time-series/studies.ts +0 -1628
|
@@ -2,6 +2,7 @@ import { Fragment, createElement, type ReactNode } from "react";
|
|
|
2
2
|
import type {
|
|
3
3
|
GloomPlugin,
|
|
4
4
|
GloomPluginContext,
|
|
5
|
+
PaneDef,
|
|
5
6
|
} from "../../types/plugin";
|
|
6
7
|
import { pluginContextInNamespace } from "../registry/plugin-state";
|
|
7
8
|
import { withPluginStateNamespace } from "../runtime/context";
|
|
@@ -63,6 +64,19 @@ function moduleEntry(input: PluginModuleInput): PluginModuleEntry {
|
|
|
63
64
|
return "module" in input ? input : { module: input };
|
|
64
65
|
}
|
|
65
66
|
|
|
67
|
+
/** Keep a pane's component lazy while moving its state into another plugin. */
|
|
68
|
+
function paneInNamespace(pane: PaneDef, stateId: string): PaneDef {
|
|
69
|
+
let component: PaneDef["component"] | undefined;
|
|
70
|
+
return Object.create(Object.getPrototypeOf(pane), {
|
|
71
|
+
...Object.getOwnPropertyDescriptors(pane),
|
|
72
|
+
component: {
|
|
73
|
+
enumerable: true,
|
|
74
|
+
configurable: true,
|
|
75
|
+
get: () => component ??= withPluginStateNamespace(stateId, pane.component),
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
66
80
|
/**
|
|
67
81
|
* The module as it runs under a namespace other than its plugin's: every
|
|
68
82
|
* surface it renders and the context its setup receives are moved there,
|
|
@@ -76,7 +90,7 @@ function moduleInNamespace(module: PluginModule, stateId: string): PluginModule
|
|
|
76
90
|
return {
|
|
77
91
|
...module,
|
|
78
92
|
...(module.panes ? {
|
|
79
|
-
panes: module.panes.map((pane) => (
|
|
93
|
+
panes: module.panes.map((pane) => paneInNamespace(pane, stateId)),
|
|
80
94
|
} : {}),
|
|
81
95
|
...(slots ? { slots } : {}),
|
|
82
96
|
...(module.setup ? {
|
|
@@ -84,7 +98,7 @@ function moduleInNamespace(module: PluginModule, stateId: string): PluginModule
|
|
|
84
98
|
const scoped = pluginContextInNamespace(ctx, stateId);
|
|
85
99
|
return module.setup!({
|
|
86
100
|
...scoped,
|
|
87
|
-
registerPane: (pane) => ctx.registerPane(
|
|
101
|
+
registerPane: (pane) => ctx.registerPane(paneInNamespace(pane, stateId)),
|
|
88
102
|
registerTickerResearchTab: (tab) => ctx.registerTickerResearchTab({
|
|
89
103
|
...tab,
|
|
90
104
|
component: withPluginStateNamespace(stateId, tab.component),
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { logFailure } from "../../../../utils/log-failure";
|
|
2
|
-
import { createBaseConverter } from "../../../../cli/base-converter";
|
|
2
|
+
import { createBaseConverter, type BaseConversion } from "../../../../cli/base-converter";
|
|
3
|
+
import { quotedFxPair } from "../../../../utils/currency-pair";
|
|
4
|
+
import { formatFxRate } from "../../../../cli/fx-pair";
|
|
3
5
|
import { savedListingName } from "../../../../cli/listing-arg";
|
|
4
6
|
import { currentListingName } from "../../../../tickers/listing-name";
|
|
5
7
|
import { withMarketData } from "../../../../cli/scoped-context";
|
|
@@ -575,6 +577,38 @@ export function weightBasisLine(allocation: Pick<PortfolioAllocation, "weightBas
|
|
|
575
577
|
return weightBasisNote(allocation, (value) => formatAllocationMoney(value, currency, { whole: true }));
|
|
576
578
|
}
|
|
577
579
|
|
|
580
|
+
/** `47h old`, or `3 days old` past two days: how far behind a stale rate is. */
|
|
581
|
+
function rateAge(asOf: number, now: number): string {
|
|
582
|
+
const hours = Math.max(0, Math.floor((now - asOf) / 3_600_000));
|
|
583
|
+
return hours < 48 ? `${hours}h old` : `${Math.floor(hours / 24)} days old`;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/** A rate the report converted at, as markets quote the pair and `fx` writes it, for `--json`. */
|
|
587
|
+
function fxRateRecord({ currency, baseCurrency, rate, asOf, stale }: BaseConversion) {
|
|
588
|
+
const quoted = quotedFxPair(currency, baseCurrency, rate);
|
|
589
|
+
return { currency, baseCurrency, pair: quoted.pair, rate: Number(formatFxRate(quoted.rate)), asOf: asOf == null ? null : new Date(asOf).toISOString(), stale };
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* `FX: USD/ZAR 16.7237, as of Fri 30 Oct 18:12 UTC`: each rate a portfolio's
|
|
594
|
+
* holdings in another currency were converted at, as markets quote the pair,
|
|
595
|
+
* dated; one past its fresh window says it is stale and how old. Null when
|
|
596
|
+
* nothing was converted.
|
|
597
|
+
*/
|
|
598
|
+
function fxRatesLine(
|
|
599
|
+
conversions: readonly BaseConversion[],
|
|
600
|
+
{ now = Date.now(), warning = (text: string) => text }: { now?: number; warning?: (text: string) => string } = {},
|
|
601
|
+
): string | null {
|
|
602
|
+
const rates = conversions.filter((conversion) => conversion.currency !== conversion.baseCurrency && Number.isFinite(conversion.rate));
|
|
603
|
+
if (rates.length === 0) return null;
|
|
604
|
+
return `FX: ${rates.map((conversion) => {
|
|
605
|
+
const quoted = quotedFxPair(conversion.currency, conversion.baseCurrency, conversion.rate);
|
|
606
|
+
const dated = conversion.asOf == null ? "" : `, as of ${formatUtcDayTime({ time: conversion.asOf, dateOnly: false }, now)} UTC`;
|
|
607
|
+
const text = `${quoted.pair} ${formatFxRate(quoted.rate)}${dated}`;
|
|
608
|
+
return conversion.stale ? warning(`${text} (stale${conversion.asOf == null ? "" : `, ${rateAge(conversion.asOf, now)}`})`) : text;
|
|
609
|
+
}).join("; ")}`;
|
|
610
|
+
}
|
|
611
|
+
|
|
578
612
|
/** What the TOTAL row weighs: all of a total; nothing on a gross base, where the weights net to the book's net over its gross. */
|
|
579
613
|
function totalWeight(allocation: Pick<PortfolioAllocation, "weightBasis" | "total">): number | null {
|
|
580
614
|
return allocation.weightBasis === "total" && allocation.total != null && allocation.total > 0 ? 100 : null;
|
|
@@ -818,7 +852,12 @@ async function showCollectionWithMarketData(
|
|
|
818
852
|
})), dividends, toBase);
|
|
819
853
|
const lotIncome = income.lots;
|
|
820
854
|
const totalIncome = income.totalIncome;
|
|
821
|
-
|
|
855
|
+
// The yield is on what is invested: cash pays no dividend, so it does not dilute it. A long-only book's is
|
|
856
|
+
// its priced holdings' net value. A book that holds a short is weighed on its gross exposure, and so is its
|
|
857
|
+
// yield: the net shrinks as the hedge grows (long 100k against short 80k nets 20k), which would inflate it.
|
|
858
|
+
const hedged = allocation.weightBasis === "gross";
|
|
859
|
+
const yieldBase = hedged ? allocation.weightBase : exposure.net;
|
|
860
|
+
const portfolioYield = totalIncome != null && yieldBase != null && yieldBase > 0 ? (totalIncome / yieldBase) * 100 : null;
|
|
822
861
|
const incomeUnavailable = [...income.gaps].map(([symbol, gap]) => ({ symbol, ...gap }));
|
|
823
862
|
const showTargets = allocation.targetSum != null;
|
|
824
863
|
// Never dropped on a narrow terminal, so --explain reads the terms off them.
|
|
@@ -956,7 +995,9 @@ async function showCollectionWithMarketData(
|
|
|
956
995
|
totalUnrealizedPnl: totalPnlValue,
|
|
957
996
|
annualIncome: totalIncome, knownAnnualIncome: income.knownIncome, portfolioYield,
|
|
958
997
|
incomeComplete: income.gaps.size === 0, incomeUnavailable,
|
|
959
|
-
incomeBasis: "Trailing twelve-month dividends per share times shares held, in the portfolio's currency; a short owes the dividend, so its income is negative. Portfolio yield is the total over the
|
|
998
|
+
incomeBasis: "Trailing twelve-month dividends per share times shares held, in the portfolio's currency; a short owes the dividend, so its income is negative. Portfolio yield is the total over the invested value without cash: the priced holdings' net value (exposure.net), or for a book that holds a short its gross exposure (weightBase), as its weights are; annualIncome is null when any holding's income is unknown, and knownAnnualIncome sums the holdings that have one.",
|
|
999
|
+
// Each rate a holding in another currency was converted at, dated, and whether it is stale.
|
|
1000
|
+
fxRates: toBase.conversions().filter((conversion) => conversion.currency !== conversion.baseCurrency).map(fxRateRecord),
|
|
960
1001
|
complete: unavailablePnl.size === 0 && unavailableCost.size === 0 && unavailableMarketValue.size === 0 && income.gaps.size === 0,
|
|
961
1002
|
unavailableSymbols: [...new Set([...unavailablePnl, ...unavailableCost, ...unavailableMarketValue])],
|
|
962
1003
|
unavailableCostSymbols: [...unavailableCost], brokerPnlSymbols: [...brokerPnlSymbols],
|
|
@@ -1098,7 +1139,16 @@ async function showCollectionWithMarketData(
|
|
|
1098
1139
|
console.log("");
|
|
1099
1140
|
if (basis === "regular-close") console.log(dayMoveLine(dayMove, currency, colorBySign, cliStyles.muted));
|
|
1100
1141
|
if (valued.some((entry) => entry.position)) console.log(exposureLine(exposure, currency));
|
|
1142
|
+
// The rates the holdings in another currency are valued at, dated, so a stale one is seen beside the value it moves.
|
|
1143
|
+
const fxLine = fxRatesLine(toBase.conversions(), { warning: cliStyles.warning });
|
|
1144
|
+
if (fxLine) console.log(fxLine);
|
|
1101
1145
|
const notes: string[] = [];
|
|
1146
|
+
// TOTAL's yield says what it divides: a hedged book's gross exposure, or, with cash in the book, the holdings alone.
|
|
1147
|
+
if (showIncome && portfolioYield != null && yieldBase != null && hedged) {
|
|
1148
|
+
notes.push(cliStyles.muted(`TOTAL yield is income over the gross exposure of ${wholeMoney(yieldBase)}, as the book holds a short; cash excluded.`));
|
|
1149
|
+
} else if (showIncome && portfolioYield != null && yieldBase != null && cashExport?.value) {
|
|
1150
|
+
notes.push(cliStyles.muted(`TOTAL yield is income over the invested ${wholeMoney(yieldBase)}, cash excluded.`));
|
|
1151
|
+
}
|
|
1102
1152
|
const weightNote = weightBasisLine(allocation, currency);
|
|
1103
1153
|
if (weightNote) notes.push(cliStyles.muted(weightNote));
|
|
1104
1154
|
// The notes name the rows as the table does.
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { PaneTemplateContext, PaneTemplateInstanceConfig, ShortcutArgError } from "../../../types/plugin";
|
|
2
2
|
import type { PluginModule } from "../plugin-module";
|
|
3
3
|
import { unknownCollectionArgError } from "../../../portfolio/collection-name";
|
|
4
|
-
import { PortfolioListPane } from "./pane";
|
|
5
4
|
import {
|
|
6
5
|
buildPortfolioPaneSettingsDef,
|
|
7
6
|
getPortfolioPaneSettings,
|
|
@@ -54,7 +53,7 @@ export const portfolioListModule: PluginModule = {
|
|
|
54
53
|
reportFreshness: { source: "Local portfolio and Gloom Cloud" },
|
|
55
54
|
name: "Portfolio",
|
|
56
55
|
icon: "P",
|
|
57
|
-
component: PortfolioListPane,
|
|
56
|
+
get component(): typeof import("./pane").PortfolioListPane { const { PortfolioListPane } = require("./pane"); return PortfolioListPane; },
|
|
58
57
|
defaultPosition: "left",
|
|
59
58
|
defaultMode: "floating",
|
|
60
59
|
defaultWidth: "40%",
|
|
@@ -34,6 +34,7 @@ import { convertCurrency } from "../../../../utils/format";
|
|
|
34
34
|
import { nextHeaderSort } from "../../../../utils/sort-values";
|
|
35
35
|
import { getSharedMarketDataCoordinator } from "../../../../market-data/coordinator";
|
|
36
36
|
import type { TickerRecord } from "../../../../types/ticker";
|
|
37
|
+
import type { TickerFinancials } from "../../../../types/financials";
|
|
37
38
|
import type { PaneProps } from "../../../../types/plugin";
|
|
38
39
|
import type { InstrumentRef } from "../../../../market-data/request-types";
|
|
39
40
|
import {
|
|
@@ -56,6 +57,7 @@ import {
|
|
|
56
57
|
} from "../summary";
|
|
57
58
|
import { usePortfolioAccountState } from "../summary/live-accounts";
|
|
58
59
|
import { useOfflineBrokerFooter } from "../../shared/broker-reconnect";
|
|
60
|
+
import { useQuoteDelayFooter } from "../../shared/cloud-upgrade";
|
|
59
61
|
import {
|
|
60
62
|
getCollectionEntries,
|
|
61
63
|
getPortfolioPaneSettings,
|
|
@@ -598,6 +600,8 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
|
|
|
598
600
|
summaryAccountState,
|
|
599
601
|
], FOOTER_TOTALS_THROTTLE_MS);
|
|
600
602
|
const fxWarning = !!(fxStatus.stale || fxStatus.unknownTime || fxStatus.unavailable);
|
|
603
|
+
// Signed out or free, the rows' prices are the delayed ones; a list of coins is live and says nothing.
|
|
604
|
+
const quoteDelay = useQuoteDelayFooter(rowQuotes(sortedTickers, financialsMap), "portfolio-delay");
|
|
601
605
|
const summaryNotices = isPortfolioTab
|
|
602
606
|
? buildPortfolioSummaryNotices({
|
|
603
607
|
totals: portfolioSummaryTotals,
|
|
@@ -675,6 +679,7 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
|
|
|
675
679
|
...offlineBrokerFooter.status,
|
|
676
680
|
...(fxStatusText && !fxWarning ? [{ id: "fx", parts: [{ text: `FX ${fxStatusText}`, tone: "muted" as const }] }] : []),
|
|
677
681
|
...(showsPerpetuals && perpetuals.stale ? [{ id: "perpetuals", parts: [{ text: "perpetuals stale", tone: "warning" as const }] }] : []),
|
|
682
|
+
...(quoteDelay ? [quoteDelay] : []),
|
|
678
683
|
],
|
|
679
684
|
hints: [
|
|
680
685
|
...offlineBrokerFooter.hints,
|
|
@@ -714,6 +719,7 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
|
|
|
714
719
|
isPortfolioTab,
|
|
715
720
|
offlineBrokerFooter,
|
|
716
721
|
perpetuals.stale,
|
|
722
|
+
quoteDelay,
|
|
717
723
|
removalCollection,
|
|
718
724
|
removeSelectedTicker,
|
|
719
725
|
selectedTicker,
|
|
@@ -840,3 +846,8 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
|
|
|
840
846
|
</Box>
|
|
841
847
|
);
|
|
842
848
|
}
|
|
849
|
+
|
|
850
|
+
/** The quotes of the rows, in order, for the delayed clock, which stops at the first late one. */
|
|
851
|
+
function* rowQuotes(tickers: readonly TickerRecord[], financialsMap: ReadonlyMap<string, TickerFinancials>) {
|
|
852
|
+
for (const ticker of tickers) yield financialsMap.get(ticker.metadata.ticker)?.quote;
|
|
853
|
+
}
|
|
@@ -12,7 +12,7 @@ import { usePluginAppActions } from "../../../runtime";
|
|
|
12
12
|
import { isDialogOpen } from "../../../../ui/dialog-stack";
|
|
13
13
|
import { colors, priceColor } from "../../../../theme/colors";
|
|
14
14
|
import { formatPercentRaw } from "../../../../utils/format";
|
|
15
|
-
import { formatMarketPrice } from "../../../../market-data/market/format";
|
|
15
|
+
import { formatMarketPrice, quoteFormatOptions } from "../../../../market-data/market/format";
|
|
16
16
|
import { listingChoiceQuery, upsertTickerFromSearchResult } from "../../../../tickers/search";
|
|
17
17
|
import type { TickerRecord } from "../../../../types/ticker";
|
|
18
18
|
import { addTickerToPortfolio, addTickerToWatchlist } from "../../../../portfolio/mutations";
|
|
@@ -79,7 +79,7 @@ function QuickAddPreview({
|
|
|
79
79
|
const assetCategory = validation.ticker?.metadata.assetCategory
|
|
80
80
|
?? (validation.resolved.kind === "provider" ? validation.resolved.result.type : undefined);
|
|
81
81
|
const priceText = quote?.price != null
|
|
82
|
-
? formatMarketPrice(quote.price, { assetCategory, maxWidth: 12 })
|
|
82
|
+
? formatMarketPrice(quote.price, { ...quoteFormatOptions(quote, assetCategory), maxWidth: 12 })
|
|
83
83
|
: "-";
|
|
84
84
|
const changeValue = quote?.changePercent;
|
|
85
85
|
const name = tickerNameFromValidation(validation);
|
|
@@ -2,7 +2,6 @@ import type { PaneTemplateInstanceConfig } from "../../../types/plugin";
|
|
|
2
2
|
import type { PluginModule } from "../plugin-module";
|
|
3
3
|
import { powerBoardCache, powerDetailCache, powerHistoryCache } from "./client";
|
|
4
4
|
import { powerHeadless } from "./headless";
|
|
5
|
-
import { PowerPane } from "./pane";
|
|
6
5
|
import { carbonHistoryCache, carbonPriceCache, powerPriceHistoryCache, powerPricesCache } from "./prices-client";
|
|
7
6
|
import { powerPricesHeadless } from "./prices-headless";
|
|
8
7
|
import { CARBON_SELECTION, CARBON_SERIES, DAY_AHEAD_SERIES, isCarbonQuery, POWER_PRICE_MARKETS, powerPriceMarket } from "./prices-model";
|
|
@@ -15,7 +14,7 @@ const CACHES = [powerBoardCache, powerHistoryCache, powerDetailCache, powerPrice
|
|
|
15
14
|
export const powerModule: PluginModule = {
|
|
16
15
|
series: [...DAY_AHEAD_SERIES, ...CARBON_SERIES, ...GAS_STORAGE_SERIES],
|
|
17
16
|
// POWER sets the symbol param, EPWR the prices tab.
|
|
18
|
-
panes: [{ id: "power", name: "Power & Grid", icon: "P", component: PowerPane, defaultPosition: "right", defaultMode: "floating", identitySettings: ["tab", "symbol"],
|
|
17
|
+
panes: [{ id: "power", name: "Power & Grid", icon: "P", get component(): typeof import("./pane").PowerPane { const { PowerPane } = require("./pane"); return PowerPane; }, defaultPosition: "right", defaultMode: "floating", identitySettings: ["tab", "symbol"],
|
|
19
18
|
defaultFloatingSize: { width: 132, height: 34 }, tableExport: true, headless: powerHeadless }],
|
|
20
19
|
paneTemplates: [{ id: "power-pane", paneId: "power", label: "Power & Grid",
|
|
21
20
|
description: "Pro: interconnection queues, historical MW and outcomes, datacenter loads, utility exposure and generation capacity, with primary evidence.",
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import type { PluginModule } from "../plugin-module";
|
|
2
2
|
import { ratePathCache } from "./client";
|
|
3
3
|
import { ratePathHeadless } from "./headless";
|
|
4
|
-
import { RatePathPane } from "./pane";
|
|
5
4
|
|
|
6
5
|
export const ratePathModule: PluginModule = {
|
|
7
|
-
panes: [{ id: "rate-path", name: "US Rate Path", icon: "R", component: RatePathPane,
|
|
6
|
+
panes: [{ id: "rate-path", name: "US Rate Path", icon: "R", get component(): typeof import("./pane").RatePathPane { const { RatePathPane } = require("./pane"); return RatePathPane; },
|
|
8
7
|
defaultPosition: "right", defaultMode: "floating", defaultFloatingSize: { width: 86, height: 30 },
|
|
9
8
|
tableExport: true, headless: ratePathHeadless }],
|
|
10
9
|
paneTemplates: [{
|
|
@@ -55,6 +55,8 @@ export function realizedVolHeadless(initialView: "graph" | "cone"): HeadlessPane
|
|
|
55
55
|
const lastBar = model.asOf && Number.isFinite(model.asOf.getTime()) ? model.asOf.toISOString().slice(0, 10) : null;
|
|
56
56
|
return {
|
|
57
57
|
freshness: { asOf: lastBar },
|
|
58
|
+
// The session still trading is left out of every estimate, and said, as BT says it.
|
|
59
|
+
...(model.formingNote ? { warnings: [`${model.formingNote}.`] } : {}),
|
|
58
60
|
sections: [
|
|
59
61
|
{ title: "Volatility cone", columns: [
|
|
60
62
|
{ key: "window", header: "Bars" },
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import type { PluginModule } from "../plugin-module";
|
|
2
2
|
import { createTickerSurfacePaneTemplate } from "../shared/ticker-surface";
|
|
3
|
-
import { RealizedVolPane } from "./pane";
|
|
4
3
|
import { realizedVolHeadless } from "./headless";
|
|
5
4
|
import { ESTIMATOR_OPTIONS, WINDOW_OPTIONS } from "./settings";
|
|
6
5
|
|
|
7
6
|
export const realizedVolModule: PluginModule = {
|
|
8
7
|
panes: [{
|
|
9
|
-
id: "realized-vol", name: "Realized Volatility", icon: "V", component: RealizedVolPane,
|
|
8
|
+
id: "realized-vol", name: "Realized Volatility", icon: "V", get component(): typeof import("./pane").RealizedVolPane { const { RealizedVolPane } = require("./pane"); return RealizedVolPane; },
|
|
10
9
|
defaultPosition: "right", tickerFollower: true, defaultMode: "floating", defaultFloatingSize: { width: 112, height: 36 },
|
|
11
10
|
tableExport: true,
|
|
12
11
|
quickSettings: [{ type: "toggle", key: "showIv", icon: "zap", label: "Current ATM IV" }],
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
type RealizedVolatilityEstimator, type RollingRealizedVolatilityPoint, type VolatilityConeStatistics,
|
|
6
6
|
} from "../shared/volatility";
|
|
7
7
|
import type { SurfaceExpiry, SurfaceSnapshot } from "../vol-surface/model";
|
|
8
|
+
import { formingBarsState, isFormingBar } from "../shared/forming-bars";
|
|
8
9
|
|
|
9
10
|
export interface RealizedVolatilityModel {
|
|
10
11
|
symbol: string;
|
|
@@ -30,6 +31,12 @@ export interface RealizedVolatilityModel {
|
|
|
30
31
|
* history covers the lookback and every window.
|
|
31
32
|
*/
|
|
32
33
|
historyNote: string | null;
|
|
34
|
+
/**
|
|
35
|
+
* The newest session left out while it is not final, as BT leaves it out:
|
|
36
|
+
* "2026-10-30 is still forming (partial) and left out: the estimates run
|
|
37
|
+
* through 2026-10-29, the last complete session". Null when every bar is final.
|
|
38
|
+
*/
|
|
39
|
+
formingNote: string | null;
|
|
33
40
|
}
|
|
34
41
|
|
|
35
42
|
/** "the 180-bar window", "the 180- and 260-bar windows", "the 90-, 180- and 260-bar windows". */
|
|
@@ -77,8 +84,15 @@ export function projectRealizedVolatility(
|
|
|
77
84
|
}
|
|
78
85
|
dates.set(date.getTime(), { ...point, date });
|
|
79
86
|
}
|
|
80
|
-
const
|
|
87
|
+
const served = [...dates.entries()].sort(([a], [b]) => a - b).map(([, point]) => point);
|
|
88
|
+
// A session still trading moves every estimate it is in until it ends: left out, as BT leaves it out, and said.
|
|
89
|
+
const forming = served.filter(isFormingBar);
|
|
90
|
+
const history = forming.length ? served.filter((point) => !isFormingBar(point)) : served;
|
|
81
91
|
const asOf = history.at(-1)?.date ?? null;
|
|
92
|
+
const day = (date: Date) => date.toISOString().slice(0, 10);
|
|
93
|
+
const formingNote = forming.length === 0 ? null
|
|
94
|
+
: `${forming.map((point) => day(point.date)).join(", ")} ${formingBarsState(forming)} and left out`
|
|
95
|
+
+ `${asOf ? `: the estimates run through ${day(asOf)}, the last complete session` : ""}`;
|
|
82
96
|
const cutoff = asOf ? lookbackCutoff(asOf, lookbackYears) : 0;
|
|
83
97
|
const cadenceIssue = realizedVolatilityCadenceIssue(history);
|
|
84
98
|
if (cadenceIssue) warnings.push(cadenceIssue);
|
|
@@ -109,7 +123,7 @@ export function projectRealizedVolatility(
|
|
|
109
123
|
: "the long windows' cone covers part of the lookback"}`;
|
|
110
124
|
return { symbol: options.symbol.trim().toUpperCase(), estimator, lookbackYears, windows,
|
|
111
125
|
history: visible, series: visibleSeries, cone, asOf, barsPerYear: barsPerYear(history.map((point) => point.date)),
|
|
112
|
-
warnings: [...new Set(warnings)], shortWindows, historyNote };
|
|
126
|
+
warnings: [...new Set(warnings)], shortWindows, historyNote, formingNote };
|
|
113
127
|
}
|
|
114
128
|
|
|
115
129
|
interface CurrentAtmIvReference {
|
|
@@ -115,10 +115,10 @@ export function RealizedVolPane({ width, height, focused }: PaneProps) {
|
|
|
115
115
|
symbol: history.data.symbol, estimator, windows, lookbackYears: Number(lookback) === 2 ? 2 : 1,
|
|
116
116
|
}) : null, [history.data, estimator, windows, lookback]);
|
|
117
117
|
const chartInput = useMemo(() => model ? { history: model.history, rolling: model.series, windows: model.windows,
|
|
118
|
-
priceUnit: priceSeriesUnit(quote?.currency ?? "", quote?.instrumentType), iv: showIv ? iv.data?.reference ?? null : null } : null,
|
|
119
|
-
[model, quote?.currency, quote?.instrumentType, showIv, iv.data]);
|
|
118
|
+
priceUnit: priceSeriesUnit(quote?.currency ?? "", quote?.instrumentType, quote?.priceBasis), iv: showIv ? iv.data?.reference ?? null : null } : null,
|
|
119
|
+
[model, quote?.currency, quote?.instrumentType, quote?.priceBasis, showIv, iv.data]);
|
|
120
120
|
const notices = [identityError, history.error, history.data?.error, iv.error, ivRefresh.error, iv.data?.error,
|
|
121
|
-
...(model?.warnings ?? []), model?.historyNote, ...(showIv ? iv.data?.warnings ?? [] : []),
|
|
121
|
+
...(model?.warnings ?? []), model?.historyNote, model?.formingNote, ...(showIv ? iv.data?.warnings ?? [] : []),
|
|
122
122
|
...(showIv && symbol && !spotAvailable ? ["Current ATM IV unavailable: underlying quote is missing or stale"] : []),
|
|
123
123
|
].filter((value): value is string => !!value);
|
|
124
124
|
usePaneNoticeFooter({ registrationId: "realized-vol-notices", notices: [...new Set(notices)], focused });
|
|
@@ -2,7 +2,6 @@ import { isOnPortfolio } from "../../../shares/pane-image";
|
|
|
2
2
|
import type { PluginModule } from "../plugin-module";
|
|
3
3
|
import { rotationCache } from "./client";
|
|
4
4
|
import { rotationHeadless } from "./headless";
|
|
5
|
-
import { RelativeRotationPane } from "./pane";
|
|
6
5
|
import { DEFAULT_ROTATION_BENCHMARK } from "./model";
|
|
7
6
|
|
|
8
7
|
export const relativeRotationModule: PluginModule = {
|
|
@@ -11,7 +10,7 @@ export const relativeRotationModule: PluginModule = {
|
|
|
11
10
|
id: "relative-rotation",
|
|
12
11
|
name: "Relative Rotation",
|
|
13
12
|
icon: "R",
|
|
14
|
-
component: RelativeRotationPane,
|
|
13
|
+
get component(): typeof import("./pane").RelativeRotationPane { const { RelativeRotationPane } = require("./pane"); return RelativeRotationPane; },
|
|
15
14
|
defaultPosition: "right",
|
|
16
15
|
defaultMode: "floating",
|
|
17
16
|
defaultFloatingSize: { width: 100, height: 36 },
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
recommendationMix,
|
|
21
21
|
formatRatingLabel,
|
|
22
22
|
formatRatingTarget,
|
|
23
|
+
ratingReason,
|
|
23
24
|
recommendationTotal,
|
|
24
25
|
sortRatingRows,
|
|
25
26
|
type RatingColumnId,
|
|
@@ -43,6 +44,27 @@ const RATING_COLUMNS: HeadlessPaneColumn[] = [
|
|
|
43
44
|
{ key: "prior", header: "Prior" },
|
|
44
45
|
];
|
|
45
46
|
|
|
47
|
+
type RatingRow = AnalystResearchData["ratings"][number];
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The reason coverage gave, on its own line under the action with its
|
|
51
|
+
* article; exports keep the line and the article's address as columns. Only
|
|
52
|
+
* a history with a reason somewhere has them.
|
|
53
|
+
*/
|
|
54
|
+
const REASON_COLUMNS: HeadlessPaneColumn[] = [
|
|
55
|
+
{
|
|
56
|
+
key: "reason",
|
|
57
|
+
header: "Reason",
|
|
58
|
+
underRow: true,
|
|
59
|
+
format: (_value, row) => ratingReason(row as unknown as RatingRow)?.text ?? "",
|
|
60
|
+
textFormat: (_value, row) => {
|
|
61
|
+
const reason = ratingReason(row as unknown as RatingRow);
|
|
62
|
+
return reason ? `${reason.text} · ${reason.url}` : "";
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{ key: "reasonUrl", header: "Reason URL", underRow: true, textFormat: () => "" },
|
|
66
|
+
];
|
|
67
|
+
|
|
46
68
|
const SORT_COLUMNS: Record<string, RatingColumnId> = {
|
|
47
69
|
date: "date",
|
|
48
70
|
firm: "firm",
|
|
@@ -170,14 +192,19 @@ export function createAnalystResearchHeadless(
|
|
|
170
192
|
direction: args.options.order === "asc" ? "asc" : "desc",
|
|
171
193
|
})
|
|
172
194
|
.slice(0, Number(args.options.limit))
|
|
173
|
-
.map((rating) =>
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
195
|
+
.map((rating) => {
|
|
196
|
+
const reason = ratingReason(rating);
|
|
197
|
+
return {
|
|
198
|
+
...rating,
|
|
199
|
+
target: rating.currentPriceTarget ?? rating.priorPriceTarget ?? null,
|
|
200
|
+
currency: currency ?? null,
|
|
201
|
+
...(reason ? { reasonUrl: reason.url } : {}),
|
|
202
|
+
};
|
|
203
|
+
});
|
|
204
|
+
const columns = ratings.some((rating) => ratingReason(rating)) ? [...RATING_COLUMNS, ...REASON_COLUMNS] : RATING_COLUMNS;
|
|
178
205
|
const sections: HeadlessBundleSection[] = [
|
|
179
206
|
{ title: "Summary", entries: overviewEntries(data, quote) },
|
|
180
|
-
{ title: "Recent analyst actions", columns
|
|
207
|
+
{ title: "Recent analyst actions", columns, rows: ratings },
|
|
181
208
|
];
|
|
182
209
|
return {
|
|
183
210
|
sections,
|
|
@@ -235,7 +235,7 @@ export function ratingTargetDelta(row: AnalystResearchData["ratings"][number]):
|
|
|
235
235
|
return row.currentPriceTarget - prior;
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
export type RatingColumnId = "date" | "firm" | "action" | "current" | "target" | "prior";
|
|
238
|
+
export type RatingColumnId = "date" | "firm" | "action" | "current" | "target" | "prior" | "reason";
|
|
239
239
|
export type RatingColumn = DataTableColumn & { id: RatingColumnId } & Partial<RatingTargetColumnSizing>;
|
|
240
240
|
|
|
241
241
|
export interface RatingSortPreference {
|
|
@@ -255,6 +255,7 @@ const DEFAULT_RATING_SORT_DIRECTIONS: Record<RatingColumnId, SortDirection> = {
|
|
|
255
255
|
current: "asc",
|
|
256
256
|
target: "desc",
|
|
257
257
|
prior: "asc",
|
|
258
|
+
reason: "asc",
|
|
258
259
|
};
|
|
259
260
|
|
|
260
261
|
const BASE_RATING_COLUMNS: RatingColumn[] = [
|
|
@@ -266,6 +267,36 @@ const BASE_RATING_COLUMNS: RatingColumn[] = [
|
|
|
266
267
|
{ id: "prior", label: "PRIOR", width: 13, align: "left" },
|
|
267
268
|
];
|
|
268
269
|
|
|
270
|
+
/** The reason coverage gives for an action: last, taking the room the pane has left. */
|
|
271
|
+
const REASON_COLUMN: RatingColumn = { id: "reason", label: "REASON", width: 28, align: "left", flexGrow: 1 };
|
|
272
|
+
|
|
273
|
+
/** The line coverage of the action quotes, or null when none gives one. */
|
|
274
|
+
export function ratingReason(row: AnalystRatingRecord): AnalystRatingRecord["reason"] | null {
|
|
275
|
+
const reason = row.reason;
|
|
276
|
+
return reason?.text?.trim() && reason.url?.trim() ? reason : null;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* The status bar room the selected action's article takes: its `source`
|
|
281
|
+
* link, the `o` hint that opens it and their separators. The consensus
|
|
282
|
+
* context gives way to it rather than cut it.
|
|
283
|
+
*/
|
|
284
|
+
export function ratingReasonFooterWidth(reason: AnalystRatingRecord["reason"] | null): number {
|
|
285
|
+
if (!reason) return 0;
|
|
286
|
+
return displayWidth(`source ${ratingReasonSource(reason)}`) + displayWidth(" · ") + displayWidth("[o]pen") + 2;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** Who published the reason: the publisher's name, else the article's site. */
|
|
290
|
+
export function ratingReasonSource(reason: NonNullable<AnalystRatingRecord["reason"]>): string {
|
|
291
|
+
const named = reason.source?.trim();
|
|
292
|
+
if (named) return named;
|
|
293
|
+
try {
|
|
294
|
+
return new URL(reason.url).hostname.replace(/^www\./, "");
|
|
295
|
+
} catch {
|
|
296
|
+
return "source";
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
269
300
|
export function buildRatingColumns(
|
|
270
301
|
rows: readonly AnalystRatingRecord[],
|
|
271
302
|
currency: string | undefined,
|
|
@@ -288,9 +319,11 @@ export function buildRatingColumns(
|
|
|
288
319
|
BASE_RATING_COLUMNS.find((column) => column.id === "target")?.width ?? 13,
|
|
289
320
|
);
|
|
290
321
|
|
|
291
|
-
|
|
322
|
+
const columns = BASE_RATING_COLUMNS.map((column) => {
|
|
292
323
|
return column.id === "target" ? { ...column, ...targetSizing, width: targetWidth } : column;
|
|
293
324
|
});
|
|
325
|
+
// A history with no reason anywhere keeps the table it always had.
|
|
326
|
+
return rows.some((row) => ratingReason(row)) ? [...columns, REASON_COLUMN] : columns;
|
|
294
327
|
}
|
|
295
328
|
|
|
296
329
|
function normalizedText(value: string | undefined): string | null {
|
|
@@ -316,6 +349,8 @@ function ratingSortValue(row: AnalystRatingRecord, columnId: RatingColumnId): st
|
|
|
316
349
|
return ratingTargetSortValue(row);
|
|
317
350
|
case "prior":
|
|
318
351
|
return normalizedText(row.prior);
|
|
352
|
+
case "reason":
|
|
353
|
+
return normalizedText(ratingReason(row)?.text);
|
|
319
354
|
}
|
|
320
355
|
}
|
|
321
356
|
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
spanAxisFormatter,
|
|
9
9
|
staticSeries,
|
|
10
10
|
useChartTableSelection,
|
|
11
|
-
|
|
11
|
+
useExternalLinkFooter,
|
|
12
12
|
type ChartTableSelection,
|
|
13
13
|
type DataTableCell,
|
|
14
14
|
type DataTableKeyEvent,
|
|
@@ -39,6 +39,9 @@ import {
|
|
|
39
39
|
buildRatingColumns,
|
|
40
40
|
firstRatingSortDirection,
|
|
41
41
|
formatRatingTarget,
|
|
42
|
+
ratingReason,
|
|
43
|
+
ratingReasonFooterWidth,
|
|
44
|
+
ratingReasonSource,
|
|
42
45
|
ratingSplit,
|
|
43
46
|
ratingTargetDelta,
|
|
44
47
|
sortRatingRows,
|
|
@@ -142,13 +145,16 @@ function AnalystHeader({ data, history, series, currency, width, height, tableRo
|
|
|
142
145
|
/**
|
|
143
146
|
* Streams the bound symbol and keeps the status bar's reference price on it.
|
|
144
147
|
* Rendered beside the table so a tick redraws the footer, not the ratings.
|
|
148
|
+
* The selected action's reason, when coverage gave one, is a link there.
|
|
145
149
|
*/
|
|
146
|
-
function AnalystFooter({ data, loading, error, width, binding }: {
|
|
150
|
+
function AnalystFooter({ data, loading, error, width, binding, focused, reason }: {
|
|
147
151
|
data: AnalystResearchData | null;
|
|
148
152
|
loading: boolean;
|
|
149
153
|
error: string | null;
|
|
150
154
|
width: number;
|
|
151
155
|
binding: AnalystQuoteBinding;
|
|
156
|
+
focused: boolean;
|
|
157
|
+
reason: ReturnType<typeof ratingReason>;
|
|
152
158
|
}) {
|
|
153
159
|
// The upside is a percentage; about one update a second is enough for it.
|
|
154
160
|
const financials = useLiveTickerFinancials(binding.ticker ? binding.symbol : null, binding.ticker, {
|
|
@@ -157,9 +163,17 @@ function AnalystFooter({ data, loading, error, width, binding }: {
|
|
|
157
163
|
weight: 40,
|
|
158
164
|
});
|
|
159
165
|
const reference = analystReferencePrice(data, financials?.quote);
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
166
|
+
const info = useMemo(
|
|
167
|
+
() => buildAnalystFooterInfo(data, { width: width - ratingReasonFooterWidth(reason), loading, error, reference }),
|
|
168
|
+
[data, error, loading, reason, reference.freshness, reference.live, reference.price, width],
|
|
169
|
+
);
|
|
170
|
+
useExternalLinkFooter({
|
|
171
|
+
registrationId: "analyst-research",
|
|
172
|
+
focused,
|
|
173
|
+
url: reason?.url,
|
|
174
|
+
source: reason ? ratingReasonSource(reason) : null,
|
|
175
|
+
info,
|
|
176
|
+
});
|
|
163
177
|
return null;
|
|
164
178
|
}
|
|
165
179
|
|
|
@@ -246,6 +260,9 @@ export function AnalystResearchView({ focused, width, height }: { focused: boole
|
|
|
246
260
|
}
|
|
247
261
|
case "prior":
|
|
248
262
|
return { text: row.prior ?? "-", color: colors.textDim };
|
|
263
|
+
case "reason":
|
|
264
|
+
// Blank, not a dash: no coverage gave a reason.
|
|
265
|
+
return { text: ratingReason(row)?.text ?? "", color: colors.textDim };
|
|
249
266
|
}
|
|
250
267
|
}, [ratingCurrency]);
|
|
251
268
|
|
|
@@ -258,6 +275,7 @@ export function AnalystResearchView({ focused, width, height }: { focused: boole
|
|
|
258
275
|
}));
|
|
259
276
|
}, []);
|
|
260
277
|
|
|
278
|
+
const selectedRow = rows.length > 0 ? rows[selectedIdx] : undefined;
|
|
261
279
|
const footer = (
|
|
262
280
|
<AnalystFooter
|
|
263
281
|
data={authWall ? null : data}
|
|
@@ -265,6 +283,8 @@ export function AnalystResearchView({ focused, width, height }: { focused: boole
|
|
|
265
283
|
error={authWall ? null : error}
|
|
266
284
|
width={width}
|
|
267
285
|
binding={binding}
|
|
286
|
+
focused={focused}
|
|
287
|
+
reason={authWall || !selectedRow ? null : ratingReason(selectedRow)}
|
|
268
288
|
/>
|
|
269
289
|
);
|
|
270
290
|
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import type { PluginModule } from "../plugin-module";
|
|
2
2
|
import { parseTickerListInput, formatTickerListInput } from "../../../tickers/list";
|
|
3
3
|
import { createTickerSurfacePaneTemplate } from "../shared/ticker-surface";
|
|
4
|
-
import { AnalystResearchView } from "./analyst-pane";
|
|
5
4
|
import { CorporateActionsView } from "./corporate-actions-pane";
|
|
6
|
-
import { EquityDiagnosticView } from "./equity-diagnostic-pane";
|
|
7
|
-
import { RelativeValuationPane } from "./relative-valuation-pane";
|
|
8
5
|
import { relativeValuationHeadless } from "./relative-valuation-headless";
|
|
9
6
|
import { AUTO_PEERS_SETTING, relativeValuationTitle } from "./relative-valuation-peers";
|
|
10
7
|
import { buildRelativeValuationSettingsDef, MAX_RELATIVE_VALUATION_TICKERS } from "./relative-valuation-settings";
|
|
@@ -29,14 +26,14 @@ export const researchModule: PluginModule = {
|
|
|
29
26
|
id: "analyst-research",
|
|
30
27
|
name: "Analyst",
|
|
31
28
|
order: 32,
|
|
32
|
-
component: AnalystResearchView,
|
|
29
|
+
get component(): typeof import("./analyst-pane").AnalystResearchView { const { AnalystResearchView } = require("./analyst-pane"); return AnalystResearchView; },
|
|
33
30
|
instruments: ["equity"],
|
|
34
31
|
});
|
|
35
32
|
ctx.registerTickerResearchTab({
|
|
36
33
|
id: "equity-diagnostic",
|
|
37
34
|
name: "Diagnostic",
|
|
38
35
|
order: 33,
|
|
39
|
-
component: EquityDiagnosticView,
|
|
36
|
+
get component(): typeof import("./equity-diagnostic-pane").EquityDiagnosticView { const { EquityDiagnosticView } = require("./equity-diagnostic-pane"); return EquityDiagnosticView; },
|
|
40
37
|
instruments: ["equity"],
|
|
41
38
|
});
|
|
42
39
|
ctx.registerTickerResearchTab({
|
|
@@ -53,7 +50,7 @@ export const researchModule: PluginModule = {
|
|
|
53
50
|
id: "analyst-research",
|
|
54
51
|
name: "Analyst Research",
|
|
55
52
|
icon: "A",
|
|
56
|
-
component: AnalystResearchView,
|
|
53
|
+
get component(): typeof import("./analyst-pane").AnalystResearchView { const { AnalystResearchView } = require("./analyst-pane"); return AnalystResearchView; },
|
|
57
54
|
defaultPosition: "right",
|
|
58
55
|
tickerFollower: true,
|
|
59
56
|
instruments: ["equity"],
|
|
@@ -68,7 +65,7 @@ export const researchModule: PluginModule = {
|
|
|
68
65
|
reportRequirements: ["Free Gloom sign-in"],
|
|
69
66
|
name: "Equity Diagnostic",
|
|
70
67
|
icon: "D",
|
|
71
|
-
component: EquityDiagnosticView,
|
|
68
|
+
get component(): typeof import("./equity-diagnostic-pane").EquityDiagnosticView { const { EquityDiagnosticView } = require("./equity-diagnostic-pane"); return EquityDiagnosticView; },
|
|
72
69
|
defaultPosition: "right",
|
|
73
70
|
tickerFollower: true,
|
|
74
71
|
instruments: ["equity"],
|
|
@@ -91,7 +88,7 @@ export const researchModule: PluginModule = {
|
|
|
91
88
|
id: "relative-valuation",
|
|
92
89
|
name: "Relative Valuation",
|
|
93
90
|
icon: "R",
|
|
94
|
-
component: RelativeValuationPane,
|
|
91
|
+
get component(): typeof import("./relative-valuation-pane").RelativeValuationPane { const { RelativeValuationPane } = require("./relative-valuation-pane"); return RelativeValuationPane; },
|
|
95
92
|
headless: relativeValuationHeadless,
|
|
96
93
|
defaultPosition: "right",
|
|
97
94
|
defaultMode: "floating",
|