gloomberb 0.18.2 → 0.18.4
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 +8 -8
- package/README.zh-CN.md +11 -11
- package/bin/{gloomberb → gloom} +3 -1
- package/package.json +6 -2
- package/patches/electrobun@1.18.1.patch +106 -5
- package/src/account/checkout-handoff.tsx +225 -0
- package/src/account/device-signin-dialog.tsx +2 -2
- package/src/account/device-signin.ts +2 -2
- package/src/account/upgrade-dialog.tsx +1 -1
- package/src/api-client/askg.ts +2 -2
- package/src/api-client/auth.ts +2 -2
- package/src/api-client/central-bank-rates.ts +6 -0
- package/src/api-client/collections.ts +5 -1
- package/src/api-client/cot.ts +2 -0
- package/src/api-client/crypto-etf-flows.ts +37 -0
- package/src/api-client/crypto-markets.ts +60 -0
- package/src/api-client/data.ts +99 -5
- package/src/api-client/doe.ts +15 -0
- package/src/api-client/equity-screener.ts +28 -0
- package/src/api-client/exchange-announcements.ts +38 -0
- package/src/api-client/fund-facts.ts +39 -0
- package/src/api-client/futures-curve.ts +9 -1
- package/src/api-client/hiring.ts +301 -0
- package/src/api-client/index.ts +24 -5
- package/src/api-client/market-discovery.ts +14 -0
- package/src/api-client/members.ts +6 -0
- package/src/api-client/mna.ts +6 -0
- package/src/api-client/paths.ts +18 -1
- package/src/api-client/request.ts +26 -7
- package/src/api-client/short-side-publications.ts +37 -0
- package/src/api-client/socket.ts +64 -4
- package/src/api-client/swap-curve.ts +35 -0
- package/src/api-client/telemetry.ts +17 -0
- package/src/api-client/themes.ts +7 -1
- package/src/api-client/types.ts +90 -2
- package/src/app/global-shortcuts.ts +1 -16
- package/src/app/pane-runtime/plugin-bindings.ts +9 -2
- package/src/app/runtime/desktop-deeplink.ts +5 -5
- package/src/app/runtime/plugin-bindings.ts +2 -2
- package/src/app/runtime/startup.ts +13 -0
- package/src/app/runtime/update.ts +28 -8
- package/src/app/star-prompt/status-line.tsx +2 -2
- package/src/architecture/core-builtin-allowlist.json +5 -2
- package/src/architecture/pane-tabs-allowlist.json +65 -0
- package/src/architecture/ui-literals-allowlist.json +3 -3
- package/src/architecture/ui-tokens-allowlist.json +1 -1
- package/src/brokers/broker-portfolio-sync.ts +37 -0
- package/src/brokers/directory.ts +11 -0
- package/src/brokers/logos.ts +3 -1
- package/src/brokers/signed-in/adapter.ts +304 -26
- package/src/brokers/signed-in/client.ts +14 -2
- package/src/brokers/signed-in/connect.ts +10 -2
- package/src/brokers/sync-broker-instance.ts +9 -1
- package/src/capabilities/chart-series.ts +22 -6
- package/src/cli/bank-section.ts +1 -1
- package/src/cli/base-converter.ts +23 -14
- package/src/cli/central-bank-events.ts +1 -1
- package/src/cli/command-options.ts +59 -4
- package/src/cli/commands/api.ts +9 -6
- package/src/cli/commands/broker.ts +2 -2
- package/src/cli/commands/command-utils.ts +2 -2
- package/src/cli/commands/crypto-hints.ts +7 -20
- package/src/cli/commands/fred-series.ts +4 -2
- package/src/cli/commands/keybindings.ts +2 -2
- package/src/cli/commands/market.ts +1189 -296
- package/src/cli/commands/news-hints.ts +2 -2
- package/src/cli/commands/news-search.ts +59 -6
- package/src/cli/commands/options-leaps.ts +41 -26
- package/src/cli/commands/overview.ts +121 -48
- package/src/cli/commands/plugins.ts +9 -9
- package/src/cli/commands/remote.ts +13 -10
- package/src/cli/commands/search.ts +64 -44
- package/src/cli/commands/system.ts +27 -19
- package/src/cli/commands/themes.ts +1 -1
- package/src/cli/commands/ticker.ts +272 -70
- package/src/cli/context.ts +3 -2
- package/src/cli/desktop-pane-shot-view.ts +2 -2
- package/src/cli/desktop-pane-shot.ts +1 -1
- package/src/cli/earnings-calendar.ts +4 -4
- package/src/cli/entry.ts +18 -1
- package/src/cli/errors.ts +20 -2
- package/src/cli/exit-codes.ts +1 -1
- package/src/cli/export-source.ts +10 -4
- package/src/cli/freshness.ts +2 -8
- package/src/cli/fx-forward.ts +130 -0
- package/src/cli/fx-pair.ts +10 -9
- package/src/cli/glossary.ts +64 -20
- package/src/cli/help.ts +20 -14
- package/src/cli/history-export.ts +126 -0
- package/src/cli/history-rows.ts +196 -43
- package/src/cli/index-roots.ts +5 -45
- package/src/cli/index.ts +32 -18
- package/src/cli/issuer-membership.ts +103 -0
- package/src/cli/known-gaps.ts +118 -25
- package/src/cli/listing-arg.ts +315 -43
- package/src/cli/name-entries.ts +73 -22
- package/src/cli/native-smoke.ts +2 -0
- package/src/cli/not-a-ticker.ts +19 -9
- package/src/cli/opentui-libc.ts +5 -0
- package/src/cli/options.ts +12 -0
- package/src/cli/pane-functions/capabilities.ts +77 -20
- package/src/cli/pane-functions/catalog.ts +40 -23
- package/src/cli/pane-functions/discovery.ts +1 -1
- package/src/cli/pane-functions/dom.ts +12 -8
- package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
- package/src/cli/pane-functions/freshness.ts +174 -23
- package/src/cli/pane-functions/function-help.ts +66 -27
- package/src/cli/pane-functions/headless.ts +48 -16
- package/src/cli/pane-functions/index.ts +82 -21
- package/src/cli/pane-functions/options.ts +22 -2
- package/src/cli/pane-functions/report-notices.ts +12 -4
- package/src/cli/pane-functions/report.ts +5 -5
- package/src/cli/pane-functions/resolver.ts +65 -14
- package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
- package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
- package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
- package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
- package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
- package/src/cli/pane-functions/screenshot-payload.ts +453 -0
- package/src/cli/pane-functions/screenshot-render.ts +316 -0
- package/src/cli/pane-functions/screenshot-types.ts +162 -0
- package/src/cli/pane-functions/shot-options.ts +8 -3
- package/src/cli/peso-dollar-rates.ts +79 -0
- package/src/cli/quote-answer.ts +38 -3
- package/src/cli/report-tables.ts +190 -27
- package/src/cli/restore-plugins.ts +29 -14
- package/src/cli/result.ts +122 -25
- package/src/cli/series-search.ts +5 -5
- package/src/cli/statement-filings.ts +19 -0
- package/src/cli/suffixed-listing-rows.ts +49 -0
- package/src/cli/symbol-args.ts +50 -15
- package/src/cli/symbol-cells.ts +120 -0
- package/src/cli/symbol-list.ts +226 -60
- package/src/cli/symbol-rows.ts +131 -25
- package/src/cli/ticker-resolution.ts +108 -11
- package/src/cli/treasury-yields.ts +5 -5
- package/src/cli/types.ts +2 -0
- package/src/cli/uncovered-instrument.ts +3 -3
- package/src/cli/unknown-command.ts +6 -6
- package/src/components/chart/composite/chart-layout.ts +131 -0
- package/src/components/chart/composite/composite-chart.tsx +387 -21
- package/src/components/chart/composite/drawing-store.ts +26 -6
- package/src/components/chart/composite/interactions.ts +9 -3
- package/src/components/chart/composite/legend.tsx +75 -3
- package/src/components/chart/composite/levels.ts +5 -0
- package/src/components/chart/composite/panel-gestures.ts +41 -0
- package/src/components/chart/composite/panel-labels.ts +2 -1
- package/src/components/chart/composite/panel-surface.tsx +316 -11
- package/src/components/chart/composite/price-axis-labels.tsx +27 -3
- package/src/components/chart/composite/rasterizer.ts +44 -19
- package/src/components/chart/composite/scene.ts +16 -4
- package/src/components/chart/composite/text-renderer.ts +48 -21
- package/src/components/chart/composite/toolbar.tsx +52 -5
- package/src/components/chart/composite/types.ts +19 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
- package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
- package/src/components/chart/composite/use-composite-viewport.ts +12 -3
- package/src/components/chart/composite/value-scale.ts +149 -0
- package/src/components/chart/composite/volume-profile-paint.ts +6 -3
- package/src/components/chart/core/pointer.ts +2 -0
- package/src/components/chart-table/index.ts +2 -0
- package/src/components/chart-table/read.tsx +74 -0
- package/src/components/command-bar/commands/collection-list.ts +41 -19
- package/src/components/command-bar/commands/collection.ts +9 -3
- package/src/components/command-bar/commands/direct/index.ts +1 -1
- package/src/components/command-bar/commands/direct/runtime.ts +3 -2
- package/src/components/command-bar/pane-templates/items.ts +59 -6
- package/src/components/command-bar/pane-templates/workflow.ts +10 -1
- package/src/components/command-bar/routes/root/command-items.ts +32 -6
- package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
- package/src/components/command-bar/routes/root/provider-search.ts +42 -11
- package/src/components/command-bar/routes/root/results.ts +18 -4
- package/src/components/command-bar/routes/root/runtime.ts +15 -3
- package/src/components/command-bar/routes/root/search-providers.ts +25 -2
- package/src/components/command-bar/routes/root/selection.ts +6 -1
- package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
- package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
- package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
- package/src/components/command-bar/selection-runtime.ts +50 -10
- package/src/components/command-bar/surface/index.tsx +24 -2
- package/src/components/command-bar/view-model.ts +7 -0
- package/src/components/command-bar/workflow/broker.ts +2 -2
- package/src/components/command-bar/workflow/collection-actions.ts +46 -7
- package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
- package/src/components/command-bar/workflow/fields.ts +8 -2
- package/src/components/command-bar/workflow/ops.ts +18 -4
- package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
- package/src/components/command-bar/workflow/submit.ts +3 -2
- package/src/components/command-bar/workflow/tickers.ts +5 -1
- package/src/components/company-logo.tsx +39 -0
- package/src/components/data-table/sections.ts +4 -2
- package/src/components/data-table/view.tsx +23 -3
- package/src/components/form-modal/confirm.tsx +2 -1
- package/src/components/form-modal/request.ts +5 -0
- package/src/components/form-modal/routes.ts +4 -1
- package/src/components/index.ts +13 -6
- package/src/components/layout/detached-pane-shell.tsx +1 -0
- package/src/components/layout/floating-pane.tsx +1 -0
- package/src/components/layout/header.tsx +234 -60
- package/src/components/layout/market-summary.ts +9 -6
- package/src/components/layout/pane/capture-status.ts +1 -1
- package/src/components/layout/pane/footer/model.ts +11 -5
- package/src/components/layout/pane/header.tsx +10 -3
- package/src/components/layout/pane/index.tsx +1 -0
- package/src/components/layout/pane/pane-tabs.tsx +9 -1
- package/src/components/layout/shell/chrome.ts +19 -6
- package/src/components/layout/shell/index.tsx +2 -1
- package/src/components/layout/shell/pane/layers.tsx +19 -1
- package/src/components/layout/status-bar.tsx +2 -2
- package/src/components/market-board/index.tsx +11 -3
- package/src/components/onboarding/onboarding-wizard.tsx +1 -0
- package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
- package/src/components/onboarding/wizard-broker-sync.ts +4 -1
- package/src/components/pane-settings-dialog/desktop.tsx +20 -7
- package/src/components/pane-settings-dialog/tui.tsx +17 -9
- package/src/components/pane-settings-dialog/value.ts +8 -1
- package/src/components/pane-settings-dialog.tsx +44 -13
- package/src/components/sign-in-code-panel.tsx +27 -19
- package/src/components/ui/column-grid.tsx +48 -4
- package/src/components/ui/country-flag-art.tsx +180 -0
- package/src/components/ui/country-flag.tsx +118 -12
- package/src/components/ui/data-table/opentui/index.tsx +61 -2
- package/src/components/ui/data-table/opentui/model.ts +109 -2
- package/src/components/ui/data-table/types.ts +1 -1
- package/src/components/ui/display.tsx +5 -1
- package/src/components/ui/index.ts +3 -1
- package/src/components/ui/logo-mark.tsx +11 -2
- package/src/components/ui/query-bar.tsx +1 -1
- package/src/components/ui/row-notes.ts +79 -0
- package/src/components/ui/stat-grid.tsx +28 -3
- package/src/components/ui/status.tsx +3 -1
- package/src/core/app-services.ts +4 -0
- package/src/core/state/app/layout.ts +4 -4
- package/src/data/cached-query.ts +8 -1
- package/src/data/config/chart-settings.ts +3 -3
- package/src/data/config/home.ts +10 -2
- package/src/data/config/layout.ts +4 -1
- package/src/data/config/store/node.ts +4 -0
- package/src/data/config/store/normalize.ts +13 -3
- package/src/data/config/store/portfolio-as-of-column.ts +2 -2
- package/src/data/json-storage.ts +2 -0
- package/src/data/saved-copies.ts +84 -0
- package/src/docs/snapshot.json +65 -32
- package/src/i18n/es.ts +51 -12
- package/src/i18n/ja.ts +51 -12
- package/src/i18n/ko.ts +51 -12
- package/src/i18n/zh-cn.ts +51 -12
- package/src/i18n/zh-tw.ts +51 -12
- package/src/layout/desks.ts +1 -1
- package/src/layout/launch-layout.ts +1 -1
- package/src/layout/pane-manager/floating-actions.ts +5 -3
- package/src/layout/pane-manager/floating.ts +43 -1
- package/src/layout/pane-manager/index.ts +2 -0
- package/src/layout/selected-ticker.ts +74 -0
- package/src/market-data/depositary-pair.ts +251 -0
- package/src/market-data/futures-board.ts +1 -1
- package/src/market-data/futures-contract.ts +124 -40
- package/src/market-data/fx-closes.ts +17 -2
- package/src/market-data/hooks.tsx +19 -11
- package/src/market-data/market/change-basis.ts +49 -7
- package/src/market-data/market/freshness.ts +34 -5
- package/src/market-data/market/period-return.ts +163 -0
- package/src/market-data/market/trading-sessions.ts +13 -0
- package/src/market-data/market/year-to-date.ts +8 -13
- package/src/market-data/performance.ts +20 -14
- package/src/market-data/perpetual-premium.ts +32 -0
- package/src/market-data/published-apac-sessions.ts +2 -1
- package/src/market-data/published-futures-sessions.ts +69 -0
- package/src/market-data/quotes/contributions.ts +5 -1
- package/src/market-data/quotes/freshness.ts +42 -0
- package/src/market-data/quotes/intraday-bar.ts +37 -0
- package/src/market-data/quotes/regular-session-valuation.ts +13 -8
- package/src/market-data/quotes/resolution.ts +4 -2
- package/src/market-data/tax-equivalent.ts +1 -1
- package/src/market-data/ticker-price-returns.ts +3 -1
- package/src/news/aggregator.ts +5 -1
- package/src/news/news-model.ts +4 -0
- package/src/news/types.ts +11 -0
- package/src/notifications/app-notifier.ts +1 -1
- package/src/plugins/auto-update.ts +2 -2
- package/src/plugins/builtin/account-management/index.tsx +1 -0
- package/src/plugins/builtin/account-management/pane.tsx +9 -8
- package/src/plugins/builtin/alerts/alert-engine.ts +30 -18
- package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
- package/src/plugins/builtin/alerts/cli.ts +485 -76
- package/src/plugins/builtin/alerts/command.ts +5 -10
- package/src/plugins/builtin/alerts/event-rows.ts +9 -5
- package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
- package/src/plugins/builtin/alerts/events.ts +108 -5
- package/src/plugins/builtin/alerts/fired-log.ts +78 -0
- package/src/plugins/builtin/alerts/format.ts +2 -1
- package/src/plugins/builtin/alerts/headless.ts +100 -39
- package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
- package/src/plugins/builtin/alerts/history-rows.ts +89 -0
- package/src/plugins/builtin/alerts/index.tsx +45 -18
- package/src/plugins/builtin/alerts/iv-level.ts +365 -0
- package/src/plugins/builtin/alerts/levels.ts +3 -3
- package/src/plugins/builtin/alerts/pane.tsx +97 -29
- package/src/plugins/builtin/alerts/price.ts +35 -0
- package/src/plugins/builtin/alerts/quotes.ts +24 -0
- package/src/plugins/builtin/alerts/research-builder.ts +84 -11
- package/src/plugins/builtin/alerts/research-rules.ts +77 -3
- package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
- package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
- package/src/plugins/builtin/alerts/scheduled.ts +188 -29
- package/src/plugins/builtin/alerts/storage.ts +13 -10
- package/src/plugins/builtin/alerts/targets.ts +12 -3
- package/src/plugins/builtin/analytics/index.tsx +8 -2
- package/src/plugins/builtin/analytics/metrics.ts +1 -1
- package/src/plugins/builtin/analytics/risk-book.ts +215 -0
- package/src/plugins/builtin/analytics/risk-client.ts +13 -6
- package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
- package/src/plugins/builtin/analytics/risk-math.ts +6 -3
- package/src/plugins/builtin/analytics/risk-model.ts +297 -104
- package/src/plugins/builtin/analytics/risk-options.ts +17 -2
- package/src/plugins/builtin/analytics/risk-pane.tsx +107 -43
- package/src/plugins/builtin/attention/pane.tsx +22 -16
- package/src/plugins/builtin/awards/headless.ts +7 -3
- package/src/plugins/builtin/awards/model.ts +18 -0
- package/src/plugins/builtin/awards/pane.tsx +12 -9
- package/src/plugins/builtin/backtest/export.ts +1 -1
- package/src/plugins/builtin/backtest/headless.ts +3 -3
- package/src/plugins/builtin/backtest/rules.ts +41 -5
- package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
- package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
- package/src/plugins/builtin/broker-manager/footer.ts +27 -11
- package/src/plugins/builtin/broker-manager/index.tsx +21 -12
- package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
- package/src/plugins/builtin/broker-manager/model.ts +12 -2
- package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
- package/src/plugins/builtin/broker-manager/table.ts +28 -12
- package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
- package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
- package/src/plugins/builtin/broker-trading/controller.ts +45 -13
- package/src/plugins/builtin/broker-trading/dock.tsx +24 -4
- package/src/plugins/builtin/broker-trading/headless.ts +2 -1
- package/src/plugins/builtin/broker-trading/index.tsx +7 -1
- package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
- package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
- package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
- package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
- package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
- package/src/plugins/builtin/broker-trading/pane.tsx +115 -26
- package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
- package/src/plugins/builtin/broker-trading/ticket.tsx +122 -36
- package/src/plugins/builtin/buildout/cells.tsx +4 -0
- package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
- package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
- package/src/plugins/builtin/buildout/pane/index.tsx +34 -18
- package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
- package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
- package/src/plugins/builtin/catalysts/client.ts +2 -2
- package/src/plugins/builtin/catalysts/detail.tsx +3 -2
- package/src/plugins/builtin/catalysts/index.tsx +1 -1
- package/src/plugins/builtin/catalysts/model.ts +49 -4
- package/src/plugins/builtin/catalysts/pane.tsx +9 -11
- package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
- package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
- package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
- package/src/plugins/builtin/changelog/index.tsx +1 -0
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
- package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
- package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
- package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
- package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
- package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
- package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
- package/src/plugins/builtin/chart-composer/headless.ts +253 -35
- package/src/plugins/builtin/chart-composer/index.tsx +12 -2
- package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
- package/src/plugins/builtin/chart-composer/pane.tsx +128 -28
- package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
- package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
- package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
- package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
- package/src/plugins/builtin/chart-composer/settings.ts +31 -19
- package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
- package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
- package/src/plugins/builtin/chat/attachments/model.ts +3 -1
- package/src/plugins/builtin/chat/content/index.tsx +1 -1
- package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
- package/src/plugins/builtin/chat/people.ts +1 -1
- package/src/plugins/builtin/clinical-trials/client.ts +5 -2
- package/src/plugins/builtin/clinical-trials/model.ts +13 -4
- package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
- package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
- package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
- package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
- package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
- package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
- package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
- package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
- package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
- package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
- package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
- package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
- package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
- package/src/plugins/builtin/commodity-balances/pane.tsx +14 -8
- package/src/plugins/builtin/company-attention/app-rank.tsx +11 -10
- package/src/plugins/builtin/company-attention/building-model.ts +222 -0
- package/src/plugins/builtin/company-attention/building.tsx +172 -0
- package/src/plugins/builtin/company-attention/client.ts +117 -1
- package/src/plugins/builtin/company-attention/evidence.ts +16 -3
- package/src/plugins/builtin/company-attention/headless.ts +101 -5
- package/src/plugins/builtin/company-attention/index.tsx +6 -3
- package/src/plugins/builtin/company-attention/model.ts +33 -7
- package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
- package/src/plugins/builtin/company-attention/moves.tsx +159 -0
- package/src/plugins/builtin/company-attention/pane.tsx +89 -31
- package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
- package/src/plugins/builtin/company-attention/signals.tsx +160 -0
- package/src/plugins/builtin/company-kpis/headless.ts +3 -2
- package/src/plugins/builtin/company-kpis/model.ts +2 -2
- package/src/plugins/builtin/company-kpis/pane.tsx +5 -4
- package/src/plugins/builtin/composite-plugins.ts +2 -1
- package/src/plugins/builtin/congress-trades/headless.ts +1 -1
- package/src/plugins/builtin/connections/index.ts +1 -0
- package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
- package/src/plugins/builtin/correlation/headless.ts +7 -4
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -0
- package/src/plugins/builtin/correlation/settings.ts +1 -0
- package/src/plugins/builtin/cot/headless.ts +28 -6
- package/src/plugins/builtin/cot/model.ts +12 -0
- package/src/plugins/builtin/cot/pane.tsx +7 -5
- package/src/plugins/builtin/cpi/headless.ts +5 -1
- package/src/plugins/builtin/cpi/pane.tsx +11 -9
- package/src/plugins/builtin/credit-boards/model.ts +2 -0
- package/src/plugins/builtin/credit-documents/headless.ts +1 -1
- package/src/plugins/builtin/credit-documents/pane.tsx +8 -7
- package/src/plugins/builtin/crypto-board/client.ts +86 -0
- package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
- package/src/plugins/builtin/crypto-board/defi.ts +239 -0
- package/src/plugins/builtin/crypto-board/headless.ts +117 -6
- package/src/plugins/builtin/crypto-board/index.tsx +8 -3
- package/src/plugins/builtin/crypto-board/model.ts +40 -8
- package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
- package/src/plugins/builtin/crypto-board/series.ts +19 -1
- package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
- package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
- package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
- package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
- package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
- package/src/plugins/builtin/debt-maturities/pane.tsx +4 -3
- package/src/plugins/builtin/debug/index.tsx +1 -0
- package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
- package/src/plugins/builtin/docs/index.tsx +1 -1
- package/src/plugins/builtin/docs/pane.tsx +2 -2
- package/src/plugins/builtin/docs/targets.ts +1 -1
- package/src/plugins/builtin/doe/client.ts +5 -1
- package/src/plugins/builtin/doe/headless.ts +12 -6
- package/src/plugins/builtin/doe/model.ts +43 -6
- package/src/plugins/builtin/doe/pane.tsx +19 -12
- package/src/plugins/builtin/earnings/board-model.ts +13 -6
- package/src/plugins/builtin/earnings/board-table.ts +4 -1
- package/src/plugins/builtin/earnings/board.tsx +253 -50
- package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
- package/src/plugins/builtin/earnings/calendar.tsx +338 -0
- package/src/plugins/builtin/earnings/client.ts +4 -3
- package/src/plugins/builtin/earnings/headless.ts +53 -15
- package/src/plugins/builtin/earnings/history-model.ts +53 -36
- package/src/plugins/builtin/earnings/index.tsx +15 -22
- package/src/plugins/builtin/earnings/model.ts +17 -12
- package/src/plugins/builtin/earnings/scope.ts +89 -0
- package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
- package/src/plugins/builtin/earnings-calls/data.ts +146 -2
- package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
- package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
- package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
- package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
- package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
- package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
- package/src/plugins/builtin/econ/calendar-model.ts +132 -20
- package/src/plugins/builtin/econ/detail-view.tsx +48 -10
- package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
- package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
- package/src/plugins/builtin/econ/index.tsx +112 -25
- package/src/plugins/builtin/econ/print-watch.ts +2 -1
- package/src/plugins/builtin/econ/types.ts +32 -1
- package/src/plugins/builtin/econ-statistics/client.ts +16 -3
- package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
- package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
- package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
- package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
- package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
- package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
- package/src/plugins/builtin/econ-statistics/view.ts +16 -1
- package/src/plugins/builtin/equity-screener/client.ts +21 -3
- package/src/plugins/builtin/equity-screener/headless.ts +77 -5
- package/src/plugins/builtin/equity-screener/live.ts +1 -1
- package/src/plugins/builtin/equity-screener/model.ts +34 -0
- package/src/plugins/builtin/equity-screener/pane.tsx +148 -106
- package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
- package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
- package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
- package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
- package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
- package/src/plugins/builtin/exposure/headless.ts +51 -6
- package/src/plugins/builtin/exposure/index.tsx +28 -2
- package/src/plugins/builtin/exposure/model.ts +7 -0
- package/src/plugins/builtin/exposure/pane.tsx +16 -10
- package/src/plugins/builtin/fear-greed/index.tsx +1 -1
- package/src/plugins/builtin/filing-events/index.tsx +1 -1
- package/src/plugins/builtin/futures/model.ts +10 -9
- package/src/plugins/builtin/futures/returns.ts +8 -36
- package/src/plugins/builtin/futures/table.tsx +1 -1
- package/src/plugins/builtin/futures-curve/client.ts +40 -9
- package/src/plugins/builtin/futures-curve/headless.ts +39 -17
- package/src/plugins/builtin/futures-curve/model.ts +258 -69
- package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
- package/src/plugins/builtin/fx-matrix/client.ts +15 -8
- package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
- package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
- package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
- package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
- package/src/plugins/builtin/gpu/board.tsx +4 -1
- package/src/plugins/builtin/gpu/changes.tsx +10 -10
- package/src/plugins/builtin/gpu/equities.tsx +4 -1
- package/src/plugins/builtin/gpu/headless.ts +9 -4
- package/src/plugins/builtin/gpu/history.tsx +4 -2
- package/src/plugins/builtin/gpu/pane.tsx +5 -3
- package/src/plugins/builtin/help/index.tsx +13 -3
- package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
- package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
- package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
- package/src/plugins/builtin/holders/client.ts +15 -2
- package/src/plugins/builtin/holders/format.ts +28 -17
- package/src/plugins/builtin/holders/headless.ts +48 -8
- package/src/plugins/builtin/holders/index-holders.ts +264 -0
- package/src/plugins/builtin/holders/pane.tsx +79 -15
- package/src/plugins/builtin/holders/report-rows.ts +35 -7
- package/src/plugins/builtin/holders/table-model.ts +2 -1
- package/src/plugins/builtin/holders/thirteenf-match.ts +3 -1
- package/src/plugins/builtin/holders/treemap.tsx +2 -2
- package/src/plugins/builtin/insider/base-values.ts +11 -7
- package/src/plugins/builtin/insider/client.ts +3 -0
- package/src/plugins/builtin/insider/headless.ts +20 -7
- package/src/plugins/builtin/insider/index.tsx +17 -8
- package/src/plugins/builtin/insider/issuer.ts +34 -4
- package/src/plugins/builtin/insider/signals-client.ts +3 -3
- package/src/plugins/builtin/insider/signals.tsx +1 -1
- package/src/plugins/builtin/insider/table-model.ts +35 -13
- package/src/plugins/builtin/insider/table.tsx +5 -2
- package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
- package/src/plugins/builtin/iv-history/client.ts +20 -0
- package/src/plugins/builtin/iv-history/events.ts +145 -0
- package/src/plugins/builtin/iv-history/format.ts +3 -0
- package/src/plugins/builtin/iv-history/headless.ts +91 -7
- package/src/plugins/builtin/iv-history/index.tsx +1 -1
- package/src/plugins/builtin/iv-history/model.ts +13 -4
- package/src/plugins/builtin/iv-history/series.ts +3 -1
- package/src/plugins/builtin/jobs/lock-note.ts +1 -1
- package/src/plugins/builtin/jobs/model.ts +4 -15
- package/src/plugins/builtin/jobs/pane.tsx +7 -5
- package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
- package/src/plugins/builtin/jodi/pane.tsx +14 -8
- package/src/plugins/builtin/layout-manager/index.tsx +1 -0
- package/src/plugins/builtin/macro-day/headless.ts +20 -7
- package/src/plugins/builtin/macro-day/index.tsx +3 -2
- package/src/plugins/builtin/macro-day/model.ts +29 -8
- package/src/plugins/builtin/macro-day/pane.tsx +46 -10
- package/src/plugins/builtin/macro-day/releases.ts +55 -13
- package/src/plugins/builtin/market-heatmap/data.ts +9 -2
- package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
- package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
- package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
- package/src/plugins/builtin/market-heatmap/model.ts +10 -7
- package/src/plugins/builtin/market-movers/client.ts +36 -21
- package/src/plugins/builtin/market-movers/headless.ts +8 -2
- package/src/plugins/builtin/market-movers/index.tsx +16 -10
- package/src/plugins/builtin/market-movers/screener.ts +33 -11
- package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
- package/src/plugins/builtin/market-movers/session-table.ts +4 -2
- package/src/plugins/builtin/market-movers/table.ts +4 -1
- package/src/plugins/builtin/market-valuation/headless.ts +2 -0
- package/src/plugins/builtin/market-valuation/view.ts +5 -0
- package/src/plugins/builtin/members/headless.ts +6 -5
- package/src/plugins/builtin/members/pane.tsx +11 -4
- package/src/plugins/builtin/mna/client.ts +1 -0
- package/src/plugins/builtin/mna/detail.tsx +20 -32
- package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
- package/src/plugins/builtin/mna/distress/model.ts +3 -2
- package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
- package/src/plugins/builtin/mna/headless.ts +6 -13
- package/src/plugins/builtin/mna/model.ts +93 -15
- package/src/plugins/builtin/mna/pane.tsx +5 -4
- package/src/plugins/builtin/news/headless.ts +12 -6
- package/src/plugins/builtin/news/index.tsx +10 -1
- package/src/plugins/builtin/news/wire/index.tsx +3 -2
- package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
- package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
- package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
- package/src/plugins/builtin/notes/cli.ts +50 -15
- package/src/plugins/builtin/notes/export.ts +17 -6
- package/src/plugins/builtin/notes/files.ts +16 -5
- package/src/plugins/builtin/openfda/pane.tsx +1 -1
- package/src/plugins/builtin/options/carry.ts +2 -2
- package/src/plugins/builtin/options/enrichment-model.ts +10 -9
- package/src/plugins/builtin/options/index.tsx +1 -1
- package/src/plugins/builtin/options/model-spot.ts +70 -4
- package/src/plugins/builtin/options/view.tsx +51 -23
- package/src/plugins/builtin/options-calculator/headless.ts +46 -7
- package/src/plugins/builtin/options-calculator/pane.tsx +3 -2
- package/src/plugins/builtin/options-positioning/headless.ts +11 -3
- package/src/plugins/builtin/options-positioning/model.ts +24 -0
- package/src/plugins/builtin/options-positioning/pane.tsx +10 -12
- package/src/plugins/builtin/options-scenario/client.ts +142 -29
- package/src/plugins/builtin/options-scenario/collar.ts +8 -6
- package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
- package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
- package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
- package/src/plugins/builtin/options-scenario/csp.ts +101 -21
- package/src/plugins/builtin/options-scenario/headless.ts +49 -21
- package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
- package/src/plugins/builtin/options-scenario/index.tsx +28 -3
- package/src/plugins/builtin/options-scenario/model.ts +13 -0
- package/src/plugins/builtin/options-scenario/pane.tsx +22 -10
- package/src/plugins/builtin/perps/equity-row.tsx +11 -3
- package/src/plugins/builtin/perps/freshness.ts +8 -5
- package/src/plugins/builtin/perps/headless.ts +3 -1
- package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
- package/src/plugins/builtin/perps/live-rows.ts +161 -0
- package/src/plugins/builtin/perps/markets-section.tsx +154 -0
- package/src/plugins/builtin/perps/pane.tsx +36 -17
- package/src/plugins/builtin/perps/venue-markets.ts +96 -0
- package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +145 -60
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +78 -27
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
- package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
- package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
- package/src/plugins/builtin/portfolio-list/income.ts +13 -2
- package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
- package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
- package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
- package/src/plugins/builtin/power/client.ts +6 -3
- package/src/plugins/builtin/power/evidence.ts +22 -7
- package/src/plugins/builtin/power/gas.tsx +5 -1
- package/src/plugins/builtin/power/pane.tsx +44 -32
- package/src/plugins/builtin/power/prices.tsx +10 -3
- package/src/plugins/builtin/research/analyst-headless.ts +25 -8
- package/src/plugins/builtin/research/analyst-model.ts +68 -3
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
- package/src/plugins/builtin/research/event-model.ts +3 -1
- package/src/plugins/builtin/research/event-sources.ts +12 -4
- package/src/plugins/builtin/research/index.tsx +2 -1
- package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
- package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
- package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
- package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
- package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
- package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
- package/src/plugins/builtin/reverse-dcf/client.ts +2 -1
- package/src/plugins/builtin/reverse-dcf/model.ts +10 -5
- package/src/plugins/builtin/risk-factors/index.tsx +2 -2
- package/src/plugins/builtin/scanner/lock-note.ts +1 -1
- package/src/plugins/builtin/seasonality/client.ts +2 -1
- package/src/plugins/builtin/sec/forms.ts +13 -0
- package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
- package/src/plugins/builtin/sec/fund-facts.ts +68 -8
- package/src/plugins/builtin/sec/headless.ts +85 -8
- package/src/plugins/builtin/sec/index.tsx +58 -12
- package/src/plugins/builtin/sectors/client.ts +6 -4
- package/src/plugins/builtin/sectors/sector-model.ts +11 -15
- package/src/plugins/builtin/series-inventory.ts +2 -0
- package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
- package/src/plugins/builtin/shared/cloud-resource.ts +15 -2
- package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
- package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
- package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
- package/src/plugins/builtin/shared/earnings-report.ts +3 -3
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
- package/src/plugins/builtin/shared/job-posting.ts +129 -0
- package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
- package/src/plugins/builtin/shared/report-freshness.ts +3 -0
- package/src/plugins/builtin/shared/research-trading.tsx +23 -0
- package/src/plugins/builtin/shared/series-cache.ts +2 -0
- package/src/plugins/builtin/shared/series-list-detail.tsx +3 -1
- package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
- package/src/plugins/builtin/shared/volatility/options.ts +2 -1
- package/src/plugins/builtin/short-interest/client.ts +2 -0
- package/src/plugins/builtin/short-interest/headless.ts +41 -12
- package/src/plugins/builtin/short-interest/index.tsx +23 -1
- package/src/plugins/builtin/short-interest/model.ts +70 -19
- package/src/plugins/builtin/short-interest/pane.tsx +19 -2
- package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
- package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
- package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
- package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
- package/src/plugins/builtin/short-interest/schedule.ts +35 -2
- package/src/plugins/builtin/short-interest/surface.tsx +11 -4
- package/src/plugins/builtin/short-interest/types.ts +9 -0
- package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
- package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
- package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
- package/src/plugins/builtin/social-mentions/client.ts +2 -1
- package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
- package/src/plugins/builtin/supply-chain/model.ts +51 -3
- package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
- package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
- package/src/plugins/builtin/themes/headless.ts +8 -5
- package/src/plugins/builtin/themes/model.ts +14 -4
- package/src/plugins/builtin/themes/pane.tsx +24 -5
- package/src/plugins/builtin/thirteenf/headless.ts +5 -5
- package/src/plugins/builtin/thirteenf/signals.ts +3 -1
- package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
- package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
- package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
- package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
- package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
- package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
- package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
- package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
- package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
- package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
- package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
- package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
- package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
- package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
- package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
- package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
- package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
- package/src/plugins/builtin/vol-surface/client.ts +28 -7
- package/src/plugins/builtin/vol-surface/headless.ts +43 -15
- package/src/plugins/builtin/vol-surface/model.ts +34 -12
- package/src/plugins/builtin/vol-surface/pane.tsx +33 -13
- package/src/plugins/builtin/vol-surface/stored.ts +34 -3
- package/src/plugins/builtin/vol-surface/tables.ts +14 -0
- package/src/plugins/builtin/volatility/model.ts +5 -10
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
- package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
- package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
- package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
- package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
- package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
- package/src/plugins/builtin/world-venue-map/index.ts +3 -26
- package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
- package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
- package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
- package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
- package/src/plugins/builtin/yield-curve/client.ts +25 -0
- package/src/plugins/builtin/yield-curve/curves.ts +7 -4
- package/src/plugins/builtin/yield-curve/headless.ts +38 -4
- package/src/plugins/builtin/yield-curve/history.ts +4 -3
- package/src/plugins/builtin/yield-curve/index.tsx +12 -6
- package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
- package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
- package/src/plugins/bundle.ts +1 -1
- package/src/plugins/catalog-browser.ts +2 -1
- package/src/plugins/compat.ts +3 -3
- package/src/plugins/dependencies.ts +75 -14
- package/src/plugins/extracted-plugins.ts +132 -34
- package/src/plugins/host-link.ts +149 -34
- package/src/plugins/installer.ts +35 -10
- package/src/plugins/loader.ts +206 -38
- package/src/plugins/manager-node.ts +2 -2
- package/src/plugins/marketplace/deactivation.ts +22 -0
- package/src/plugins/marketplace/model.ts +2 -2
- package/src/plugins/marketplace/packs.ts +1 -1
- package/src/plugins/ownership.ts +1 -1
- package/src/plugins/peer-retry.ts +155 -0
- package/src/plugins/registry/contributions.ts +3 -1
- package/src/plugins/registry/index.ts +4 -3
- package/src/plugins/registry/plugin-state.ts +3 -0
- package/src/plugins/seed-notice.ts +20 -0
- package/src/plugins/shortcut-argument.ts +39 -0
- package/src/portfolio/allocation.ts +1 -1
- package/src/portfolio/collection-name.ts +31 -0
- package/src/portfolio/column-values.ts +10 -8
- package/src/portfolio/cost-fx.ts +296 -19
- package/src/portfolio/manual-lots.ts +75 -0
- package/src/portfolio/mutations.ts +60 -22
- package/src/portfolio/suffixed-listings.ts +209 -0
- package/src/portfolio/totals-currency.ts +24 -0
- package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
- package/src/public/time-series.ts +11 -8
- package/src/remote/schema.ts +1 -1
- package/src/renderers/browser/config-host.ts +3 -0
- package/src/renderers/browser/main.tsx +23 -3
- package/src/renderers/dom/boot-frame-page.ts +187 -0
- package/src/renderers/dom/boot-frame.ts +237 -0
- package/src/renderers/dom/build-assets.ts +46 -8
- package/src/renderers/dom/desktop/controls.tsx +1 -1
- package/src/renderers/dom/desktop/query-bar.tsx +2 -0
- package/src/renderers/dom/dom-ui-host.tsx +4 -29
- package/src/renderers/dom/host/ascii-text.ts +16 -2
- package/src/renderers/dom/host/box.tsx +43 -2
- package/src/renderers/dom/host/chart-surface.tsx +2 -0
- package/src/renderers/dom/host/hls.chunk.ts +3 -0
- package/src/renderers/dom/host/image-surface.tsx +49 -0
- package/src/renderers/dom/host/media-surface.tsx +24 -18
- package/src/renderers/dom/host/mouse.ts +30 -0
- package/src/renderers/dom/host/size-observer.ts +1 -1
- package/src/renderers/dom/host/style.ts +1 -1
- package/src/renderers/dom/host/tabs.tsx +16 -5
- package/src/renderers/dom/host/top-surface.ts +127 -0
- package/src/renderers/dom/styles.css +115 -0
- package/src/renderers/dom/test-utils.tsx +2 -1
- package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
- package/src/renderers/electrobun/bun/core-capabilities.ts +9 -1
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +56 -3
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
- package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
- package/src/renderers/electrobun/bun/desktop/update.ts +210 -30
- package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
- package/src/renderers/electrobun/bun/index.ts +11 -1
- package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
- package/src/renderers/electrobun/bun/window/create.ts +4 -1
- package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
- package/src/renderers/electrobun/shared/protocol.ts +6 -1
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
- package/src/renderers/electrobun/view/config-host.ts +3 -0
- package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
- package/src/renderers/electrobun/view/main.tsx +30 -4
- package/src/renderers/electrobun/view/news-source.ts +9 -7
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +9 -2
- package/src/renderers/electrobun/view/ui-host.tsx +1 -1
- package/src/renderers/opentui/browser-open.ts +88 -0
- package/src/renderers/opentui/host.tsx +5 -14
- package/src/renderers/opentui/image/loader.ts +3 -2
- package/src/renderers/opentui/native-smoke.ts +10 -1
- package/src/renderers/opentui/pane-image/index.ts +2 -1
- package/src/renderers/opentui/render-lib.ts +253 -0
- package/src/renderers/opentui/render-timing-smoke.ts +1 -1
- package/src/renderers/opentui/start.tsx +8 -1
- package/src/renderers/share/layout-view.tsx +2 -2
- package/src/renderers/share/main.tsx +4 -4
- package/src/renderers/share/view.tsx +1 -1
- package/src/series/resolve.ts +22 -6
- package/src/series/standalone.ts +30 -2
- package/src/series/types.ts +8 -1
- package/src/shares/api.ts +4 -1
- package/src/shares/pane.ts +1 -1
- package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
- package/src/sources/gloomberb-cloud/index.ts +39 -16
- package/src/sources/gloomberb-cloud/news.ts +39 -0
- package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
- package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
- package/src/sources/listing-symbols.ts +37 -0
- package/src/sources/provider-errors.ts +16 -2
- package/src/sources/provider-router/financial-routes.ts +21 -3
- package/src/sources/provider-router/financials.ts +15 -2
- package/src/sources/provider-router/history.ts +30 -8
- package/src/sources/provider-router/index.ts +16 -0
- package/src/sources/provider-router/primary.ts +1 -1
- package/src/state/app/bootstrap.ts +23 -0
- package/src/state/hooks/inline-tickers.ts +30 -5
- package/src/sync/controller.ts +1 -1
- package/src/sync/core-contributors.ts +46 -14
- package/src/team/collections-sync.ts +2 -1
- package/src/team/collections.ts +178 -17
- package/src/telemetry/crash-reports.ts +21 -4
- package/src/telemetry/update-failures-node.ts +59 -0
- package/src/telemetry/update-failures.ts +307 -0
- package/src/test-support/builtin-panes.ts +1 -1
- package/src/theme/colors.ts +3 -30
- package/src/theme/ui-tokens.ts +37 -1
- package/src/tickers/company-name-listing.ts +215 -36
- package/src/tickers/company-name.ts +43 -0
- package/src/tickers/index-roots.ts +47 -0
- package/src/tickers/instrument-label.ts +5 -1
- package/src/tickers/listing-fate.ts +30 -0
- package/src/tickers/metadata.ts +10 -0
- package/src/tickers/perpetual-listing.ts +5 -2
- package/src/tickers/search/home-listing.ts +75 -0
- package/src/tickers/search/index.ts +76 -27
- package/src/tickers/search/ranking.ts +54 -4
- package/src/tickers/search/upsert.ts +29 -0
- package/src/tickers/terminal-codes.ts +416 -40
- package/src/time-series/bar-aggregation.ts +243 -0
- package/src/time-series/base-series.ts +307 -0
- package/src/time-series/chart-bounds.ts +349 -0
- package/src/time-series/chart-seed.ts +142 -0
- package/src/time-series/economic.ts +5 -0
- package/src/time-series/fundamentals.ts +18 -3
- package/src/time-series/history-acquisition.ts +499 -0
- package/src/time-series/leverage.ts +100 -0
- package/src/time-series/market-resolution.ts +4 -2
- package/src/time-series/market.ts +2 -1
- package/src/time-series/price-comparison.ts +175 -30
- package/src/time-series/range.ts +9 -1
- package/src/time-series/resolution.ts +174 -16
- package/src/time-series/resolve-context.ts +157 -0
- package/src/time-series/resolve.ts +126 -1577
- package/src/time-series/series-name.ts +38 -0
- package/src/time-series/series-presentation.ts +208 -0
- package/src/time-series/spec.ts +11 -6
- package/src/time-series/studies.ts +109 -12
- package/src/time-series/tail-reconcile.ts +121 -0
- package/src/time-series/types.ts +29 -2
- package/src/time-series/use-chart-resolution.ts +4 -5
- package/src/types/broker.ts +10 -0
- package/src/types/config.ts +14 -0
- package/src/types/data-provider.ts +20 -0
- package/src/types/exchange-rate.ts +6 -0
- package/src/types/financials.ts +104 -7
- package/src/types/headless.ts +83 -6
- package/src/types/instrument.ts +3 -0
- package/src/types/issuer-listings.ts +28 -0
- package/src/types/plugin.ts +65 -8
- package/src/types/price-history.ts +2 -0
- package/src/types/ticker.ts +13 -0
- package/src/types/trading.ts +59 -1
- package/src/ui/ascii-font.ts +13 -1
- package/src/ui/host.tsx +6 -1
- package/src/updater/command-names.ts +175 -0
- package/src/updater/failure.ts +163 -0
- package/src/updater/index.ts +97 -28
- package/src/utils/calendar-date.ts +32 -15
- package/src/utils/cash-runway.ts +241 -0
- package/src/utils/central-banks.ts +42 -0
- package/src/utils/cli-output.ts +259 -80
- package/src/utils/contract-month.ts +16 -0
- package/src/utils/crypto-pair.ts +61 -3
- package/src/utils/currency-pair.ts +26 -0
- package/src/utils/currency-units.ts +29 -0
- package/src/utils/datetime-format.ts +10 -0
- package/src/utils/debug-log.ts +1 -1
- package/src/utils/decimal-comma.ts +39 -6
- package/src/utils/exchange-announcements.ts +71 -0
- package/src/utils/exchange-rate-snapshot.ts +10 -0
- package/src/utils/financial-statements.ts +83 -4
- package/src/utils/format.ts +34 -16
- package/src/utils/fundamentals.ts +150 -34
- package/src/utils/fx-market-hours.ts +10 -1
- package/src/utils/latest-financial-period.ts +8 -0
- package/src/utils/linux-libc.ts +54 -0
- package/src/utils/market-capitalization.ts +111 -15
- package/src/utils/max-drawdown.ts +64 -0
- package/src/utils/network-failure.ts +83 -0
- package/src/utils/option-expiry.ts +139 -7
- package/src/utils/price-earnings.ts +11 -5
- package/src/utils/price-history.ts +18 -8
- package/src/utils/price-window.ts +131 -0
- package/src/utils/release-date.ts +47 -0
- package/src/utils/sec.ts +71 -0
- package/src/utils/throttled-fetch.ts +11 -4
- package/src/utils/trailing-eps.ts +67 -0
- package/src/utils/typed-text.ts +21 -0
- package/src/utils/utc-time.ts +24 -1
- package/src/version.ts +6 -0
- package/src/cli/pane-functions/screenshot.ts +0 -2122
|
@@ -57,6 +57,7 @@ import {
|
|
|
57
57
|
formatDistance,
|
|
58
58
|
formatGamma,
|
|
59
59
|
formatLevel,
|
|
60
|
+
positioningSpotDetail,
|
|
60
61
|
formatPayout,
|
|
61
62
|
formatRatio,
|
|
62
63
|
formatStrike,
|
|
@@ -204,6 +205,7 @@ function OptionsPositioningView({ width, height, focused, symbol }: PaneProps &
|
|
|
204
205
|
const openInterest = useAsyncResource<OpenInterestPayload>(openInterestLoader, { keepPreviousData: true });
|
|
205
206
|
const data = openInterest.data;
|
|
206
207
|
const spot = data?.spot ?? null;
|
|
208
|
+
const spotStamp = useMemo(() => positioningSpotDetail(spot, data?.spotAsOf), [spot, data?.spotAsOf]);
|
|
207
209
|
const expiries = data?.expiries ?? [];
|
|
208
210
|
const shownExpiry = data?.expiry ?? requestedExpiry;
|
|
209
211
|
const changes = data?.previousOiDate != null;
|
|
@@ -264,9 +266,7 @@ function OptionsPositioningView({ width, height, focused, symbol }: PaneProps &
|
|
|
264
266
|
enabled: expiryIndex < expiryDates.length - 1, onSelect: () => stepExpiry(1) },
|
|
265
267
|
], [expiryDates.length, expiryIndex, stepExpiry, tab]);
|
|
266
268
|
|
|
267
|
-
const { strip: tabStrip, rows: tabRows } = usePaneTabs(
|
|
268
|
-
? { tabs, activeValue: tab, onSelect: (value: string) => setTab(value), focused, dense: true }
|
|
269
|
-
: null);
|
|
269
|
+
const { strip: tabStrip, rows: tabRows } = usePaneTabs({ tabs, activeValue: tab, onSelect: (value: string) => setTab(value), focused, dense: true });
|
|
270
270
|
const bodyHeight = Math.max(3, height - tabRows);
|
|
271
271
|
|
|
272
272
|
// Footer: what the data is (delayed or real time, the OI session), and its gaps.
|
|
@@ -335,13 +335,13 @@ function OptionsPositioningView({ width, height, focused, symbol }: PaneProps &
|
|
|
335
335
|
const strikeFigures = useMemo<StatItem[]>(() => !callTotal ? [] : [
|
|
336
336
|
{ id: "max-pain", label: "Max pain", value: maxPain == null ? "--" : formatStrike(maxPain), color: colors.warning,
|
|
337
337
|
detail: maxPain == null ? undefined : `${formatDistance(maxPain, spot)} vs spot` },
|
|
338
|
-
{ id: "spot", label: "Spot", value: formatLevel(spot) },
|
|
338
|
+
{ id: "spot", label: "Spot", value: formatLevel(spot), ...spotStamp },
|
|
339
339
|
{ id: "pc", label: "P/C OI", value: formatRatio(callTotal.putCallRatio) },
|
|
340
340
|
{ id: "calls", label: "Call OI", value: formatCompact(callTotal.callOI), color: colors.positive,
|
|
341
341
|
detail: callTotal.callChange == null ? undefined : formatCountChange(callTotal.callChange) },
|
|
342
342
|
{ id: "puts", label: "Put OI", value: formatCompact(callTotal.putOI), color: colors.negative,
|
|
343
343
|
detail: callTotal.putChange == null ? undefined : formatCountChange(callTotal.putChange) },
|
|
344
|
-
], [callTotal, colors.negative, colors.positive, colors.warning, maxPain, spot]);
|
|
344
|
+
], [callTotal, colors.negative, colors.positive, colors.warning, maxPain, spot, spotStamp]);
|
|
345
345
|
const selectedStrikeRow = strikes.find((row) => strikeKey(row) === strikeSelectedId) ?? null;
|
|
346
346
|
const strikeStrip = useMemo<ChartStripSpec | null>(() => strikeWindow.length < 3 ? null : {
|
|
347
347
|
label: "Open interest by strike",
|
|
@@ -404,9 +404,9 @@ function OptionsPositioningView({ width, height, focused, symbol }: PaneProps &
|
|
|
404
404
|
split: [{ id: "calls", value: calls, color: colors.positive }, { id: "puts", value: puts, color: colors.negative }] },
|
|
405
405
|
{ id: "pc", label: "P/C OI", value: formatRatio(calls > 0 ? puts / calls : null) },
|
|
406
406
|
{ id: "largest", label: "Largest expiry", value: expiryLabel(largest.date), detail: formatCompact(expirySize(largest)) },
|
|
407
|
-
{ id: "spot", label: "Spot", value: formatLevel(spot) },
|
|
407
|
+
{ id: "spot", label: "Spot", value: formatLevel(spot), ...spotStamp },
|
|
408
408
|
];
|
|
409
|
-
}, [changes, colors.negative, colors.positive, expiries, spot]);
|
|
409
|
+
}, [changes, colors.negative, colors.positive, expiries, spot, spotStamp]);
|
|
410
410
|
const selectedExpiryRow = expiries.find((row) => row.date === expirySelectedId) ?? null;
|
|
411
411
|
const expiryStrip = useMemo<ChartStripSpec | null>(() => expiries.length < 3 ? null : {
|
|
412
412
|
label: "Open interest by expiry",
|
|
@@ -479,7 +479,7 @@ function OptionsPositioningView({ width, height, focused, symbol }: PaneProps &
|
|
|
479
479
|
})),
|
|
480
480
|
...(band ? [{ id: "band", label: "Dealer range", value: `${formatGamma(band.low)} to ${formatGamma(band.high)}`,
|
|
481
481
|
detail: `${shares} with dealers${gammaData.boxes?.length ? ", boxes out" : ""}` }] : []),
|
|
482
|
-
{ id: "spot", label: "Spot", value: formatLevel(gammaSpot) },
|
|
482
|
+
{ id: "spot", label: "Spot", value: formatLevel(gammaSpot), ...positioningSpotDetail(gammaSpot, gammaData.spotAsOf) },
|
|
483
483
|
], [band, colors.negative, colors.positive, gammaData, gammaSpot, shares, walls]);
|
|
484
484
|
// The assumption rides in the legend, where the numbers it changes are read; the
|
|
485
485
|
// dealer range figure names its own share. It gives way before the series name does.
|
|
@@ -610,13 +610,11 @@ function OptionsPositioningView({ width, height, focused, symbol }: PaneProps &
|
|
|
610
610
|
}
|
|
611
611
|
|
|
612
612
|
return <Box width={width} height={height} flexDirection="column">
|
|
613
|
+
{tabStrip}
|
|
613
614
|
<PaneStatusBody loading={openInterest.loading && !data} error={!data ? openInterest.error : null}
|
|
614
615
|
empty={!!data && !data.expiries.length} subject="open interest"
|
|
615
616
|
emptyTitle={`No listed options for ${parsePublicTickerKey(symbol).symbol.replace(/^\^/, "")}.`}>
|
|
616
|
-
{data?.expiries.length ?
|
|
617
|
-
{tabStrip}
|
|
618
|
-
{content}
|
|
619
|
-
</> : null}
|
|
617
|
+
{data?.expiries.length ? content : null}
|
|
620
618
|
</PaneStatusBody>
|
|
621
619
|
</Box>;
|
|
622
620
|
}
|
|
@@ -6,15 +6,19 @@ import type { DataProvider } from "../../../types/data-provider";
|
|
|
6
6
|
import type { CorporateActionsData, OptionsChain, Quote, TickerFinancials } from "../../../types/financials";
|
|
7
7
|
import { canonicalExchange, parsePublicTickerKey } from "../../../utils/exchanges";
|
|
8
8
|
import { numberErrorMessage } from "../../../utils/decimal-comma";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
expiredExpiryText, expiryChoiceText, expiryDayLabel, expiryIsoDate, findListedExpiry, isLiveOptionExpiry, liveDefaultExpiry, liveOptionExpiries,
|
|
11
|
+
missingExpiryText, nextLiveExpiry,
|
|
12
|
+
} from "../../../utils/option-expiry";
|
|
10
13
|
import { surfaceTreasuryRate } from "../vol-surface/model";
|
|
11
|
-
import { daysToExpiryFrom, extractImpliedForward, optionMid, solveImpliedVolatility } from "../shared/volatility";
|
|
14
|
+
import { daysToExpiryFrom, extractImpliedForward, optionDelta, optionMid, solveImpliedVolatility, valueOption } from "../shared/volatility";
|
|
12
15
|
import type { YieldPoint } from "../yield-curve/treasury-data";
|
|
13
16
|
import { parseLegs, scenarioCurrency, validatePosition, type ScenarioControls, type ScenarioLeg, type ScenarioPosition } from "./model";
|
|
14
17
|
import { loadModelDividendYield, type ModelDividendYield } from "../../../market-data/model-dividend-yield";
|
|
15
18
|
import { abortable, abortError } from "../../../utils/async-deadline";
|
|
16
|
-
import { extendedSession } from "../options/model-spot";
|
|
19
|
+
import { extendedSession, modelSpotStamp, modelSpotStampVariants, type OptionModelSpot } from "../options/model-spot";
|
|
17
20
|
import { errorMessage } from "../../../utils/errors";
|
|
21
|
+
import { dateOptionError, dateOptionFormatsOr, readCalendarDate } from "../../../utils/calendar-date";
|
|
18
22
|
|
|
19
23
|
export interface ScenarioMarketSnapshot {
|
|
20
24
|
symbol: string;
|
|
@@ -86,10 +90,13 @@ export async function loadScenarioMarket(
|
|
|
86
90
|
const symbol = request.instrument.symbol.trim().toUpperCase();
|
|
87
91
|
const options = { forceRefresh: request.forceRefresh };
|
|
88
92
|
const warnings: string[] = [];
|
|
93
|
+
const exchange = request.instrument.exchange;
|
|
94
|
+
// An expiry whose last session has closed has no chain: the default one lists the live expiries to name instead.
|
|
95
|
+
const expired = request.expiration != null && !isLiveOptionExpiry(request.expiration, now, exchange);
|
|
89
96
|
const settled = await abortable(Promise.allSettled([
|
|
90
97
|
dependencies.loadQuote(request.instrument, options),
|
|
91
98
|
dependencies.loadSnapshot(request.instrument, options),
|
|
92
|
-
dependencies.loadOptions({ instrument: request.instrument, expirationDate: request.expiration }, options),
|
|
99
|
+
dependencies.loadOptions({ instrument: request.instrument, expirationDate: expired ? undefined : request.expiration }, options),
|
|
93
100
|
dependencies.loadYieldCurve(),
|
|
94
101
|
]), request.signal, CANCELLED);
|
|
95
102
|
if (request.signal?.aborted) throw abortError(CANCELLED);
|
|
@@ -125,31 +132,41 @@ export async function loadScenarioMarket(
|
|
|
125
132
|
if (chain && !symbolMatches(chain.underlyingSymbol, symbol)) {
|
|
126
133
|
warnings.push("Options chain does not match the requested ticker"); chain = null;
|
|
127
134
|
}
|
|
128
|
-
const expirationDates =
|
|
129
|
-
positive(expiration) && daysToExpiryFrom(expiration, now) > 0))].sort((a, b) => a - b);
|
|
135
|
+
const expirationDates = liveOptionExpiries(chain?.expirationDates ?? [], now, exchange);
|
|
130
136
|
// A typed date is that day's UTC midnight; the chain's own stamp for the
|
|
131
137
|
// expiry is matched by calendar date, as OMON matches it.
|
|
132
|
-
const listedExpiration = request.expiration == null ? undefined : findListedExpiry(request.expiration, expirationDates);
|
|
138
|
+
const listedExpiration = request.expiration == null || expired ? undefined : findListedExpiry(request.expiration, expirationDates);
|
|
133
139
|
const onExpiry = (value: OptionsChain, expiration: number) => [...value.calls, ...value.puts]
|
|
134
140
|
.every((contract) => expiryIsoDate(contract.expiration) === expiryIsoDate(expiration));
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
141
|
+
// A default chain on the expiry that lapsed at the last close gives way to the nearest live one.
|
|
142
|
+
const liveDefault = request.expiration == null && chain ? liveDefaultExpiry(chain, now, exchange) : undefined;
|
|
143
|
+
const reload = liveDefault ?? (chain && listedExpiration != null && listedExpiration !== request.expiration
|
|
144
|
+
&& !chain.calls.length && !chain.puts.length ? listedExpiration : undefined);
|
|
145
|
+
if (reload != null) {
|
|
146
|
+
// Or a source that keys chains by its exact stamp answered the midnight request empty.
|
|
147
|
+
chainEntry = await abortable(dependencies.loadOptions({ instrument: request.instrument, expirationDate: reload }, options)
|
|
138
148
|
.catch((error: unknown) => { warnings.push(`Options chain: ${errorMessage(error)}`); return null; }), request.signal, CANCELLED);
|
|
139
149
|
if (request.signal?.aborted) throw abortError(CANCELLED);
|
|
140
150
|
if (chainEntry?.error) warnings.push(`Options chain: ${chainEntry.error.message}`);
|
|
141
151
|
chain = chainEntry ? resolveEntryValue(chainEntry) : null;
|
|
142
152
|
}
|
|
143
153
|
let missingExpiry: string | undefined;
|
|
144
|
-
if (
|
|
154
|
+
if (expired) {
|
|
155
|
+
missingExpiry = sentence(`expiry ${expiryIsoDate(request.expiration!)} for ${symbol} `
|
|
156
|
+
+ expiredExpiryText(request.expiration!, expirationDates, now, { exchange, flag: "expiration" }));
|
|
157
|
+
warnings.push(missingExpiry); chain = null;
|
|
158
|
+
} else if (chain && request.expiration != null && listedExpiration == null) {
|
|
145
159
|
missingExpiry = sentence(missingExpiryText(request.expiration, expirationDates, symbol));
|
|
146
160
|
warnings.push(missingExpiry); chain = null;
|
|
147
|
-
} else if (
|
|
161
|
+
} else if (liveDefault === null) {
|
|
162
|
+
missingExpiry = `No live expiry listed for ${symbol}`;
|
|
163
|
+
warnings.push(missingExpiry); chain = null;
|
|
164
|
+
} else if (chain && (listedExpiration ?? liveDefault) != null && !onExpiry(chain, (listedExpiration ?? liveDefault)!)) {
|
|
148
165
|
warnings.push("Selected expiration unavailable in the returned options chain"); chain = null;
|
|
149
166
|
}
|
|
150
167
|
if (!chain) warnings.push("Options chain unavailable");
|
|
151
168
|
else if (chainEntry?.error || (chainEntry?.staleAt != null && chainEntry.staleAt <= now)) warnings.push("Options chain is stale");
|
|
152
|
-
const rateExpiration = request.rateExpiration ?? request.expiration ?? expirationDates[0];
|
|
169
|
+
const rateExpiration = request.rateExpiration ?? (expired ? undefined : request.expiration) ?? expirationDates[0];
|
|
153
170
|
const curve = curveResult.status === "fulfilled" ? curveResult.value : [];
|
|
154
171
|
if (curveResult.status === "rejected") warnings.push(`Treasury: ${errorMessage(curveResult.reason)}`);
|
|
155
172
|
const rate = surfaceTreasuryRate(curve, rateExpiration == null ? NaN : daysToExpiryFrom(rateExpiration, now) / 365);
|
|
@@ -191,6 +208,24 @@ export function scenarioSpotBasis(
|
|
|
191
208
|
return (market?.underlyingQuote ? extendedSession(market.underlyingQuote) : null) ?? "last price";
|
|
192
209
|
}
|
|
193
210
|
|
|
211
|
+
const EXTENDED_BASES: readonly string[] = ["pre-market", "after hours", "overnight"];
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* A spot basis as the pane and report name it: an extended-session print with
|
|
215
|
+
* its time, stamped as every options pane stamps its spot (`modelSpotStamp`),
|
|
216
|
+
* `pre-market Wed 21 Oct 09:42 UTC`; any other basis as it is.
|
|
217
|
+
*/
|
|
218
|
+
export function scenarioSpotStamp(basis: string, observedAt: number): string {
|
|
219
|
+
if (!EXTENDED_BASES.includes(basis)) return basis;
|
|
220
|
+
return modelSpotStamp({ basis: "last", session: basis as OptionModelSpot["session"], observedAt }) ?? basis;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** That stamp's shorter forms, longest first (`modelSpotStampVariants`): `pre-market 09:42 UTC`, `pre-market`. */
|
|
224
|
+
export function scenarioSpotStampVariants(basis: string, observedAt: number): string[] {
|
|
225
|
+
if (!EXTENDED_BASES.includes(basis)) return [];
|
|
226
|
+
return modelSpotStampVariants({ basis: "last", session: basis as OptionModelSpot["session"], observedAt });
|
|
227
|
+
}
|
|
228
|
+
|
|
194
229
|
function supplied(value: unknown): boolean { return value != null && value !== ""; }
|
|
195
230
|
|
|
196
231
|
/** A position typed whole: its legs and the spot, rate and dividend yield they are valued at, so no market data is read. */
|
|
@@ -207,13 +242,17 @@ function numericSetting(settings: Record<string, unknown>, key: string): number
|
|
|
207
242
|
return Number(value);
|
|
208
243
|
}
|
|
209
244
|
|
|
210
|
-
/** Dates are explicit UTC ISO timestamps or UTC calendar dates. Milliseconds are accepted in persisted state. */
|
|
245
|
+
/** Dates are explicit UTC ISO timestamps or UTC calendar dates, written as a date option takes them. Milliseconds are accepted in persisted state. */
|
|
211
246
|
function dateSetting(settings: Record<string, unknown>, key: string): number | undefined {
|
|
212
247
|
const value = settings[key];
|
|
213
248
|
if (!supplied(value)) return undefined;
|
|
214
249
|
if (typeof value === "number" && positive(value) && Number.isFinite(new Date(value).getTime())) return value;
|
|
250
|
+
const day = typeof value === "string" ? readCalendarDate(value) : null;
|
|
251
|
+
if (day) return Date.parse(`${day}T00:00:00Z`);
|
|
215
252
|
if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}(?::\d{2}(?:\.\d{1,3})?)?Z)?$/.test(value)) {
|
|
216
|
-
throw new Error(
|
|
253
|
+
throw new Error(dateOptionError(String(value), key === "asOf" ? "--as-of" : `--${key}`, {
|
|
254
|
+
subject: key === "asOf" ? "a valuation date" : "a scenario date", formats: dateOptionFormatsOr("an ISO timestamp ending in Z"),
|
|
255
|
+
}));
|
|
217
256
|
}
|
|
218
257
|
const date = Date.parse(value);
|
|
219
258
|
if (!positive(date) || new Date(date).toISOString().slice(0, 10) !== value.slice(0, 10)) throw new Error(`${key} is not a valid date`);
|
|
@@ -248,6 +287,8 @@ export function scenarioPositionFromSettings(
|
|
|
248
287
|
const strike = numericSetting(settings, "strike");
|
|
249
288
|
if (strike != null && !(strike > 0)) throw new Error("strike must be positive");
|
|
250
289
|
if (strike != null && !supplied(settings.strategy)) throw new Error("strike picks the strike of --strategy; add --strategy put, csp, vertical or straddle");
|
|
290
|
+
const delta = putDeltaSetting(settings);
|
|
291
|
+
if (delta != null && strike != null) throw new Error("delta and strike each pick the put; give one of them");
|
|
251
292
|
const collarStrikes = { put: numericSetting(settings, "putStrike"), call: numericSetting(settings, "callStrike") };
|
|
252
293
|
if ((collarStrikes.put != null || collarStrikes.call != null) && settings.strategy !== "collar") {
|
|
253
294
|
throw new Error("put-strike and call-strike pick a collar's strikes; add --strategy collar");
|
|
@@ -270,8 +311,10 @@ export function scenarioPositionFromSettings(
|
|
|
270
311
|
}
|
|
271
312
|
if (spot == null) throw new Error("A current underlying price or explicit --spot is required");
|
|
272
313
|
// Leg IVs are solved at the market's own spot and time, never at a what-if override.
|
|
273
|
-
const pricing = market.spot != null && rate != null ? { spot: market.spot, asOf: market.asOf, rate } : null;
|
|
274
|
-
|
|
314
|
+
const pricing = market.spot != null && rate != null ? { spot: market.spot, asOf: market.asOf, rate, dividendYield: dividendYield ?? 0 } : null;
|
|
315
|
+
if (delta != null && !pricing) throw new Error("Choosing the put by delta needs the Treasury rate; supply --rate, or pick it with --strike");
|
|
316
|
+
const seeded = scenarioStrategyLegs(market.chain, spot, settings.strategy, pricing, strike, collarStrikes, delta,
|
|
317
|
+
unusableChainText(market, exchange));
|
|
275
318
|
legs = seeded.legs;
|
|
276
319
|
shareEntry = market.spot;
|
|
277
320
|
// Mids priced off the parity forward are worth their cost only at the spot
|
|
@@ -308,6 +351,19 @@ export function scenarioPositionFromSettings(
|
|
|
308
351
|
return position;
|
|
309
352
|
}
|
|
310
353
|
|
|
354
|
+
/**
|
|
355
|
+
* `--delta`: the put a csp or put seed sells or buys, by the absolute delta it
|
|
356
|
+
* is nearest (0.30, or -0.30 as a put's own sign reads it); undefined when not set.
|
|
357
|
+
*/
|
|
358
|
+
function putDeltaSetting(settings: Record<string, unknown>): number | undefined {
|
|
359
|
+
const value = numericSetting(settings, "delta");
|
|
360
|
+
if (value == null) return undefined;
|
|
361
|
+
if (settings.strategy !== "csp" && settings.strategy !== "put") throw new Error("delta picks the put of --strategy csp or put");
|
|
362
|
+
const delta = Math.abs(value);
|
|
363
|
+
if (!(delta > 0 && delta < 1)) throw new Error(`delta must be a put's delta between 0 and 1, such as 0.30; got ${String(settings.delta)}`);
|
|
364
|
+
return delta;
|
|
365
|
+
}
|
|
366
|
+
|
|
311
367
|
/** `--shares`: a signed whole number of shares of the underlying, or undefined when not set. */
|
|
312
368
|
function sharesSetting(settings: Record<string, unknown>): number | undefined {
|
|
313
369
|
const value = settings.shares;
|
|
@@ -328,7 +384,7 @@ export const SCENARIO_STRATEGIES = ["vertical", "straddle", "put", "csp", "colla
|
|
|
328
384
|
type ScenarioStrategy = typeof SCENARIO_STRATEGIES[number];
|
|
329
385
|
const isScenarioStrategy = (value: unknown): value is ScenarioStrategy => SCENARIO_STRATEGIES.includes(value as ScenarioStrategy);
|
|
330
386
|
|
|
331
|
-
interface StrategyPricing { spot: number; asOf: number; rate: number }
|
|
387
|
+
interface StrategyPricing { spot: number; asOf: number; rate: number; dividendYield: number }
|
|
332
388
|
|
|
333
389
|
const usableVolatility = (value: unknown): value is number => positive(value) && value <= 5;
|
|
334
390
|
|
|
@@ -339,8 +395,8 @@ interface StrategyParity { forward: number; daysToExpiry: number }
|
|
|
339
395
|
* at its quote midpoint, so each leg takes the IV that midpoint implies against
|
|
340
396
|
* the expiry's put-call parity forward, with the time left at the market
|
|
341
397
|
* timestamp OSA values at. This holds even when the chain carries a provider
|
|
342
|
-
* IV measured at another time (a same-day IV solved
|
|
343
|
-
* hours
|
|
398
|
+
* IV measured at another time (a same-day IV solved at the close's quotes,
|
|
399
|
+
* hours before the after-hours print OSA values at). The forward comes from the
|
|
344
400
|
* same quotes, so a spot that moved after they were taken (an after-hours or
|
|
345
401
|
* pre-market print against the close's chain) does not skew the call against
|
|
346
402
|
* the put. A leg whose midpoint cannot be solved (a spot too far from every
|
|
@@ -355,10 +411,12 @@ interface StrategyParity { forward: number; daysToExpiry: number }
|
|
|
355
411
|
* to the next listed strike up, or a straddle at the anchor. A collar buys
|
|
356
412
|
* the put at `collar.put` and sells the call at `collar.call` on the put's
|
|
357
413
|
* expiry, each the quoted strike nearest 10% out of the money when omitted.
|
|
414
|
+
* A put or csp seed given a `delta` takes the put whose spot delta, valued at
|
|
415
|
+
* the IV its own midpoint implies, is nearest that delta's negative.
|
|
358
416
|
*/
|
|
359
417
|
function scenarioStrategyLegs(
|
|
360
418
|
chain: OptionsChain, spot: number, strategy: ScenarioStrategy, pricing: StrategyPricing | null, strike?: number,
|
|
361
|
-
collar: { put?: number; call?: number } = {},
|
|
419
|
+
collar: { put?: number; call?: number } = {}, delta?: number, unusable: UnusableChainText = defaultUnusableChainText,
|
|
362
420
|
): { legs: ScenarioLeg[]; parity: StrategyParity | null } {
|
|
363
421
|
const parity = new Map<number, StrategyParity | null>();
|
|
364
422
|
const parityFor = (expiration: number) => {
|
|
@@ -388,15 +446,16 @@ function scenarioStrategyLegs(
|
|
|
388
446
|
const calls = quoted(chain.calls, "call").sort(nearest);
|
|
389
447
|
const puts = quoted(chain.puts, "put").sort(nearest);
|
|
390
448
|
const missing = (candidates: { contract: { strike: number } }[], at = strike, what: string = strategy === "csp" ? "put to sell" : strategy) => {
|
|
391
|
-
if (at == null) return new Error("
|
|
449
|
+
if (at == null) return new Error(unusable("strategy"));
|
|
392
450
|
const listed = [...new Set(candidates.map(({ contract }) => contract.strike))]
|
|
393
451
|
.sort((a, b) => Math.abs(a - at) - Math.abs(b - at)).slice(0, 4).sort((a, b) => a - b);
|
|
394
|
-
|
|
395
|
-
|
|
452
|
+
// Another strike on this expiry is the nearer fix; with none quoted, the next expiry is.
|
|
453
|
+
return new Error(listed.length ? `${unusable(`${what} at strike ${at}`, false)}; nearest quoted strikes: ${listed.join(", ")}`
|
|
454
|
+
: unusable(`${what} at strike ${at}`));
|
|
396
455
|
};
|
|
397
|
-
if (strategy === "collar") return collarLegs(calls, puts, spot, collar, missing, parityFor);
|
|
456
|
+
if (strategy === "collar") return collarLegs(calls, puts, spot, collar, missing, parityFor, unusable);
|
|
398
457
|
if (strategy === "put" || strategy === "csp") {
|
|
399
|
-
const put = puts.find(anchored);
|
|
458
|
+
const put = delta == null ? puts.find(anchored) : nearestDelta(puts, -delta, spot, pricing, parityFor);
|
|
400
459
|
if (!put) throw missing(puts);
|
|
401
460
|
return { legs: [{ id: put.contract.contractSymbol, side: "put", quantity: strategy === "csp" ? -1 : 1, strike: put.contract.strike,
|
|
402
461
|
expiration: put.contract.expiration, price: put.mid, priceSource: "mid", volatility: put.volatility, multiplier: 100,
|
|
@@ -423,6 +482,60 @@ function scenarioStrategyLegs(
|
|
|
423
482
|
|
|
424
483
|
interface QuotedContract { contract: OptionsChain["calls"][number]; mid: number; volatility: number; solved: boolean }
|
|
425
484
|
|
|
485
|
+
/** Why a chain seeds nothing: `what` it has no usable quote for, then the next live expiry to try unless `next` is false. */
|
|
486
|
+
type UnusableChainText = (what: string, next?: boolean) => string;
|
|
487
|
+
const defaultUnusableChainText: UnusableChainText = (what) => `The selected chain has no complete quoted ${what} with usable IV`;
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* The seed failure naming the expiry the chain is on and the next live one to
|
|
491
|
+
* ask for: `The 30 Oct chain has no complete quoted strategy with usable IV;
|
|
492
|
+
* try the next expiry, 6 Nov (--expiration 2026-11-06)`.
|
|
493
|
+
*/
|
|
494
|
+
function unusableChainText(market: ScenarioMarketSnapshot, exchange: string | undefined): UnusableChainText {
|
|
495
|
+
const contracts = market.chain ? [...market.chain.calls, ...market.chain.puts] : [];
|
|
496
|
+
const tried = contracts[0]?.expiration;
|
|
497
|
+
if (tried == null) return defaultUnusableChainText;
|
|
498
|
+
const now = market.asOf;
|
|
499
|
+
const next = nextLiveExpiry(tried, market.expirationDates, now, exchange ?? market.exchange);
|
|
500
|
+
return (what, withNext = true) => `The ${expiryDayLabel(tried, now)} chain has no complete quoted ${what} with usable IV`
|
|
501
|
+
+ (withNext && next != null ? `; try the next expiry, ${expiryChoiceText(next, now, "expiration")}` : "");
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* A put's spot delta at the IV it trades at: against the parity forward its
|
|
506
|
+
* IV was solved on when it was (forward delta, carried to spot), else at the
|
|
507
|
+
* seed's spot. Null when it cannot be valued.
|
|
508
|
+
*/
|
|
509
|
+
function quotedPutDelta(quoted: QuotedContract, spot: number, pricing: StrategyPricing | null, parity: StrategyParity | null): number | null {
|
|
510
|
+
const { contract, volatility, solved } = quoted;
|
|
511
|
+
if (!pricing) return null;
|
|
512
|
+
if (solved && parity) {
|
|
513
|
+
// On the forward, with the dividend yield set to the rate so it carries no drift, as the IV was solved.
|
|
514
|
+
const forwardDelta = valueOption({ side: "put", spot: parity.forward, strike: contract.strike, daysToExpiry: parity.daysToExpiry,
|
|
515
|
+
rate: pricing.rate, dividendYield: pricing.rate, volatility }).delta;
|
|
516
|
+
return Number.isFinite(forwardDelta) ? forwardDelta * Math.exp((pricing.rate - pricing.dividendYield) * parity.daysToExpiry / 365) : null;
|
|
517
|
+
}
|
|
518
|
+
const years = daysToExpiryFrom(contract.expiration, pricing.asOf) / 365;
|
|
519
|
+
return optionDelta({ spot, years, volatility, rate: pricing.rate, dividendYield: pricing.dividendYield }, contract.strike, "put");
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/** The put whose delta is nearest `target` (negative, as a put's delta reads), the lower strike on a tie; null when none can be valued. */
|
|
523
|
+
function nearestDelta(
|
|
524
|
+
puts: readonly QuotedContract[], target: number, spot: number, pricing: StrategyPricing | null,
|
|
525
|
+
parityFor: (expiration: number) => StrategyParity | null,
|
|
526
|
+
): QuotedContract | null {
|
|
527
|
+
let best: { put: QuotedContract; distance: number } | null = null;
|
|
528
|
+
for (const put of puts) {
|
|
529
|
+
const delta = quotedPutDelta(put, spot, pricing, put.solved ? parityFor(put.contract.expiration) : null);
|
|
530
|
+
if (delta == null) continue;
|
|
531
|
+
const distance = Math.abs(delta - target);
|
|
532
|
+
if (!best || distance < best.distance - 1e-12 || (Math.abs(distance - best.distance) <= 1e-12 && put.contract.strike < best.put.contract.strike)) {
|
|
533
|
+
best = { put, distance };
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
return best?.put ?? null;
|
|
537
|
+
}
|
|
538
|
+
|
|
426
539
|
/** How far out of the money a collar's put and call sit when their strikes are not given. */
|
|
427
540
|
const COLLAR_DEFAULT_DISTANCE = 0.1;
|
|
428
541
|
|
|
@@ -430,18 +543,18 @@ const COLLAR_DEFAULT_DISTANCE = 0.1;
|
|
|
430
543
|
function collarLegs(
|
|
431
544
|
calls: QuotedContract[], puts: QuotedContract[], spot: number, strikes: { put?: number; call?: number },
|
|
432
545
|
missing: (candidates: QuotedContract[], at: number | undefined, what: string) => Error,
|
|
433
|
-
parityFor: (expiration: number) => StrategyParity | null,
|
|
546
|
+
parityFor: (expiration: number) => StrategyParity | null, unusable: UnusableChainText,
|
|
434
547
|
): { legs: ScenarioLeg[]; parity: StrategyParity | null } {
|
|
435
548
|
const closest = (candidates: QuotedContract[], target: number) => candidates.toSorted((a, b) =>
|
|
436
549
|
Math.abs(a.contract.strike - target) - Math.abs(b.contract.strike - target) || a.contract.strike - b.contract.strike);
|
|
437
550
|
const at = (candidates: QuotedContract[], value: number) => candidates.filter(({ contract }) => Math.abs(contract.strike - value) < 1e-9);
|
|
438
551
|
const put = strikes.put != null ? at(puts, strikes.put)[0]
|
|
439
552
|
: closest(puts.filter(({ contract }) => strikes.call == null || contract.strike < strikes.call), spot * (1 - COLLAR_DEFAULT_DISTANCE))[0];
|
|
440
|
-
if (!put) throw strikes.put != null ? missing(puts, strikes.put, "put to buy") : new Error("
|
|
553
|
+
if (!put) throw strikes.put != null ? missing(puts, strikes.put, "put to buy") : new Error(unusable("put to buy"));
|
|
441
554
|
const sameExpiry = calls.filter(({ contract }) => contract.expiration === put.contract.expiration);
|
|
442
555
|
const call = strikes.call != null ? at(sameExpiry, strikes.call)[0]
|
|
443
556
|
: closest(sameExpiry.filter(({ contract }) => contract.strike > put.contract.strike), spot * (1 + COLLAR_DEFAULT_DISTANCE))[0];
|
|
444
|
-
if (!call) throw strikes.call != null ? missing(sameExpiry, strikes.call, "call to sell") : new Error("
|
|
557
|
+
if (!call) throw strikes.call != null ? missing(sameExpiry, strikes.call, "call to sell") : new Error(unusable("call to sell above the put"));
|
|
445
558
|
if (call.contract.strike <= put.contract.strike) throw new Error("A collar's put strike must be below its call strike");
|
|
446
559
|
if (put.contract.currency !== call.contract.currency) throw new Error("Strategy quote currencies differ");
|
|
447
560
|
const legs = [[put, "put", 1], [call, "call", -1]] as const;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { StatItem } from "../../../components";
|
|
2
2
|
import type { HeadlessPaneEntry } from "../../../types/headless";
|
|
3
3
|
import { formatHedgePrice } from "./hedge";
|
|
4
|
-
import { UNKNOWN_CURRENCY, type ScenarioPosition } from "./model";
|
|
4
|
+
import { amountUnit, UNKNOWN_CURRENCY, type ScenarioPosition } from "./model";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* A collar (docs/research-data.md#collar): one long put and one short call on
|
|
@@ -104,17 +104,19 @@ function boundText(collar: Collar, value: number | null, side: "put" | "call"):
|
|
|
104
104
|
export function collarReportEntries(collar: Collar): HeadlessPaneEntry[] {
|
|
105
105
|
const unit = unitOf(collar);
|
|
106
106
|
const premium = Math.abs(collar.netPremium);
|
|
107
|
+
// Every figure is per share, so an export writes the number with that unit.
|
|
108
|
+
const perShare = { unit: `${amountUnit(collar.currency)} per share` };
|
|
107
109
|
return [
|
|
108
|
-
{ key: "putBought", label: "Put bought", value: collar.put.price,
|
|
110
|
+
{ key: "putBought", label: "Put bought", value: collar.put.price, ...perShare,
|
|
109
111
|
formatted: `${strikeText(collar.put.strike)} put at ${formatHedgePrice(collar.put.price)} per share (${priceWord(collar.put)})` },
|
|
110
|
-
{ key: "callSold", label: "Call sold", value: collar.call.price,
|
|
112
|
+
{ key: "callSold", label: "Call sold", value: collar.call.price, ...perShare,
|
|
111
113
|
formatted: `${strikeText(collar.call.strike)} call at ${formatHedgePrice(collar.call.price)} per share (${priceWord(collar.call)})` },
|
|
112
|
-
{ key: "netPremium", label: "Net premium", value: collar.netPremium,
|
|
114
|
+
{ key: "netPremium", label: "Net premium", value: collar.netPremium, ...perShare,
|
|
113
115
|
formatted: collar.netPremium === 0 ? `0.00 per share (zero cost)`
|
|
114
116
|
: `${formatHedgePrice(premium)} per share ${premiumWord(collar)} (${money(Math.abs(collar.netPremiumTotal))}${unit} `
|
|
115
117
|
+ `for ${collar.contracts.toLocaleString("en-US")} ${collar.contracts === 1 ? "contract" : "contracts"} each)` },
|
|
116
|
-
{ key: "floor", label: "Floor", value: collar.floor, formatted: boundText(collar, collar.floor, "put") },
|
|
117
|
-
{ key: "cap", label: "Cap", value: collar.cap, formatted: boundText(collar, collar.cap, "call") },
|
|
118
|
+
{ key: "floor", label: "Floor", value: collar.floor, ...perShare, formatted: boundText(collar, collar.floor, "put") },
|
|
119
|
+
{ key: "cap", label: "Cap", value: collar.cap, ...perShare, formatted: boundText(collar, collar.cap, "call") },
|
|
118
120
|
];
|
|
119
121
|
}
|
|
120
122
|
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type { HeadlessPaneColumn, HeadlessPaneDefinition } from "../../../types/plugin";
|
|
2
|
+
import { expirationOptionSeconds, OPTION_EXPIRATION_FORMAT, OPTION_EXPIRATION_PLACEHOLDER } from "../../../utils/option-expiry";
|
|
3
|
+
import { resolveHeadlessInstrument } from "../shared/headless-market-data";
|
|
4
|
+
import { createScenarioDependencies } from "./client";
|
|
5
|
+
import { formatHedgePrice } from "./hedge";
|
|
6
|
+
import { exportPercent } from "./model";
|
|
7
|
+
import {
|
|
8
|
+
CSP_SCREEN_DEFAULTS, CSP_SCREEN_LIMIT, cspEarningsText, cspScreenCriteriaText, loadCspScreen, readCspScreenCriteria,
|
|
9
|
+
type CspScreen, type CspScreenRow,
|
|
10
|
+
} from "./csp-screen";
|
|
11
|
+
|
|
12
|
+
const percentCell = (digits: number) => (value: unknown) => typeof value === "number" ? `${value.toFixed(digits)}%` : "--";
|
|
13
|
+
const priceCell = (value: unknown) => typeof value === "number" ? formatHedgePrice(value) : "--";
|
|
14
|
+
const strikeCell = (value: unknown) => typeof value === "number" ? String(value) : "--";
|
|
15
|
+
|
|
16
|
+
/** One name's row, flat, every percent in percent. */
|
|
17
|
+
export type CspScreenReportRow = {
|
|
18
|
+
rank: number | null; symbol: string; expiry: string | null; days: number | null; strike: number | null;
|
|
19
|
+
bid: number | null; ask: number | null; spread: number | null; wide: boolean | null; delta: number | null; otm: number | null;
|
|
20
|
+
midYield: number | null; bidYield: number | null; ivRank: number | null;
|
|
21
|
+
earnings: string; earningsBeforeExpiry: boolean | null; earningsDate: string | null; spot: number | null; note: string | null;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export function cspScreenReportRow(row: CspScreenRow): CspScreenReportRow {
|
|
25
|
+
const { csp } = row;
|
|
26
|
+
return {
|
|
27
|
+
rank: row.rank, symbol: row.symbol,
|
|
28
|
+
expiry: csp?.expiry ?? null, days: csp?.daysToExpiry ?? null, strike: csp?.strike ?? null,
|
|
29
|
+
bid: csp?.quote?.bid ?? null, ask: csp?.quote?.ask ?? null, spread: exportPercent(csp?.quote?.spreadOfMid), wide: csp?.quote ? row.wideSpread : null,
|
|
30
|
+
delta: row.delta, otm: exportPercent(csp?.outOfTheMoney), midYield: exportPercent(csp?.annualizedYield),
|
|
31
|
+
bidYield: exportPercent(csp?.quote?.bidAnnualizedYield), ivRank: row.ivRank,
|
|
32
|
+
earnings: cspEarningsText(csp), earningsBeforeExpiry: csp ? csp.earnings.beforeExpiry : null, earningsDate: csp?.earnings.date ?? null,
|
|
33
|
+
spot: csp?.spot ?? null, note: row.note,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const COLUMNS: HeadlessPaneColumn[] = [
|
|
38
|
+
{ key: "rank", header: "#", align: "right", format: (value) => typeof value === "number" ? String(value) : "" },
|
|
39
|
+
{ key: "symbol", header: "Symbol" },
|
|
40
|
+
{ key: "expiry", header: "Expiry" },
|
|
41
|
+
{ key: "days", header: "DTE", align: "right" },
|
|
42
|
+
{ key: "strike", header: "Strike", align: "right", format: strikeCell },
|
|
43
|
+
{ key: "bid", header: "Bid", align: "right", format: priceCell },
|
|
44
|
+
{ key: "ask", header: "Ask", align: "right", format: priceCell },
|
|
45
|
+
// The text view marks a wide spread in its cell; exports keep the number and say so in Wide.
|
|
46
|
+
{ key: "spread", header: "Spread", align: "right", format: percentCell(1),
|
|
47
|
+
textFormat: (value, row) => `${percentCell(1)(value)}${row.wide ? " wide" : ""}` },
|
|
48
|
+
{ key: "delta", header: "Delta", align: "right", format: (value) => typeof value === "number" ? value.toFixed(2) : "--" },
|
|
49
|
+
{ key: "otm", header: "OTM", align: "right", format: percentCell(1) },
|
|
50
|
+
{ key: "midYield", header: "Mid yield/yr", align: "right", format: percentCell(2) },
|
|
51
|
+
{ key: "bidYield", header: "Bid yield/yr", align: "right", format: percentCell(2) },
|
|
52
|
+
{ key: "ivRank", header: "IVR", align: "right", format: (value) => typeof value === "number" ? value.toFixed(0) : "--" },
|
|
53
|
+
{ key: "earnings", header: "Earnings" },
|
|
54
|
+
];
|
|
55
|
+
const NOTE: HeadlessPaneColumn = { key: "note", header: "Note", underRow: true };
|
|
56
|
+
const EXPORT_ONLY: HeadlessPaneColumn[] = [
|
|
57
|
+
{ key: "wide", header: "Wide spread", format: (value) => value === true ? "yes" : value === false ? "no" : "" },
|
|
58
|
+
{ key: "earningsBeforeExpiry", header: "Earnings before expiry", format: (value) => value === true ? "yes" : value === false ? "no" : "unknown" },
|
|
59
|
+
{ key: "earningsDate", header: "Earnings date" },
|
|
60
|
+
{ key: "spot", header: "Spot", format: priceCell },
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
/** `A`, `A and B`, `A, B and C`. */
|
|
64
|
+
const listText = (items: readonly string[]) => items.length <= 1 ? items.join("") : `${items.slice(0, -1).join(", ")} and ${items.at(-1)}`;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The ranking basis and the wide flag's limit, then the names IV history has no
|
|
68
|
+
* rank for: those with a reason say it (`No IV rank: BBB (fewer than 120
|
|
69
|
+
* sessions).`), and a bare symbol, which has none to give, is just not ranked
|
|
70
|
+
* yet (`No IV rank for DAL yet.`).
|
|
71
|
+
*/
|
|
72
|
+
export function cspScreenNotes(screen: Pick<CspScreen, "criteria" | "missingRanks">): string[] {
|
|
73
|
+
const reasoned = screen.missingRanks.filter((entry) => entry.includes(" "));
|
|
74
|
+
const bare = screen.missingRanks.filter((entry) => !entry.includes(" "));
|
|
75
|
+
return [
|
|
76
|
+
`Ranked by annualised yield at the bid. Wide is a spread over ${screen.criteria.maxSpreadPercent}% of the mid (--max-spread).`,
|
|
77
|
+
...(reasoned.length ? [`No IV rank: ${reasoned.join(", ")}.`] : []),
|
|
78
|
+
...(bare.length ? [`No IV rank for ${listText(bare)} yet.`] : []),
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export const cspScreenHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
83
|
+
shape: "rows",
|
|
84
|
+
argument: { kind: "tickers", maximum: CSP_SCREEN_LIMIT, description: "US option underlyings to rank" },
|
|
85
|
+
usListingsOnly: "Options data",
|
|
86
|
+
failsWithoutData: true,
|
|
87
|
+
description: "Cash-secured puts across a list, ranked by annualised yield on cash at the bid: for each name, the put nearest a delta "
|
|
88
|
+
+ "(0.30) on the listed expiry nearest a date or a number of days out (30), with its strike, bid, ask, spread (flagged wide over "
|
|
89
|
+
+ "--max-spread, never left out), delta, distance out of the money, yield at the mid and at the bid, IV rank and whether earnings fall before expiry.",
|
|
90
|
+
discovery: { screenshotReadiness: "live-dom", dataRequirements: ["Current option chains", "Cloud stored implied volatility", "Earnings calendar"],
|
|
91
|
+
limitations: ["Assignment, margin and the interest the cash earns are not modelled."] },
|
|
92
|
+
describe: (_args, result) => {
|
|
93
|
+
const criteria = (result?.metadata as { criteria?: CspScreen["criteria"] } | undefined)?.criteria;
|
|
94
|
+
return ["Cash-secured puts", ...(criteria ? [cspScreenCriteriaText(criteria, Date.now())] : [])].join(" · ");
|
|
95
|
+
},
|
|
96
|
+
options: [
|
|
97
|
+
{ key: "delta", type: "string", placeholder: "0.30", example: "--delta 0.20",
|
|
98
|
+
description: `Each name's put is the one whose delta is nearest this, as a put's delta reads without its sign. Default ${CSP_SCREEN_DEFAULTS.delta.toFixed(2)}` },
|
|
99
|
+
{ key: "days", type: "string", placeholder: "days", example: "--days 45",
|
|
100
|
+
description: `Each name's expiry is its listed one nearest this many calendar days out. Default ${CSP_SCREEN_DEFAULTS.days}` },
|
|
101
|
+
{ key: "expiration", type: "string", placeholder: OPTION_EXPIRATION_PLACEHOLDER, example: "--expiration 2026-11-20",
|
|
102
|
+
description: `Each name's expiry is its listed one nearest this date, in place of --days, as ${OPTION_EXPIRATION_FORMAT}`,
|
|
103
|
+
normalize: (value) => expirationOptionSeconds(value) },
|
|
104
|
+
{ key: "maxSpread", aliases: ["max-spread"], type: "string", placeholder: "percent", example: "--max-spread 15",
|
|
105
|
+
description: `A put whose bid/ask spread is over this percent of its mid is marked wide; it is still ranked. Default ${CSP_SCREEN_DEFAULTS.maxSpreadPercent}` },
|
|
106
|
+
],
|
|
107
|
+
async load(args, ctx) {
|
|
108
|
+
const criteria = readCspScreenCriteria(args.options);
|
|
109
|
+
const instruments = await Promise.all(args.symbols.map((symbol) => resolveHeadlessInstrument(ctx, symbol)));
|
|
110
|
+
const screen = await loadCspScreen(instruments, criteria, {
|
|
111
|
+
scenario: createScenarioDependencies(ctx.marketData, ctx.apiClient), earnings: ctx.marketData, ivApi: ctx.apiClient,
|
|
112
|
+
}, ctx.signal);
|
|
113
|
+
const unavailable = screen.rows.filter((row) => !row.csp);
|
|
114
|
+
return {
|
|
115
|
+
freshness: screen.freshness,
|
|
116
|
+
columns: [...COLUMNS, ...EXPORT_ONLY, NOTE],
|
|
117
|
+
textColumns: [...COLUMNS, NOTE],
|
|
118
|
+
rows: screen.rows.map(cspScreenReportRow),
|
|
119
|
+
complete: unavailable.length === 0 && !screen.ivRankError,
|
|
120
|
+
unavailableSymbols: unavailable.map((row) => row.symbol),
|
|
121
|
+
errors: screen.ivRankError ? [`IV rank unavailable: ${screen.ivRankError}`] : [],
|
|
122
|
+
notes: cspScreenNotes(screen),
|
|
123
|
+
metadata: { criteria: screen.criteria, rankedBy: "annualized yield on cash at the bid", unit: "percent; prices per share",
|
|
124
|
+
methodology: "docs/research-data.md#cash-secured-put-screen" },
|
|
125
|
+
};
|
|
126
|
+
},
|
|
127
|
+
};
|