gloomberb 0.16.4 → 0.16.6
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 +14 -91
- package/package.json +5 -1
- package/src/{plugins/builtin/cloud → account}/auth-form.tsx +9 -9
- package/src/{plugins/builtin/cloud → account}/auth-model.ts +4 -4
- package/src/account/billing.ts +57 -0
- package/src/{plugins/builtin/cloud → account}/device-signin-dialog.tsx +18 -12
- package/src/{plugins/builtin/cloud → account}/device-signin.ts +2 -2
- package/src/{plugins/builtin/cloud → account}/email-auth-attempt.ts +2 -2
- package/src/account/session.ts +16 -0
- package/src/{plugins/builtin/cloud → account}/upgrade-dialog.tsx +16 -15
- package/src/{plugins/builtin/cloud → account}/upgrade-personalization.ts +7 -7
- package/src/{plugins/builtin/cloud → account}/upgrade-tickers.ts +6 -6
- package/src/{plugins/builtin/cloud → account}/verification-panel.tsx +6 -6
- package/src/api-client/central-bank-rates.ts +6 -1
- package/src/api-client/chat.ts +26 -0
- package/src/api-client/credit-boards.ts +2 -0
- package/src/api-client/data.ts +73 -3
- package/src/api-client/earnings.ts +6 -0
- package/src/api-client/europe-energy.ts +106 -0
- package/src/api-client/futures-curve.ts +56 -0
- package/src/api-client/index.ts +13 -1
- package/src/api-client/market-discovery.ts +13 -1
- package/src/api-client/normalizers.ts +32 -0
- package/src/api-client/paths.ts +7 -0
- package/src/api-client/perps.ts +8 -0
- package/src/api-client/request.ts +9 -2
- package/src/api-client/research-activity.ts +15 -10
- package/src/api-client/socket.ts +29 -0
- package/src/api-client/themes.ts +22 -1
- package/src/api-client/types.ts +78 -2
- package/src/api-client/yield-curves.ts +8 -0
- package/src/app/global-shortcuts.ts +50 -2
- package/src/app/keybindings/actions.ts +12 -1
- package/src/app/pane-runtime/plugin-bindings.ts +2 -2
- package/src/app/pane-runtime/ticker-open-runtime.ts +16 -6
- package/src/app/runtime/desktop-deeplink.ts +10 -5
- package/src/app/runtime/startup.ts +1 -1
- package/src/app.tsx +6 -0
- package/src/architecture/core-builtin-allowlist.json +8 -26
- package/src/ask-gloom/pane-context.ts +114 -0
- package/src/ask-gloom/pane-request.ts +70 -0
- package/src/ask-gloom/pane-text.ts +201 -0
- package/src/brokers/signed-in/sign-in-dialog.tsx +11 -5
- package/src/capabilities/chart-series.ts +19 -2
- package/src/capabilities/factories.ts +1 -0
- package/src/cli/central-bank-events.ts +23 -0
- package/src/cli/command-options.ts +17 -5
- package/src/cli/commands/crypto-hints.ts +35 -2
- package/src/cli/commands/fred-series.ts +146 -0
- package/src/cli/commands/market.ts +501 -115
- package/src/cli/commands/news-hints.ts +62 -0
- package/src/cli/commands/news-search.ts +53 -0
- package/src/cli/commands/options-leaps.ts +5 -2
- package/src/cli/commands/overview.ts +132 -26
- package/src/cli/commands/remote.ts +2 -1
- package/src/cli/commands/search.ts +317 -13
- package/src/cli/commands/system.ts +55 -8
- package/src/cli/commands/ticker.ts +155 -18
- package/src/cli/context.ts +45 -14
- package/src/cli/desktop-pane-shot.ts +76 -7
- package/src/cli/earnings-calendar.ts +71 -0
- package/src/cli/errors.ts +7 -5
- package/src/cli/exit-codes.ts +8 -0
- package/src/cli/export-source.ts +58 -0
- package/src/cli/freshness.ts +18 -7
- package/src/cli/glossary.ts +483 -0
- package/src/cli/help.ts +10 -0
- package/src/cli/helpers.ts +2 -5
- package/src/cli/history-rows.ts +118 -7
- package/src/cli/index-roots.ts +7 -0
- package/src/cli/index.ts +29 -9
- package/src/cli/known-gaps.ts +84 -0
- package/src/cli/listing-arg.ts +551 -97
- package/src/cli/not-a-ticker.ts +24 -9
- package/src/cli/pane-functions/access-gate.ts +13 -2
- package/src/cli/pane-functions/capabilities.ts +4 -3
- package/src/cli/pane-functions/catalog.ts +214 -40
- package/src/cli/pane-functions/data.ts +42 -8
- package/src/cli/pane-functions/discovery.ts +1 -0
- package/src/cli/pane-functions/dom.ts +37 -8
- package/src/cli/pane-functions/freshness.ts +393 -49
- package/src/cli/pane-functions/function-help.ts +31 -15
- package/src/cli/pane-functions/headless.ts +98 -30
- package/src/cli/pane-functions/index.ts +101 -19
- package/src/cli/pane-functions/market-session.ts +22 -8
- package/src/cli/pane-functions/options.ts +71 -22
- package/src/cli/pane-functions/report-notices.ts +25 -7
- package/src/cli/pane-functions/report.ts +15 -8
- package/src/cli/pane-functions/resolver.ts +74 -19
- package/src/cli/pane-functions/screenshot.ts +250 -27
- package/src/cli/perpetual-contract.ts +60 -0
- package/src/cli/registry.ts +3 -1
- package/src/cli/report-tables.ts +26 -7
- package/src/cli/result.ts +45 -11
- package/src/cli/series-search.ts +111 -0
- package/src/cli/staged-tickers.ts +52 -0
- package/src/cli/symbol-args.ts +27 -0
- package/src/cli/symbol-list.ts +154 -0
- package/src/cli/symbol-rows.ts +154 -0
- package/src/cli/ticker-resolution.ts +311 -27
- package/src/cli/types.ts +5 -0
- package/src/components/chart/composite/axis-overlays.tsx +14 -3
- package/src/components/chart/composite/composite-chart.tsx +71 -11
- package/src/components/chart/composite/crosshair-readout.tsx +150 -0
- package/src/components/chart/composite/downsample.ts +1 -1
- package/src/components/chart/composite/format.ts +29 -0
- package/src/components/chart/composite/interactions.ts +9 -2
- package/src/components/chart/composite/legend.tsx +100 -33
- package/src/components/chart/composite/panel-bitmap.ts +70 -35
- package/src/components/chart/composite/panel-labels.ts +18 -17
- package/src/components/chart/composite/panel-series.ts +1 -0
- package/src/components/chart/composite/panel-surface.tsx +46 -21
- package/src/components/chart/composite/price-axis-labels.tsx +3 -1
- package/src/components/chart/composite/rasterizer.ts +50 -8
- package/src/components/chart/composite/scene.ts +2 -1
- package/src/components/chart/composite/time-scale.ts +26 -9
- package/src/components/chart/composite/types.ts +18 -0
- package/src/components/chart/composite/use-composite-viewport.ts +30 -2
- package/src/components/chart/native/raster/crosshair.ts +8 -3
- package/src/components/chart/native/raster/primitives.ts +85 -21
- package/src/components/chart/native/surface/manager.ts +33 -8
- package/src/components/chart/surface3d/chart.tsx +1 -1
- package/src/components/command-bar/action-runtime.ts +1 -1
- package/src/components/command-bar/commands/collection-list.ts +210 -0
- package/src/components/command-bar/commands/collection.ts +40 -1
- package/src/components/command-bar/commands/direct/index.ts +4 -0
- package/src/components/command-bar/commands/registry.ts +8 -0
- package/src/components/command-bar/panel/index.tsx +11 -3
- package/src/components/command-bar/panel/runtime.ts +3 -0
- package/src/components/command-bar/panel/types.ts +2 -0
- package/src/components/command-bar/routes/root/plugin-install.ts +4 -4
- package/src/components/command-bar/routes/root/provider-search.ts +4 -3
- package/src/components/command-bar/routes/ticker-search/results.ts +12 -11
- package/src/components/command-bar/routes/ticker-search/route.ts +4 -3
- package/src/components/command-bar/routing/actions.ts +1 -1
- package/src/components/command-bar/workflow/tickers.ts +42 -17
- package/src/components/layout/detached-pane-shell.tsx +68 -39
- package/src/components/layout/floating-pane.tsx +10 -1
- package/src/components/layout/header.tsx +25 -5
- package/src/components/layout/missing-pane.tsx +3 -3
- package/src/components/layout/pane/capture-stamp.ts +41 -0
- package/src/components/layout/pane/capture-status.ts +12 -0
- package/src/components/layout/pane/content.tsx +7 -13
- package/src/components/layout/pane/footer/index.tsx +6 -2
- package/src/components/layout/pane/footer/keyboard.ts +3 -0
- package/src/components/layout/pane/footer/model.ts +41 -1
- package/src/components/layout/pane/header.tsx +50 -1
- package/src/components/layout/pane/index.tsx +21 -3
- package/src/components/layout/pane/sidebar.tsx +88 -21
- package/src/components/layout/shell/active-drag.ts +21 -5
- package/src/components/layout/shell/cursor-occlusion.ts +2 -1
- package/src/components/layout/shell/drag/index.ts +39 -9
- package/src/components/layout/shell/drag/live.ts +61 -51
- package/src/components/layout/shell/drag/runtime.ts +54 -12
- package/src/components/layout/shell/index.tsx +84 -65
- package/src/components/layout/shell/menu.ts +14 -1
- package/src/components/layout/shell/native/pointer-runtime.ts +3 -1
- package/src/components/layout/shell/pane/actions.ts +32 -10
- package/src/components/layout/shell/pane/ask.ts +131 -0
- package/src/components/layout/shell/pane/capture.ts +162 -0
- package/src/components/layout/shell/pane/layers.tsx +218 -50
- package/src/components/layout/shell/pane/management-shortcuts.ts +46 -1
- package/src/components/layout/shell/shortcuts.ts +21 -4
- package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -0
- package/src/components/markdown-text.tsx +62 -20
- package/src/components/metric-treemap/heat-surface.tsx +8 -1
- package/src/components/onboarding/account-step/form-panel.tsx +1 -1
- package/src/components/onboarding/account-step/index.tsx +1 -1
- package/src/components/onboarding/account-step/qr-panel.tsx +1 -1
- package/src/components/onboarding/account-step/signed-in-panel.tsx +1 -1
- package/src/components/onboarding/onboarding-keyboard.ts +1 -1
- package/src/components/onboarding/onboarding-wizard.tsx +2 -2
- package/src/components/onboarding/use-onboarding-upgrade.ts +3 -3
- package/src/components/onboarding/wizard-account.ts +2 -2
- package/src/components/pane-template-wizard.tsx +9 -1
- package/src/components/price-selector-dialog.tsx +11 -2
- package/src/components/reader/article-reader.tsx +642 -0
- package/src/components/reader/article-text.ts +527 -0
- package/src/components/sign-in-gate.tsx +3 -3
- package/src/components/ticker/list-table-view.tsx +43 -2
- package/src/components/ui/action-row.tsx +2 -1
- package/src/components/ui/button.tsx +7 -1
- package/src/components/ui/choice-dialog.tsx +6 -4
- package/src/components/ui/confirm-dialog.tsx +28 -18
- package/src/components/ui/data-table/index.tsx +18 -6
- package/src/components/ui/data-table/opentui/index.tsx +37 -6
- package/src/components/ui/data-table/types.ts +12 -0
- package/src/components/ui/dialog-actions.tsx +64 -0
- package/src/components/ui/display.tsx +17 -3
- package/src/components/ui/frame.tsx +35 -2
- package/src/components/ui/icon.tsx +6 -1
- package/src/components/ui/query-bar.tsx +10 -1
- package/src/components/ui/text-prompt-dialog.tsx +11 -9
- package/src/data/cached-query.ts +2 -0
- package/src/data/config/store/migrations.ts +7 -0
- package/src/data/config/store/normalize.ts +7 -2
- package/src/data/config/store/portfolio-as-of-column.ts +57 -0
- package/src/data/ticker-repository.ts +5 -0
- package/src/data/ticker-store.ts +15 -0
- package/src/docs/content.ts +215 -0
- package/src/docs/load.ts +139 -0
- package/src/docs/requests.ts +39 -0
- package/src/docs/snapshot.chunk.ts +8 -0
- package/src/docs/snapshot.json +7555 -0
- package/src/docs/topics.ts +216 -0
- package/src/i18n/es.ts +65 -5
- package/src/i18n/ja.ts +65 -5
- package/src/i18n/ko.ts +65 -5
- package/src/i18n/zh-cn.ts +65 -5
- package/src/i18n/zh-tw.ts +65 -5
- package/src/layout/desks.ts +1 -1
- package/src/layout/pane-manager/dock-tree.ts +18 -0
- package/src/layout/pane-manager/index.ts +1 -0
- package/src/layout-marketplace/gallery.tsx +1 -1
- package/src/market-data/coordinator/chart.ts +10 -4
- package/src/market-data/coordinator/index.ts +6 -3
- package/src/{plugins/builtin/futures/contracts.ts → market-data/futures-board.ts} +81 -28
- package/src/market-data/futures-contract.ts +151 -0
- package/src/market-data/hooks.tsx +10 -2
- package/src/market-data/market/format.ts +39 -21
- package/src/market-data/market/freshness.ts +84 -20
- package/src/market-data/market/session-close-note.ts +3 -2
- package/src/market-data/market/status.ts +19 -23
- package/src/market-data/published-apac-sessions.ts +23 -1
- package/src/market-data/quotes/contributions.ts +5 -0
- package/src/market-data/quotes/metadata.ts +19 -24
- package/src/market-data/quotes/resolution.ts +5 -0
- package/src/market-data/quotes/screener-live-quotes.ts +5 -4
- package/src/market-data/result-types.ts +2 -0
- package/src/notifications/app-notifier.ts +17 -1
- package/src/notifications/notification-log.ts +180 -0
- package/src/plugins/auto-update-node.ts +2 -2
- package/src/plugins/auto-update.ts +2 -2
- package/src/plugins/builtin/account-management/index.tsx +1 -0
- package/src/plugins/builtin/account-management/model.ts +1 -56
- package/src/plugins/builtin/account-management/pane.tsx +6 -4
- package/src/plugins/builtin/account-management/password-dialog.tsx +1 -1
- package/src/plugins/builtin/alerts/catalysts.ts +1 -1
- package/src/plugins/builtin/alerts/cli.ts +313 -47
- package/src/plugins/builtin/alerts/events-pane.tsx +45 -7
- package/src/plugins/builtin/alerts/events.ts +23 -2
- package/src/plugins/builtin/alerts/focus.ts +27 -0
- package/src/plugins/builtin/alerts/history-pane.tsx +7 -2
- package/src/plugins/builtin/alerts/history.ts +2 -0
- package/src/plugins/builtin/alerts/index.tsx +47 -11
- package/src/plugins/builtin/alerts/pane.tsx +27 -1
- package/src/plugins/builtin/alerts/research-builder.ts +8 -3
- package/src/plugins/builtin/alerts/research-rules.ts +18 -2
- package/src/plugins/builtin/alerts/scheduled-check.ts +122 -0
- package/src/plugins/builtin/alerts/scheduled-sources.ts +25 -0
- package/src/plugins/builtin/alerts/scheduled.ts +254 -0
- package/src/plugins/builtin/alerts/targets.ts +92 -0
- package/src/plugins/builtin/analytics/index.tsx +8 -3
- package/src/plugins/builtin/analytics/risk-headless.ts +60 -27
- package/src/plugins/builtin/analytics/risk-math.ts +91 -27
- package/src/plugins/builtin/analytics/risk-model.ts +35 -5
- package/src/plugins/builtin/analytics/risk-pane.tsx +15 -8
- package/src/plugins/builtin/attention/headless.ts +1 -1
- package/src/plugins/builtin/attention/index.tsx +2 -0
- package/src/plugins/builtin/attention/pane.tsx +3 -1
- package/src/plugins/builtin/attention/series.ts +26 -0
- package/src/plugins/builtin/awards/headless.ts +88 -18
- package/src/plugins/builtin/awards/index.tsx +2 -0
- package/src/plugins/builtin/awards/model.ts +41 -1
- package/src/plugins/builtin/awards/pane.tsx +22 -13
- package/src/plugins/builtin/awards/series.ts +29 -0
- package/src/plugins/builtin/backtest/headless.ts +2 -2
- package/src/plugins/builtin/bond-calculator/model.ts +2 -1
- package/src/plugins/builtin/broker-manager/index.tsx +1 -0
- package/src/plugins/builtin/catalysts/headless.ts +1 -1
- package/src/plugins/builtin/catalysts/pane.tsx +3 -1
- package/src/plugins/builtin/cds/client.ts +49 -12
- package/src/plugins/builtin/cds/headless.ts +119 -19
- package/src/plugins/builtin/cds/index.tsx +3 -1
- package/src/plugins/builtin/cds/model.ts +214 -32
- package/src/plugins/builtin/cds/pane.tsx +58 -14
- package/src/plugins/builtin/cds/series.ts +19 -0
- package/src/plugins/builtin/central-bank-rates/client.ts +4 -0
- package/src/plugins/builtin/central-bank-rates/headless.ts +46 -16
- package/src/plugins/builtin/central-bank-rates/index.tsx +3 -1
- package/src/plugins/builtin/central-bank-rates/model.ts +99 -0
- package/src/plugins/builtin/central-bank-rates/pane.tsx +1 -1
- package/src/plugins/builtin/central-bank-rates/series.ts +36 -0
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +193 -255
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +84 -46
- package/src/plugins/builtin/chart-composer/editor.tsx +5 -4
- package/src/plugins/builtin/chart-composer/field-series.ts +40 -0
- package/src/plugins/builtin/chart-composer/headless-schema.ts +1 -1
- package/src/plugins/builtin/chart-composer/headless.ts +70 -5
- package/src/plugins/builtin/chart-composer/index.tsx +15 -3
- package/src/plugins/builtin/chart-composer/pane.tsx +81 -38
- package/src/plugins/builtin/chart-composer/series-catalog.ts +58 -50
- package/src/plugins/builtin/chart-composer/series-expression.ts +18 -10
- package/src/plugins/builtin/chart-composer/use-series-catalog.ts +59 -3
- package/src/plugins/builtin/chart-composer/user-series.ts +84 -0
- package/src/plugins/builtin/chat/content/composer-runtime.ts +6 -1
- package/src/plugins/builtin/chat/content/composer.tsx +5 -1
- package/src/plugins/builtin/chat/content/footer.tsx +12 -0
- package/src/plugins/builtin/chat/content/index.tsx +89 -5
- package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +10 -2
- package/src/plugins/builtin/chat/content/new-messages.tsx +89 -0
- package/src/plugins/builtin/chat/content/row-activity.ts +132 -0
- package/src/plugins/builtin/chat/content/scroll.ts +127 -27
- package/src/plugins/builtin/chat/content/shortcuts.ts +2 -2
- package/src/plugins/builtin/chat/content/transcript.tsx +145 -78
- package/src/plugins/builtin/chat/content/types.ts +1 -0
- package/src/plugins/builtin/chat/controller/fetch.ts +8 -2
- package/src/plugins/builtin/chat/controller/index.ts +123 -1
- package/src/plugins/builtin/chat/controller/message-loading.ts +3 -0
- package/src/plugins/builtin/chat/controller/messages.ts +7 -2
- package/src/plugins/builtin/chat/controller/realtime.ts +10 -1
- package/src/plugins/builtin/chat/controller/send.ts +61 -1
- package/src/plugins/builtin/chat/controller/state.ts +8 -0
- package/src/plugins/builtin/chat/ghost-user.ts +20 -0
- package/src/plugins/builtin/chat/index.tsx +23 -5
- package/src/plugins/builtin/chat/layout.ts +78 -5
- package/src/plugins/builtin/chat/message/ai-badge.tsx +18 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +55 -6
- package/src/plugins/builtin/chat/message/header.tsx +16 -4
- package/src/plugins/builtin/chat/message/profile-popover.tsx +5 -1
- package/src/plugins/builtin/chat/message/reactions.tsx +210 -0
- package/src/plugins/builtin/chat/message/render-state.ts +18 -2
- package/src/plugins/builtin/chat/message/terminal.tsx +43 -4
- package/src/plugins/builtin/chat/message/types.ts +12 -0
- package/src/plugins/builtin/chat/reactions.ts +197 -0
- package/src/plugins/builtin/chat/share/flow.tsx +87 -0
- package/src/plugins/builtin/chat/share/targets.ts +27 -0
- package/src/plugins/builtin/chat/status-widget.tsx +6 -3
- package/src/plugins/builtin/chat/unread-inbox-pane.tsx +148 -27
- package/src/plugins/builtin/chat/unread-inbox.ts +22 -0
- package/src/plugins/builtin/cloud/askg/attached-pane.tsx +69 -0
- package/src/plugins/builtin/cloud/askg/controller.ts +111 -19
- package/src/plugins/builtin/cloud/askg/executor.ts +57 -3
- package/src/plugins/builtin/cloud/askg/manifest.ts +32 -7
- package/src/plugins/builtin/cloud/askg/model.ts +27 -8
- package/src/plugins/builtin/cloud/askg/pane-attachment.ts +94 -0
- package/src/plugins/builtin/cloud/askg/pane.tsx +141 -12
- package/src/plugins/builtin/cloud/askg/pending-question.ts +11 -0
- package/src/plugins/builtin/cloud/askg/protocol.ts +10 -1
- package/src/plugins/builtin/cloud/askg/tool-display.ts +3 -0
- package/src/plugins/builtin/cloud/askg/undo.ts +2 -0
- package/src/plugins/builtin/cloud/auth-actions.tsx +1 -1
- package/src/plugins/builtin/cloud/auth-commands.ts +1 -1
- package/src/plugins/builtin/cloud/auth-dialog.tsx +3 -3
- package/src/plugins/builtin/cloud/company-picker.tsx +1 -1
- package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +3 -0
- package/src/plugins/builtin/cloud/plugin.tsx +19 -2
- package/src/plugins/builtin/cloud/team/model.ts +5 -0
- package/src/plugins/builtin/cloud/team/module.tsx +1 -0
- package/src/plugins/builtin/cloud/team/store.ts +8 -3
- package/src/plugins/builtin/cloud/terminal-relay/engine.ts +77 -9
- package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +6 -1
- package/src/plugins/builtin/cloud/terminal-relay/policy.ts +9 -0
- package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +35 -11
- package/src/plugins/builtin/cloud/thesis/exposure.ts +1 -1
- package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
- package/src/plugins/builtin/cloud/thesis/prompts.tsx +2 -1
- package/src/plugins/builtin/company-attention/app-rank.tsx +1 -1
- package/src/plugins/builtin/company-attention/headless.ts +21 -7
- package/src/plugins/builtin/company-attention/index.tsx +2 -0
- package/src/plugins/builtin/company-attention/model.ts +26 -7
- package/src/plugins/builtin/company-attention/pane.tsx +12 -9
- package/src/plugins/builtin/company-attention/series.ts +52 -0
- package/src/plugins/builtin/company-kpis/headless.ts +97 -10
- package/src/plugins/builtin/company-kpis/model.ts +24 -2
- package/src/plugins/builtin/company-kpis/pane.tsx +17 -16
- package/src/plugins/builtin/composite-plugins.ts +19 -13
- package/src/plugins/builtin/connections/index.ts +1 -0
- package/src/plugins/builtin/cot/headless.ts +1 -1
- package/src/plugins/builtin/cot/index.tsx +3 -1
- package/src/plugins/builtin/cot/model.ts +40 -11
- package/src/plugins/builtin/cot/series.ts +27 -0
- package/src/plugins/builtin/cpi/headless.ts +3 -3
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +10 -1
- package/src/plugins/builtin/credit-boards/client.ts +6 -2
- package/src/plugins/builtin/credit-boards/headless.ts +108 -31
- package/src/plugins/builtin/credit-boards/index.tsx +2 -0
- package/src/plugins/builtin/credit-boards/model.ts +11 -1
- package/src/plugins/builtin/credit-boards/series.ts +66 -0
- package/src/plugins/builtin/credit-conditions/client.ts +12 -9
- package/src/plugins/builtin/credit-conditions/headless.ts +13 -2
- package/src/plugins/builtin/credit-conditions/index.tsx +18 -9
- package/src/plugins/builtin/credit-conditions/model.ts +19 -11
- package/src/plugins/builtin/credit-conditions/series.ts +16 -0
- package/src/plugins/builtin/credit-documents/headless.ts +33 -3
- package/src/plugins/builtin/credit-documents/pane.tsx +3 -1
- package/src/plugins/builtin/crypto-board/headless.ts +2 -3
- package/src/plugins/builtin/crypto-board/index.tsx +2 -0
- package/src/plugins/builtin/crypto-board/model.ts +12 -0
- package/src/plugins/builtin/crypto-board/pane.tsx +19 -12
- package/src/plugins/builtin/crypto-board/series.ts +48 -0
- package/src/plugins/builtin/custom-view/live-quotes.ts +2 -2
- package/src/plugins/builtin/debt-maturities/headless.ts +17 -11
- package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
- package/src/plugins/builtin/debt-maturities/series.ts +45 -0
- package/src/plugins/builtin/dividend-yield/client.ts +3 -0
- package/src/plugins/builtin/dividend-yield/headless.ts +7 -4
- package/src/plugins/builtin/dividend-yield/index.tsx +3 -1
- package/src/plugins/builtin/dividend-yield/pane.tsx +3 -1
- package/src/plugins/builtin/dividend-yield/series.ts +20 -0
- package/src/plugins/builtin/dividend-yield/types.ts +2 -0
- package/src/plugins/builtin/docs/blocks.tsx +181 -0
- package/src/plugins/builtin/docs/index.tsx +68 -0
- package/src/plugins/builtin/docs/pane.tsx +426 -0
- package/src/plugins/builtin/docs/targets.ts +72 -0
- package/src/plugins/builtin/docs/use-docs.ts +60 -0
- package/src/plugins/builtin/doe/headless.ts +12 -8
- package/src/plugins/builtin/doe/index.tsx +2 -0
- package/src/plugins/builtin/doe/series.ts +62 -0
- package/src/plugins/builtin/earnings/client.ts +3 -2
- package/src/plugins/builtin/earnings/format.ts +1 -5
- package/src/plugins/builtin/earnings/headless.ts +58 -6
- package/src/plugins/builtin/earnings/history-model.ts +15 -1
- package/src/plugins/builtin/earnings/history-table.ts +13 -2
- package/src/plugins/builtin/earnings/history.tsx +7 -3
- package/src/plugins/builtin/earnings/index.tsx +9 -0
- package/src/plugins/builtin/earnings-calls/headless.ts +28 -2
- package/src/plugins/builtin/earnings-calls/index.tsx +1 -1
- package/src/plugins/builtin/earnings-ripple/index.tsx +2 -0
- package/src/plugins/builtin/econ/fred-catalog.ts +198 -0
- package/src/plugins/builtin/econ/fred-series-map.ts +0 -46
- package/src/plugins/builtin/econ/index.tsx +2 -0
- package/src/plugins/builtin/econ-statistics/defs.ts +5 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +19 -4
- package/src/plugins/builtin/econ-statistics/stats.ts +1 -0
- package/src/plugins/builtin/equity-screener/headless.ts +3 -3
- package/src/plugins/builtin/equity-screener/pane.tsx +4 -11
- package/src/plugins/builtin/estimate-revisions/headless.ts +3 -3
- package/src/plugins/builtin/exposure/drivers.ts +13 -0
- package/src/plugins/builtin/exposure/headless.ts +205 -13
- package/src/plugins/builtin/exposure/holdings.ts +1 -1
- package/src/plugins/builtin/exposure/index.tsx +1 -0
- package/src/plugins/builtin/exposure/model.ts +23 -3
- package/src/plugins/builtin/exposure/pane.tsx +14 -12
- package/src/plugins/builtin/fear-greed/index.tsx +18 -10
- package/src/plugins/builtin/fear-greed/series.ts +52 -0
- package/src/plugins/builtin/futures/index.tsx +43 -3
- package/src/plugins/builtin/futures/model.ts +1 -1
- package/src/plugins/builtin/futures/returns.ts +1 -1
- package/src/plugins/builtin/futures/series.ts +13 -0
- package/src/plugins/builtin/futures/table.tsx +1 -1
- package/src/plugins/builtin/futures/use-front-returns.ts +1 -1
- package/src/plugins/builtin/futures-curve/client.ts +12 -3
- package/src/plugins/builtin/futures-curve/headless.ts +71 -10
- package/src/plugins/builtin/futures-curve/index.tsx +1 -1
- package/src/plugins/builtin/futures-curve/model.ts +66 -11
- package/src/plugins/builtin/futures-curve/pane.tsx +52 -18
- package/src/plugins/builtin/fx-matrix/client.ts +63 -0
- package/src/plugins/builtin/fx-matrix/export.ts +2 -1
- package/src/plugins/builtin/fx-matrix/headless.ts +154 -0
- package/src/plugins/builtin/fx-matrix/index.tsx +4 -4
- package/src/plugins/builtin/gpu/board.tsx +13 -10
- package/src/plugins/builtin/gpu/changes.tsx +4 -4
- package/src/plugins/builtin/gpu/client.ts +19 -1
- package/src/plugins/builtin/gpu/equities.tsx +14 -10
- package/src/plugins/builtin/gpu/headless.ts +58 -27
- package/src/plugins/builtin/gpu/history.tsx +3 -3
- package/src/plugins/builtin/gpu/index.tsx +2 -0
- package/src/plugins/builtin/gpu/model.ts +101 -16
- package/src/plugins/builtin/gpu/pane.tsx +28 -12
- package/src/plugins/builtin/gpu/series.ts +38 -0
- package/src/plugins/builtin/help/function-card.tsx +25 -6
- package/src/plugins/builtin/help/function-index.ts +2 -0
- package/src/plugins/builtin/help/index.tsx +31 -9
- package/src/plugins/builtin/holders/beneficial-model.ts +90 -3
- package/src/plugins/builtin/holders/beneficial-report.ts +57 -5
- package/src/plugins/builtin/holders/beneficial-view.tsx +55 -11
- package/src/plugins/builtin/holders/client.ts +22 -3
- package/src/plugins/builtin/holders/format.ts +18 -3
- package/src/plugins/builtin/holders/headless.ts +36 -133
- package/src/plugins/builtin/holders/pane.tsx +11 -4
- package/src/plugins/builtin/holders/report-header.ts +40 -5
- package/src/plugins/builtin/holders/report-rows.ts +240 -0
- package/src/plugins/builtin/insider/client.ts +35 -20
- package/src/plugins/builtin/insider/headless.ts +41 -11
- package/src/plugins/builtin/insider/index.tsx +26 -9
- package/src/plugins/builtin/insider/insider-data.ts +10 -0
- package/src/plugins/builtin/insider/issuer.ts +49 -0
- package/src/plugins/builtin/insider/model.ts +3 -0
- package/src/plugins/builtin/ipo-calendar/headless.ts +1 -1
- package/src/plugins/builtin/iv-history/client.ts +20 -6
- package/src/plugins/builtin/iv-history/format.ts +9 -0
- package/src/plugins/builtin/iv-history/headless.ts +56 -21
- package/src/plugins/builtin/iv-history/index.tsx +2 -0
- package/src/plugins/builtin/iv-history/model.ts +143 -8
- package/src/plugins/builtin/iv-history/screen-pane.tsx +5 -9
- package/src/plugins/builtin/iv-history/series.ts +29 -0
- package/src/plugins/builtin/jobs/headless.ts +26 -3
- package/src/plugins/builtin/jobs/index.tsx +3 -1
- package/src/plugins/builtin/jobs/series.ts +19 -0
- package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +2 -1
- package/src/plugins/builtin/kelly-sizer/portfolio.ts +0 -39
- package/src/plugins/builtin/macro-day/client.ts +44 -3
- package/src/plugins/builtin/macro-day/headless.ts +13 -10
- package/src/plugins/builtin/macro-day/model.ts +56 -10
- package/src/plugins/builtin/macro-day/pane.tsx +30 -20
- package/src/plugins/builtin/market-heatmap/headless.ts +20 -5
- package/src/plugins/builtin/market-heatmap/index.tsx +6 -0
- package/src/plugins/builtin/market-heatmap/model.ts +19 -11
- package/src/plugins/builtin/market-heatmap/portfolio.ts +2 -2
- package/src/plugins/builtin/market-movers/client.ts +7 -5
- package/src/plugins/builtin/market-movers/index.tsx +3 -2
- package/src/plugins/builtin/market-movers/model.ts +30 -0
- package/src/plugins/builtin/market-movers/screener.ts +31 -0
- package/src/plugins/builtin/market-valuation/chart-series.ts +29 -69
- package/src/plugins/builtin/market-valuation/index.tsx +3 -3
- package/src/plugins/builtin/market-valuation/indicators.ts +0 -5
- package/src/plugins/builtin/members/headless.ts +8 -3
- package/src/plugins/builtin/members/model.ts +31 -3
- package/src/plugins/builtin/members/pane.tsx +6 -8
- package/src/plugins/builtin/mna/distress/headless.ts +4 -4
- package/src/plugins/builtin/mna/headless.ts +18 -6
- package/src/plugins/builtin/money-markets/headless.ts +5 -4
- package/src/plugins/builtin/money-markets/index.tsx +2 -0
- package/src/plugins/builtin/money-markets/series.ts +41 -0
- package/src/plugins/builtin/news/index.tsx +0 -2
- package/src/plugins/builtin/news/wire/news/detail-view.tsx +53 -104
- package/src/plugins/builtin/news/wire/news/footer.ts +2 -25
- package/src/plugins/builtin/news/wire/news/preset-pane.tsx +0 -2
- package/src/plugins/builtin/notes/cli.ts +12 -7
- package/src/plugins/builtin/notes/index.tsx +1 -0
- package/src/plugins/builtin/options/index.tsx +3 -0
- package/src/plugins/builtin/options/view.tsx +1 -1
- package/src/plugins/builtin/options-calculator/inputs.ts +2 -1
- package/src/plugins/builtin/options-positioning/client.ts +7 -3
- package/src/plugins/builtin/options-positioning/headless.ts +4 -3
- package/src/plugins/builtin/options-positioning/pane.tsx +2 -2
- package/src/plugins/builtin/options-scenario/client.ts +2 -1
- package/src/plugins/builtin/options-scenario/headless.ts +1 -0
- package/src/plugins/builtin/options-scenario/hedge.ts +2 -1
- package/src/plugins/builtin/perps/client.ts +90 -16
- package/src/plugins/builtin/perps/equity-row.tsx +52 -17
- package/src/plugins/builtin/perps/freshness.ts +66 -0
- package/src/plugins/builtin/perps/headless.ts +47 -32
- package/src/plugins/builtin/perps/index.tsx +23 -4
- package/src/plugins/builtin/perps/list-perpetuals.ts +118 -0
- package/src/plugins/builtin/perps/model.ts +20 -5
- package/src/plugins/builtin/perps/open-market.ts +15 -0
- package/src/plugins/builtin/perps/pane.tsx +76 -20
- package/src/plugins/builtin/perps/series.ts +76 -0
- package/src/plugins/builtin/plugin-marketplace/index.tsx +1 -1
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +73 -67
- package/src/plugins/builtin/plugin-module.ts +3 -0
- package/src/plugins/builtin/portfolio-list/account-metrics.ts +1 -1
- package/src/plugins/builtin/portfolio-list/allocation.ts +5 -4
- package/src/plugins/builtin/portfolio-list/cell-version.ts +8 -1
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +161 -0
- package/src/plugins/builtin/portfolio-list/cli/import-13f.ts +109 -0
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +384 -74
- package/src/plugins/builtin/portfolio-list/cli/render.ts +437 -71
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +21 -4
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +121 -47
- package/src/plugins/builtin/portfolio-list/column-values.ts +104 -26
- package/src/plugins/builtin/portfolio-list/grid.tsx +1 -1
- package/src/plugins/builtin/portfolio-list/headless.ts +84 -18
- package/src/plugins/builtin/portfolio-list/imported-from.ts +8 -0
- package/src/plugins/builtin/portfolio-list/index.tsx +5 -1
- package/src/plugins/builtin/portfolio-list/live-valuation.ts +6 -2
- package/src/plugins/builtin/portfolio-list/mutations.ts +2 -9
- package/src/plugins/builtin/portfolio-list/pane/data.ts +5 -1
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +52 -9
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +33 -11
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +21 -1
- package/src/plugins/builtin/portfolio-list/settings.ts +17 -0
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +12 -0
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +9 -4
- package/src/plugins/builtin/portfolio-list/table.tsx +37 -7
- package/src/plugins/builtin/power/client.ts +16 -0
- package/src/plugins/builtin/power/evidence.ts +63 -10
- package/src/plugins/builtin/power/headless.ts +77 -9
- package/src/plugins/builtin/power/index.tsx +28 -3
- package/src/plugins/builtin/power/model.ts +73 -2
- package/src/plugins/builtin/power/pane.tsx +37 -9
- package/src/plugins/builtin/power/prices-client.ts +139 -0
- package/src/plugins/builtin/power/prices-headless.ts +137 -0
- package/src/plugins/builtin/power/prices-model.ts +103 -0
- package/src/plugins/builtin/power/prices.tsx +179 -0
- package/src/plugins/builtin/rate-path/headless.ts +46 -18
- package/src/plugins/builtin/realized-vol/headless.ts +5 -0
- package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +5 -2
- package/src/plugins/builtin/research/event-model.ts +68 -24
- package/src/plugins/builtin/research/events-headless.ts +2 -1
- package/src/plugins/builtin/research/headless.ts +2 -1
- package/src/plugins/builtin/research/index.tsx +2 -0
- package/src/plugins/builtin/research-search/article.ts +65 -0
- package/src/plugins/builtin/research-search/document-view.tsx +33 -215
- package/src/plugins/builtin/research-search/model.ts +0 -9
- package/src/plugins/builtin/research-search/pane.tsx +41 -30
- package/src/plugins/builtin/research-search/snippet.ts +0 -29
- package/src/plugins/builtin/revenue-breakdown/headless.ts +18 -6
- package/src/plugins/builtin/seasonality/client.ts +15 -7
- package/src/plugins/builtin/seasonality/headless.ts +36 -12
- package/src/plugins/builtin/seasonality/index.tsx +2 -2
- package/src/plugins/builtin/seasonality/model.ts +119 -0
- package/src/plugins/builtin/seasonality/pane.tsx +108 -37
- package/src/plugins/builtin/sec/headless.ts +25 -3
- package/src/plugins/builtin/sec/index.tsx +2 -1
- package/src/plugins/builtin/series-inventory.ts +93 -0
- package/src/plugins/builtin/shared/cloud-denied.ts +15 -0
- package/src/plugins/builtin/shared/cloud-upgrade.ts +1 -1
- package/src/plugins/builtin/shared/command-tab.ts +30 -12
- package/src/plugins/builtin/shared/earnings-report.ts +55 -0
- package/src/plugins/builtin/shared/fred-points.ts +20 -0
- package/src/plugins/builtin/shared/free-preview.ts +47 -0
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +101 -0
- package/src/plugins/builtin/shared/open-description.ts +29 -0
- package/src/plugins/builtin/shared/report-freshness.ts +12 -1
- package/src/plugins/builtin/shared/series-warning.ts +5 -0
- package/src/plugins/builtin/shared/volatility/options.ts +4 -1
- package/src/plugins/builtin/short-interest/headless.ts +1 -0
- package/src/plugins/builtin/short-interest/index.tsx +2 -0
- package/src/plugins/builtin/short-interest/series.ts +36 -0
- package/src/plugins/builtin/short-interest/watch-headless.ts +3 -2
- package/src/plugins/builtin/short-interest/watch-model.ts +9 -5
- package/src/plugins/builtin/short-volume/headless.ts +2 -1
- package/src/plugins/builtin/short-volume/index.tsx +2 -0
- package/src/plugins/builtin/short-volume/series.ts +23 -0
- package/src/plugins/builtin/social-mentions/headless.ts +1 -1
- package/src/plugins/builtin/social-mentions/index.tsx +2 -0
- package/src/plugins/builtin/social-mentions/series.ts +23 -0
- package/src/plugins/builtin/supply-chain/graph-pane.tsx +3 -2
- package/src/plugins/builtin/supply-chain/headless.ts +43 -11
- package/src/plugins/builtin/supply-chain/model.ts +13 -0
- package/src/plugins/builtin/supply-chain/pane.tsx +8 -6
- package/src/plugins/builtin/themes/headless.ts +74 -10
- package/src/plugins/builtin/themes/model.ts +71 -4
- package/src/plugins/builtin/themes/pane.tsx +22 -5
- package/src/plugins/builtin/thirteenf/api.ts +1 -0
- package/src/plugins/builtin/thirteenf/data.ts +6 -4
- package/src/plugins/builtin/thirteenf/headless.ts +217 -36
- package/src/plugins/builtin/thirteenf/model.ts +39 -1
- package/src/plugins/builtin/thirteenf/overlap.ts +75 -0
- package/src/plugins/builtin/thirteenf/pane.tsx +10 -1
- package/src/plugins/builtin/thirteenf/report-notes.ts +103 -1
- package/src/plugins/builtin/thirteenf/types.ts +2 -0
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +114 -0
- package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +57 -2
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +19 -55
- package/src/plugins/builtin/ticker-detail/headless-schema.ts +30 -0
- package/src/plugins/builtin/ticker-detail/headless.ts +86 -0
- package/src/plugins/builtin/ticker-detail/index.tsx +26 -11
- package/src/plugins/builtin/ticker-detail/overview/components.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/overview/futures-contract.ts +31 -0
- package/src/plugins/builtin/ticker-detail/overview/model.ts +3 -3
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +2 -1
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +49 -5
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +13 -3
- package/src/plugins/builtin/time-sales/headless.ts +2 -1
- package/src/plugins/builtin/time-sales/index.tsx +2 -1
- package/src/plugins/builtin/treasury-auctions/headless.ts +16 -2
- package/src/plugins/builtin/treasury-auctions/index.tsx +1 -0
- package/src/plugins/builtin/treasury-auctions/model.ts +8 -0
- package/src/plugins/builtin/vol-surface/evidence.ts +7 -1
- package/src/plugins/builtin/vol-surface/headless.ts +51 -17
- package/src/plugins/builtin/vol-surface/heat-grid.tsx +113 -0
- package/src/plugins/builtin/vol-surface/model.ts +39 -6
- package/src/plugins/builtin/vol-surface/pane.tsx +14 -13
- package/src/plugins/builtin/vol-surface/stored.ts +63 -3
- package/src/plugins/builtin/vol-surface/surface.tsx +30 -2
- package/src/plugins/builtin/volatility/index.tsx +2 -0
- package/src/plugins/builtin/volatility/series.ts +84 -0
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +6 -5
- package/src/plugins/builtin/world-venue-map/basemap.ts +6 -3
- package/src/plugins/builtin/world-venue-map/geo-draw.tsx +2 -1
- package/src/plugins/builtin/world-venue-map/geo-series.ts +26 -1
- package/src/plugins/builtin/world-venue-map/geo-svg.tsx +6 -6
- package/src/plugins/builtin/world-venue-map/headless.ts +4 -1
- package/src/plugins/builtin/world-venue-map/index.ts +2 -1
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +24 -13
- package/src/plugins/builtin/world-venue-map/layers.ts +29 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +144 -13
- package/src/plugins/builtin/world-venue-map/model.ts +56 -19
- package/src/plugins/builtin/world-venue-map/pane.tsx +5 -2
- package/src/plugins/builtin/yield-curve/chart.ts +2 -2
- package/src/plugins/builtin/yield-curve/curves.ts +21 -8
- package/src/plugins/builtin/yield-curve/headless.ts +71 -18
- package/src/plugins/builtin/yield-curve/index.tsx +4 -2
- package/src/plugins/builtin/yield-curve/series.ts +86 -0
- package/src/plugins/catalog-browser.ts +2 -1
- package/src/plugins/installer.ts +2 -2
- package/src/plugins/loader.ts +15 -0
- package/src/plugins/manager-node.ts +1 -1
- package/src/plugins/{builtin/plugin-marketplace → marketplace}/feed.ts +2 -2
- package/src/plugins/{builtin/plugin-marketplace → marketplace}/model.ts +6 -6
- package/src/plugins/{builtin/plugin-marketplace → marketplace}/store.ts +1 -1
- package/src/plugins/registry/host-actions.ts +11 -0
- package/src/plugins/registry/index.ts +89 -4
- package/src/portfolio/collection-name.ts +31 -0
- package/src/{plugins/builtin/portfolio-list → portfolio}/position-metrics.ts +6 -6
- package/src/portfolio/position-value.ts +40 -0
- package/src/portfolio/valuation-basis.ts +79 -0
- package/src/public/__snapshots__/public-api.test.ts.snap +7 -0
- package/src/public/time-series.ts +17 -0
- package/src/react/auto-refresh.ts +13 -3
- package/src/react/input.ts +33 -1
- package/src/react/key-repeat.ts +86 -0
- package/src/remote/app-host.tsx +20 -4
- package/src/remote/confirm-change.tsx +85 -0
- package/src/remote/controller-utils.ts +8 -1
- package/src/remote/controller.ts +144 -7
- package/src/remote/pane-screenshot.ts +47 -0
- package/src/remote/schema.ts +65 -2
- package/src/remote/types.ts +30 -0
- package/src/remote/watchlist.ts +306 -0
- package/src/renderers/browser/main.tsx +4 -3
- package/src/renderers/browser/research-entry.ts +4 -2
- package/src/renderers/cloudflare/worker.ts +1 -1
- package/src/renderers/dom/data-table/frozen-column.ts +3 -1
- package/src/renderers/dom/data-table/index.tsx +33 -6
- package/src/renderers/dom/data-table/row.tsx +30 -1
- package/src/renderers/dom/desktop/control-styles.ts +63 -1
- package/src/renderers/dom/desktop/controls.tsx +30 -23
- package/src/renderers/dom/desktop/dialog-actions.tsx +170 -0
- package/src/renderers/dom/desktop/icons.tsx +16 -0
- package/src/renderers/dom/dom-ui-host.tsx +3 -0
- package/src/renderers/dom/host/block-glyph-canvas.tsx +6 -3
- package/src/renderers/dom/host/box.tsx +8 -0
- package/src/renderers/dom/host/chart-surface.tsx +33 -2
- package/src/renderers/dom/host/live-frame.ts +6 -2
- package/src/renderers/dom/host/overflow-fade.ts +14 -1
- package/src/renderers/dom/host/scroll-box.tsx +32 -0
- package/src/renderers/dom/host/size-observer.ts +41 -0
- package/src/renderers/dom/host/sticky-scroll.ts +128 -0
- package/src/renderers/dom/host/style.ts +1 -1
- package/src/renderers/dom/host/surface-3d.tsx +19 -7
- package/src/renderers/dom/host/surface-fit.ts +406 -0
- package/src/renderers/dom/host/text.tsx +1 -1
- package/src/renderers/dom/input-host.tsx +1 -0
- package/src/renderers/dom/styles.css +102 -5
- package/src/renderers/electrobun/bun/application-menu/click.ts +18 -0
- package/src/renderers/electrobun/bun/index.ts +3 -2
- package/src/renderers/electrobun/shared/protocol.ts +1 -1
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +29 -2
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +63 -20
- package/src/renderers/electrobun/view/cli-pane-shot-health.ts +10 -26
- package/src/renderers/electrobun/view/main.tsx +5 -3
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +2 -0
- package/src/renderers/opentui/chart-surface.tsx +1 -0
- package/src/renderers/opentui/frame-capture.ts +33 -0
- package/src/renderers/opentui/host.tsx +10 -13
- package/src/renderers/opentui/pane-image/glyphs-license.txt +107 -0
- package/src/renderers/opentui/pane-image/glyphs.json +1 -0
- package/src/renderers/opentui/pane-image/index.ts +107 -0
- package/src/renderers/opentui/pane-image/raster.ts +428 -0
- package/src/renderers/opentui/start.tsx +3 -3
- package/src/renderers/opentui/test-utils.tsx +3 -0
- package/src/renderers/opentui/ui-host.tsx +29 -1
- package/src/series/capability.ts +75 -0
- package/src/series/csv.ts +160 -0
- package/src/series/files.ts +107 -0
- package/src/series/registry.ts +198 -0
- package/src/series/resolve.ts +108 -0
- package/src/series/standalone.ts +48 -0
- package/src/series/types.ts +153 -0
- package/src/series/validate.ts +171 -0
- package/src/shares/chat.ts +34 -0
- package/src/shares/dialog.tsx +295 -0
- package/src/shares/flow.tsx +56 -0
- package/src/shares/live.ts +14 -22
- package/src/shares/pane-image.ts +152 -0
- package/src/shares/personal-pane.ts +64 -0
- package/src/shares/portable-layout.ts +4 -2
- package/src/shares/prepare.ts +20 -0
- package/src/sources/gloomberb-cloud/index.ts +109 -10
- package/src/sources/gloomberb-cloud/normalizers.ts +3 -0
- package/src/sources/gloomberb-cloud/perpetuals.ts +249 -0
- package/src/sources/history-result.ts +1 -0
- package/src/sources/history-retention.ts +11 -0
- package/src/sources/listing-symbols.ts +4 -1
- package/src/sources/listing-target.ts +4 -0
- package/src/sources/provider-router/batches.ts +4 -1
- package/src/sources/provider-router/cache.ts +4 -2
- package/src/sources/provider-router/cached-routes.ts +1 -1
- package/src/sources/provider-router/financial-routes.ts +1 -0
- package/src/sources/provider-router/financials.ts +13 -0
- package/src/sources/provider-router/history.ts +43 -25
- package/src/sources/provider-router/index.ts +14 -0
- package/src/sources/provider-router/search.ts +1 -0
- package/src/state/hooks/inline-tickers.ts +49 -11
- package/src/sync/core-contributors.ts +1 -0
- package/src/test-support/shell-pane-keys.tsx +1 -0
- package/src/theme/theme-context.tsx +15 -1
- package/src/tickers/company-name.ts +75 -0
- package/src/tickers/instrument-kind.ts +34 -1
- package/src/tickers/listing-name.ts +34 -0
- package/src/tickers/listing-venues.ts +132 -0
- package/src/tickers/open-target.ts +13 -4
- package/src/tickers/perpetual-listing.ts +151 -0
- package/src/tickers/prediction-listing.ts +26 -0
- package/src/tickers/search/index.ts +72 -11
- package/src/tickers/search/ranking.ts +98 -20
- package/src/tickers/search/types.ts +7 -1
- package/src/tickers/ticker-changes.ts +213 -0
- package/src/tickers/us-listing.ts +34 -0
- package/src/time-series/economic.ts +2 -6
- package/src/time-series/hooks.ts +9 -0
- package/src/time-series/ice-credit.ts +39 -0
- package/src/time-series/resolve.ts +211 -29
- package/src/time-series/studies.ts +1 -0
- package/src/time-series/types.ts +12 -2
- package/src/time-series/use-chart-resolution.ts +32 -0
- package/src/types/config.ts +10 -2
- package/src/types/data-provider.ts +11 -0
- package/src/types/financials.ts +62 -1
- package/src/types/headless.ts +113 -0
- package/src/types/instrument.ts +4 -0
- package/src/types/plugin.ts +52 -2
- package/src/types/price-history.ts +7 -0
- package/src/types/ticker-changes.ts +26 -0
- package/src/types/ticker.ts +14 -0
- package/src/ui/context-menu.tsx +13 -1
- package/src/ui/host.tsx +57 -3
- package/src/ui/live-resize.ts +91 -0
- package/src/ui/live-stretch.ts +153 -0
- package/src/ui/measured-cells.ts +58 -0
- package/src/ui/sticky-scroll.ts +7 -0
- package/src/utils/basis-points.ts +17 -0
- package/src/utils/central-banks.ts +76 -0
- package/src/utils/cli-output.ts +131 -15
- package/src/utils/concurrency.ts +25 -0
- package/src/utils/crypto-pair.ts +20 -0
- package/src/utils/currency-pair.ts +19 -0
- package/src/utils/currency-units.ts +11 -0
- package/src/utils/datetime-format.ts +27 -6
- package/src/utils/decimal-comma.ts +19 -0
- package/src/utils/dom-screenshot-css.ts +265 -0
- package/src/utils/dom-screenshot-rasters.ts +276 -0
- package/src/utils/dom-screenshot.ts +439 -52
- package/src/utils/double-escape-close.ts +15 -1
- package/src/utils/exchange-rate-snapshot.ts +6 -2
- package/src/utils/exchanges.ts +143 -1
- package/src/utils/format.ts +35 -5
- package/src/utils/forward-dividend.ts +14 -0
- package/src/utils/fundamentals.ts +66 -0
- package/src/utils/futures-generic.ts +6 -12
- package/src/utils/fx-market-hours.ts +15 -5
- package/src/utils/fx-status.ts +6 -1
- package/src/utils/inline-content-tokenizer.ts +22 -3
- package/src/utils/market-capitalization.ts +8 -0
- package/src/utils/one-shot.ts +73 -0
- package/src/utils/options.ts +37 -8
- package/src/utils/price-history.ts +99 -42
- package/src/utils/sec-eps-basis.ts +24 -11
- package/src/utils/sec.ts +61 -7
- package/src/utils/utc-time.ts +63 -4
- package/src/plugins/builtin/fx-matrix/freshness.ts +0 -65
- /package/src/plugins/{builtin/plugin-marketplace → marketplace}/activation.ts +0 -0
- /package/src/plugins/{builtin/plugin-marketplace → marketplace}/ids.ts +0 -0
- /package/src/plugins/{builtin/plugin-marketplace → marketplace}/packs.ts +0 -0
- /package/src/{plugins/builtin/cloud → tickers}/starter-symbols.ts +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { apiClient } from "../../../api-client";
|
|
2
|
-
import type { PerpBoardPayload, PerpBoardQuery, PerpBoardRow, PerpEquityListing, PerpHistoryPayload, PerpHistoryQuery, PerpLongShortPoint,
|
|
3
|
-
PerpRankingsPayload } from "../../../api-client/perps";
|
|
2
|
+
import type { PerpBoardPayload, PerpBoardQuery, PerpBoardRow, PerpEquitiesPayload, PerpEquityListing, PerpHistoryPayload, PerpHistoryQuery, PerpLongShortPoint,
|
|
3
|
+
PerpLongShortRatio, PerpMarketPayload, PerpRankingsPayload } from "../../../api-client/perps";
|
|
4
4
|
import { createPluginCache } from "../../../data/plugin-cache";
|
|
5
5
|
import { cachedCloudResource, loadCloudResource } from "../shared/cloud-resource";
|
|
6
6
|
|
|
@@ -81,15 +81,18 @@ export const loadPerpsRankings = (access: string, force = false) => loadCloudRes
|
|
|
81
81
|
const compareKey = (baseAsset: string, access: string) => `compare:v1:${baseAsset.toUpperCase()}:${access}`;
|
|
82
82
|
export const cachedPerpsCompare = (baseAsset: string, access: string) => cachedCloudResource(perpsCache, compareKey(baseAsset, access), (data) => validatePerpsCompare(data, baseAsset));
|
|
83
83
|
export const loadPerpsCompare = (baseAsset: string, access: string, force = false) => loadCloudResource(perpsCache, compareKey(baseAsset, access), () => fetchPerpsCompare(baseAsset), { force, validate: (data) => validatePerpsCompare(data, baseAsset) });
|
|
84
|
+
const sameListing = (value: PerpEquityListing | null | undefined, listing: PerpEquityListing) =>
|
|
85
|
+
value?.symbol === listing.symbol && value.exchange === listing.exchange;
|
|
86
|
+
/** The server's proof that a stock contract belongs to the listing asked about. */
|
|
87
|
+
const provesListing = (row: PerpBoardRow, listing: PerpEquityListing) => {
|
|
88
|
+
const match = row.equityMatch;
|
|
89
|
+
return sameListing(match?.listing, listing) && row.assetClass === "stocks" && !!match?.underlying.exchange
|
|
90
|
+
&& match.underlying.symbol === row.underlyingSymbol
|
|
91
|
+
&& (match.basis === "issuer" || match.basis === "listing" && sameListing(match.underlying, listing));
|
|
92
|
+
};
|
|
84
93
|
function validatePerpsEquity(data: PerpBoardPayload, listing: PerpEquityListing): PerpBoardPayload {
|
|
85
94
|
validatePerpsBoard(data);
|
|
86
|
-
|
|
87
|
-
if (!same(data.listing) || !data.rows.every((row) => {
|
|
88
|
-
const match = row.equityMatch;
|
|
89
|
-
return same(match?.listing) && row.assetClass === "stocks" && !!match?.underlying.exchange
|
|
90
|
-
&& match.underlying.symbol === row.underlyingSymbol
|
|
91
|
-
&& (match.basis === "issuer" || match.basis === "listing" && same(match.underlying));
|
|
92
|
-
})) throw new Error("The server returned perpetuals for another listing");
|
|
95
|
+
if (!sameListing(data.listing, listing) || !data.rows.every((row) => provesListing(row, listing))) throw new Error("The server returned perpetuals for another listing");
|
|
93
96
|
return data;
|
|
94
97
|
}
|
|
95
98
|
export const loadPerpsEquity = (listing: PerpEquityListing, access: string, force = false) => {
|
|
@@ -98,6 +101,38 @@ export const loadPerpsEquity = (listing: PerpEquityListing, access: string, forc
|
|
|
98
101
|
async () => validate(await apiClient.getCloudPerpsEquity(listing.symbol, listing.exchange)), { force, validate });
|
|
99
102
|
};
|
|
100
103
|
|
|
104
|
+
/** The most listings the server looks up in one request; a longer list asks in pages of this size. */
|
|
105
|
+
const PERP_EQUITIES_PAGE = 100;
|
|
106
|
+
export const perpsListCache = createPluginCache<PerpEquitiesPayload>({ kind: "perps-equities", source: "gloom-cloud", schemaVersion: 1,
|
|
107
|
+
policy: { staleMs: 60_000, expireMs: 86_400_000 } });
|
|
108
|
+
/** One answer per listing asked about, in its order; a contract only with its proof for that listing. */
|
|
109
|
+
export function validatePerpsEquities(data: PerpEquitiesPayload, listings: readonly PerpEquityListing[]): PerpEquitiesPayload {
|
|
110
|
+
if (!envelope(data) || !Array.isArray(data.results) || data.results.length !== listings.length
|
|
111
|
+
|| !data.results.every((result, index) => !!result && (result.market === null
|
|
112
|
+
|| sameListing(result.listing, listings[index]!) && validRow(result.market) && provesListing(result.market, listings[index]!))))
|
|
113
|
+
throw new Error("The server returned perpetuals for another listing");
|
|
114
|
+
return data;
|
|
115
|
+
}
|
|
116
|
+
async function fetchPerpsEquities(listings: readonly PerpEquityListing[], client: Pick<typeof apiClient, "getCloudPerpsEquities"> = apiClient): Promise<PerpEquitiesPayload> {
|
|
117
|
+
const pages: PerpEquityListing[][] = [];
|
|
118
|
+
for (let start = 0; start < listings.length; start += PERP_EQUITIES_PAGE) pages.push(listings.slice(start, start + PERP_EQUITIES_PAGE));
|
|
119
|
+
const answers = await Promise.all(pages.map(async (page) => validatePerpsEquities(await client.getCloudPerpsEquities(page), page)));
|
|
120
|
+
const [first] = answers;
|
|
121
|
+
if (!first) return { status: "ok", asOf: null, access: "preview", locked: 0, results: [] };
|
|
122
|
+
return { ...first, locked: answers.reduce((sum, answer) => sum + answer.locked, 0), results: answers.flatMap((answer) => answer.results) };
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* The perpetual of every listing in a watchlist or portfolio, from one request (one per hundred listings): the
|
|
126
|
+
* rows share one lookup instead of asking for each stock. `listings` come sorted and unique, so a list keeps its
|
|
127
|
+
* cache entry whatever its order; cached per account and plan like the other perps loaders, and a failed refresh
|
|
128
|
+
* keeps the last answer, marked stale.
|
|
129
|
+
*/
|
|
130
|
+
export const loadPerpsEquities = (listings: readonly PerpEquityListing[], access: string, force = false) => {
|
|
131
|
+
const validate = (data: PerpEquitiesPayload) => validatePerpsEquities(data, listings);
|
|
132
|
+
return loadCloudResource(perpsListCache, `equities:v1:${listings.map((listing) => `${listing.symbol}:${listing.exchange}`).join(",")}:${access}`,
|
|
133
|
+
() => fetchPerpsEquities(listings), { force, validate });
|
|
134
|
+
};
|
|
135
|
+
|
|
101
136
|
function validatePerpsMarket(data: PerpMarketPayload): PerpMarketPayload {
|
|
102
137
|
validatePerpsBoard(data);
|
|
103
138
|
if (!Array.isArray(data.evidence) || !data.evidence.every((row) => date(row.period_at) && date(row.received_at) && typeof row.fingerprint === "string" && (row.superseded_at === null || date(row.superseded_at)))) throw new Error("The server returned unreadable market evidence");
|
|
@@ -105,16 +140,55 @@ function validatePerpsMarket(data: PerpMarketPayload): PerpMarketPayload {
|
|
|
105
140
|
}
|
|
106
141
|
const fetchPerpsMarket = async (marketId: string, client: Pick<typeof apiClient, "getCloudPerpsMarket"> = apiClient) => validatePerpsMarket(await client.getCloudPerpsMarket(marketId));
|
|
107
142
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
143
|
+
/**
|
|
144
|
+
* The Market column's label for a market on a Hyperliquid builder dex (`SP500 · XYZ`) read back as the `xyz:SP500`
|
|
145
|
+
* identity the board search and the venue know it by; anything else is returned as typed.
|
|
146
|
+
*/
|
|
147
|
+
export const marketQuery = (input: string) => {
|
|
148
|
+
const label = /^([^\s·]+)\s*·\s*([^\s·]+)$/.exec(input.trim());
|
|
149
|
+
return label ? `${label[2]!.toLowerCase()}:${label[1]}` : input.trim();
|
|
150
|
+
};
|
|
151
|
+
// An identity or symbol, never free text: a market id the server rejects as malformed would surface as raw JSON.
|
|
152
|
+
const SAFE_MARKET_ID = /^[\w.:-]+$/;
|
|
153
|
+
// A venue's usual contract for a base asset, by the identity a market lookup fetches without the board (the free
|
|
154
|
+
// board preview lists a few markets per asset class, an individual market is shown whole). Only the venues
|
|
155
|
+
// Gloom Cloud collects are listed; another venue has no contract to open.
|
|
156
|
+
const VENUE_CONTRACTS: Record<string, (base: string) => string[]> = {
|
|
157
|
+
hyperliquid: (base) => [`hyperliquid:default:${base}`, `hyperliquid:xyz:${base}`],
|
|
158
|
+
binance: (base) => [`binance:${base}USDT`],
|
|
159
|
+
bybit: (base) => [`bybit:${base}USDT`],
|
|
160
|
+
okx: (base) => [`okx:${base}-USDT-SWAP`, `okx:${base}-USD-SWAP`],
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* One market by base asset, underlying, symbol, canonical identity or the Market column's label (`SP500 · XYZ`).
|
|
164
|
+
* A `venue` opens that venue's contract, from the board's matches or by its own identity; when the venue has none
|
|
165
|
+
* the usual market comes back and the caller sees its venue differ.
|
|
166
|
+
*/
|
|
167
|
+
export async function fetchPerpSelection(input: string, client: Pick<typeof apiClient, "getCloudPerpsBoard" | "getCloudPerpsMarket"> = apiClient, venue?: string): Promise<PerpMarketPayload> {
|
|
168
|
+
const query = marketQuery(input) || "BTC";
|
|
169
|
+
if (/^(hyperliquid|binance|bybit|okx|deribit|coinbase|kraken|dydx):/.test(query)) {
|
|
170
|
+
const result = await fetchPerpsMarket(query, client);
|
|
171
|
+
// A watchlist row is saved upper case; Hyperliquid writes its thousand-unit coins with a small k (kPEPE).
|
|
172
|
+
const kCoin = /^hyperliquid:default:K([A-Z0-9]+)$/.exec(query);
|
|
173
|
+
return result.rows.length || !kCoin ? result : fetchPerpsMarket(`hyperliquid:default:k${kCoin[1]}`, client);
|
|
174
|
+
}
|
|
111
175
|
const board = validatePerpsBoard(await client.getCloudPerpsBoard({ search: query }));
|
|
112
|
-
const
|
|
176
|
+
const matches = board.rows.filter((row) => !row.delisted && [row.baseAsset, row.symbol, row.underlyingSymbol].some((value) => value?.toUpperCase() === query.toUpperCase()));
|
|
177
|
+
const exact = venue && matches.some((row) => row.venue === venue) ? matches.filter((row) => row.venue === venue) : matches;
|
|
113
178
|
const market = exact.find((row) => row.dex === "default") ?? exact.find((row) => row.dex === "xyz") ?? exact[0];
|
|
179
|
+
if (venue && market?.venue !== venue && /^[A-Za-z0-9]+$/.test(query)) {
|
|
180
|
+
for (const id of VENUE_CONTRACTS[venue]?.(matches[0]?.baseAsset ?? query.toUpperCase()) ?? []) {
|
|
181
|
+
const result = await fetchPerpsMarket(id, client);
|
|
182
|
+
if (result.rows.length) return result;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
114
185
|
if (market) return fetchPerpsMarket(market.marketId, client);
|
|
115
|
-
// Individual latest-value previews are intentionally broader than the fixed board preview.
|
|
116
|
-
|
|
117
|
-
|
|
186
|
+
// Individual latest-value previews are intentionally broader than the fixed board preview. A builder dex's own
|
|
187
|
+
// identity (`xyz:SP500`) names its Hyperliquid market; a bare symbol is tried on the default dex, then xyz.
|
|
188
|
+
const builder = /^([a-z0-9]+):(.+)$/i.exec(query);
|
|
189
|
+
for (const id of builder ? [`hyperliquid:${builder[1]!.toLowerCase()}:${builder[2]}`] : ["default", "xyz"].map((dex) => `hyperliquid:${dex}:${query.toUpperCase()}`)) {
|
|
190
|
+
if (!SAFE_MARKET_ID.test(id)) continue;
|
|
191
|
+
const result = await fetchPerpsMarket(id, client);
|
|
118
192
|
if (result.rows.length) return result;
|
|
119
193
|
}
|
|
120
194
|
return { ...board, rows: [], evidence: [], methodologyUrl: "https://gloom.sh/docs/perpetuals" };
|
|
@@ -1,33 +1,68 @@
|
|
|
1
1
|
import { useCallback } from "react";
|
|
2
2
|
import { isAccessDenied } from "../../../api-client/errors";
|
|
3
3
|
import { usePlanAccess } from "../../../api-client/plan-access";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import type { PerpBoardRow } from "../../../api-client/perps";
|
|
5
|
+
import { ActionRow, usePaneLinkMenuEntry } from "../../../components";
|
|
6
|
+
import { displayWidth } from "../../../utils/format";
|
|
7
|
+
import { useAsyncResource, useAutoRefresh } from "../../../public/react";
|
|
6
8
|
import { useResearchCloudSession } from "../shared/research-cloud-session";
|
|
7
9
|
import { perpEquityIdentity } from "./equity-identity";
|
|
8
|
-
import {
|
|
10
|
+
import { perpetualListing } from "../../../tickers/perpetual-listing";
|
|
11
|
+
import { loadPerpSelection, loadPerpsEquity } from "./client";
|
|
9
12
|
import { compact, percent, perpDescription, price, readingTime } from "./model";
|
|
13
|
+
import { openPerpLabel, useOpenPerpMarket } from "./open-market";
|
|
10
14
|
|
|
11
|
-
/**
|
|
12
|
-
|
|
15
|
+
/**
|
|
16
|
+
* A stock's perpetuals, or for a perpetual market itself its own contract: funding, open interest and when the venue
|
|
17
|
+
* was read, beside the quote. A failed optional market comparison never blocks a stock's quote.
|
|
18
|
+
*/
|
|
19
|
+
export function PerpEquityRow({ symbol, exchange, instrumentType, maxRows = 3, width }: {
|
|
20
|
+
symbol: string; exchange?: string; instrumentType?: string; maxRows?: number;
|
|
21
|
+
/** Columns the row has, in a narrow card: the contract gets its short name and the least read figures go first. */
|
|
22
|
+
width?: number;
|
|
23
|
+
}) {
|
|
13
24
|
const session = useResearchCloudSession();
|
|
14
25
|
const plan = usePlanAccess();
|
|
15
|
-
const
|
|
16
|
-
const identity = perpEquityIdentity(symbol, exchange);
|
|
26
|
+
const marketId = perpetualListing(symbol, exchange)?.marketId ?? null;
|
|
27
|
+
const identity = marketId ? null : perpEquityIdentity(symbol, exchange);
|
|
17
28
|
const listingSymbol = identity?.symbol;
|
|
18
29
|
const listingExchange = identity?.exchange;
|
|
19
|
-
const enabled = !!identity && ["STK", "EQUITY", "STOCK", "COMMON STOCK"].includes(instrumentType?.toUpperCase() ?? "");
|
|
30
|
+
const enabled = !!marketId || !!identity && ["STK", "EQUITY", "STOCK", "COMMON STOCK"].includes(instrumentType?.toUpperCase() ?? "");
|
|
20
31
|
const accessKey = `${session.requestKey}:${plan.hasProAccess ? "pro" : "preview"}`;
|
|
21
|
-
const loader = useCallback((force: boolean) =>
|
|
32
|
+
const loader = useCallback((force: boolean) => marketId
|
|
33
|
+
? loadPerpSelection(marketId, accessKey, force)
|
|
34
|
+
: loadPerpsEquity({ symbol: listingSymbol!, exchange: listingExchange! }, accessKey, force), [marketId, listingSymbol, listingExchange, accessKey]);
|
|
22
35
|
const resource = useAsyncResource(enabled ? loader : null, { clearOnError: isAccessDenied });
|
|
23
36
|
useAutoRefresh(resource.updatedAt, resource.load, { intervalMs: 60_000 });
|
|
24
|
-
const rows = resource.data?.payload.rows.filter((row) => !row.delisted) ?? [];
|
|
37
|
+
const rows = resource.data?.payload.rows.filter((row) => !row.delisted && (!marketId || row.marketId === marketId)) ?? [];
|
|
25
38
|
if (!enabled || !rows.length) return null;
|
|
26
|
-
return <>{rows.slice(0, maxRows).map((row) => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
39
|
+
return <>{rows.slice(0, maxRows).map((row) => <PerpRow key={row.marketId} row={row} stale={!!resource.data?.stale} width={width} own={!!marketId} />)}</>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** The parts that fit `width`, dropped from the end; all of them when the width is not known. */
|
|
43
|
+
function fitParts(parts: string[], separator: string, width: number | undefined): string {
|
|
44
|
+
let kept = parts;
|
|
45
|
+
while (width !== undefined && kept.length > 1 && displayWidth(kept.join(separator)) > width) kept = kept.slice(0, -1);
|
|
46
|
+
return kept.join(separator);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* One contract on the stock, or the market the quote is of (`own`, whose mark the quote already shows): a click, or
|
|
51
|
+
* its entry in the pane menu, opens PERP on that market.
|
|
52
|
+
*/
|
|
53
|
+
function PerpRow({ row, stale, width, own = false }: { row: PerpBoardRow; stale: boolean; width?: number; own?: boolean }) {
|
|
54
|
+
const openMarket = useOpenPerpMarket();
|
|
55
|
+
const open = () => openMarket(row.marketId);
|
|
56
|
+
usePaneLinkMenuEntry(`function:perps-pane:${row.marketId}`, openPerpLabel(row), open);
|
|
57
|
+
const read = readingTime(row.observedAt);
|
|
58
|
+
const staleText = row.stale || stale ? " · stale" : "";
|
|
59
|
+
const figures = own
|
|
60
|
+
? row.underlyingPremium != null ? [`${percent(row.underlyingPremium, 2)} vs ${row.underlyingSymbol ?? "underlying"} last${staleText}`] : staleText ? ["stale"] : []
|
|
61
|
+
: [`${price(row.markPrice)} ${row.quoteCurrency}`, `${percent(row.underlyingPremium, 2)} vs last${staleText}`];
|
|
62
|
+
const named = [`${row.baseAsset} · ${perpDescription(row)}`, ...figures].join(" ");
|
|
63
|
+
const first = width === undefined || displayWidth(named) <= width ? named : [`${row.baseAsset} perpetual`, ...figures].join(" ");
|
|
64
|
+
// Funding reads per 8h here as it does in PERP, whatever interval the venue pays on.
|
|
65
|
+
const second = fitParts([`Funding ${percent(row.fundingRate8h, 4)} per 8 h`, `OI ${compact(row.openInterestUsd)} USD`, `oracle ${percent(row.premium, 2)}`,
|
|
66
|
+
...(read ? [`as of ${read}`] : [])], " · ", width);
|
|
67
|
+
return <ActionRow height={2} label={`${first}\n${second}`} onPress={open} />;
|
|
33
68
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { PerpBoardRow } from "../../../api-client/perps";
|
|
2
|
+
import type { HeadlessPaneFreshness } from "../../../types/headless";
|
|
3
|
+
import { venueName, venuesOf } from "./model";
|
|
4
|
+
|
|
5
|
+
type Dated = Pick<PerpBoardRow, "venue" | "observedAt">;
|
|
6
|
+
type Funded = Pick<PerpBoardRow, "venue" | "fundingRate" | "fundingRate8h" | "fundingKind" | "nextFundingAt">;
|
|
7
|
+
|
|
8
|
+
const WEEKDAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] as const;
|
|
9
|
+
const KINDS: Array<[PerpBoardRow["fundingKind"], string]> = [["current", "current estimate"], ["last-paid", "last paid"], ["continuous", "accrues continuously"]];
|
|
10
|
+
|
|
11
|
+
/** `08:00` on the UTC day of `now`, else with its weekday: `Mon 00:00`. */
|
|
12
|
+
function payTime(at: number, now: number): string {
|
|
13
|
+
const iso = new Date(at).toISOString();
|
|
14
|
+
return iso.slice(0, 10) === new Date(now).toISOString().slice(0, 10) ? iso.slice(11, 16) : `${WEEKDAYS[new Date(at).getUTCDay()]} ${iso.slice(11, 16)}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* When current estimates pay: the next funding time when every contract shown pays then, else each time with the
|
|
19
|
+
* venues that report it (`08:00 UTC (Binance, Bybit)`). A venue that reports no next time is not given one.
|
|
20
|
+
*/
|
|
21
|
+
function paysText(rows: readonly Funded[], now: number): string | null {
|
|
22
|
+
const venuesAt = new Map<number, Funded[]>();
|
|
23
|
+
let unknown = false;
|
|
24
|
+
for (const row of rows) {
|
|
25
|
+
const at = row.nextFundingAt ? Date.parse(row.nextFundingAt) : Number.NaN;
|
|
26
|
+
if (!Number.isFinite(at) || at < now) unknown = true;
|
|
27
|
+
else venuesAt.set(at, [...venuesAt.get(at) ?? [], row]);
|
|
28
|
+
}
|
|
29
|
+
const times = [...venuesAt].sort(([a], [b]) => a - b);
|
|
30
|
+
if (!times.length) return null;
|
|
31
|
+
if (times.length === 1 && !unknown) return `${payTime(times[0]![0], now)} UTC`;
|
|
32
|
+
return times.map(([at, group]) => `${payTime(at, now)} UTC (${venuesOf(group).map(venueName).join(", ")})`).join(", ");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* What a view's funding figures are, so a reader does not take a venue's current estimate for a settled rate:
|
|
37
|
+
* `funding = current estimate, pays 08:00 UTC`. With several bases each names its venues. Null when no row shows funding.
|
|
38
|
+
*/
|
|
39
|
+
export function fundingNote(rows: readonly Funded[], now = Date.now()): string | null {
|
|
40
|
+
const funded = rows.filter((row) => row.fundingRate != null || row.fundingRate8h != null);
|
|
41
|
+
const kinds = KINDS.filter(([kind]) => funded.some((row) => row.fundingKind === kind));
|
|
42
|
+
if (!kinds.length) return null;
|
|
43
|
+
return `funding = ${kinds.map(([kind, text]) => {
|
|
44
|
+
const group = funded.filter((row) => row.fundingKind === kind);
|
|
45
|
+
const pays = kind === "current" ? paysText(group, now) : null;
|
|
46
|
+
return `${text}${kinds.length > 1 ? ` (${venuesOf(group).map(venueName).join(", ")})` : ""}${pays ? `, pays ${pays}` : ""}`;
|
|
47
|
+
}).join("; ")}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* How current a view of perpetual markets is: each venue's own newest observation, polled rather than streamed and
|
|
52
|
+
* stale after an hour without a poll, and what the funding figures it shows (`funding`) are. The report, the capture
|
|
53
|
+
* and the pane footer all read this, so they end with the same line.
|
|
54
|
+
*/
|
|
55
|
+
export function perpFreshness(rows: readonly Dated[], { funding = [], venue = "all", now = Date.now() }: {
|
|
56
|
+
funding?: readonly Funded[]; venue?: string; now?: number;
|
|
57
|
+
} = {}): HeadlessPaneFreshness {
|
|
58
|
+
const sources = venuesOf(rows).map((id) => ({ source: venueName(id), asOf: new Date(Math.max(...rows.filter((row) => row.venue === id)
|
|
59
|
+
.map((row) => Date.parse(row.observedAt)))).toISOString() }));
|
|
60
|
+
const source = sources.length ? sources.map((entry) => entry.source).join(", ") : venue !== "all" ? venueName(venue) : null;
|
|
61
|
+
const note = fundingNote(funding, now);
|
|
62
|
+
return { ...(source ? { source } : {}), sources, status: "delayed", maxAgeMinutes: 60, ...(note ? { note } : {}) };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** What a capture reads of a row: when it was observed and whether the venue has stopped answering for it. */
|
|
66
|
+
export const perpObservation = (row: Pick<PerpBoardRow, "observedAt" | "stale">) => ({ observedAt: row.observedAt, stale: row.stale });
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { PerpBoardPayload, PerpBoardRow } from "../../../api-client/perps";
|
|
2
2
|
import type { HeadlessBundleSection, HeadlessPaneColumn, HeadlessPaneLoadArgs, HeadlessPaneRow } from "../../../types/headless";
|
|
3
3
|
import type { HeadlessPaneDefinition } from "../../../types/plugin";
|
|
4
|
-
import { fetchPerpSelection, fetchPerpsBoard, fetchPerpsCompare, fetchPerpsHistory, fetchPerpsRankings } from "./client";
|
|
4
|
+
import { fetchPerpSelection, fetchPerpsBoard, fetchPerpsCompare, fetchPerpsHistory, fetchPerpsRankings, marketQuery } from "./client";
|
|
5
|
+
import { perpFreshness } from "./freshness";
|
|
5
6
|
import { ASSET_FILTERS, BOARD_COLUMNS, BOARD_SORTS, COMPARE_COLUMNS, compact, fundingSpread, HISTORY_METRICS, label, openingTab, PERP_TABS, perpCellText, perpColumnLabel, percent,
|
|
6
|
-
positioningFields, price, RANKING_COLUMNS, rankingRows, RANKINGS, ratioText, share, time, VENUES,
|
|
7
|
+
positioningFields, price, RANKING_COLUMNS, rankingRows, RANKINGS, ratioText, share, time, VENUES, venueName, type PerpColumnId } from "./model";
|
|
7
8
|
|
|
8
9
|
// Text columns only: the text report shows these, JSON keeps every field of every row. Rates, premiums and
|
|
9
10
|
// changes stay fractions in the rows; `percent` multiplies by 100 so the text agrees with the desktop pane.
|
|
@@ -68,9 +69,10 @@ const REVISION_COLUMNS: HeadlessPaneColumn[] = [
|
|
|
68
69
|
{ key: "fingerprint", header: "Fingerprint", format: (value) => text(value)?.slice(0, 8) || "--" },
|
|
69
70
|
];
|
|
70
71
|
|
|
71
|
-
// With no market the report shows the first; a market nothing matches names
|
|
72
|
+
// With no market the report shows the first; a market nothing matches names ones that work, a builder dex's among them.
|
|
72
73
|
const EXAMPLE_MARKETS = ["BTC", "ETH", "SOL"] as const;
|
|
73
74
|
const DEFAULT_MARKET = EXAMPLE_MARKETS[0];
|
|
75
|
+
const noMarket = (input: string) => new Error(`No perpetual market matches "${input}". Try BTC, ETH, SP500, xyz:SP500.`);
|
|
74
76
|
|
|
75
77
|
const requestedOf = (args: HeadlessPaneLoadArgs) => String(Array.isArray(args.argument) ? args.argument.join(" ") : args.argument ?? "").trim();
|
|
76
78
|
// No tab named: a market opens its history, nothing opens the board, as the pane does.
|
|
@@ -79,81 +81,94 @@ const TITLES: Record<typeof PERP_TABS[number], string> = { board: "Perpetual mar
|
|
|
79
81
|
history: "Perpetual history (Pro)", evidence: "Perpetual evidence (Pro)" };
|
|
80
82
|
const copy = (rows: readonly PerpBoardRow[]) => rows.map((row) => ({ ...row }));
|
|
81
83
|
const more = (count: number, noun: string) => `${count.toLocaleString("en-US")} more ${noun} need Gloom Pro`;
|
|
82
|
-
//
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
// What a table the free view leaves empty says in place of "No data."; the report's Pro lines say what Pro adds.
|
|
85
|
+
const lockedEmpty = (locked: unknown) => locked ? { empty: "Locked: Gloom Pro" } : {};
|
|
86
|
+
// A venue filter the report cannot honour is said, not ignored.
|
|
87
|
+
const venueNotice = (venue: string, selected: PerpBoardRow, requested: string, access: string) => {
|
|
88
|
+
if (venue === "all" || selected.venue === venue) return [];
|
|
89
|
+
const [wanted, shown] = [venueName(venue), venueName(selected.venue)];
|
|
90
|
+
return [VENUES.some((id) => requested.startsWith(`${id}:`)) ? `${requested} is a ${shown} market, so the ${wanted} filter does not apply.`
|
|
91
|
+
: `${wanted} has no ${selected.baseAsset} contract${access === "pro" ? "" : " in the free preview"}; showing ${shown}.`];
|
|
86
92
|
};
|
|
93
|
+
const venueUnused = (venue: string, tab: string) => venue === "all" ? [] : [`The ${venueName(venue)} filter applies to the board, not ${tab}; showing every venue.`];
|
|
87
94
|
const listMetadata = (data: Pick<PerpBoardPayload, "asOf" | "access" | "status"> & { locked: number | boolean }) => ({ asOf: data.asOf, access: data.access, locked: data.locked, status: data.status, rates: "fraction", oiCurrency: "USD" });
|
|
88
95
|
|
|
89
96
|
export const perpsHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
90
97
|
shape: "bundle", argument: { kind: "free-text", optional: true, placeholder: "market",
|
|
91
|
-
description: "A base asset, underlying
|
|
98
|
+
description: "A base asset, underlying, canonical market identity or Market column label, such as BTC, hyperliquid:xyz:TSLA or SP500 · XYZ. Opens its history; with --tab board it searches the board, with --tab compare it is the base asset. Without one, the board." },
|
|
92
99
|
options: [
|
|
93
100
|
{ key: "tab", type: "enum", settingKey: "tab", values: PERP_TABS.map((value) => ({ value })), description: "Board, rankings, compare, history or evidence. Board without a market, history with one." },
|
|
94
101
|
{ key: "asset-class", type: "enum", settingKey: "assetClass", values: ASSET_FILTERS.map((value) => ({ value })), defaultValue: "all", description: "Board asset class." },
|
|
95
|
-
{ key: "venue", type: "enum", settingKey: "venue", values: ["all", ...VENUES].map((value) => ({ value })), defaultValue: "all", description: "Board venue." },
|
|
102
|
+
{ key: "venue", type: "enum", settingKey: "venue", values: ["all", ...VENUES].map((value) => ({ value })), defaultValue: "all", description: "Board venue; with a market, opens that venue's contract when the board lists it." },
|
|
96
103
|
{ key: "sort", type: "enum", settingKey: "sort", values: BOARD_SORTS.map((value) => ({ value })), defaultValue: "oi", description: "Board order: open interest, funding, open-interest change, premium or long share of accounts." },
|
|
97
104
|
{ key: "days", type: "enum", settingKey: "days", values: ["1", "7", "30", "90", "365"].map((value) => ({ value })), defaultValue: "7", description: "History lookback in days." },
|
|
98
105
|
{ key: "metric", type: "enum", settingKey: "metric", values: HISTORY_METRICS.map((value) => ({ value })), defaultValue: "funding", description: "Displayed history chart; JSON retains every series." },
|
|
99
106
|
],
|
|
100
|
-
discovery: { aliases: ["PERP"], dataRequirements: ["Perpetual market observations"], limitations: ["Free accounts see a fixed preview of the board, rankings and comparisons, and latest values for one market", "Pro unlocks every market, full rankings and history", "Rankings list up to ten markets each", "Rates, premiums and changes are fractions in JSON", "Open-interest history begins at first collection", "Funding APR is a simple annualization, not a forecast",
|
|
101
|
-
"Long/short account shares: venue definitions differ; history begins at first collection"] },
|
|
107
|
+
discovery: { aliases: ["PERP"], dataRequirements: ["Perpetual market observations"], limitations: ["Free accounts see a fixed preview of the board, rankings and comparisons, and latest values for one market.", "Pro unlocks every market, full rankings and history.", "Rankings list up to ten markets each.", "Rates, premiums and changes are fractions in JSON.", "Open-interest history begins at first collection.", "Funding APR is a simple annualization, not a forecast.",
|
|
108
|
+
"Long/short account shares: venue definitions differ; history begins at first collection."] },
|
|
102
109
|
describe: (args) => TITLES[tabOf(args)],
|
|
103
110
|
async load(args, ctx) {
|
|
104
111
|
const requested = requestedOf(args);
|
|
105
112
|
const tab = tabOf(args);
|
|
106
113
|
if (tab === "board") {
|
|
107
114
|
const assetClass = String(args.options["asset-class"] ?? "all"), venue = String(args.options.venue ?? "all"), sort = String(args.options.sort ?? "oi");
|
|
108
|
-
const board = await fetchPerpsBoard({ ...(assetClass !== "all" ? { assetClass } : {}), ...(requested ? { search: requested } : {}), sort }, ctx.apiClient);
|
|
115
|
+
const board = await fetchPerpsBoard({ ...(assetClass !== "all" ? { assetClass } : {}), ...(requested ? { search: marketQuery(requested) } : {}), sort }, ctx.apiClient);
|
|
109
116
|
const rows = venue === "all" ? board.rows : board.rows.filter((row) => row.venue === venue);
|
|
110
|
-
|
|
111
|
-
|
|
117
|
+
// The server counts what the free view hides across every venue; a venue's own share of it is not known, so a venue filter names no count.
|
|
118
|
+
const lock = venue === "all" ? more(board.locked, "markets") : `${venueName(venue)} markets beyond the free preview need Gloom Pro`;
|
|
119
|
+
return { sections: [{ title: "Markets", columns: BOARD_TEXT_COLUMNS, rows: copy(rows), ...lockedEmpty(board.locked && !rows.length) }], complete: !board.locked && board.status === "ok",
|
|
120
|
+
errors: board.locked ? [lock] : [], freshness: perpFreshness(rows, { funding: rows, venue }),
|
|
112
121
|
metadata: { ...listMetadata(board), total: board.total, assetClass, venue, sort, ...(requested ? { search: requested } : {}) } };
|
|
113
122
|
}
|
|
114
123
|
if (tab === "rankings") {
|
|
115
124
|
const rankings = await fetchPerpsRankings(ctx.apiClient);
|
|
116
|
-
const sections: HeadlessBundleSection[] = RANKINGS.map((ranking) => ({ title: ranking.label, columns: rankingTextColumns(ranking), rows: copy(rankingRows(rankings, ranking.key)) }));
|
|
125
|
+
const sections: HeadlessBundleSection[] = RANKINGS.map((ranking) => ({ title: ranking.label, columns: rankingTextColumns(ranking), rows: copy(rankingRows(rankings, ranking.key)), ...lockedEmpty(rankings.locked) }));
|
|
126
|
+
const notices = venueUnused(String(args.options.venue ?? "all"), "rankings");
|
|
127
|
+
// Only the funding lists show funding.
|
|
128
|
+
const funding = RANKINGS.filter((ranking) => ranking.field === "fundingRate8h").flatMap((ranking) => rankingRows(rankings, ranking.key));
|
|
117
129
|
return { sections, complete: !rankings.locked && rankings.status === "ok", errors: rankings.locked ? ["Full rankings need Gloom Pro"] : [],
|
|
118
|
-
freshness:
|
|
130
|
+
freshness: perpFreshness(RANKINGS.flatMap((ranking) => rankingRows(rankings, ranking.key)), { funding }), metadata: { ...(notices.length ? { notices } : {}), ...listMetadata(rankings) } };
|
|
119
131
|
}
|
|
120
132
|
if (tab === "compare") {
|
|
121
133
|
// A canonical identity names one contract; its base asset is what the venues share.
|
|
122
|
-
const
|
|
134
|
+
const identity = marketQuery(requested);
|
|
135
|
+
const base = identity.includes(":") ? (await fetchPerpSelection(identity, ctx.apiClient)).rows[0]?.baseAsset ?? identity : (requested || DEFAULT_MARKET).toUpperCase();
|
|
123
136
|
const compare = await fetchPerpsCompare(base, ctx.apiClient);
|
|
124
|
-
if (!compare.rows.length && !compare.locked) throw
|
|
137
|
+
if (!compare.rows.length && !compare.locked) throw noMarket(requested || base);
|
|
125
138
|
const spread = fundingSpread(compare.rows);
|
|
126
|
-
|
|
139
|
+
const notices = [...(requested ? [] : [`Showing ${DEFAULT_MARKET}. Try fn PERP ${EXAMPLE_MARKETS[1]} --tab compare.`]), ...venueUnused(String(args.options.venue ?? "all"), "compare")];
|
|
140
|
+
return { sections: [{ title: "Contracts", columns: COMPARE_TEXT_COLUMNS, rows: copy(compare.rows), ...lockedEmpty(compare.locked) },
|
|
127
141
|
...(spread ? [{ title: "Funding spread", entries: [{ key: "fundingSpread8h", label: "Funding spread 8h", value: spread.value, formatted: `${spread.text} ${spread.detail}` }] }] : [])],
|
|
128
142
|
complete: !compare.locked && compare.status === "ok", errors: compare.locked ? [more(compare.locked, compare.locked === 1 ? "contract" : "contracts")] : [],
|
|
129
|
-
freshness:
|
|
130
|
-
metadata: { ...(requested ? {} : { defaultArgument: DEFAULT_MARKET, notices
|
|
143
|
+
freshness: perpFreshness(compare.rows, { funding: compare.rows }),
|
|
144
|
+
metadata: { ...(requested ? {} : { defaultArgument: DEFAULT_MARKET }), ...(notices.length ? { notices } : {}),
|
|
131
145
|
...listMetadata(compare), total: compare.total, baseAsset: base,
|
|
132
146
|
...(spread ? { fundingSpread8h: spread.value, fundingSpreadHigh: spread.high.marketId, fundingSpreadLow: spread.low.marketId } : {}) } };
|
|
133
147
|
}
|
|
134
|
-
const search = requested || DEFAULT_MARKET;
|
|
135
|
-
const market = await fetchPerpSelection(search, ctx.apiClient);
|
|
148
|
+
const search = requested || DEFAULT_MARKET, venue = String(args.options.venue ?? "all");
|
|
149
|
+
const market = await fetchPerpSelection(search, ctx.apiClient, venue !== "all" ? venue : undefined);
|
|
136
150
|
const selected = market.rows[0];
|
|
137
|
-
if (!selected) throw
|
|
138
|
-
const
|
|
139
|
-
const metadata = { ...
|
|
151
|
+
if (!selected) throw noMarket(search);
|
|
152
|
+
const notices = [...(requested ? [] : [`Showing ${DEFAULT_MARKET}. Try fn PERP ${EXAMPLE_MARKETS[1]}.`]), ...venueNotice(venue, selected, requested, market.access)];
|
|
153
|
+
const metadata = { ...(requested ? {} : { defaultArgument: DEFAULT_MARKET }), ...(notices.length ? { notices } : {}), marketId: selected.marketId, sourceUrl: selected.sourceUrl, observedAt: selected.observedAt, sourceAsOf: selected.sourceAsOf,
|
|
140
154
|
rates: "fraction", quoteCurrency: selected.quoteCurrency, oiCurrency: "USD", fundingIntervalHours: selected.fundingIntervalHours };
|
|
141
|
-
// The venue's market
|
|
142
|
-
const freshness =
|
|
155
|
+
// The venue's market as last polled, with the funding its latest row shows.
|
|
156
|
+
const freshness = perpFreshness([selected], { funding: [selected] });
|
|
143
157
|
// The same Positioning lines the pane's Evidence shows; JSON keeps the raw reading on the market row.
|
|
144
158
|
const positioning = positioningFields(selected);
|
|
145
159
|
if (tab === "evidence") return {
|
|
146
160
|
sections: [{ title: "Market evidence", columns: MARKET_COLUMNS, rows: market.rows.map((row) => ({ ...row })) },
|
|
147
161
|
...(positioning ? [{ title: "Positioning", entries: positioning.map((field) => ({ key: field.key, label: field.label, value: field.value,
|
|
148
162
|
formatted: field.detail ? `${field.text} · ${field.detail}` : field.text })) }] : []),
|
|
149
|
-
{ title: "Observation revisions", columns: REVISION_COLUMNS, rows: market.evidence.map((row) => ({ ...row })) }],
|
|
163
|
+
{ title: "Observation revisions", columns: REVISION_COLUMNS, rows: market.evidence.map((row) => ({ ...row })), ...lockedEmpty(market.access !== "pro") }],
|
|
150
164
|
complete: market.access === "pro" && market.status === "ok", errors: market.access !== "pro" ? ["Full evidence requires Gloom Pro"] : [], freshness,
|
|
151
165
|
metadata: { ...metadata, asOf: market.asOf, access: market.access, locked: market.locked, status: market.status },
|
|
152
166
|
};
|
|
153
167
|
const history = await fetchPerpsHistory({ marketId: selected.marketId, from: new Date(Date.now() - Number(args.options.days ?? 7) * 86_400_000).toISOString(), resolution: "auto", limit: 5000 }, ctx.apiClient);
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
{ title: "
|
|
168
|
+
const locked = lockedEmpty(history.locked);
|
|
169
|
+
return { sections: [{ title: "Latest market", columns: MARKET_COLUMNS, rows: [{ ...selected }] }, { title: "Own observations", columns: observationColumns(selected.quoteCurrency), rows: history.rows.map((row) => ({ ...row })), ...locked },
|
|
170
|
+
{ title: "Paid funding", columns: FUNDING_COLUMNS, rows: history.funding.map((row) => ({ ...row })), ...locked }, { title: "Hourly candles", columns: candleColumns(selected.quoteCurrency), rows: history.candles.map((row) => ({ ...row })), ...locked },
|
|
171
|
+
{ title: "Long/short history", columns: LONG_SHORT_COLUMNS, rows: (history.longShortRatio ?? []).map((row) => ({ ...row })), ...locked }],
|
|
157
172
|
complete: !history.locked && !history.truncated && history.status === "ok", freshness,
|
|
158
173
|
errors: history.locked ? ["Full history requires Gloom Pro"] : history.truncated ? ["History reached the 5,000-observation limit; narrow the range"] : [],
|
|
159
174
|
metadata: { ...metadata, asOf: history.asOf, access: history.access, locked: history.locked, status: history.status, from: history.from, to: history.to, resolution: history.resolution, truncated: history.truncated ?? false },
|
|
@@ -1,14 +1,33 @@
|
|
|
1
|
+
import type { PaneTemplateInstanceConfig } from "../../../types/plugin";
|
|
1
2
|
import type { PluginModule } from "../plugin-module";
|
|
2
|
-
import {
|
|
3
|
+
import { commandRequestParams } from "../shared/command-tab";
|
|
4
|
+
import { PERP_SERIES } from "./series";
|
|
5
|
+
import { perpsCache, perpsHistoryCache, perpsListCache, perpsMarketCache, perpsRankingsCache } from "./client";
|
|
3
6
|
import { perpsHeadless } from "./headless";
|
|
4
7
|
import { PerpsPane } from "./pane";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A named market has its own pane, and asking for it again (PERP, a stock's perpetual row in DES or QQ) brings that
|
|
11
|
+
* pane back to the market's history, whatever it was showing: the request is stamped onto the instance, so the pane
|
|
12
|
+
* sees it even when nothing else about the instance changed. Without a market, the board.
|
|
13
|
+
*/
|
|
14
|
+
export function perpsInstance(arg: string | undefined): PaneTemplateInstanceConfig {
|
|
15
|
+
const market = arg?.trim() ?? "";
|
|
16
|
+
if (!market) return { placement: "floating", settings: { market } };
|
|
17
|
+
return { instanceId: `perps:${encodeURIComponent(market.toUpperCase()).replace(/%/g, "~")}`, placement: "floating",
|
|
18
|
+
settings: { market }, params: commandRequestParams({ market }) };
|
|
19
|
+
}
|
|
20
|
+
|
|
5
21
|
export const perpsModule: PluginModule = {
|
|
22
|
+
series: PERP_SERIES,
|
|
6
23
|
panes: [{ id: "perps", name: "Perpetuals", icon: "P", component: PerpsPane, defaultPosition: "right", defaultMode: "floating",
|
|
7
24
|
defaultFloatingSize: { width: 138, height: 34 }, tableExport: true, headless: perpsHeadless }],
|
|
8
25
|
paneTemplates: [{ id: "perps-pane", paneId: "perps", label: "Perpetuals", description: "Perpetual funding, open interest and premiums by market and venue, with rankings, a venue comparison and Pro history.",
|
|
9
26
|
keywords: ["perp", "perpetual", "perpetuals", "funding", "funding rate", "open interest", "hip-3", "stock perps", "basis", "venue", "funding spread", "long short ratio", "long/short", "positioning"],
|
|
10
27
|
shortcut: { prefix: "PERP", argKind: "text", argOptional: true, argPlaceholder: "market" }, headless: perpsHeadless,
|
|
11
|
-
createInstance: (_ctx, options) => (
|
|
12
|
-
setup(ctx) {
|
|
13
|
-
|
|
28
|
+
createInstance: (_ctx, options) => perpsInstance(options?.arg) }],
|
|
29
|
+
setup(ctx) {
|
|
30
|
+
for (const cache of [perpsCache, perpsHistoryCache, perpsListCache, perpsMarketCache, perpsRankingsCache]) cache.attach(ctx.persistence);
|
|
31
|
+
},
|
|
32
|
+
dispose() { for (const cache of [perpsCache, perpsHistoryCache, perpsListCache, perpsMarketCache, perpsRankingsCache]) cache.reset(); },
|
|
14
33
|
};
|