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
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { startCatalystAlerts } from "./catalysts";
|
|
2
|
-
import {
|
|
2
|
+
import { notTheCoinNote } from "../../../cli/commands/crypto-hints";
|
|
3
|
+
import { createFiredAlertRecorder, firedAlertTime, quoteSourceWords } from "./fired-log";
|
|
4
|
+
import { checkIvLevelAlertsNow, startIvLevelAlerts } from "./iv-level";
|
|
5
|
+
import { logFailure } from "../../../utils/log-failure";
|
|
6
|
+
import { RESEARCH_FORM_KINDS, RESEARCH_LABELS, researchWizardFields, createResearchAlert } from "./research-builder";
|
|
3
7
|
import { newYorkToday } from "../earnings/board-model";
|
|
4
8
|
import { checkScheduledEventAlertsNow, startScheduledEventAlerts } from "./scheduled-check";
|
|
5
9
|
import { scheduledEventSources } from "./scheduled-sources";
|
|
@@ -12,7 +16,7 @@ import {
|
|
|
12
16
|
scheduledTargetKey,
|
|
13
17
|
} from "./scheduled";
|
|
14
18
|
import { isResearchAlertKind, MAX_LEAD_DAYS } from "./research-rules";
|
|
15
|
-
import {
|
|
19
|
+
import { EVENT_ALERT_TEMPLATES, MAX_EVENT_ALERTS, createEventAlert, eventAlertStoreKey, readEventAlertStores, updateEventAlerts } from "./events";
|
|
16
20
|
import { formatMarketPrice } from "../../../market-data/market/format";
|
|
17
21
|
import { settleTypedListingKey } from "../../../tickers/listing-venues";
|
|
18
22
|
import type { Quote } from "../../../types/financials";
|
|
@@ -32,6 +36,7 @@ import { AlertsPane } from "./pane";
|
|
|
32
36
|
import { alertsCliCommand } from "./cli";
|
|
33
37
|
import {
|
|
34
38
|
createQuoteErrorMessage,
|
|
39
|
+
farTargetMessage,
|
|
35
40
|
quoteAlertFields,
|
|
36
41
|
quoteErrorAlertFields,
|
|
37
42
|
resolveAlertQuote,
|
|
@@ -45,6 +50,7 @@ import type { AlertRule } from "./types";
|
|
|
45
50
|
|
|
46
51
|
let catalystAlertsStop: (() => void) | null = null;
|
|
47
52
|
let scheduledAlertsStop: (() => void) | null = null;
|
|
53
|
+
let ivLevelAlertsStop: (() => void) | null = null;
|
|
48
54
|
let pollGeneration = 0;
|
|
49
55
|
let pollTimer: ReturnType<typeof setTimeout> | null = null;
|
|
50
56
|
let alertStream: AlertQuoteStream | null = null;
|
|
@@ -66,11 +72,22 @@ export const alertsPlugin: GloomPlugin = {
|
|
|
66
72
|
|
|
67
73
|
setup(ctx) {
|
|
68
74
|
const generation = ++pollGeneration;
|
|
75
|
+
// Every alert the app fires is kept on this device, for History and `fn ALRT --tab history`.
|
|
76
|
+
const recordFired = createFiredAlertRecorder(ctx.resume, logFailure("alerts.fired-log", "Record fired alert failed"));
|
|
69
77
|
catalystAlertsStop?.();
|
|
70
78
|
catalystAlertsStop = startCatalystAlerts(ctx);
|
|
71
79
|
scheduledAlertsStop?.();
|
|
72
|
-
scheduledAlertsStop = startScheduledEventAlerts(ctx, scheduledEventSources(ctx.marketData));
|
|
73
|
-
|
|
80
|
+
scheduledAlertsStop = startScheduledEventAlerts(ctx, scheduledEventSources(ctx.marketData), Date.now, recordFired);
|
|
81
|
+
ivLevelAlertsStop?.();
|
|
82
|
+
ivLevelAlertsStop = startIvLevelAlerts(ctx, recordFired);
|
|
83
|
+
const notifyTriggered = (alert: AlertRule, quote: Quote, firedAt: number) => {
|
|
84
|
+
const price = quote.price;
|
|
85
|
+
recordFired({
|
|
86
|
+
kind: "price", ruleId: alert.id, rule: `${alert.exchange ? `${alert.symbol}:${alert.exchange}` : alert.symbol} ${alert.condition} ${alert.targetPrice}`,
|
|
87
|
+
firedAt, value: price, ...(quote.currency ? { unit: quote.currency } : {}),
|
|
88
|
+
quoteAt: firedAlertTime(quote.lastUpdated), source: quoteSourceWords(quote.dataSource),
|
|
89
|
+
symbol: alert.symbol, ...(alert.exchange ? { exchange: alert.exchange } : {}),
|
|
90
|
+
});
|
|
74
91
|
ctx.notify({
|
|
75
92
|
body: `${formatAlertDescription(alert)} triggered at ${price}`,
|
|
76
93
|
type: "success",
|
|
@@ -110,7 +127,7 @@ export const alertsPlugin: GloomPlugin = {
|
|
|
110
127
|
alert.status = "triggered";
|
|
111
128
|
alert.triggeredAt = now;
|
|
112
129
|
ctx.log.info("stream: TRIGGERED", { symbol: alert.symbol, price: quote.price });
|
|
113
|
-
notifyTriggered(alert, quote
|
|
130
|
+
notifyTriggered(alert, quote, now);
|
|
114
131
|
persist = true;
|
|
115
132
|
}
|
|
116
133
|
streamedBaselines.set(alert.id, quote.price);
|
|
@@ -119,7 +136,7 @@ export const alertsPlugin: GloomPlugin = {
|
|
|
119
136
|
}
|
|
120
137
|
if (!persist && !(touched && now - lastStreamPersistAt >= STREAM_PERSIST_MS)) return;
|
|
121
138
|
lastStreamPersistAt = now;
|
|
122
|
-
saveAlerts(ctx, alerts);
|
|
139
|
+
void saveAlerts(ctx, alerts).catch(logFailure("alerts.stream", "Save streamed price alerts failed"));
|
|
123
140
|
if (persist) alertStream?.sync();
|
|
124
141
|
};
|
|
125
142
|
alertStream?.dispose();
|
|
@@ -168,6 +185,9 @@ export const alertsPlugin: GloomPlugin = {
|
|
|
168
185
|
const symbol = (await settleTypedListingKey(input.symbol, { store: ctx.tickerRepository, dataProvider: ctx.marketData })).toUpperCase();
|
|
169
186
|
|
|
170
187
|
const quote = await resolveAlertQuote(ctx.marketData, symbol);
|
|
188
|
+
// A target ten times away is a slip or another instrument's price, such as bitcoin's on the BTC fund.
|
|
189
|
+
const far = farTargetMessage(symbol, input.price, quote.price, symbol.includes(":") ? null : notTheCoinNote(symbol, quote));
|
|
190
|
+
if (far) throw new Error(far);
|
|
171
191
|
|
|
172
192
|
const alert = {
|
|
173
193
|
...createAlert(quote.symbol || symbol, input.condition, input.price),
|
|
@@ -175,7 +195,7 @@ export const alertsPlugin: GloomPlugin = {
|
|
|
175
195
|
};
|
|
176
196
|
const existing = loadAlerts(ctx);
|
|
177
197
|
existing.push(alert);
|
|
178
|
-
saveAlerts(ctx, existing);
|
|
198
|
+
await saveAlerts(ctx, existing);
|
|
179
199
|
alertStream?.sync();
|
|
180
200
|
|
|
181
201
|
ctx.notify({
|
|
@@ -188,11 +208,11 @@ export const alertsPlugin: GloomPlugin = {
|
|
|
188
208
|
ctx.registerCommand({
|
|
189
209
|
id: "set-event-alert",
|
|
190
210
|
label: "Add Event Alert",
|
|
191
|
-
description: "Create an alert before earnings, CPI or FOMC, or for filings, news and market moves",
|
|
211
|
+
description: "Create an alert before earnings, CPI or FOMC, when earnings results are out, or for filings, news, IV levels, hiring and market moves",
|
|
192
212
|
keywords: [
|
|
193
213
|
"alert", "event", "congress", "13f", "fund", "member", "follow", "earnings", "cpi", "fomc", "days before",
|
|
194
214
|
"filing", "filings", "sec", "8-k", "news", "keyword", "analyst", "52-week", "unusual volume", "volume",
|
|
195
|
-
"short interest", "insider", "catalyst", "implied volatility", "iv spike", "options flow", "perps", "funding",
|
|
215
|
+
"short interest", "insider", "catalyst", "implied volatility", "iv spike", "iv level", "risk reversal", "skew", "options flow", "perps", "funding", "hiring", "jobs",
|
|
196
216
|
],
|
|
197
217
|
category: "data",
|
|
198
218
|
wizardLayout: "form",
|
|
@@ -202,7 +222,7 @@ export const alertsPlugin: GloomPlugin = {
|
|
|
202
222
|
label: "Event",
|
|
203
223
|
type: "select",
|
|
204
224
|
defaultValue: "congress-watched",
|
|
205
|
-
options: [...
|
|
225
|
+
options: [...RESEARCH_FORM_KINDS.map((value) => ({ value, label: RESEARCH_LABELS[value] })), ...EVENT_ALERT_TEMPLATES.map((entry) => ({ label: entry.label, value: entry.id }))],
|
|
206
226
|
},
|
|
207
227
|
...EVENT_ALERT_TEMPLATES.filter((entry) => entry.field != null).map((entry) => ({
|
|
208
228
|
key: entry.id,
|
|
@@ -216,13 +236,15 @@ export const alertsPlugin: GloomPlugin = {
|
|
|
216
236
|
],
|
|
217
237
|
async execute(values = {}) {
|
|
218
238
|
const event = values?.event || "congress-watched";
|
|
219
|
-
const
|
|
239
|
+
const readAll = () => readEventAlertStores((key) => ctx.configState.get<string>(key));
|
|
240
|
+
const initial = readAll();
|
|
220
241
|
if (initial.error) throw new Error(initial.error);
|
|
221
242
|
if (initial.rules.length >= MAX_EVENT_ALERTS)
|
|
222
243
|
throw new Error("Keep at most 40 event alerts.");
|
|
223
244
|
// Earnings and macro events alert before a date: one has to be known, or the rule would never go off.
|
|
224
245
|
const scheduled = event === "earnings_date" || event === "macro_event";
|
|
225
|
-
|
|
246
|
+
const awaitsResults = event === "earnings_date" && values["earnings_date:when"] === "results";
|
|
247
|
+
if (scheduled && !awaitsResults && parseLeadDays(values[`${event}:leadDays`]) == null)
|
|
226
248
|
throw new Error(`Days before must be a whole number from 1 to ${MAX_LEAD_DAYS}.`);
|
|
227
249
|
let rule = isResearchAlertKind(event) ? createResearchAlert(event, values) : createEventAlert(event, values?.[event] || "");
|
|
228
250
|
const target = scheduled ? readScheduledRule(rule)?.target : null;
|
|
@@ -234,7 +256,7 @@ export const alertsPlugin: GloomPlugin = {
|
|
|
234
256
|
rule = { ...rule, eventDate: lookup.date };
|
|
235
257
|
}
|
|
236
258
|
// Read again: the lookup took a while and the rules may have changed meanwhile.
|
|
237
|
-
const result = scheduled ?
|
|
259
|
+
const result = scheduled ? readAll() : initial;
|
|
238
260
|
if (result.error) throw new Error(result.error);
|
|
239
261
|
if (
|
|
240
262
|
result.rules.some(
|
|
@@ -245,9 +267,12 @@ export const alertsPlugin: GloomPlugin = {
|
|
|
245
267
|
)
|
|
246
268
|
)
|
|
247
269
|
throw new Error("This event is already followed.");
|
|
248
|
-
|
|
270
|
+
// An IV level goes in its own list, which released versions never read.
|
|
271
|
+
const key = eventAlertStoreKey(rule);
|
|
272
|
+
await ctx.configState.set(key, updateEventAlerts(ctx.configState.get<string>(key), (rules) => [...rules, rule]));
|
|
249
273
|
ctx.notify({ body: "Event alert saved.", type: "success" });
|
|
250
274
|
if (scheduled) checkScheduledEventAlertsNow();
|
|
275
|
+
if (rule.kind === "iv_level") checkIvLevelAlertsNow();
|
|
251
276
|
},
|
|
252
277
|
});
|
|
253
278
|
|
|
@@ -294,7 +319,7 @@ export const alertsPlugin: GloomPlugin = {
|
|
|
294
319
|
alert.status = "triggered";
|
|
295
320
|
alert.triggeredAt = Date.now();
|
|
296
321
|
ctx.log.info("poll: TRIGGERED", { symbol: alert.symbol, price: quote.price });
|
|
297
|
-
notifyTriggered(alert, quote.
|
|
322
|
+
notifyTriggered(alert, quote, alert.triggeredAt);
|
|
298
323
|
}
|
|
299
324
|
streamedBaselines.delete(alert.id);
|
|
300
325
|
Object.assign(alert, quoteAlertFields(quote));
|
|
@@ -302,7 +327,7 @@ export const alertsPlugin: GloomPlugin = {
|
|
|
302
327
|
}
|
|
303
328
|
|
|
304
329
|
if (changed) {
|
|
305
|
-
saveAlerts(ctx, alerts);
|
|
330
|
+
await saveAlerts(ctx, alerts);
|
|
306
331
|
}
|
|
307
332
|
};
|
|
308
333
|
|
|
@@ -313,11 +338,11 @@ export const alertsPlugin: GloomPlugin = {
|
|
|
313
338
|
const seconds = Number(ctx.paneSettings?.get<string>("alerts", POLL_SECONDS_KEY));
|
|
314
339
|
const delay = Number.isFinite(seconds) && seconds > 0 ? seconds * 1000 : POLL_INTERVAL_MS;
|
|
315
340
|
pollTimer = setTimeout(() => {
|
|
316
|
-
void poll().finally(scheduleNextPoll);
|
|
341
|
+
void poll().catch(logFailure("alerts.poll", "Check price alerts failed")).finally(scheduleNextPoll);
|
|
317
342
|
}, delay);
|
|
318
343
|
};
|
|
319
344
|
|
|
320
|
-
void poll().finally(scheduleNextPoll);
|
|
345
|
+
void poll().catch(logFailure("alerts.poll", "Check price alerts failed")).finally(scheduleNextPoll);
|
|
321
346
|
|
|
322
347
|
ctx.registerPane({
|
|
323
348
|
id: "alerts",
|
|
@@ -369,6 +394,8 @@ export const alertsPlugin: GloomPlugin = {
|
|
|
369
394
|
catalystAlertsStop = null;
|
|
370
395
|
scheduledAlertsStop?.();
|
|
371
396
|
scheduledAlertsStop = null;
|
|
397
|
+
ivLevelAlertsStop?.();
|
|
398
|
+
ivLevelAlertsStop = null;
|
|
372
399
|
pollGeneration += 1;
|
|
373
400
|
alertStream?.dispose();
|
|
374
401
|
alertStream = null;
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import type { DataProvider } from "../../../types/data-provider";
|
|
2
|
+
import type { GloomPluginContext } from "../../../types/plugin";
|
|
3
|
+
import { getSharedMarketDataCoordinator } from "../../../market-data/coordinator";
|
|
4
|
+
import { withDeadline } from "../../../utils/async-deadline";
|
|
5
|
+
import { errorMessage } from "../../../utils/errors";
|
|
6
|
+
import { createSurfaceDependencies, loadVolatilitySurface, withReusedYieldCurve, type SurfaceLoaderDependencies } from "../vol-surface/client";
|
|
7
|
+
import { buildSurfaceGrid, DEFAULT_SURFACE_SETTINGS, type SurfaceExpiry, type SurfaceSnapshot } from "../vol-surface/model";
|
|
8
|
+
import { IV_LEVEL_ALERTS_KEY, readEventAlerts, updateEventAlerts, type EventAlertRule } from "./events";
|
|
9
|
+
import { type FiredAlertInput } from "./fired-log";
|
|
10
|
+
import { formatIvLevel, IV_LEVEL_NAMES, researchAlertDescription } from "./research-builder";
|
|
11
|
+
import { readResearchRule, type IvLevelMetric, type ResearchAlertConfig } from "./research-rules";
|
|
12
|
+
|
|
13
|
+
/** OVDV's 1M fixed tenor: the constant maturity an IV level rule reads. */
|
|
14
|
+
const IV_LEVEL_TENOR = { label: "1M", years: 30 / 365 };
|
|
15
|
+
/** OVDV's delta axis at that tenor: the 25-delta put, ATM (the delta-neutral strike) and the 25-delta call. */
|
|
16
|
+
const IV_LEVEL_DELTAS = [-0.25, 0, 0.25] as const;
|
|
17
|
+
/**
|
|
18
|
+
* A tenor with listed expiries on one side only is carried flat from the
|
|
19
|
+
* nearest (OVDV marks it E); an IV level takes that only from an expiry this
|
|
20
|
+
* close to 30 days.
|
|
21
|
+
*/
|
|
22
|
+
const MAX_EXTRAPOLATION_DAYS = 10;
|
|
23
|
+
/** Option quotes move through the session; readings are taken this often while the app runs. */
|
|
24
|
+
const CHECK_INTERVAL_MS = 15 * 60_000;
|
|
25
|
+
const FIRST_CHECK_DELAY_MS = 8_000;
|
|
26
|
+
/** A symbol's option chains that have not all arrived by then are given up on until the next check. */
|
|
27
|
+
const LOAD_TIMEOUT_MS = 60_000;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The device's last reading of each IV level rule, by rule id, in plugin
|
|
31
|
+
* resume state: never synced, so a reading every 15 minutes writes nothing
|
|
32
|
+
* another device pulls, and a pull never takes one away.
|
|
33
|
+
*/
|
|
34
|
+
export const IV_LEVEL_CHECKS_KEY = "ivLevelChecks";
|
|
35
|
+
|
|
36
|
+
/** One check of an IV level rule: the level in the rule's unit, and the option quotes it was read from. */
|
|
37
|
+
export interface IvLevelCheck {
|
|
38
|
+
checkedAt: number;
|
|
39
|
+
/** % IV for an ATM rule, vol points for a risk reversal; null when the check found none. */
|
|
40
|
+
value: number | null;
|
|
41
|
+
/** When the option quotes behind the reading were observed. */
|
|
42
|
+
quoteAt?: string;
|
|
43
|
+
/** How current those quotes are: `real-time`, `15 min delayed`. */
|
|
44
|
+
source?: string;
|
|
45
|
+
/** Why there was no reading. */
|
|
46
|
+
error?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const isText = (value: unknown): value is string => typeof value === "string" && value.length > 0 && value.length <= 300;
|
|
50
|
+
|
|
51
|
+
/** The saved readings that read; anything else is dropped, and the next check writes it again. */
|
|
52
|
+
export function readIvLevelChecks(value: unknown): Record<string, IvLevelCheck> {
|
|
53
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
54
|
+
const checks: Record<string, IvLevelCheck> = {};
|
|
55
|
+
for (const [id, raw] of Object.entries(value as Record<string, unknown>)) {
|
|
56
|
+
if (!raw || typeof raw !== "object") continue;
|
|
57
|
+
const check = raw as Record<string, unknown>;
|
|
58
|
+
if (!Number.isFinite(check.checkedAt) || (check.value !== null && !Number.isFinite(check.value))) continue;
|
|
59
|
+
checks[id] = {
|
|
60
|
+
checkedAt: check.checkedAt as number,
|
|
61
|
+
value: check.value as number | null,
|
|
62
|
+
...(isText(check.quoteAt) ? { quoteAt: check.quoteAt } : {}),
|
|
63
|
+
...(isText(check.source) ? { source: check.source } : {}),
|
|
64
|
+
...(isText(check.error) ? { error: check.error } : {}),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return checks;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* An IV level rule's symbol's 30-day ATM IV and 25-delta risk reversal, in
|
|
72
|
+
* decimals: the 1M row of OVDV's Table on the delta axis with fixed tenors
|
|
73
|
+
* (ATM, 25dP and 25dC), solved at 30 days on the same fits. Null with `error`
|
|
74
|
+
* when the chain gives none.
|
|
75
|
+
*/
|
|
76
|
+
export interface IvLevelReading {
|
|
77
|
+
atm: number | null;
|
|
78
|
+
rr: number | null;
|
|
79
|
+
/** When the newest option quotes behind it were observed. */
|
|
80
|
+
quoteAt: string | null;
|
|
81
|
+
/** How current those quotes are: `real-time`, `15 min delayed`, `delayed`. */
|
|
82
|
+
source: string | null;
|
|
83
|
+
error?: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** How current option quotes are, worded as reports word a feed. */
|
|
87
|
+
function feedWords(expiries: readonly Pick<SurfaceExpiry, "dataSource" | "delayMinutes">[]): string | null {
|
|
88
|
+
if (expiries.length === 0) return null;
|
|
89
|
+
if (expiries.every((expiry) => expiry.dataSource === "live")) return "real-time";
|
|
90
|
+
const delay = Math.max(0, ...expiries.map((expiry) => expiry.delayMinutes ?? 0));
|
|
91
|
+
if (expiries.some((expiry) => expiry.dataSource === "delayed")) return delay > 0 ? `${delay} min delayed` : "delayed";
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The 30-day reading of a surface as OVDV loads it: its own fixed-tenor solve
|
|
97
|
+
* (`buildSurfaceGrid`), so the figure is the one OVDV shows, with the time and
|
|
98
|
+
* feed of the expiries either side of 30 days that it comes from.
|
|
99
|
+
*/
|
|
100
|
+
export function ivLevelReading(snapshot: Pick<SurfaceSnapshot, "spot" | "expiries" | "failures">): IvLevelReading {
|
|
101
|
+
const grid = buildSurfaceGrid(snapshot as SurfaceSnapshot, {
|
|
102
|
+
axis: "delta", tenors: "fixed", fixedTenors: [IV_LEVEL_TENOR], coordinates: IV_LEVEL_DELTAS,
|
|
103
|
+
});
|
|
104
|
+
const row = grid.rows[0];
|
|
105
|
+
// The expiries the solve stands on: the ones either side of 30 days, or the nearest when there is one side only.
|
|
106
|
+
const available = snapshot.expiries
|
|
107
|
+
.filter((expiry) => expiry.fit && expiry.forward != null && expiry.rate != null && expiry.dividendYield != null)
|
|
108
|
+
.sort((a, b) => a.years - b.years);
|
|
109
|
+
const right = available.findIndex((expiry) => expiry.years >= IV_LEVEL_TENOR.years);
|
|
110
|
+
const used = right < 0 ? available.slice(-1) : right === 0 ? available.slice(0, 1) : available.slice(right - 1, right + 1);
|
|
111
|
+
const tooFar = !!row?.extrapolated && used.every((expiry) => Math.abs(expiry.years - IV_LEVEL_TENOR.years) * 365 > MAX_EXTRAPOLATION_DAYS);
|
|
112
|
+
const [put, atm, call] = tooFar || !row ? [null, null, null] : row.cells.map((cell) => cell.volatility);
|
|
113
|
+
const rr = put != null && call != null ? call - put : null;
|
|
114
|
+
const quoteAt = used.map((expiry) => expiry.asOf).filter((value): value is string => !!value).sort().at(-1) ?? null;
|
|
115
|
+
const error = atm == null && rr == null
|
|
116
|
+
? snapshot.failures.find((failure) => failure.message)?.message ?? snapshot.expiries.find((expiry) => expiry.error)?.error
|
|
117
|
+
?? "No clean option quotes near 30 days"
|
|
118
|
+
: undefined;
|
|
119
|
+
return { atm: atm ?? null, rr, quoteAt, source: feedWords(used), ...(error ? { error } : {}) };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** The symbol's listing as an option chain is requested: a research rule's `US` names no venue. */
|
|
123
|
+
const instrumentOf = (config: Pick<ResearchAlertConfig, "symbol" | "exchange">) => ({
|
|
124
|
+
symbol: config.symbol!,
|
|
125
|
+
...(config.exchange && config.exchange !== "US" ? { exchange: config.exchange } : {}),
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
/** The symbol's surface as OVDV loads it by default: the same expiries, settings and spot. */
|
|
129
|
+
async function loadIvLevelReading(
|
|
130
|
+
config: Pick<ResearchAlertConfig, "symbol" | "exchange">,
|
|
131
|
+
marketData: Pick<DataProvider, "getQuote">,
|
|
132
|
+
dependencies: SurfaceLoaderDependencies,
|
|
133
|
+
signal: AbortSignal,
|
|
134
|
+
): Promise<IvLevelReading> {
|
|
135
|
+
const instrument = instrumentOf(config);
|
|
136
|
+
const quote = await marketData.getQuote(instrument.symbol, instrument.exchange);
|
|
137
|
+
if (!quote || !(quote.price > 0) || !Number.isFinite(quote.price) || quote.stale) throw new Error(`No current price for ${instrument.symbol}`);
|
|
138
|
+
const snapshot = await loadVolatilitySurface({
|
|
139
|
+
instrument, spot: quote.price, spotAsOf: quote.lastUpdated, quote, settings: DEFAULT_SURFACE_SETTINGS, signal,
|
|
140
|
+
}, dependencies);
|
|
141
|
+
return ivLevelReading(snapshot);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** The reading an IV level rule follows, in its unit: % IV for ATM, vol points for a risk reversal. */
|
|
145
|
+
function ivLevelValue(reading: IvLevelReading, metric: IvLevelMetric): number | null {
|
|
146
|
+
const value = metric === "atm" ? reading.atm : reading.rr;
|
|
147
|
+
return value == null ? null : Number((value * 100).toFixed(2));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Whether a reading is past the rule's level, above it or below it, as a price alert's `above` and `below` are. */
|
|
151
|
+
function ivLevelReached(config: Pick<ResearchAlertConfig, "direction" | "threshold">, value: number | null): boolean {
|
|
152
|
+
if (value == null || config.threshold == null) return false;
|
|
153
|
+
return config.direction === "below" ? value < config.threshold : value > config.threshold;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** A rule's check from a reading, or from the reason there was none. */
|
|
157
|
+
function ivLevelCheck(reading: IvLevelReading | Error, metric: IvLevelMetric, checkedAt: number): IvLevelCheck {
|
|
158
|
+
if (reading instanceof Error) return { checkedAt, value: null, error: reading.message };
|
|
159
|
+
const value = ivLevelValue(reading, metric);
|
|
160
|
+
return {
|
|
161
|
+
checkedAt,
|
|
162
|
+
value,
|
|
163
|
+
...(reading.quoteAt ? { quoteAt: reading.quoteAt } : {}),
|
|
164
|
+
...(reading.source ? { source: reading.source } : {}),
|
|
165
|
+
...(value == null ? { error: reading.error ?? (metric === "rr" ? "No 25-delta quotes near 30 days" : "No ATM quotes near 30 days") } : {}),
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** "IBIT 30d ATM IV 52.31% is above 50%". */
|
|
170
|
+
function ivLevelMessage(config: ResearchAlertConfig, value: number): string {
|
|
171
|
+
const metric = config.metric as IvLevelMetric;
|
|
172
|
+
return `${config.symbol} ${IV_LEVEL_NAMES[metric]} ${formatIvLevel(metric, value)} is ${config.direction} ${formatIvLevel(metric, config.threshold ?? 0)}`;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* An IV level rule's last check, for its row: "52.31% · quotes 10-22 20:14 UTC, 15 min delayed", the reason
|
|
177
|
+
* there was no reading, or that the running app has not checked it yet.
|
|
178
|
+
*/
|
|
179
|
+
export function ivLevelCheckText(rule: Pick<EventAlertRule, "value">, check: IvLevelCheck | undefined): string {
|
|
180
|
+
if (!check) return "Not checked yet";
|
|
181
|
+
const metric = readResearchRule("iv_level", rule.value)?.metric as IvLevelMetric | undefined;
|
|
182
|
+
if (check.value == null || !metric) return check.error ?? "No reading";
|
|
183
|
+
const quoted = check.quoteAt ? new Date(check.quoteAt) : null;
|
|
184
|
+
const when = quoted && Number.isFinite(quoted.getTime())
|
|
185
|
+
? `quotes ${quoted.toISOString().slice(5, 16).replace("T", " ")} UTC` : null;
|
|
186
|
+
return [formatIvLevel(metric, check.value), [when, check.source].filter(Boolean).join(", ")].filter(Boolean).join(" · ");
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** A rule that went off arms again; its last reading stays until the next check. */
|
|
190
|
+
export function rearmIvLevelAlert(rule: EventAlertRule): EventAlertRule {
|
|
191
|
+
const { triggeredAt: _triggered, ...rest } = rule;
|
|
192
|
+
return rest;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
let checkNow: (() => void) | null = null;
|
|
196
|
+
|
|
197
|
+
/** Check at once, after a rule was added or re-armed, rather than at the next interval. */
|
|
198
|
+
export function checkIvLevelAlertsNow(): void {
|
|
199
|
+
checkNow?.();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export interface IvLevelAlertOptions {
|
|
203
|
+
/** One symbol's reading; it is given up on when `signal` aborts. */
|
|
204
|
+
load?: (config: ResearchAlertConfig, signal: AbortSignal) => Promise<IvLevelReading>;
|
|
205
|
+
now?: () => number;
|
|
206
|
+
/** How long one symbol's reading may take; about a minute. */
|
|
207
|
+
timeoutMs?: number;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Takes a reading for every active IV level rule while the app runs, one per
|
|
212
|
+
* symbol, and keeps it on the device for the Events tab. A rule whose reading
|
|
213
|
+
* is past its level, above or below it as a price alert's is (so one added or
|
|
214
|
+
* re-armed already past it goes off at that check), is saved as Alerted first
|
|
215
|
+
* and then notified, once: a save that fails tells no one, so the next check
|
|
216
|
+
* cannot tell twice. The rule then reads Alerted until it is re-armed. Synced
|
|
217
|
+
* config changes only then. With no such rules it requests nothing.
|
|
218
|
+
*/
|
|
219
|
+
export function startIvLevelAlerts(
|
|
220
|
+
ctx: Pick<GloomPluginContext, "configState" | "resume" | "notify" | "showPane" | "log" | "marketData">,
|
|
221
|
+
record: (entry: FiredAlertInput) => void,
|
|
222
|
+
options: IvLevelAlertOptions = {},
|
|
223
|
+
): () => void {
|
|
224
|
+
const now = options.now ?? Date.now;
|
|
225
|
+
const timeoutMs = options.timeoutMs ?? LOAD_TIMEOUT_MS;
|
|
226
|
+
let dependencies: SurfaceLoaderDependencies | null = null;
|
|
227
|
+
// OVDV's chains, through the coordinator the panes share, so a symbol open in OVDV is read once.
|
|
228
|
+
const load = options.load ?? ((config: ResearchAlertConfig, signal: AbortSignal) => {
|
|
229
|
+
dependencies ??= withReusedYieldCurve(createSurfaceDependencies(getSharedMarketDataCoordinator() ? undefined : ctx.marketData));
|
|
230
|
+
return loadIvLevelReading(config, ctx.marketData, dependencies, signal);
|
|
231
|
+
});
|
|
232
|
+
let stopped = false;
|
|
233
|
+
let running = false;
|
|
234
|
+
let rerun = false;
|
|
235
|
+
let timer: ReturnType<typeof setTimeout> | null = null;
|
|
236
|
+
const read = () => readEventAlerts(ctx.configState.get<string>(IV_LEVEL_ALERTS_KEY) ?? "[]");
|
|
237
|
+
const watched = (rule: EventAlertRule) => rule.kind === "iv_level" && rule.status === "active" && !rule.triggeredAt;
|
|
238
|
+
const configOf = (rule: EventAlertRule) => readResearchRule("iv_level", rule.value);
|
|
239
|
+
const keyOf = (config: ResearchAlertConfig) => `${config.symbol}:${config.exchange ?? ""}`;
|
|
240
|
+
|
|
241
|
+
/** One symbol's reading, or why there was none: a failure, or no answer within `timeoutMs`. */
|
|
242
|
+
const readingFor = async (config: ResearchAlertConfig): Promise<IvLevelReading | Error> => {
|
|
243
|
+
const abort = new AbortController();
|
|
244
|
+
try {
|
|
245
|
+
return await withDeadline(load(config, abort.signal), timeoutMs,
|
|
246
|
+
`Option quotes for ${config.symbol} did not arrive within ${timeoutMs >= 1000 ? `${Math.round(timeoutMs / 1000)} s` : `${timeoutMs} ms`}`,
|
|
247
|
+
() => abort.abort());
|
|
248
|
+
} catch (failure) {
|
|
249
|
+
ctx.log.warn("IV level unavailable", { symbol: config.symbol, error: errorMessage(failure) });
|
|
250
|
+
return new Error(errorMessage(failure));
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
const check = async () => {
|
|
255
|
+
const { rules, error } = read();
|
|
256
|
+
if (error) return;
|
|
257
|
+
const symbols = new Map<string, ResearchAlertConfig>();
|
|
258
|
+
for (const rule of rules.filter(watched)) {
|
|
259
|
+
const config = configOf(rule);
|
|
260
|
+
if (config) symbols.set(keyOf(config), config);
|
|
261
|
+
}
|
|
262
|
+
if (symbols.size === 0) return;
|
|
263
|
+
const readings = new Map<string, IvLevelReading | Error>();
|
|
264
|
+
// One symbol at a time: each reads OVDV's option chains.
|
|
265
|
+
for (const [key, config] of symbols) {
|
|
266
|
+
if (stopped) return;
|
|
267
|
+
readings.set(key, await readingFor(config));
|
|
268
|
+
}
|
|
269
|
+
if (stopped) return;
|
|
270
|
+
// Read again: the pane or a sync may have changed the rules while the chains loaded.
|
|
271
|
+
const current = read();
|
|
272
|
+
if (current.error) return;
|
|
273
|
+
const checkedAt = now();
|
|
274
|
+
const saved = readIvLevelChecks(ctx.resume.getState(IV_LEVEL_CHECKS_KEY));
|
|
275
|
+
const checks: Record<string, IvLevelCheck> = {};
|
|
276
|
+
const reached = new Map<string, { config: ResearchAlertConfig; check: IvLevelCheck }>();
|
|
277
|
+
for (const rule of current.rules) {
|
|
278
|
+
const config = watched(rule) ? configOf(rule) : null;
|
|
279
|
+
const reading = config ? readings.get(keyOf(config)) : undefined;
|
|
280
|
+
if (!config || !reading) {
|
|
281
|
+
// A rule not read this time keeps its last reading; a deleted one's goes.
|
|
282
|
+
if (saved[rule.id]) checks[rule.id] = saved[rule.id]!;
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
const result = ivLevelCheck(reading, config.metric as IvLevelMetric, checkedAt);
|
|
286
|
+
checks[rule.id] = result;
|
|
287
|
+
if (ivLevelReached(config, result.value)) reached.set(rule.id, { config, check: result });
|
|
288
|
+
}
|
|
289
|
+
try {
|
|
290
|
+
ctx.resume.setState(IV_LEVEL_CHECKS_KEY, checks);
|
|
291
|
+
} catch (failure) {
|
|
292
|
+
ctx.log.warn("IV level readings not kept", { error: errorMessage(failure) });
|
|
293
|
+
}
|
|
294
|
+
if (reached.size === 0 || stopped) return;
|
|
295
|
+
|
|
296
|
+
// Alerted on every device before anyone is told; only rules still watching when it is saved go off.
|
|
297
|
+
const fired: EventAlertRule[] = [];
|
|
298
|
+
const next = updateEventAlerts(ctx.configState.get<string>(IV_LEVEL_ALERTS_KEY), (latest) => latest.map((rule) => {
|
|
299
|
+
if (!reached.has(rule.id) || !watched(rule)) return rule;
|
|
300
|
+
fired.push(rule);
|
|
301
|
+
return { ...rule, triggeredAt: checkedAt };
|
|
302
|
+
}));
|
|
303
|
+
if (fired.length === 0) return;
|
|
304
|
+
try {
|
|
305
|
+
await ctx.configState.set(IV_LEVEL_ALERTS_KEY, next);
|
|
306
|
+
} catch (failure) {
|
|
307
|
+
ctx.log.warn("IV level alert not saved, so not sent", { error: errorMessage(failure) });
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
for (const rule of fired) {
|
|
311
|
+
const { config, check: result } = reached.get(rule.id)!;
|
|
312
|
+
const metric = config.metric as IvLevelMetric;
|
|
313
|
+
ctx.notify({
|
|
314
|
+
body: ivLevelMessage(config, result.value!),
|
|
315
|
+
type: "success",
|
|
316
|
+
desktop: "always",
|
|
317
|
+
persistent: true,
|
|
318
|
+
sound: "Glass",
|
|
319
|
+
action: { label: "Open", onClick: () => ctx.showPane("alerts") },
|
|
320
|
+
});
|
|
321
|
+
record({
|
|
322
|
+
kind: "iv_level", ruleId: rule.id, rule: researchAlertDescription(rule), firedAt: checkedAt,
|
|
323
|
+
value: result.value, unit: metric === "atm" ? "%" : "vol pts",
|
|
324
|
+
quoteAt: result.quoteAt ?? null, source: result.source ?? null,
|
|
325
|
+
symbol: config.symbol, ...(config.exchange && config.exchange !== "US" ? { exchange: config.exchange } : {}),
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
const run = async () => {
|
|
331
|
+
if (stopped) return;
|
|
332
|
+
if (running) {
|
|
333
|
+
rerun = true;
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
running = true;
|
|
337
|
+
if (timer) clearTimeout(timer);
|
|
338
|
+
timer = null;
|
|
339
|
+
try {
|
|
340
|
+
await check();
|
|
341
|
+
} catch (failure) {
|
|
342
|
+
if (!stopped) ctx.log.warn("IV level alerts check failed", { error: errorMessage(failure) });
|
|
343
|
+
} finally {
|
|
344
|
+
running = false;
|
|
345
|
+
if (!stopped) {
|
|
346
|
+
if (rerun) {
|
|
347
|
+
rerun = false;
|
|
348
|
+
void run();
|
|
349
|
+
} else {
|
|
350
|
+
timer = setTimeout(() => void run(), CHECK_INTERVAL_MS);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
timer = setTimeout(() => void run(), FIRST_CHECK_DELAY_MS);
|
|
357
|
+
const trigger = () => void run();
|
|
358
|
+
checkNow = trigger;
|
|
359
|
+
return () => {
|
|
360
|
+
stopped = true;
|
|
361
|
+
if (timer) clearTimeout(timer);
|
|
362
|
+
timer = null;
|
|
363
|
+
if (checkNow === trigger) checkNow = null;
|
|
364
|
+
};
|
|
365
|
+
}
|
|
@@ -42,14 +42,14 @@ export function levelAlertCondition(level: number, currentPrice: number | null):
|
|
|
42
42
|
* duplicate, and a store that does not parse is left alone.
|
|
43
43
|
*/
|
|
44
44
|
export function addLevelAlert(
|
|
45
|
-
storeJson:
|
|
45
|
+
storeJson: unknown,
|
|
46
46
|
target: AlertTarget,
|
|
47
47
|
level: number,
|
|
48
48
|
currentPrice: number | null,
|
|
49
49
|
): { json: string; alert: AlertRule; created: boolean } | { error: string } {
|
|
50
|
-
const
|
|
51
|
-
const error = readAlertsStoreError(json);
|
|
50
|
+
const error = readAlertsStoreError(storeJson);
|
|
52
51
|
if (error) return { error };
|
|
52
|
+
const json = typeof storeJson === "string" ? storeJson : "[]";
|
|
53
53
|
const alerts = deserializeAlerts(json);
|
|
54
54
|
const existing = alerts.find((alert) => (
|
|
55
55
|
alert.status === "active" && alert.targetPrice === level && watches(alert, target)
|