gloomberb 0.16.0 → 0.16.2
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 +2 -1
- package/package.json +2 -1
- package/src/api-client/beneficial-owners.ts +92 -0
- package/src/api-client/data.ts +44 -11
- package/src/api-client/errors.ts +12 -0
- package/src/api-client/geo.ts +363 -0
- package/src/api-client/index.ts +5 -0
- package/src/api-client/market-discovery.ts +10 -0
- package/src/api-client/members.ts +26 -0
- package/src/api-client/paths.ts +30 -1
- package/src/api-client/perps.ts +41 -0
- package/src/api-client/request.ts +5 -2
- package/src/api-client/types.ts +9 -1
- package/src/app/global-shortcuts.ts +14 -6
- package/src/app/keybindings/actions.ts +1 -1
- package/src/app/runtime/update.ts +38 -2
- package/src/app.tsx +10 -6
- package/src/brokers/account-cache.ts +24 -0
- package/src/cli/commands/command-utils.ts +8 -0
- package/src/cli/commands/crypto-hints.ts +75 -0
- package/src/cli/commands/market.ts +414 -106
- package/src/cli/commands/overview.ts +77 -32
- package/src/cli/commands/ticker.ts +101 -43
- package/src/cli/desktop-pane-shot.ts +34 -4
- package/src/cli/freshness.ts +61 -0
- package/src/cli/help.ts +1 -0
- package/src/cli/helpers.ts +4 -8
- package/src/cli/index.ts +12 -2
- package/src/cli/listing-arg.ts +321 -0
- package/src/cli/pane-functions/access-gate.ts +42 -0
- package/src/cli/pane-functions/catalog.ts +28 -1
- package/src/cli/pane-functions/data.ts +3 -1
- package/src/cli/pane-functions/dom.ts +20 -2
- package/src/cli/pane-functions/freshness.ts +400 -0
- package/src/cli/pane-functions/function-help.ts +36 -22
- package/src/cli/pane-functions/headless.ts +39 -11
- package/src/cli/pane-functions/index.ts +15 -4
- package/src/cli/pane-functions/options.ts +3 -0
- package/src/cli/pane-functions/report.ts +4 -0
- package/src/cli/pane-functions/resolver.ts +35 -7
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +7 -3
- package/src/cli/result.ts +41 -27
- package/src/cli/ticker-resolution.ts +7 -5
- package/src/components/chart/composite/composite-chart.tsx +88 -2536
- package/src/components/chart/composite/drawing-store.ts +59 -0
- package/src/components/chart/composite/legend.tsx +319 -0
- package/src/components/chart/composite/panel-bitmap.ts +139 -0
- package/src/components/chart/composite/panel-gestures.ts +59 -0
- package/src/components/chart/composite/panel-labels.ts +107 -0
- package/src/components/chart/composite/panel-surface.tsx +876 -0
- package/src/components/chart/composite/tool-catalog.ts +98 -0
- package/src/components/chart/composite/toolbar.tsx +186 -0
- package/src/components/chart/composite/tools.ts +8 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +703 -0
- package/src/components/chart/composite/use-composite-viewport.ts +143 -0
- package/src/components/command-bar/commands/collection.ts +5 -1
- package/src/components/command-bar/list/model.ts +5 -0
- package/src/components/command-bar/list/view.tsx +16 -3
- package/src/components/command-bar/pane-templates/workflow.ts +1 -0
- package/src/components/command-bar/routes/root/command-items.ts +9 -2
- package/src/components/command-bar/routes/root/plugin-install.ts +2 -2
- package/src/components/command-bar/routes/root/provider-search.ts +19 -5
- package/src/components/command-bar/routes/root/runtime.ts +14 -5
- package/src/components/command-bar/routes/ticker-search/actions.ts +5 -0
- package/src/components/command-bar/routes/ticker-search/results.ts +31 -5
- package/src/components/command-bar/routes/ticker-search/route.ts +2 -2
- package/src/components/command-bar/routing/actions.ts +2 -0
- package/src/components/command-bar/selection-runtime.ts +38 -0
- package/src/components/command-bar/surface/index.tsx +7 -2
- package/src/components/command-bar/workflow/ops.ts +1 -1
- package/src/components/command-bar/workflow/tickers.ts +6 -0
- package/src/components/data-table/view.tsx +29 -10
- package/src/components/feedback-dialog.tsx +2 -1
- package/src/components/form-modal/field-row.tsx +2 -2
- package/src/components/index.ts +2 -2
- package/src/components/layout/detached-pane-shell.tsx +6 -3
- package/src/components/layout/floating-pane.tsx +6 -0
- package/src/components/layout/header.tsx +24 -7
- package/src/components/layout/missing-pane.tsx +2 -2
- package/src/components/layout/pane/content.tsx +23 -10
- package/src/components/layout/pane/error-boundary.tsx +103 -0
- package/src/components/layout/pane/footer/registration.tsx +68 -23
- package/src/components/layout/pane/header.tsx +61 -28
- package/src/components/layout/pane/index.tsx +6 -0
- package/src/components/layout/pane/title.ts +31 -7
- package/src/components/layout/shell/drag/index.ts +6 -5
- package/src/components/layout/shell/drag/runtime.ts +3 -0
- package/src/components/layout/shell/index.tsx +6 -0
- package/src/components/layout/shell/menu.ts +2 -1
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +29 -10
- package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -3
- package/src/components/layout/shell/ticker-link-menu.ts +23 -9
- package/src/components/metric-treemap/heat-surface.tsx +745 -0
- package/src/components/metric-treemap/heat-tiles.ts +228 -0
- package/src/components/metric-treemap/index.tsx +2 -0
- package/src/components/metric-treemap/layout.ts +8 -0
- package/src/components/metric-treemap/scene.ts +432 -0
- package/src/components/onboarding/onboarding-keyboard.ts +311 -0
- package/src/components/onboarding/onboarding-wizard.tsx +101 -788
- package/src/components/onboarding/use-onboarding-broker-form.ts +263 -0
- package/src/components/onboarding/use-onboarding-progress.ts +298 -0
- package/src/components/onboarding/use-onboarding-upgrade.ts +83 -0
- package/src/components/pane-settings-dialog/field-dialogs.tsx +1 -0
- package/src/components/ticker/list-table-view.tsx +13 -1
- package/src/components/toggle-list.tsx +38 -12
- package/src/components/ui/country-flag-art.tsx +449 -0
- package/src/components/ui/country-flag.tsx +41 -0
- package/src/components/ui/data-table/types.ts +13 -0
- package/src/components/ui/fields.tsx +8 -0
- package/src/components/ui/icon.tsx +2 -0
- package/src/components/ui/index.ts +4 -0
- package/src/components/ui/multi-select/dialog.tsx +108 -22
- package/src/components/ui/range-track.tsx +53 -0
- package/src/components/ui/status.tsx +8 -2
- package/src/components/ui/tabs.tsx +11 -4
- package/src/components/ui/text-prompt-dialog.tsx +4 -2
- package/src/core/state/app/types.ts +10 -1
- package/src/data/config/store/normalize.ts +17 -1
- package/src/i18n/es.ts +24 -4
- package/src/i18n/ja.ts +24 -4
- package/src/i18n/ko.ts +24 -4
- package/src/i18n/zh-cn.ts +24 -4
- package/src/i18n/zh-tw.ts +24 -4
- package/src/layout/ticker-navigation.ts +28 -2
- package/src/market-data/coordinator/chart.ts +1 -1
- package/src/market-data/coordinator/quotes.ts +23 -4
- package/src/market-data/fx-closes.ts +72 -0
- package/src/market-data/market/freshness.ts +78 -6
- package/src/market-data/market/session-close-note.ts +57 -0
- package/src/market-data/market/status.ts +151 -0
- package/src/market-data/published-apac-sessions.ts +66 -0
- package/src/market-data/quotes/contributions.ts +8 -0
- package/src/market-data/quotes/freshness.ts +36 -0
- package/src/market-data/quotes/resolution.ts +24 -8
- package/src/market-data/quotes/screener-live-quotes.ts +49 -4
- package/src/market-data/quotes/time.ts +16 -0
- package/src/plugins/builtin/account-management/pane.tsx +4 -0
- package/src/plugins/builtin/alerts/cli.ts +10 -5
- package/src/plugins/builtin/alerts/index.tsx +1 -0
- package/src/plugins/builtin/analytics/metrics.ts +8 -3
- package/src/plugins/builtin/analytics/risk-client.ts +330 -79
- package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
- package/src/plugins/builtin/analytics/risk-headless.ts +61 -49
- package/src/plugins/builtin/analytics/risk-math.ts +33 -13
- package/src/plugins/builtin/analytics/risk-model.ts +282 -64
- package/src/plugins/builtin/analytics/risk-pane.tsx +62 -30
- package/src/plugins/builtin/analytics/risk-test-data.ts +206 -0
- package/src/plugins/builtin/attention/headless.ts +6 -4
- package/src/plugins/builtin/attention/index.tsx +1 -1
- package/src/plugins/builtin/attention/pane.tsx +1 -1
- package/src/plugins/builtin/awards/headless.ts +1 -0
- package/src/plugins/builtin/awards/pane.tsx +1 -1
- package/src/plugins/builtin/backtest/headless.ts +1 -0
- package/src/plugins/builtin/bond-calculator/headless.ts +1 -0
- package/src/plugins/builtin/buildout/cells.tsx +15 -12
- package/src/plugins/builtin/buildout/detail/company.tsx +3 -3
- package/src/plugins/builtin/buildout/detail/index.tsx +0 -1
- package/src/plugins/builtin/buildout/detail/intel.tsx +6 -6
- package/src/plugins/builtin/buildout/detail/site.tsx +4 -7
- package/src/plugins/builtin/buildout/detail/ui.tsx +0 -19
- package/src/plugins/builtin/buildout/index.tsx +1 -0
- package/src/plugins/builtin/catalysts/headless.ts +3 -1
- package/src/plugins/builtin/catalysts/index.tsx +2 -2
- package/src/plugins/builtin/catalysts/pane.tsx +3 -1
- package/src/plugins/builtin/cds/headless.ts +2 -0
- package/src/plugins/builtin/cds/index.tsx +1 -0
- package/src/plugins/builtin/central-bank-rates/headless.ts +1 -0
- package/src/plugins/builtin/chart-composer/headless.ts +38 -3
- package/src/plugins/builtin/chart-composer/index.tsx +3 -1
- package/src/plugins/builtin/chart-composer/series-expression.ts +18 -2
- package/src/plugins/builtin/chat/channels.ts +19 -3
- package/src/plugins/builtin/chat/content/composer-runtime.ts +28 -13
- package/src/plugins/builtin/chat/content/footer.tsx +15 -6
- package/src/plugins/builtin/chat/content/index.tsx +120 -21
- package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +261 -113
- package/src/plugins/builtin/chat/content/transcript.tsx +20 -2
- package/src/plugins/builtin/chat/direct-messages.ts +200 -0
- package/src/plugins/builtin/chat/index.tsx +1 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +3 -0
- package/src/plugins/builtin/chat/message/header.tsx +16 -6
- package/src/plugins/builtin/chat/message/inline-tokens.tsx +72 -32
- package/src/plugins/builtin/chat/message/profile-popover.tsx +96 -12
- package/src/plugins/builtin/chat/message/terminal.tsx +3 -0
- package/src/plugins/builtin/chat/message/types.ts +14 -2
- package/src/plugins/builtin/chat/profile-popover.ts +18 -13
- package/src/plugins/builtin/clinical-trials/index.tsx +1 -0
- package/src/plugins/builtin/cloud/askg/executor.ts +2 -1
- package/src/plugins/builtin/cloud/plugin.tsx +1 -0
- package/src/plugins/builtin/cloud/team/module.tsx +1 -0
- package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
- package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
- package/src/plugins/builtin/comment-letters/index.tsx +1 -0
- package/src/plugins/builtin/company-attention/headless.ts +5 -1
- package/src/plugins/builtin/company-attention/pane.tsx +1 -1
- package/src/plugins/builtin/company-kpis/headless.ts +1 -0
- package/src/plugins/builtin/congress-trades/headless.ts +1 -0
- package/src/plugins/builtin/correlation/compute.ts +59 -16
- package/src/plugins/builtin/correlation/geo.ts +34 -0
- package/src/plugins/builtin/correlation/headless-schema.ts +4 -1
- package/src/plugins/builtin/correlation/headless.ts +42 -8
- package/src/plugins/builtin/correlation/history.ts +2 -0
- package/src/plugins/builtin/correlation/index.tsx +68 -14
- package/src/plugins/builtin/correlation/matrix/model.ts +17 -2
- package/src/plugins/builtin/correlation/matrix/selection.ts +5 -3
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
- package/src/plugins/builtin/correlation/relationship/pane.tsx +4 -2
- package/src/plugins/builtin/correlation/relationship/view-model.ts +16 -1
- package/src/plugins/builtin/correlation/settings.ts +1 -1
- package/src/plugins/builtin/cot/headless.ts +6 -3
- package/src/plugins/builtin/cot/index.tsx +3 -3
- package/src/plugins/builtin/cot/model.ts +36 -3
- package/src/plugins/builtin/cpi/headless.ts +4 -0
- package/src/plugins/builtin/credit-boards/headless.ts +2 -0
- package/src/plugins/builtin/credit-conditions/headless.ts +1 -0
- package/src/plugins/builtin/credit-documents/gauge.tsx +5 -8
- package/src/plugins/builtin/credit-documents/headless.ts +2 -0
- package/src/plugins/builtin/crypto-board/headless.ts +3 -0
- package/src/plugins/builtin/custom-view/loader.ts +1 -1
- package/src/plugins/builtin/debt-maturities/headless.ts +4 -0
- package/src/plugins/builtin/debt-maturities/wall-bar.tsx +14 -41
- package/src/plugins/builtin/dividend-yield/client.ts +4 -2
- package/src/plugins/builtin/dividend-yield/headless.ts +1 -0
- package/src/plugins/builtin/doe/headless.ts +7 -0
- package/src/plugins/builtin/doe/range-bar.tsx +7 -37
- package/src/plugins/builtin/earnings/client.ts +2 -2
- package/src/plugins/builtin/earnings/headless.ts +5 -0
- package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
- package/src/plugins/builtin/earnings-calls/index.tsx +1 -0
- package/src/plugins/builtin/earnings-ripple/client.ts +91 -18
- package/src/plugins/builtin/earnings-ripple/headless.ts +28 -8
- package/src/plugins/builtin/earnings-ripple/index.tsx +2 -2
- package/src/plugins/builtin/earnings-ripple/model.ts +97 -7
- package/src/plugins/builtin/earnings-ripple/pane.tsx +148 -23
- package/src/plugins/builtin/econ/index.tsx +1 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +2 -0
- package/src/plugins/builtin/equity-screener/headless.ts +2 -0
- package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
- package/src/plugins/builtin/executives/index.tsx +1 -0
- package/src/plugins/builtin/exposure/headless.ts +3 -1
- package/src/plugins/builtin/fear-greed/headless.ts +2 -0
- package/src/plugins/builtin/filing-events/index.tsx +1 -0
- package/src/plugins/builtin/futures-curve/client.ts +12 -3
- package/src/plugins/builtin/futures-curve/headless.ts +39 -10
- package/src/plugins/builtin/futures-curve/index.tsx +3 -3
- package/src/plugins/builtin/futures-curve/model.ts +188 -4
- package/src/plugins/builtin/futures-curve/pane.tsx +51 -9
- package/src/plugins/builtin/fx-matrix/direction.ts +81 -0
- package/src/plugins/builtin/fx-matrix/index.tsx +71 -33
- package/src/plugins/builtin/fx-matrix/live-legs.ts +17 -0
- package/src/plugins/builtin/fx-matrix/pairs.ts +68 -14
- package/src/plugins/builtin/fx-matrix/settings.ts +62 -0
- package/src/plugins/builtin/gpu/headless.ts +7 -3
- package/src/plugins/builtin/gpu/ladder.tsx +26 -30
- package/src/plugins/builtin/gpu/model.ts +27 -1
- package/src/plugins/builtin/holders/beneficial-client.ts +209 -0
- package/src/plugins/builtin/holders/beneficial-model.ts +279 -0
- package/src/plugins/builtin/holders/beneficial-report.ts +126 -0
- package/src/plugins/builtin/holders/beneficial-view.tsx +241 -0
- package/src/plugins/builtin/holders/headless.ts +139 -5
- package/src/plugins/builtin/holders/index.tsx +10 -3
- package/src/plugins/builtin/holders/pane.tsx +20 -3
- package/src/plugins/builtin/holders/report-header.ts +95 -0
- package/src/plugins/builtin/holders/table-model.ts +20 -5
- package/src/plugins/builtin/holders/thirteenf-match.ts +29 -1
- package/src/plugins/builtin/holders/types.ts +2 -1
- package/src/plugins/builtin/insider/headless.ts +2 -0
- package/src/plugins/builtin/ipo-calendar/headless.ts +1 -0
- package/src/plugins/builtin/iv-history/headless.ts +4 -1
- package/src/plugins/builtin/jobs/headless.ts +1 -0
- package/src/plugins/builtin/jobs/index.tsx +1 -0
- package/src/plugins/builtin/jobs/share-bars.tsx +5 -28
- package/src/plugins/builtin/kelly-sizer/index.tsx +1 -0
- package/src/plugins/builtin/macro-day/headless.ts +2 -0
- package/src/plugins/builtin/market-halts/index.tsx +1 -0
- package/src/plugins/builtin/market-heatmap/data.ts +30 -2
- package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
- package/src/plugins/builtin/market-heatmap/index.tsx +245 -81
- package/src/plugins/builtin/market-heatmap/live.ts +88 -0
- package/src/plugins/builtin/market-heatmap/model.ts +146 -0
- package/src/plugins/builtin/market-heatmap/portfolio.ts +50 -11
- package/src/plugins/builtin/market-movers/client.ts +3 -2
- package/src/plugins/builtin/market-movers/headless.ts +10 -1
- package/src/plugins/builtin/market-movers/screener.ts +18 -5
- package/src/plugins/builtin/market-valuation/headless.ts +2 -0
- package/src/plugins/builtin/members/client.ts +53 -0
- package/src/plugins/builtin/members/headless.ts +35 -0
- package/src/plugins/builtin/members/index.tsx +20 -0
- package/src/plugins/builtin/members/model.ts +68 -0
- package/src/plugins/builtin/members/pane.tsx +175 -0
- package/src/plugins/builtin/mna/distress/headless.ts +1 -0
- package/src/plugins/builtin/mna/headless.ts +1 -0
- package/src/plugins/builtin/mna/index.tsx +2 -1
- package/src/plugins/builtin/mna/pane.tsx +5 -2
- package/src/plugins/builtin/money-markets/headless.ts +1 -0
- package/src/plugins/builtin/news/headless.ts +2 -0
- package/src/plugins/builtin/news/wire/index.tsx +8 -1
- package/src/plugins/builtin/notes/cli.ts +14 -6
- package/src/plugins/builtin/notes/index.tsx +1 -0
- package/src/plugins/builtin/openfda/index.tsx +1 -0
- package/src/plugins/builtin/options/index.tsx +2 -1
- package/src/plugins/builtin/options-calculator/headless.ts +2 -0
- package/src/plugins/builtin/options-positioning/headless.ts +3 -0
- package/src/plugins/builtin/options-scenario/headless.ts +5 -0
- package/src/plugins/builtin/pe-band/client.ts +74 -2
- package/src/plugins/builtin/pe-band/headless.ts +26 -8
- package/src/plugins/builtin/pe-band/model.ts +102 -22
- package/src/plugins/builtin/pe-band/pane.tsx +34 -16
- package/src/plugins/builtin/pe-band/report-dates.ts +78 -0
- package/src/plugins/builtin/perps/client.ts +66 -5
- package/src/plugins/builtin/perps/equity-identity.ts +16 -0
- package/src/plugins/builtin/perps/equity-row.tsx +6 -4
- package/src/plugins/builtin/perps/headless.ts +144 -16
- package/src/plugins/builtin/perps/index.tsx +6 -6
- package/src/plugins/builtin/perps/model.ts +189 -12
- package/src/plugins/builtin/perps/pane.tsx +248 -47
- package/src/plugins/builtin/plugin-marketplace/activation.ts +19 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +2 -2
- package/src/plugins/builtin/plugin-marketplace/store.ts +2 -0
- package/src/plugins/builtin/portfolio-list/allocation.ts +245 -0
- package/src/plugins/builtin/portfolio-list/cached-account.ts +33 -0
- package/src/plugins/builtin/portfolio-list/cell-version.ts +19 -1
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +328 -29
- package/src/plugins/builtin/portfolio-list/cli/render.ts +230 -39
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +67 -2
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +35 -31
- package/src/plugins/builtin/portfolio-list/column-values.ts +124 -47
- package/src/plugins/builtin/portfolio-list/headless.ts +98 -16
- package/src/plugins/builtin/portfolio-list/index.tsx +14 -3
- package/src/plugins/builtin/portfolio-list/live-valuation.ts +7 -5
- package/src/plugins/builtin/portfolio-list/mutations.ts +55 -1
- package/src/plugins/builtin/portfolio-list/pane/data.ts +6 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +47 -13
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +43 -2
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +48 -5
- package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +24 -1
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +26 -7
- package/src/plugins/builtin/power/headless.ts +3 -1
- package/src/plugins/builtin/rate-path/headless.ts +2 -0
- package/src/plugins/builtin/realized-vol/headless.ts +2 -0
- package/src/plugins/builtin/relative-rotation/headless.ts +2 -0
- package/src/plugins/builtin/research/analyst-headless.ts +3 -0
- package/src/plugins/builtin/research/events-headless.ts +2 -0
- package/src/plugins/builtin/research/headless.ts +2 -0
- package/src/plugins/builtin/research/index.tsx +1 -0
- package/src/plugins/builtin/research/relative-valuation-headless.ts +10 -5
- package/src/plugins/builtin/research/relative-valuation-model.ts +11 -3
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +3 -3
- package/src/plugins/builtin/research-search/index.tsx +1 -0
- package/src/plugins/builtin/revenue-breakdown/headless.ts +2 -0
- package/src/plugins/builtin/reverse-dcf/headless.ts +2 -0
- package/src/plugins/builtin/risk-factors/headless.ts +2 -0
- package/src/plugins/builtin/scanner/flow-history.ts +2 -13
- package/src/plugins/builtin/scanner/headless.ts +14 -0
- package/src/plugins/builtin/scanner/hilo-bars.tsx +12 -70
- package/src/plugins/builtin/scanner/hilo-model.ts +0 -18
- package/src/plugins/builtin/seasonality/headless.ts +2 -0
- package/src/plugins/builtin/sec/command-bar-search.ts +14 -4
- package/src/plugins/builtin/sec/filing-content.ts +42 -17
- package/src/plugins/builtin/sec/forms.ts +12 -0
- package/src/plugins/builtin/sec/headless.ts +2 -0
- package/src/plugins/builtin/sectors/client.ts +1 -0
- package/src/plugins/builtin/sectors/headless.ts +9 -1
- package/src/plugins/builtin/sectors/move-bar.tsx +10 -32
- package/src/plugins/builtin/sectors/sector-model.ts +2 -0
- package/src/plugins/builtin/shared/crypto-pair.ts +14 -0
- package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
- package/src/plugins/builtin/shared/report-freshness.ts +57 -0
- package/src/plugins/builtin/shared/research-cells.tsx +4 -9
- package/src/plugins/builtin/short-interest/headless.ts +2 -0
- package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
- package/src/plugins/builtin/short-volume/headless.ts +1 -0
- package/src/plugins/builtin/social-mentions/headless.ts +1 -0
- package/src/plugins/builtin/social-mentions/index.tsx +1 -1
- package/src/plugins/builtin/supply-chain/headless.ts +7 -1
- package/src/plugins/builtin/supply-chain/index.tsx +10 -1
- package/src/plugins/builtin/supply-chain/model.ts +27 -2
- package/src/plugins/builtin/supply-chain/pane.tsx +71 -32
- package/src/plugins/builtin/themes/headless.ts +3 -0
- package/src/plugins/builtin/thirteenf/headless.ts +110 -25
- package/src/plugins/builtin/thirteenf/index.tsx +2 -1
- package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
- package/src/plugins/builtin/ticker-detail/headless.ts +7 -1
- package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
- package/src/plugins/builtin/ticker-detail/overview/components.tsx +5 -60
- package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -2
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +26 -26
- package/src/plugins/builtin/ticker-detail/pane.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/quote-footer.ts +7 -1
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +20 -4
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -2
- package/src/plugins/builtin/time-sales/headless.ts +5 -1
- package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
- package/src/plugins/builtin/vol-surface/index.tsx +1 -1
- package/src/plugins/builtin/volatility/headless.ts +6 -1
- package/src/plugins/builtin/world-indices/headless.ts +2 -0
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +157 -0
- package/src/plugins/builtin/world-venue-map/basemap.ts +214 -0
- package/src/plugins/builtin/world-venue-map/client.ts +45 -0
- package/src/plugins/builtin/world-venue-map/entity-detail.tsx +147 -0
- package/src/plugins/builtin/world-venue-map/entity-table.ts +59 -0
- package/src/plugins/builtin/world-venue-map/evidence.ts +77 -0
- package/src/plugins/builtin/world-venue-map/feed.ts +293 -0
- package/src/plugins/builtin/world-venue-map/geo-draw.tsx +248 -0
- package/src/plugins/builtin/world-venue-map/geo-series.ts +142 -0
- package/src/plugins/builtin/world-venue-map/geo-svg.tsx +447 -0
- package/src/plugins/builtin/world-venue-map/headless.ts +146 -0
- package/src/plugins/builtin/world-venue-map/ids.ts +1 -0
- package/src/plugins/builtin/world-venue-map/index.ts +67 -4
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +552 -0
- package/src/plugins/builtin/world-venue-map/layers.ts +348 -0
- package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +381 -45
- package/src/plugins/builtin/world-venue-map/model.ts +7 -4
- package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +199 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/world-50m.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/pane.tsx +28 -43
- package/src/plugins/builtin/world-venue-map/use-geo.ts +55 -0
- package/src/plugins/builtin/world-venue-map/venue-header.tsx +32 -0
- package/src/plugins/builtin/yield-curve/headless.ts +16 -0
- package/src/plugins/catalog-browser.ts +2 -0
- package/src/plugins/catalog-manifest.ts +1 -0
- package/src/plugins/catalog-ui.ts +3 -1
- package/src/plugins/catalog.ts +1 -1
- package/src/plugins/host-link.ts +33 -1
- package/src/plugins/installer.ts +48 -12
- package/src/plugins/loader.ts +30 -3
- package/src/plugins/manager-node.ts +15 -5
- package/src/plugins/registry/index.ts +1 -1
- package/src/plugins/registry/pane-settings.ts +26 -7
- package/src/public/__snapshots__/public-api.test.ts.snap +2 -0
- package/src/renderers/dom/build-assets.ts +81 -3
- package/src/renderers/dom/data-table/row.tsx +52 -16
- package/src/renderers/dom/desktop/controls.tsx +7 -3
- package/src/renderers/dom/desktop/icons.tsx +1 -0
- package/src/renderers/dom/desktop/list-view.tsx +35 -10
- package/src/renderers/dom/desktop/popover.tsx +73 -14
- package/src/renderers/dom/host/box.tsx +69 -26
- package/src/renderers/dom/host/input.tsx +14 -3
- package/src/renderers/dom/host/tabs.tsx +37 -1
- package/src/renderers/dom/styles.css +41 -7
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +11 -6
- package/src/renderers/electrobun/bun/desktop/backend.ts +1 -0
- package/src/renderers/electrobun/bun/desktop/update.ts +181 -87
- package/src/renderers/electrobun/bun/index.ts +73 -6
- package/src/renderers/electrobun/bun/window/remembered-frame.ts +122 -0
- package/src/renderers/electrobun/shared/protocol.ts +3 -0
- package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +3 -1
- package/src/renderers/electrobun/view/main.tsx +7 -1
- package/src/renderers/electrobun/view/renderer-window-error.ts +18 -0
- package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
- package/src/renderers/electrobun/view/update-host.ts +45 -21
- package/src/renderers/opentui/host.tsx +5 -0
- package/src/sources/gloomberb-cloud/index.ts +25 -4
- package/src/sources/gloomberb-cloud/normalizers.ts +36 -5
- package/src/sources/provider-router/cached-routes.ts +4 -1
- package/src/sources/provider-router/financials.ts +11 -8
- package/src/sources/provider-router/history.ts +15 -10
- package/src/sources/sec-registrant.ts +75 -0
- package/src/state/app/context/index.tsx +24 -8
- package/src/state/hooks/quote-streaming.ts +41 -26
- package/src/sync/core-contributors.ts +4 -0
- package/src/telemetry/benign-window-error.ts +7 -0
- package/src/telemetry/crash-reports-dom.ts +2 -0
- package/src/telemetry/crash-reports.ts +4 -1
- package/src/test-support/cli-context.ts +10 -2
- package/src/test-support/daily-nav.ts +25 -0
- package/src/theme/heat-colors.ts +357 -2
- package/src/tickers/instrument-kind.ts +34 -7
- package/src/tickers/search/asset-classes.ts +24 -9
- package/src/tickers/search/index.ts +44 -11
- package/src/tickers/search/ranking.ts +23 -3
- package/src/time-series/resolve.ts +1 -1
- package/src/time-series/use-chart-resolution.ts +1 -1
- package/src/types/context-menu.ts +6 -0
- package/src/types/data-provider.ts +2 -0
- package/src/types/financials.ts +5 -0
- package/src/types/headless.ts +79 -2
- package/src/types/plugin.ts +38 -6
- package/src/types/ticker.ts +15 -0
- package/src/ui/context-menu.tsx +1 -0
- package/src/ui/host.tsx +16 -0
- package/src/updater/index.ts +38 -13
- package/src/utils/async-deadline.ts +21 -0
- package/src/utils/cli-output.ts +5 -1
- package/src/utils/crypto-pair.ts +41 -0
- package/src/utils/currency-units.ts +14 -0
- package/src/utils/depositary-receipt.ts +26 -0
- package/src/utils/exchanges.ts +72 -0
- package/src/utils/fire-and-forget.ts +24 -0
- package/src/utils/format.ts +13 -0
- package/src/utils/price-earnings.ts +70 -3
- package/src/utils/price-history.ts +58 -13
- package/src/utils/rpc-timeout-error.ts +27 -0
- package/src/utils/sec.ts +13 -1
- package/src/utils/utc-time.ts +79 -0
|
@@ -5,13 +5,28 @@ import { compositeAxisTicks } from "../../../components/chart/composite/format";
|
|
|
5
5
|
import type { CompositeAxisDomain } from "../../../components/chart/composite/types";
|
|
6
6
|
import { FUTURES_CONTRACTS, tickDecimals } from "../futures/contracts";
|
|
7
7
|
import { formatPercentileRank } from "../../../utils/format";
|
|
8
|
+
import { cryptoPairCoin, isFuturesSymbol } from "../shared/crypto-pair";
|
|
9
|
+
import { parseReportTime } from "../../../utils/utc-time";
|
|
8
10
|
import { compareSortValues, type SortDirection } from "../../../utils/sort-values";
|
|
9
11
|
|
|
12
|
+
/**
|
|
13
|
+
* CME crypto futures have a curve but no FUT board row, so their name and tick
|
|
14
|
+
* live here rather than in the catalogue the board lists. Outright ticks:
|
|
15
|
+
* BTC $5, ETH $0.50, SOL $0.05, XRP $0.0005 (each $25 a contract).
|
|
16
|
+
*/
|
|
17
|
+
const CRYPTO_CURVE_ROOTS: readonly { code: string; name: string; tick: number }[] = [
|
|
18
|
+
{ code: "BTC", name: "Bitcoin", tick: 5 }, { code: "ETH", name: "Ether", tick: 0.5 },
|
|
19
|
+
{ code: "SOL", name: "Solana", tick: 0.05 }, { code: "XRP", name: "XRP", tick: 0.0005 },
|
|
20
|
+
];
|
|
21
|
+
const rootLabel = (code: string, name: string) => name === code ? code : `${code} ${name}`;
|
|
22
|
+
|
|
10
23
|
export const CURVE_ROOTS = [
|
|
11
|
-
...FUTURES_CONTRACTS.filter((row) => row.curve !== false).map((row) => ({ value: row.code, label:
|
|
24
|
+
...FUTURES_CONTRACTS.filter((row) => row.curve !== false).map((row) => ({ value: row.code, label: rootLabel(row.code, row.name) })),
|
|
12
25
|
{ value: "VX", label: "VX VIX Futures" },
|
|
26
|
+
...CRYPTO_CURVE_ROOTS.map((row) => ({ value: row.code, label: rootLabel(row.code, row.name) })),
|
|
13
27
|
];
|
|
14
28
|
|
|
29
|
+
/** A root typed as an argument, a stored pane setting or a request: every listed root, crypto included. */
|
|
15
30
|
export function normalizeCurveRoot(value: unknown): string | null {
|
|
16
31
|
if (typeof value !== "string") return null;
|
|
17
32
|
const raw = value.trim().toUpperCase().replace(/=F$/, "");
|
|
@@ -19,6 +34,26 @@ export function normalizeCurveRoot(value: unknown): string | null {
|
|
|
19
34
|
return CURVE_ROOTS.some((row) => row.value === root) ? root : null;
|
|
20
35
|
}
|
|
21
36
|
|
|
37
|
+
/** What a root nothing lists is told, with roots that work. */
|
|
38
|
+
export function unsupportedCurveRootMessage(value: unknown): string {
|
|
39
|
+
const examples = ["ES", "CL", "GC", "ZN"].filter((root) => CURVE_ROOTS.some((row) => row.value === root));
|
|
40
|
+
return `Unsupported futures root: ${String(value)}. Try ${examples.join(", ")}.`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The root for the ticker under the cursor, when CTM is opened without an
|
|
45
|
+
* argument. The crypto roots are also US ticker symbols (Grayscale's mini
|
|
46
|
+
* trusts are BTC and ETH), so a bare one is the equity's, never the future's:
|
|
47
|
+
* only a futures symbol (BTC=F) or a coin pair (BTC-USD) names the crypto curve.
|
|
48
|
+
*/
|
|
49
|
+
export function curveRootForTicker(ticker: unknown): string | null {
|
|
50
|
+
if (typeof ticker !== "string") return null;
|
|
51
|
+
const coin = cryptoPairCoin(ticker);
|
|
52
|
+
if (coin) return CRYPTO_CURVE_ROOTS.some((row) => row.code === coin) ? coin : null;
|
|
53
|
+
const root = normalizeCurveRoot(ticker);
|
|
54
|
+
return root && CRYPTO_CURVE_ROOTS.some((row) => row.code === root) && !isFuturesSymbol(ticker) ? null : root;
|
|
55
|
+
}
|
|
56
|
+
|
|
22
57
|
/**
|
|
23
58
|
* Treasury futures trade in fractions of a 32nd (ZT to 1/256, ZF 1/128, ZN
|
|
24
59
|
* 1/64, ZB and UB 1/32), so the catalogue leaves their tick unset. A root
|
|
@@ -32,7 +67,7 @@ function curvePriceDecimals(root: string): number {
|
|
|
32
67
|
const rateTick = RATE_TICKS[root];
|
|
33
68
|
if (rateTick != null) return tickDecimals(rateTick);
|
|
34
69
|
if (root === "VX") return 4;
|
|
35
|
-
const tick = FUTURES_CONTRACTS.find((row) => row.code === root)?.tick;
|
|
70
|
+
const tick = FUTURES_CONTRACTS.find((row) => row.code === root)?.tick ?? CRYPTO_CURVE_ROOTS.find((row) => row.code === root)?.tick;
|
|
36
71
|
return tick == null ? 5 : Math.max(2, tickDecimals(tick));
|
|
37
72
|
}
|
|
38
73
|
|
|
@@ -155,17 +190,166 @@ const CHANGE_COLUMNS: Readonly<Record<string, CurveLookback>> = { change1w: "1W"
|
|
|
155
190
|
|
|
156
191
|
type CurveSortKey = "symbol" | "expiration" | "price" | "change" | "openInterest" | "volume" | "percentile" | "asOf";
|
|
157
192
|
|
|
193
|
+
const BASIS_COLUMNS: Readonly<Record<string, "vsSpotPct" | "annualisedBasisPct">> = { vsSpot: "vsSpotPct", annBasis: "annualisedBasisPct" };
|
|
194
|
+
|
|
158
195
|
export function sortCurveContracts(rows: readonly FuturesContract[], id: string, direction: SortDirection,
|
|
159
|
-
changes?: CurveContractChanges): FuturesContract[] {
|
|
196
|
+
changes?: CurveContractChanges, basis?: CurveBasisRows): FuturesContract[] {
|
|
160
197
|
const keys: Record<string, CurveSortKey> = { symbol: "symbol", expiry: "expiration", price: "price", change: "change", oi: "openInterest", volume: "volume", percentile: "percentile", asOf: "asOf" };
|
|
161
198
|
const key = keys[id] ?? "expiration";
|
|
162
199
|
const lookback = CHANGE_COLUMNS[id];
|
|
163
|
-
const
|
|
200
|
+
const basisKey = BASIS_COLUMNS[id];
|
|
201
|
+
const value = (row: FuturesContract) => lookback ? changes?.get(row.symbol)?.[lookback] ?? null
|
|
202
|
+
: basisKey ? basis?.get(row.symbol)?.[basisKey] ?? null : row[key] ?? null;
|
|
164
203
|
return [...rows].sort((a, b) => compareSortValues(value(a), value(b), direction));
|
|
165
204
|
}
|
|
166
205
|
|
|
167
206
|
const DAY_MS = 86_400_000;
|
|
168
207
|
|
|
208
|
+
/**
|
|
209
|
+
* The quote each crypto root's basis is measured against: the terminal's USD
|
|
210
|
+
* pair, the same quote every other pane shows, not the CME reference rate, so
|
|
211
|
+
* a small gap to settlement is expected. A root missing here has no basis
|
|
212
|
+
* columns; add its spot symbol to give it some.
|
|
213
|
+
*/
|
|
214
|
+
const BASIS_SPOT_SYMBOLS: ReadonlyMap<string, string> = new Map([
|
|
215
|
+
["BTC", "BTC-USD"], ["ETH", "ETH-USD"], ["SOL", "SOL-USD"], ["XRP", "XRP-USD"],
|
|
216
|
+
]);
|
|
217
|
+
|
|
218
|
+
export function basisSpotSymbol(root: string): string | null {
|
|
219
|
+
return BASIS_SPOT_SYMBOLS.get(root) ?? null;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** Crypto trades around the clock, so a spot quote older than this no longer prices a live future. */
|
|
223
|
+
const SPOT_STALE_MS = 10 * 60_000;
|
|
224
|
+
/** A free account's quote is held back on purpose; that delay is not staleness, so it is allowed on top. */
|
|
225
|
+
const DELAYED_SPOT_MS = 15 * 60_000;
|
|
226
|
+
|
|
227
|
+
/** The spot a curve's basis uses, or why there is none. `asOf` is the quote's own time, never the fetch's. */
|
|
228
|
+
export interface CurveSpot {
|
|
229
|
+
symbol: string;
|
|
230
|
+
price: number | null;
|
|
231
|
+
/** UTC ISO instant of the quote. */
|
|
232
|
+
asOf: string | null;
|
|
233
|
+
status: "ok" | "stale" | "missing";
|
|
234
|
+
reason: string | null;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export interface SpotQuote {
|
|
238
|
+
price: number;
|
|
239
|
+
lastUpdated: number;
|
|
240
|
+
stale?: boolean;
|
|
241
|
+
dataSource?: string;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const positive = (value: unknown): value is number => typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
245
|
+
|
|
246
|
+
function quoteAge(ms: number): string {
|
|
247
|
+
const minutes = Math.floor(ms / 60_000);
|
|
248
|
+
if (minutes < 60) return `${minutes}m`;
|
|
249
|
+
const hours = Math.floor(minutes / 60);
|
|
250
|
+
return hours < 48 ? `${hours}h` : `${Math.floor(hours / 24)}d`;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** Judges one spot quote at `now`: usable, older than the rule allows, or absent. */
|
|
254
|
+
export function curveSpot(symbol: string, quote: SpotQuote | null | undefined, now: number): CurveSpot {
|
|
255
|
+
if (!quote || !positive(quote.price)) return { symbol, price: null, asOf: null, status: "missing", reason: `no ${symbol} quote` };
|
|
256
|
+
const time = quote.lastUpdated;
|
|
257
|
+
if (!Number.isFinite(time) || time <= 0) {
|
|
258
|
+
return { symbol, price: quote.price, asOf: null, status: "stale", reason: `${symbol} quote has no time` };
|
|
259
|
+
}
|
|
260
|
+
const asOf = new Date(time).toISOString().replace(".000Z", "Z");
|
|
261
|
+
const age = now - time;
|
|
262
|
+
const limit = SPOT_STALE_MS + (quote.dataSource === "delayed" ? DELAYED_SPOT_MS : 0);
|
|
263
|
+
if (age > limit) return { symbol, price: quote.price, asOf, status: "stale", reason: `${symbol} quote is ${quoteAge(age)} old` };
|
|
264
|
+
if (quote.stale === true) return { symbol, price: quote.price, asOf, status: "stale", reason: `${symbol} quote is stale` };
|
|
265
|
+
return { symbol, price: quote.price, asOf, status: "ok", reason: null };
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** How far the contract trades over (positive) or under spot, in percent. */
|
|
269
|
+
export function vsSpotPct(futures: number | null | undefined, spot: number | null | undefined): number | null {
|
|
270
|
+
return positive(futures) && positive(spot) ? (futures / spot - 1) * 100 : null;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** Calendar days from the UTC date of the spot's timestamp to the contract's expiration date. */
|
|
274
|
+
export function daysToExpiry(spotTime: number, expiration: string): number | null {
|
|
275
|
+
const expiry = Date.parse(`${expiration}T00:00:00Z`);
|
|
276
|
+
if (!Number.isFinite(spotTime) || !Number.isFinite(expiry)) return null;
|
|
277
|
+
const spotDay = Date.parse(`${new Date(spotTime).toISOString().slice(0, 10)}T00:00:00Z`);
|
|
278
|
+
return Math.round((expiry - spotDay) / DAY_MS);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/** The premium over spot as a yearly rate, on a 365-day year. Blank on or past expiry, where it has no meaning. */
|
|
282
|
+
export function annualisedBasisPct(futures: number | null | undefined, spot: number | null | undefined, days: number | null): number | null {
|
|
283
|
+
if (!positive(futures) || !positive(spot) || days == null || !Number.isFinite(days) || days <= 0) return null;
|
|
284
|
+
return (futures / spot - 1) * 365 / days * 100;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** A contract that printed longer than this before the spot quote is too old to read against it. */
|
|
288
|
+
const CONTRACT_PRINT_MAX_AGE_MS = 60 * 60_000;
|
|
289
|
+
|
|
290
|
+
export interface ContractBasis {
|
|
291
|
+
vsSpotPct: number | null;
|
|
292
|
+
annualisedBasisPct: number | null;
|
|
293
|
+
/** Priced and not flagged stale, but its last print is over an hour before spot: a thin month. */
|
|
294
|
+
thin: boolean;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const NO_BASIS: ContractBasis = { vsSpotPct: null, annualisedBasisPct: null, thin: false };
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* One contract's basis. Blank without a usable spot, and for a contract whose
|
|
301
|
+
* own price is missing or stale: an old future against a live spot misleads.
|
|
302
|
+
* So does a print more than an hour older than the spot (`thin`): the server's
|
|
303
|
+
* stale flag allows two sessions, which a quote that moves all day outruns. A
|
|
304
|
+
* date-only `asOf` is UTC midnight of that date, one that cannot be read
|
|
305
|
+
* counts as old, and a print newer than the spot is never old (the spot of a
|
|
306
|
+
* delayed feed trails the futures).
|
|
307
|
+
*/
|
|
308
|
+
export function contractBasis(row: Pick<FuturesContract, "price" | "stale" | "expiration" | "asOf">, spot: CurveSpot): ContractBasis {
|
|
309
|
+
if (spot.status !== "ok" || spot.asOf == null || row.stale) return NO_BASIS;
|
|
310
|
+
const vs = vsSpotPct(row.price, spot.price);
|
|
311
|
+
if (vs == null) return NO_BASIS;
|
|
312
|
+
const spotTime = Date.parse(spot.asOf);
|
|
313
|
+
const printed = parseReportTime(row.asOf)?.time ?? null;
|
|
314
|
+
if (printed == null || spotTime - printed > CONTRACT_PRINT_MAX_AGE_MS) return { ...NO_BASIS, thin: true };
|
|
315
|
+
return { vsSpotPct: vs, annualisedBasisPct: annualisedBasisPct(row.price, spot.price, daysToExpiry(spotTime, row.expiration)), thin: false };
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/** A basis in percent, signed; one that rounds to zero stays unsigned. */
|
|
319
|
+
export function curveBasisPercent(value: number | null, decimals: number): string {
|
|
320
|
+
if (value == null) return "--";
|
|
321
|
+
const text = Math.abs(value).toFixed(decimals);
|
|
322
|
+
return /[1-9]/.test(text) ? `${value > 0 ? "+" : "-"}${text}%` : `${text}%`;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/** The footer's spot: `spot BTC-USD 67,250.10 · 07:25 UTC`, with the date when the quote is not from today. */
|
|
326
|
+
export function curveSpotLabel(spot: CurveSpot, root: string, now: number): string {
|
|
327
|
+
const decimals = curvePriceDecimals(root);
|
|
328
|
+
const price = spot.price == null ? "--" : spot.price.toLocaleString("en-US", { minimumFractionDigits: decimals, maximumFractionDigits: decimals });
|
|
329
|
+
const stamp = curveTimestamp(spot.asOf);
|
|
330
|
+
const today = new Date(now).toISOString().slice(0, 10);
|
|
331
|
+
return `spot ${spot.symbol} ${price} · ${spot.asOf?.startsWith(today) ? stamp.slice(11) : stamp} UTC`;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** The basis columns' sort values, which live beside the contract rather than on it. */
|
|
335
|
+
export type CurveBasisRows = ReadonlyMap<string, ContractBasis>;
|
|
336
|
+
|
|
337
|
+
export function curveBasisRows(rows: readonly FuturesContract[], spot: CurveSpot | null): CurveBasisRows {
|
|
338
|
+
return new Map(rows.map((row) => [row.symbol, spot ? contractBasis(row, spot) : NO_BASIS]));
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/** The contracts a good spot left blank for their old print. */
|
|
342
|
+
export function thinContractCount(basis: Iterable<ContractBasis>): number {
|
|
343
|
+
let count = 0;
|
|
344
|
+
for (const row of basis) if (row.thin) count += 1;
|
|
345
|
+
return count;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/** The footer warning that thin contracts have no basis: the pane's `!` notice, which keeps the footer row for the quote times. */
|
|
349
|
+
export function thinContractsNotice(count: number): string {
|
|
350
|
+
return `Basis blank on ${count} thin contract${count === 1 ? "" : "s"} (last print over 1h before spot)`;
|
|
351
|
+
}
|
|
352
|
+
|
|
169
353
|
/** A past date for the as-of view: empty (or "latest") for the live curve, else YYYY-MM-DD no later than today. */
|
|
170
354
|
export function curveAsOfDate(value: unknown, now = new Date()): string {
|
|
171
355
|
const date = typeof value === "string" ? value.trim() : "";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { chartTableChromeRows, ChartTableHeader, CurveSurface, curveGhostColors, DataTableView, Notice, PaneStatusBody, QueryBar, useChartTableSelection, usePaneNoticeFooter, usePaneStatusFooter, usePaneTabs, type DataTableColumn, type StatItem } from "../../../components";
|
|
3
|
+
import { fitChartTableColumns } from "../../../components/chart-table";
|
|
3
4
|
import { curveStrip, curveSurfaceMinRows } from "../../../components/chart/curve";
|
|
4
5
|
import { isAccessDenied } from "../../../api-client/errors";
|
|
5
6
|
import type { FuturesContract } from "../../../api-client/futures-curve";
|
|
@@ -13,8 +14,9 @@ import { nextHeaderSort, type SortDirection } from "../../../utils/sort-values";
|
|
|
13
14
|
import { useAutoRefresh } from "../../../react/auto-refresh";
|
|
14
15
|
import { futuresSessionRefreshInterval } from "../shared/futures-session";
|
|
15
16
|
import { useResearchCloudSession } from "../shared/research-cloud-session";
|
|
17
|
+
import { useQuoteBoard } from "../shared/use-quote-board";
|
|
16
18
|
import { getCachedFuturesCurve, loadFuturesCurve, loadFuturesCurveAsOf } from "./client";
|
|
17
|
-
import { curveAsOfDate, curveAxisPrice, curveChangeText, curveContractChanges, curvePrice, curveRank, curveTimestamp, DEFAULT_CURVE_HORIZON, futuresCurveSeries, newestQuote, normalizeCurveRoot, sortCurveContracts, type CurveContractChanges } from "./model";
|
|
19
|
+
import { basisSpotSymbol, curveAsOfDate, curveAxisPrice, curveBasisPercent, curveBasisRows, curveChangeText, curveContractChanges, curvePrice, curveRank, curveSpot, curveSpotLabel, curveTimestamp, DEFAULT_CURVE_HORIZON, futuresCurveSeries, newestQuote, normalizeCurveRoot, sortCurveContracts, thinContractCount, thinContractsNotice, unsupportedCurveRootMessage, type CurveContractChanges } from "./model";
|
|
18
20
|
|
|
19
21
|
const TABS = [{ value: "curve", label: "Curve" }, { value: "contracts", label: "Contracts" }];
|
|
20
22
|
const COLUMNS: DataTableColumn[] = [
|
|
@@ -38,6 +40,19 @@ const CURVE_COLUMNS: DataTableColumn[] = [
|
|
|
38
40
|
{ id: "change1m", label: "VS 1M", width: 10, align: "right" },
|
|
39
41
|
...COLUMNS.slice(4, -1),
|
|
40
42
|
];
|
|
43
|
+
// A crypto curve also reads against spot. Its widths are the tightest each column
|
|
44
|
+
// holds (BTCV26.CME, 128000.00), so the two new columns fit beside the rest, and
|
|
45
|
+
// a narrow pane drops the least useful ones before a number would be clipped.
|
|
46
|
+
const BASIS_CURVE_COLUMNS: DataTableColumn[] = [
|
|
47
|
+
{ ...CURVE_COLUMNS[0]!, width: 10 }, CURVE_COLUMNS[1]!, { ...CURVE_COLUMNS[2]!, width: 10 },
|
|
48
|
+
{ id: "vsSpot", label: "VS SPOT", width: 9, align: "right" },
|
|
49
|
+
{ id: "annBasis", label: "ANN BASIS", width: 11, align: "right" },
|
|
50
|
+
...CURVE_COLUMNS.slice(3),
|
|
51
|
+
];
|
|
52
|
+
const BASIS_DROP_ORDER = ["percentile", "volume", "change1m", "oi"];
|
|
53
|
+
const NO_SYMBOLS: string[] = [];
|
|
54
|
+
/** The spot's age is judged against the clock, so a quote that stops moving still goes stale on screen. */
|
|
55
|
+
const SPOT_CLOCK_MS = 30_000;
|
|
41
56
|
const signedPercent = (value: number | null) => value == null ? "--" : formatPercentRaw(value);
|
|
42
57
|
const integer = (value: number | null) => value == null ? "--" : value.toLocaleString("en-US");
|
|
43
58
|
const contractKey = (row: FuturesContract) => row.symbol;
|
|
@@ -50,7 +65,7 @@ export function FuturesCurvePane(props: PaneProps) {
|
|
|
50
65
|
const requested = pane?.settings?.root ?? pane?.params?.root ?? "ES";
|
|
51
66
|
const root = normalizeCurveRoot(requested);
|
|
52
67
|
return root ? <FuturesCurveView key={root} {...props} root={root} />
|
|
53
|
-
: <PaneStatusBody error={
|
|
68
|
+
: <PaneStatusBody error={unsupportedCurveRootMessage(requested)} subject="futures curve" />;
|
|
54
69
|
}
|
|
55
70
|
|
|
56
71
|
function FuturesCurveView({ width, height, focused, root }: PaneProps & { root: string }) {
|
|
@@ -79,6 +94,23 @@ function FuturesCurveView({ width, height, focused, root }: PaneProps & { root:
|
|
|
79
94
|
// A pending date change must never relabel the previous curve as the new one.
|
|
80
95
|
const data = resource.data?.date === requestedDate ? resource.data.payload : null;
|
|
81
96
|
usePaneTitle(`CTM ${root}`);
|
|
97
|
+
const curveTab = tab === "curve";
|
|
98
|
+
// The Curve tab of a crypto root reads against spot; a past date has no spot history.
|
|
99
|
+
const spotSymbol = basisSpotSymbol(root);
|
|
100
|
+
const basisActive = curveTab && !requestedDate && spotSymbol != null;
|
|
101
|
+
const spotSymbols = useMemo(() => basisActive ? [spotSymbol] : NO_SYMBOLS, [basisActive, spotSymbol]);
|
|
102
|
+
const { quotes: spotQuotes } = useQuoteBoard(spotSymbols);
|
|
103
|
+
const [clock, setClock] = useState(() => Date.now());
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
if (!basisActive) return;
|
|
106
|
+
setClock(Date.now());
|
|
107
|
+
const timer = setInterval(() => setClock(Date.now()), SPOT_CLOCK_MS);
|
|
108
|
+
return () => clearInterval(timer);
|
|
109
|
+
}, [basisActive]);
|
|
110
|
+
const spotState = spotSymbol ? spotQuotes.get(spotSymbol) : undefined;
|
|
111
|
+
// Until the first answer there is nothing to say: no reason, only blank cells.
|
|
112
|
+
const spot = useMemo(() => !basisActive || !spotSymbol || !spotState || spotState.loading && !spotState.quote ? null
|
|
113
|
+
: curveSpot(spotSymbol, spotState.quote, clock), [basisActive, clock, spotState, spotSymbol]);
|
|
82
114
|
const staleCount = data?.contracts.filter((row) => row.stale).length ?? 0;
|
|
83
115
|
const newest = data ? newestQuote(data.contracts) : null;
|
|
84
116
|
// A past curve is named by the session it holds: a weekend or holiday date shows the session before it.
|
|
@@ -86,8 +118,9 @@ function FuturesCurveView({ width, height, focused, root }: PaneProps & { root:
|
|
|
86
118
|
requestedDate ? Date.parse(`${requestedDate}T00:00:00Z`) : Date.now(), requestedDate ? data.asOf ?? requestedDate : undefined) : [],
|
|
87
119
|
[data, colors, horizon, requestedDate]);
|
|
88
120
|
const changes = useMemo<CurveContractChanges>(() => data ? curveContractChanges(data) : new Map(), [data]);
|
|
89
|
-
const
|
|
90
|
-
const
|
|
121
|
+
const basis = useMemo(() => curveBasisRows(basisActive ? data?.contracts ?? [] : [], spot), [basisActive, data, spot]);
|
|
122
|
+
const thinCount = useMemo(() => thinContractCount(basis.values()), [basis]);
|
|
123
|
+
const rows = useMemo(() => sortCurveContracts(data?.contracts ?? [], sort.columnId, sort.direction, changes, basis), [data, sort, changes, basis]);
|
|
91
124
|
// The curve tab lists the contracts the chart plots; Contracts keeps every one.
|
|
92
125
|
const curveRows = useMemo(() => {
|
|
93
126
|
const charted = new Set(curves[0]?.points.map((point) => point.id));
|
|
@@ -108,7 +141,8 @@ function FuturesCurveView({ width, height, focused, root }: PaneProps & { root:
|
|
|
108
141
|
const { strip: tabStrip, rows: tabRows } = usePaneTabs({ tabs: TABS, activeValue: tab, onSelect: setTab, focused, dense: true });
|
|
109
142
|
// The query bar takes one row below the tabs, and a refused date one more.
|
|
110
143
|
const bodyHeight = Math.max(1, height - tabRows - 1 - (dateError ? 1 : 0));
|
|
111
|
-
const columns = curveTab ?
|
|
144
|
+
const columns = useMemo(() => !curveTab ? COLUMNS : basisActive ? fitChartTableColumns(BASIS_CURVE_COLUMNS, width, BASIS_DROP_ORDER) : CURVE_COLUMNS,
|
|
145
|
+
[basisActive, curveTab, width]);
|
|
112
146
|
const formatValue = useCallback((value: number) => curvePrice(value, root), [root]);
|
|
113
147
|
const formatChange = useCallback((value: number) => curveChangeText(value, root), [root]);
|
|
114
148
|
const caption = `${sentenceCase(data?.quoteUnit ?? data?.currency ?? "price")} by contract month`;
|
|
@@ -142,7 +176,9 @@ function FuturesCurveView({ width, height, focused, root }: PaneProps & { root:
|
|
|
142
176
|
};
|
|
143
177
|
// A past date with no archived curve says why in the body, not behind the warning.
|
|
144
178
|
const emptyPast = !!requestedDate && !!data && !data.contracts.length;
|
|
145
|
-
|
|
179
|
+
// Thin contracts join the data warnings: the info row has no room for them beside the quote times.
|
|
180
|
+
usePaneNoticeFooter({ registrationId: "futures-curve:notices", focused,
|
|
181
|
+
notices: emptyPast ? [] : [...data?.gaps ?? [], ...thinCount ? [thinContractsNotice(thinCount)] : []] });
|
|
146
182
|
const delay = Math.max(0, ...(data?.contracts.map((row) => row.delayMinutes ?? 0) ?? []));
|
|
147
183
|
usePaneStatusFooter({ registrationId: "futures-curve", loading: resource.loading, error: resource.error,
|
|
148
184
|
hints: [
|
|
@@ -152,6 +188,8 @@ function FuturesCurveView({ width, height, focused, root }: PaneProps & { root:
|
|
|
152
188
|
info: data ? [
|
|
153
189
|
{ id: "source", parts: [{ text: `${requestedDate ? "daily archive" : data.source === "cboe" ? "settlement" : delay > 0 ? `${delay}m delayed` : "dated quotes"} · ${data.quoteUnit ?? data.currency ?? "units unavailable"} · ${curveTimestamp(newest)}${newest?.includes("T") ? " UTC" : ""}`, tone: "muted" }] },
|
|
154
190
|
...(staleCount ? [{ id: "stale", parts: [{ text: `${staleCount} of ${data.contracts.length} stale`, tone: "warning" as const }] }] : []),
|
|
191
|
+
...(spot ? [{ id: "spot", parts: [spot.status === "ok" ? { text: curveSpotLabel(spot, root, clock), tone: "muted" as const }
|
|
192
|
+
: { text: `Basis blank: ${spot.reason}`, tone: "warning" as const }] }] : []),
|
|
155
193
|
] : [],
|
|
156
194
|
});
|
|
157
195
|
const tableChromeRows = chartTableChromeRows(columns, width);
|
|
@@ -166,8 +204,8 @@ function FuturesCurveView({ width, height, focused, root }: PaneProps & { root:
|
|
|
166
204
|
const renderCell = useCallback((row: FuturesContract, column: DataTableColumn) => {
|
|
167
205
|
if (column.id === "symbol") return { text: row.symbol };
|
|
168
206
|
if (column.id === "expiry") return { text: row.expiration, color: colors.textMuted };
|
|
169
|
-
// Without the AS OF column, a stale quote shows on its price.
|
|
170
|
-
if (column.id === "price") return { text: curvePrice(row.price, root), color: curveTab && row.stale ? colors.warning : undefined };
|
|
207
|
+
// Without the AS OF column, a stale quote shows on its price, and so does a print too old for the spot.
|
|
208
|
+
if (column.id === "price") return { text: curvePrice(row.price, root), color: curveTab && (row.stale || basis.get(row.symbol)?.thin) ? colors.warning : undefined };
|
|
171
209
|
if (column.id === "change") {
|
|
172
210
|
const text = curveChangeText(row.change ?? null, root);
|
|
173
211
|
return { text, color: text.startsWith("+") ? colors.positive : text.startsWith("-") && /[1-9]/.test(text) ? colors.negative : colors.textMuted };
|
|
@@ -176,11 +214,15 @@ function FuturesCurveView({ width, height, focused, root }: PaneProps & { root:
|
|
|
176
214
|
const change = changes.get(row.symbol)?.[column.id === "change1w" ? "1W" : "1M"] ?? null;
|
|
177
215
|
return { text: curveChangeText(change, root), color: colors.textMuted };
|
|
178
216
|
}
|
|
217
|
+
if (column.id === "vsSpot" || column.id === "annBasis") {
|
|
218
|
+
const cell = basis.get(row.symbol);
|
|
219
|
+
return { text: column.id === "vsSpot" ? curveBasisPercent(cell?.vsSpotPct ?? null, 2) : curveBasisPercent(cell?.annualisedBasisPct ?? null, 1), color: colors.textMuted };
|
|
220
|
+
}
|
|
179
221
|
if (column.id === "percentile") return { text: row.samples < 2 || row.percentile == null ? "--" : row.percentile.toFixed(0) };
|
|
180
222
|
if (column.id === "oi") return { text: integer(row.openInterest) };
|
|
181
223
|
if (column.id === "volume") return { text: integer(row.volume) };
|
|
182
224
|
return { text: curveTimestamp(row.asOf), color: row.stale ? colors.warning : colors.textMuted };
|
|
183
|
-
}, [changes, colors, curveTab, root]);
|
|
225
|
+
}, [basis, changes, colors, curveTab, root]);
|
|
184
226
|
return <Box width={width} height={height} flexDirection="column">
|
|
185
227
|
{tabStrip}
|
|
186
228
|
<QueryBar width={width} filters={[{
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { colors } from "../../../theme/colors";
|
|
2
|
+
import { blendHex, contrastRatio } from "../../../theme/color-utils";
|
|
3
|
+
|
|
4
|
+
/** A cross that moved at least this many percent from its previous close earns the step. */
|
|
5
|
+
export const TINT_THRESHOLDS = [0.05, 0.15, 0.3, 0.6, 1] as const;
|
|
6
|
+
/**
|
|
7
|
+
* A step holds until the move falls this far below the threshold that earned
|
|
8
|
+
* it: a fifth of the threshold, and never less than 0.02% (about 2 pips on
|
|
9
|
+
* EUR/USD, the size a quote jitters between ticks).
|
|
10
|
+
*/
|
|
11
|
+
const RELEASE_BAND_SHARE = 0.2;
|
|
12
|
+
const RELEASE_BAND_MIN = 0.02;
|
|
13
|
+
/** How far each step leans toward the theme's up or down colour. */
|
|
14
|
+
const TINT_STRENGTH = [0.14, 0.2, 0.27, 0.35, 0.44] as const;
|
|
15
|
+
const MIN_TEXT_CONTRAST = 4.5;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The cross's move since the previous close, in percent: the row currency
|
|
19
|
+
* against the column currency, so a positive move is the row currency gaining.
|
|
20
|
+
* Each rate and reference is USD per unit.
|
|
21
|
+
*/
|
|
22
|
+
export function crossMovePercent(
|
|
23
|
+
rowRate: number,
|
|
24
|
+
rowReference: number,
|
|
25
|
+
columnRate: number,
|
|
26
|
+
columnReference: number,
|
|
27
|
+
): number | null {
|
|
28
|
+
const move = (rowRate / rowReference / (columnRate / columnReference) - 1) * 100;
|
|
29
|
+
return Number.isFinite(move) ? move : null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The signed tint step (0 for none, 1 to 5 up, -1 to -5 down) of a move.
|
|
34
|
+
* `held` is the step the cell showed last: it stays while the move is still
|
|
35
|
+
* within the release band of its threshold, so a rate ticking around a
|
|
36
|
+
* boundary does not flicker between two shades. A move of the other sign
|
|
37
|
+
* starts afresh.
|
|
38
|
+
*/
|
|
39
|
+
export function tintLevel(movePercent: number, held = 0): number {
|
|
40
|
+
const sign = Math.sign(movePercent);
|
|
41
|
+
if (sign === 0) return 0;
|
|
42
|
+
const size = Math.abs(movePercent);
|
|
43
|
+
const earned = TINT_THRESHOLDS.filter((threshold) => size >= threshold).length;
|
|
44
|
+
const kept = sign === Math.sign(held) ? Math.abs(held) : 0;
|
|
45
|
+
const heldThreshold = kept > 0 ? TINT_THRESHOLDS[kept - 1]! : 0;
|
|
46
|
+
const holds = kept > earned && size >= heldThreshold - Math.max(heldThreshold * RELEASE_BAND_SHARE, RELEASE_BAND_MIN);
|
|
47
|
+
const level = holds ? kept : earned;
|
|
48
|
+
return level === 0 ? 0 : sign * level;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** The step a cell shows now, remembering it under `key` for the next tick; null forgets it. */
|
|
52
|
+
export function nextTintLevel(held: Map<string, number>, key: string, movePercent: number | null): number {
|
|
53
|
+
const level = movePercent === null ? 0 : tintLevel(movePercent, held.get(key) ?? 0);
|
|
54
|
+
if (level === 0) held.delete(key);
|
|
55
|
+
else held.set(key, level);
|
|
56
|
+
return level;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const tints = new Map<string, string | undefined>();
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A cell background for a tint step: the theme's own up or down colour
|
|
63
|
+
* blended into `background`. The strength comes down from the step's until
|
|
64
|
+
* `text` reads as well on it as on the plain background (4.5 to 1 where the
|
|
65
|
+
* theme allows), so the numbers stay the primary element in every theme.
|
|
66
|
+
*/
|
|
67
|
+
export function directionTint(level: number, surface: { background: string; text: string }): string | undefined {
|
|
68
|
+
if (level === 0) return undefined;
|
|
69
|
+
const hue = level > 0 ? colors.positive : colors.negative;
|
|
70
|
+
const key = `${level}|${hue}|${surface.background}|${surface.text}`;
|
|
71
|
+
if (tints.has(key)) return tints.get(key);
|
|
72
|
+
const floor = Math.min(MIN_TEXT_CONTRAST, contrastRatio(surface.text, surface.background) * 0.9);
|
|
73
|
+
let tint: string | undefined;
|
|
74
|
+
for (let strength = TINT_STRENGTH[Math.abs(level) - 1]!; strength > 0; strength = Math.round((strength - 0.02) * 100) / 100) {
|
|
75
|
+
const candidate = blendHex(surface.background, hue, strength);
|
|
76
|
+
if (contrastRatio(surface.text, candidate) >= floor) { tint = candidate; break; }
|
|
77
|
+
}
|
|
78
|
+
if (tints.size > 512) tints.clear();
|
|
79
|
+
tints.set(key, tint);
|
|
80
|
+
return tint;
|
|
81
|
+
}
|