gloomberb 0.18.4 → 0.19.0
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/package.json +1 -1
- package/patches/electrobun@1.18.1.patch +169 -5
- package/src/account/auth-model.ts +7 -3
- package/src/api-client/auth.ts +9 -4
- package/src/api-client/catalysts.ts +2 -1
- package/src/api-client/cot.ts +6 -2
- package/src/api-client/credit-documents.ts +6 -0
- package/src/api-client/data.ts +31 -6
- package/src/api-client/equity-screener.ts +24 -0
- package/src/api-client/fund-facts.ts +45 -4
- package/src/api-client/index.ts +171 -11
- package/src/api-client/live-scan.ts +91 -0
- package/src/api-client/market-discovery.ts +10 -0
- package/src/api-client/market-movers.ts +7 -0
- package/src/api-client/members.ts +13 -1
- package/src/api-client/perps.ts +43 -0
- package/src/api-client/request.ts +222 -41
- package/src/api-client/research-activity.ts +6 -12
- package/src/api-client/types.ts +74 -0
- package/src/app/keybindings/index.ts +3 -0
- package/src/app/keybindings/labels.ts +18 -1
- package/src/app/keybindings/resolve.ts +14 -0
- package/src/app/pane-runtime/plugin-bindings.ts +9 -5
- package/src/app/runtime/broker-import.ts +42 -27
- package/src/app/runtime/plugin-bindings.ts +73 -56
- package/src/architecture/core-builtin-allowlist.json +1 -1
- package/src/architecture/pane-tabs-allowlist.json +3 -0
- package/src/architecture/ttl-caches-allowlist.json +19 -0
- package/src/brokers/sync-broker-instance.ts +2 -8
- package/src/capabilities/chart-series.ts +1 -1
- package/src/cli/commands/crypto-hints.ts +40 -24
- package/src/cli/commands/fred-series.ts +5 -0
- package/src/cli/commands/keybindings.ts +23 -0
- package/src/cli/commands/market.ts +138 -46
- package/src/cli/commands/options-chain.ts +107 -10
- package/src/cli/commands/options-leaps.ts +9 -3
- package/src/cli/commands/overview.ts +176 -39
- package/src/cli/commands/search.ts +39 -3
- package/src/cli/commands/themes.ts +11 -2
- package/src/cli/commands/ticker.ts +57 -35
- package/src/cli/company-name-hint.ts +41 -0
- package/src/cli/earnings-calendar.ts +1 -1
- package/src/cli/errors.ts +10 -2
- package/src/cli/export-source.ts +29 -1
- package/src/cli/glossary.ts +73 -1
- package/src/cli/history-rows.ts +87 -16
- package/src/cli/index.ts +2 -0
- package/src/cli/known-gaps.ts +5 -2
- package/src/cli/listing-arg.ts +195 -56
- package/src/cli/output-file.ts +68 -0
- package/src/cli/pane-functions/capabilities.ts +3 -0
- package/src/cli/pane-functions/catalog.ts +80 -7
- package/src/cli/pane-functions/dom.ts +13 -3
- package/src/cli/pane-functions/freshness.ts +111 -16
- package/src/cli/pane-functions/function-help.ts +23 -13
- package/src/cli/pane-functions/headless.ts +56 -12
- package/src/cli/pane-functions/index.ts +58 -16
- package/src/cli/pane-functions/market-session.ts +81 -9
- package/src/cli/pane-functions/options.ts +19 -1
- package/src/cli/pane-functions/report.ts +5 -1
- package/src/cli/pane-functions/resolver.ts +35 -8
- package/src/cli/pane-functions/screenshot-assessment.ts +6 -4
- package/src/cli/pane-functions/screenshot-types.ts +5 -0
- package/src/cli/quote-answer.ts +30 -13
- package/src/cli/report-tables.ts +18 -7
- package/src/cli/restore-plugins.ts +13 -1
- package/src/cli/result.ts +57 -5
- package/src/cli/ticker-resolution.ts +3 -2
- package/src/components/chart/composite/composite-chart.tsx +26 -4
- package/src/components/chart/composite/format.ts +27 -0
- package/src/components/chart/composite/interactions.ts +6 -0
- package/src/components/chart/composite/legend.tsx +45 -7
- package/src/components/chart/composite/levels.ts +2 -0
- package/src/components/chart/composite/panel-gestures.ts +33 -0
- package/src/components/chart/composite/panel-series.ts +1 -0
- package/src/components/chart/composite/panel-surface.tsx +61 -5
- package/src/components/chart/composite/range-statistics.ts +62 -0
- package/src/components/chart/composite/rasterizer.ts +24 -13
- package/src/components/chart/composite/scene.ts +46 -7
- package/src/components/chart/composite/series-axis-tags.tsx +16 -9
- package/src/components/chart/composite/series-cues.ts +14 -0
- package/src/components/chart/composite/text-renderer.ts +9 -2
- package/src/components/chart/composite/tool-catalog.ts +36 -0
- package/src/components/chart/composite/tools.ts +203 -44
- package/src/components/chart/composite/types.ts +4 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +11 -4
- package/src/components/command-bar/assist/inventory.ts +2 -1
- package/src/components/command-bar/commands/direct/index.ts +28 -13
- package/src/components/command-bar/pane-templates/items.ts +3 -2
- package/src/components/command-bar/panel/prompt-binding.ts +0 -8
- package/src/components/command-bar/workflow/alert.ts +1 -1
- package/src/components/command-bar/workflow/collection-actions.ts +3 -3
- package/src/components/layout/header.tsx +26 -40
- package/src/components/layout/pane/footer/index.tsx +1 -0
- package/src/components/layout/pane/footer/model.ts +27 -0
- package/src/components/onboarding/onboarding-frame.tsx +1 -1
- package/src/components/onboarding/onboarding-wizard.tsx +4 -1
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +14 -9
- package/src/components/onboarding/wizard-broker-sync.ts +0 -1
- package/src/components/onboarding/wizard-positions.ts +3 -3
- package/src/components/ticker/list-table-view.tsx +4 -1
- package/src/components/ui/choice-dialog.tsx +23 -18
- package/src/components/ui/choice-groups.ts +18 -0
- package/src/components/ui/data-table/opentui/index.tsx +9 -7
- package/src/components/ui/data-table/opentui/model.ts +26 -1
- package/src/components/ui/data-table/types.ts +2 -0
- package/src/components/ui/display.tsx +5 -1
- package/src/components/ui/list-view.tsx +8 -4
- package/src/components/ui/query-bar-keys.tsx +2 -0
- package/src/components/ui/query-bar.tsx +1 -0
- package/src/components/ui/select-button.tsx +5 -1
- package/src/components/ui/select-field.tsx +1 -0
- package/src/components/ui/table-layout.ts +8 -5
- package/src/core/app-runtime.ts +2 -0
- package/src/core/app-services.ts +2 -2
- package/src/core/state/app/layout.ts +2 -0
- package/src/core/state/app/state.ts +9 -0
- package/src/core/state/app/types.ts +3 -0
- package/src/data/config/chart-settings.ts +1 -1
- package/src/data/json-ticker-repository.ts +17 -8
- package/src/data/saved-copies.ts +55 -16
- package/src/data/ticker-repository.ts +16 -9
- package/src/data/ticker-writes.ts +81 -0
- package/src/data/ttl-cache.ts +165 -0
- package/src/docs/snapshot.json +427 -216
- package/src/i18n/es.ts +19 -3
- package/src/i18n/ja.ts +19 -3
- package/src/i18n/ko.ts +19 -3
- package/src/i18n/zh-cn.ts +19 -3
- package/src/i18n/zh-tw.ts +19 -3
- package/src/market-data/coordinator/financials.ts +10 -2
- package/src/market-data/coordinator/index.ts +3 -1
- package/src/market-data/coordinator/quotes.ts +4 -2
- package/src/market-data/depositary-pair.ts +2 -2
- package/src/market-data/fund-facts.ts +50 -0
- package/src/market-data/market/change-basis.ts +48 -7
- package/src/market-data/market/dated-previous-close.ts +203 -0
- package/src/market-data/market/format.ts +25 -0
- package/src/market-data/market/freshness.ts +2 -1
- package/src/market-data/market/futures-week.ts +68 -0
- package/src/market-data/market/status.ts +16 -4
- package/src/market-data/options-alternatives.ts +141 -4
- package/src/market-data/quotes/contributions.ts +20 -2
- package/src/market-data/quotes/resolution.ts +3 -0
- package/src/market-data/selectors.ts +3 -0
- package/src/news/aggregator.ts +113 -9
- package/src/news/cloud-session.ts +21 -0
- package/src/news/hooks.ts +1 -0
- package/src/news/news-model.ts +1 -0
- package/src/news/types.ts +11 -0
- package/src/notifications/notification-log.ts +6 -4
- package/src/plugins/builtin/alerts/alert-engine.ts +25 -2
- package/src/plugins/builtin/alerts/alert-log.ts +33 -0
- package/src/plugins/builtin/alerts/calendar-events.ts +57 -6
- package/src/plugins/builtin/alerts/cli-forms.ts +216 -0
- package/src/plugins/builtin/alerts/cli.ts +380 -82
- package/src/plugins/builtin/alerts/command.ts +31 -0
- package/src/plugins/builtin/alerts/constants.ts +1 -1
- package/src/plugins/builtin/alerts/events-pane.tsx +19 -4
- package/src/plugins/builtin/alerts/fired-log.ts +113 -8
- package/src/plugins/builtin/alerts/format.ts +80 -4
- package/src/plugins/builtin/alerts/headless.ts +30 -7
- package/src/plugins/builtin/alerts/history-rows.ts +7 -3
- package/src/plugins/builtin/alerts/history.ts +2 -0
- package/src/plugins/builtin/alerts/index.tsx +135 -22
- package/src/plugins/builtin/alerts/live.ts +3 -3
- package/src/plugins/builtin/alerts/metric-command.ts +134 -0
- package/src/plugins/builtin/alerts/metric-data.ts +111 -0
- package/src/plugins/builtin/alerts/metric-model.ts +324 -0
- package/src/plugins/builtin/alerts/metric-parity-fixture.json +725 -0
- package/src/plugins/builtin/alerts/pane.tsx +90 -39
- package/src/plugins/builtin/alerts/quotes.ts +6 -0
- package/src/plugins/builtin/alerts/storage.ts +37 -10
- package/src/plugins/builtin/alerts/types.ts +7 -0
- package/src/plugins/builtin/analytics/index.tsx +2 -1
- package/src/plugins/builtin/analytics/risk-client.ts +16 -5
- package/src/plugins/builtin/analytics/risk-fx.ts +70 -15
- package/src/plugins/builtin/analytics/risk-headless.ts +27 -0
- package/src/plugins/builtin/analytics/risk-model.ts +55 -9
- package/src/plugins/builtin/analytics/risk-pane.tsx +8 -2
- package/src/plugins/builtin/attention/index.tsx +2 -1
- package/src/plugins/builtin/attention/listing.ts +14 -0
- package/src/plugins/builtin/backtest/headless.ts +10 -5
- package/src/plugins/builtin/backtest/pane.tsx +9 -4
- package/src/plugins/builtin/backtest/presets.ts +29 -3
- package/src/plugins/builtin/broker-manager/index.tsx +10 -5
- package/src/plugins/builtin/broker-manager/model.ts +6 -1
- package/src/plugins/builtin/broker-trading/controller.ts +22 -12
- package/src/plugins/builtin/broker-trading/index.tsx +13 -1
- package/src/plugins/builtin/broker-trading/order-feed.ts +9 -4
- package/src/plugins/builtin/broker-trading/pane.tsx +1 -1
- package/src/plugins/builtin/buildout/cells.tsx +12 -4
- package/src/plugins/builtin/buildout/format.ts +38 -0
- package/src/plugins/builtin/buildout/model/normalizers.ts +36 -1
- package/src/plugins/builtin/buildout/pane/index.tsx +4 -1
- package/src/plugins/builtin/buildout/table-model.ts +23 -2
- package/src/plugins/builtin/builtin-plugin-meta.ts +7 -3
- package/src/plugins/builtin/catalysts/model.ts +2 -1
- package/src/plugins/builtin/changelog/index.tsx +9 -6
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +6 -1
- package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +1 -1
- package/src/plugins/builtin/chart-composer/cli-options.ts +9 -5
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +12 -2
- package/src/plugins/builtin/chart-composer/editor/controller.ts +4 -2
- package/src/plugins/builtin/chart-composer/editor/model.ts +2 -0
- package/src/plugins/builtin/chart-composer/editor.tsx +7 -5
- package/src/plugins/builtin/chart-composer/formula.ts +71 -18
- package/src/plugins/builtin/chart-composer/headless-schema.ts +21 -4
- package/src/plugins/builtin/chart-composer/headless.ts +19 -3
- package/src/plugins/builtin/chart-composer/index.tsx +1 -1
- package/src/plugins/builtin/chart-composer/pane.tsx +53 -9
- package/src/plugins/builtin/chart-composer/presets.ts +50 -15
- package/src/plugins/builtin/chart-composer/quick-add.tsx +40 -25
- package/src/plugins/builtin/chart-composer/session-history.ts +18 -9
- package/src/plugins/builtin/chart-composer/settings.ts +27 -0
- package/src/plugins/builtin/chart-composer/use-series-catalog.ts +40 -26
- package/src/plugins/builtin/chat/content/command-suggestions.ts +93 -0
- package/src/plugins/builtin/chat/content/composer.tsx +13 -6
- package/src/plugins/builtin/chat/content/footer.tsx +6 -3
- package/src/plugins/builtin/chat/content/index.tsx +50 -21
- package/src/plugins/builtin/chat/content/open-targets.ts +14 -3
- package/src/plugins/builtin/chat/controller/session-runtime.ts +4 -2
- package/src/plugins/builtin/chat/index.tsx +23 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +1 -0
- package/src/plugins/builtin/chat/message/inline-tokens.tsx +23 -0
- package/src/plugins/builtin/chat/message/pane-chip.tsx +50 -20
- package/src/plugins/builtin/chat/pane-links/commands.ts +271 -0
- package/src/plugins/builtin/chat/pane-links/model.ts +12 -3
- package/src/plugins/builtin/chat/pane-links/open.ts +8 -1
- package/src/plugins/builtin/chat/unread-inbox-pane.tsx +10 -1
- package/src/plugins/builtin/clinical-trials/model.ts +0 -9
- package/src/plugins/builtin/clinical-trials/pane.tsx +15 -22
- package/src/plugins/builtin/clinical-trials/sponsor-tickers.ts +8 -6
- package/src/plugins/builtin/cloud/askg/manifest.ts +2 -0
- package/src/plugins/builtin/cloud/plugin.tsx +1 -1
- package/src/plugins/builtin/company-attention/building.tsx +5 -1
- package/src/plugins/builtin/company-attention/client.ts +8 -9
- package/src/plugins/builtin/company-attention/evidence.ts +4 -1
- package/src/plugins/builtin/company-attention/moves.tsx +5 -1
- package/src/plugins/builtin/company-attention/pane.tsx +9 -2
- package/src/plugins/builtin/company-attention/signals.tsx +5 -1
- package/src/plugins/builtin/correlation/headless.ts +13 -5
- package/src/plugins/builtin/correlation/history.ts +22 -0
- package/src/plugins/builtin/cot/client.ts +22 -18
- package/src/plugins/builtin/cot/headless.ts +15 -10
- package/src/plugins/builtin/cot/model.ts +14 -1
- package/src/plugins/builtin/cot/pane.tsx +22 -14
- package/src/plugins/builtin/credit-boards/client.ts +6 -10
- package/src/plugins/builtin/credit-conditions/headless.ts +8 -2
- package/src/plugins/builtin/credit-conditions/index.tsx +5 -1
- package/src/plugins/builtin/credit-conditions/model.ts +4 -0
- package/src/plugins/builtin/credit-conditions/series.ts +3 -1
- package/src/plugins/builtin/credit-documents/detail.tsx +2 -2
- package/src/plugins/builtin/credit-documents/export.ts +173 -0
- package/src/plugins/builtin/credit-documents/headless.ts +7 -7
- package/src/plugins/builtin/credit-documents/model.ts +104 -14
- package/src/plugins/builtin/credit-documents/pane.tsx +12 -5
- package/src/plugins/builtin/custom-view/sources.ts +2 -0
- package/src/plugins/builtin/dividend-yield/client.ts +131 -23
- package/src/plugins/builtin/dividend-yield/headless.ts +44 -16
- package/src/plugins/builtin/dividend-yield/model.ts +8 -5
- package/src/plugins/builtin/dividend-yield/pane.tsx +38 -13
- package/src/plugins/builtin/dividend-yield/ranking.ts +37 -14
- package/src/plugins/builtin/dividend-yield/types.ts +20 -2
- package/src/plugins/builtin/dividend-yield/view.ts +30 -2
- package/src/plugins/builtin/docs/targets.ts +5 -1
- package/src/plugins/builtin/earnings/board-model.ts +16 -15
- package/src/plugins/builtin/earnings/board.tsx +62 -71
- package/src/plugins/builtin/earnings/headless.ts +40 -4
- package/src/plugins/builtin/earnings/scope.ts +31 -43
- package/src/plugins/builtin/earnings-calls/calendar.tsx +2 -2
- package/src/plugins/builtin/earnings-calls/format.ts +31 -2
- package/src/plugins/builtin/earnings-calls/headless.ts +7 -2
- package/src/plugins/builtin/earnings-calls/model.ts +6 -1
- package/src/plugins/builtin/earnings-calls/pane.tsx +5 -4
- package/src/plugins/builtin/econ/calendar-model.ts +14 -9
- package/src/plugins/builtin/econ/figures.ts +72 -0
- package/src/plugins/builtin/econ/index.tsx +33 -3
- package/src/plugins/builtin/econ/types.ts +4 -0
- package/src/plugins/builtin/econ-statistics/defs.ts +6 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +85 -35
- package/src/plugins/builtin/econ-statistics/stats.ts +37 -9
- package/src/plugins/builtin/econ-statistics/view.ts +3 -0
- package/src/plugins/builtin/equity-screener/categories.ts +179 -0
- package/src/plugins/builtin/equity-screener/client.ts +4 -2
- package/src/plugins/builtin/equity-screener/headless.ts +144 -13
- package/src/plugins/builtin/equity-screener/ideas.ts +49 -0
- package/src/plugins/builtin/equity-screener/model.ts +99 -10
- package/src/plugins/builtin/equity-screener/pane.tsx +70 -15
- package/src/plugins/builtin/exposure/charts.tsx +2 -2
- package/src/plugins/builtin/exposure/model.ts +13 -1
- package/src/plugins/builtin/exposure/pane.tsx +4 -4
- package/src/plugins/builtin/fixed-income/pane.tsx +2 -1
- package/src/plugins/builtin/futures/index.tsx +1 -0
- package/src/plugins/builtin/futures/model.ts +2 -1
- package/src/plugins/builtin/futures/table.tsx +2 -2
- package/src/plugins/builtin/futures/use-board-terms.ts +42 -28
- package/src/plugins/builtin/futures/use-front-returns.ts +45 -28
- package/src/plugins/builtin/fx-matrix/client.ts +11 -3
- package/src/plugins/builtin/fx-matrix/headless.ts +6 -3
- package/src/plugins/builtin/fx-matrix/index.tsx +16 -4
- package/src/plugins/builtin/fx-matrix/live-legs.ts +54 -3
- package/src/plugins/builtin/gpu/headless.ts +8 -2
- package/src/plugins/builtin/help/function-index.ts +4 -1
- package/src/plugins/builtin/help/index.tsx +1 -0
- package/src/plugins/builtin/help/keybindings-editor.tsx +18 -14
- package/src/plugins/builtin/help/shortcut-model.ts +1 -1
- package/src/plugins/builtin/holders/fund-holders.ts +51 -0
- package/src/plugins/builtin/holders/headless.ts +18 -1
- package/src/plugins/builtin/iv-history/client.ts +52 -11
- package/src/plugins/builtin/iv-history/format.ts +36 -23
- package/src/plugins/builtin/iv-history/headless.ts +36 -18
- package/src/plugins/builtin/iv-history/index.tsx +2 -2
- package/src/plugins/builtin/iv-history/model.ts +163 -27
- package/src/plugins/builtin/iv-history/pane.tsx +10 -6
- package/src/plugins/builtin/iv-history/screen-pane.tsx +22 -15
- package/src/plugins/builtin/iv-history/universe.ts +5 -1
- package/src/plugins/builtin/jobs/client.ts +25 -29
- package/src/plugins/builtin/kelly-sizer/model.ts +12 -8
- package/src/plugins/builtin/kelly-sizer/pane.tsx +9 -9
- package/src/plugins/builtin/kelly-sizer/sections.tsx +19 -10
- package/src/plugins/builtin/kelly-sizer/types.ts +10 -4
- package/src/plugins/builtin/macro-day/pane.tsx +7 -5
- package/src/plugins/builtin/macro-day/release-table.ts +2 -2
- package/src/plugins/builtin/market-heatmap/data.ts +8 -33
- package/src/plugins/builtin/market-movers/client.ts +25 -7
- package/src/plugins/builtin/market-movers/footer.ts +2 -2
- package/src/plugins/builtin/market-movers/headless.ts +32 -12
- package/src/plugins/builtin/market-movers/index.tsx +26 -14
- package/src/plugins/builtin/market-movers/min-float.ts +74 -0
- package/src/plugins/builtin/market-movers/model.ts +4 -1
- package/src/plugins/builtin/market-movers/screener.ts +14 -0
- package/src/plugins/builtin/market-movers/session-body.tsx +13 -8
- package/src/plugins/builtin/market-movers/session-table.ts +4 -3
- package/src/plugins/builtin/market-movers/table.ts +17 -5
- package/src/plugins/builtin/members/breadth-pane.tsx +82 -0
- package/src/plugins/builtin/members/client.ts +19 -4
- package/src/plugins/builtin/members/headless.ts +20 -7
- package/src/plugins/builtin/members/index.tsx +9 -9
- package/src/plugins/builtin/members/model.ts +23 -4
- package/src/plugins/builtin/members/pane.tsx +25 -15
- package/src/plugins/builtin/news/index.tsx +1 -0
- package/src/plugins/builtin/news/wire/categories.ts +19 -3
- package/src/plugins/builtin/news/wire/industry-pane.tsx +1 -0
- package/src/plugins/builtin/news/wire/news/footer.ts +31 -5
- package/src/plugins/builtin/news/wire/news/preset-pane.tsx +6 -1
- package/src/plugins/builtin/news/wire/news/table.tsx +2 -2
- package/src/plugins/builtin/openfda/client.ts +14 -2
- package/src/plugins/builtin/openfda/index.tsx +3 -2
- package/src/plugins/builtin/openfda/model.ts +9 -0
- package/src/plugins/builtin/openfda/pane.tsx +42 -6
- package/src/plugins/builtin/options/analytics.ts +54 -6
- package/src/plugins/builtin/options/enrichment.ts +17 -5
- package/src/plugins/builtin/options/model-spot.ts +5 -2
- package/src/plugins/builtin/options/strike-window.ts +2 -1
- package/src/plugins/builtin/options/table.ts +6 -9
- package/src/plugins/builtin/options/types.ts +2 -0
- package/src/plugins/builtin/options/view.tsx +42 -12
- package/src/plugins/builtin/options-positioning/client.ts +30 -0
- package/src/plugins/builtin/options-positioning/headless.ts +74 -21
- package/src/plugins/builtin/options-positioning/index.tsx +4 -4
- package/src/plugins/builtin/options-positioning/model.ts +122 -14
- package/src/plugins/builtin/options-positioning/pane.tsx +87 -42
- package/src/plugins/builtin/options-scenario/client.ts +116 -47
- package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +142 -10
- package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +206 -55
- package/src/plugins/builtin/options-scenario/csp-screen.ts +63 -23
- package/src/plugins/builtin/options-scenario/csp.ts +8 -2
- package/src/plugins/builtin/options-scenario/index.tsx +9 -7
- package/src/plugins/builtin/options-scenario/strategy-screen.ts +532 -0
- package/src/plugins/builtin/pe-band/model.ts +12 -49
- package/src/plugins/builtin/perps/cascade-tabs.tsx +161 -0
- package/src/plugins/builtin/perps/cascade.ts +236 -0
- package/src/plugins/builtin/perps/client.ts +56 -2
- package/src/plugins/builtin/perps/freshness.ts +12 -10
- package/src/plugins/builtin/perps/headless.ts +65 -9
- package/src/plugins/builtin/perps/index.tsx +7 -5
- package/src/plugins/builtin/perps/live-rows.ts +10 -3
- package/src/plugins/builtin/perps/model.ts +18 -4
- package/src/plugins/builtin/perps/pane.tsx +32 -31
- package/src/plugins/builtin/perps/status-line.ts +25 -0
- package/src/plugins/builtin/plugin-module.ts +5 -1
- package/src/plugins/builtin/portfolio-list/cached-account.ts +3 -1
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +2 -8
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +4 -4
- package/src/plugins/builtin/portfolio-list/cli/render.ts +12 -7
- package/src/plugins/builtin/portfolio-list/headless.ts +1 -1
- package/src/plugins/builtin/portfolio-list/pane/futures-front.ts +40 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +4 -1
- package/src/plugins/builtin/portfolio-list/pane/streaming.ts +5 -2
- package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +3 -2
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +3 -1
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +11 -8
- package/src/plugins/builtin/portfolio-list/table.tsx +11 -3
- package/src/plugins/builtin/primary-dealers/client.ts +13 -38
- package/src/plugins/builtin/rate-path/pane.tsx +2 -2
- package/src/plugins/builtin/realized-vol/index.tsx +2 -2
- package/src/plugins/builtin/realized-vol/pane.tsx +3 -3
- package/src/plugins/builtin/relative-rotation/client.ts +18 -4
- package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
- package/src/plugins/builtin/relative-rotation/index.tsx +2 -1
- package/src/plugins/builtin/relative-rotation/model.ts +16 -40
- package/src/plugins/builtin/relative-rotation/pane.tsx +3 -2
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +3 -2
- package/src/plugins/builtin/research/event-model.ts +10 -8
- package/src/plugins/builtin/research/headless.ts +1 -1
- package/src/plugins/builtin/research/relative-valuation-headless.ts +5 -1
- package/src/plugins/builtin/research/relative-valuation-model.ts +31 -3
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +11 -9
- package/src/plugins/builtin/reverse-dcf/headless.ts +5 -3
- package/src/plugins/builtin/reverse-dcf/model.ts +61 -6
- package/src/plugins/builtin/reverse-dcf/pane.tsx +7 -4
- package/src/plugins/builtin/scanner/feed.ts +2 -2
- package/src/plugins/builtin/scanner/flow-model.ts +50 -4
- package/src/plugins/builtin/scanner/flow-pane.tsx +367 -65
- package/src/plugins/builtin/scanner/flow-session.ts +146 -0
- package/src/plugins/builtin/scanner/headless.ts +204 -35
- package/src/plugins/builtin/scanner/index.ts +40 -6
- package/src/plugins/builtin/scanner/live-condition-editor.tsx +222 -0
- package/src/plugins/builtin/scanner/live-feed.ts +168 -0
- package/src/plugins/builtin/scanner/live-headless.ts +138 -0
- package/src/plugins/builtin/scanner/live-model.ts +362 -0
- package/src/plugins/builtin/scanner/live-pane.tsx +677 -0
- package/src/plugins/builtin/scanner/live-track.ts +186 -0
- package/src/plugins/builtin/scanner/lock-note.ts +3 -2
- package/src/plugins/builtin/seasonality/headless.ts +10 -1
- package/src/plugins/builtin/sec/fund-facts-view.tsx +5 -2
- package/src/plugins/builtin/sec/fund-facts.ts +116 -34
- package/src/plugins/builtin/sec/headless.ts +2 -1
- package/src/plugins/builtin/series-inventory.ts +3 -0
- package/src/plugins/builtin/shared/cloud-resource.ts +3 -2
- package/src/plugins/builtin/shared/cloud-upgrade.ts +4 -3
- package/src/plugins/builtin/shared/earnings-calendar.ts +6 -2
- package/src/plugins/builtin/shared/earnings-report.ts +2 -2
- package/src/plugins/builtin/shared/job-posting.ts +1 -0
- package/src/plugins/builtin/shared/macro-releases.ts +65 -0
- package/src/plugins/builtin/shared/members-menu.tsx +3 -2
- package/src/plugins/builtin/shared/pro-lock-note.ts +12 -12
- package/src/plugins/builtin/shared/report-freshness.ts +3 -2
- package/src/plugins/builtin/shared/scanner-capture.ts +3 -0
- package/src/plugins/builtin/shared/ticker-choice.tsx +2 -1
- package/src/plugins/builtin/shared/ticker-company.ts +77 -0
- package/src/plugins/builtin/shared/use-quote-board.ts +10 -3
- package/src/plugins/builtin/shared/volatility/live-session.ts +34 -8
- package/src/plugins/builtin/shared/volatility/pricing.ts +26 -1
- package/src/plugins/builtin/shared/wall-view-lifecycle.ts +3 -1
- package/src/plugins/builtin/themes/headless.ts +6 -4
- package/src/plugins/builtin/themes/model.ts +17 -8
- package/src/plugins/builtin/themes/pane.tsx +7 -7
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +43 -18
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +3 -2
- package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +62 -0
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +83 -46
- package/src/plugins/builtin/ticker-detail/headless.ts +31 -16
- package/src/plugins/builtin/ticker-detail/overview/model.ts +1 -1
- package/src/plugins/builtin/ticker-detail/pane.tsx +3 -2
- package/src/plugins/builtin/ticker-detail/quote-footer.ts +6 -1
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -1
- package/src/plugins/builtin/ticker-detail/settings.ts +1 -0
- package/src/plugins/builtin/time-sales/pane.tsx +31 -19
- package/src/plugins/builtin/treasury-daily/client.ts +41 -5
- package/src/plugins/builtin/treasury-daily/headless.ts +2 -2
- package/src/plugins/builtin/treasury-daily/index.tsx +1 -1
- package/src/plugins/builtin/treasury-daily/model.ts +50 -3
- package/src/plugins/builtin/treasury-daily/pane.tsx +81 -2
- package/src/plugins/builtin/vol-surface/charts.tsx +9 -4
- package/src/plugins/builtin/vol-surface/client.ts +9 -17
- package/src/plugins/builtin/vol-surface/headless.ts +63 -14
- package/src/plugins/builtin/vol-surface/index.tsx +2 -2
- package/src/plugins/builtin/vol-surface/model.ts +22 -7
- package/src/plugins/builtin/vol-surface/pane.tsx +48 -9
- package/src/plugins/builtin/vol-surface/tables.ts +31 -3
- package/src/plugins/builtin/volatility/dvol.ts +46 -0
- package/src/plugins/builtin/volatility/index.tsx +2 -2
- package/src/plugins/builtin/volatility/pane.tsx +4 -4
- package/src/plugins/builtin/volatility/series.ts +26 -0
- package/src/plugins/builtin/world-indices/footer.ts +1 -1
- package/src/plugins/builtin/world-venue-map/headless.ts +3 -3
- package/src/plugins/catalog-browser.ts +13 -8
- package/src/plugins/catalog-manifest.ts +2 -1
- package/src/plugins/marketplace/model.ts +18 -5
- package/src/portfolio/column-values.ts +5 -5
- package/src/portfolio/futures-positions.ts +6 -3
- package/src/portfolio/position-quantity.ts +15 -9
- package/src/public/__snapshots__/public-api.test.ts.snap +1 -0
- package/src/remote/resources.ts +2 -1
- package/src/renderers/browser/app-services.ts +1 -7
- package/src/renderers/browser/config-host.ts +2 -55
- package/src/renderers/browser/main.tsx +7 -57
- package/src/renderers/dom/data-table/row.tsx +26 -0
- package/src/renderers/dom/desktop/list-view.tsx +13 -10
- package/src/renderers/dom/desktop/query-bar.tsx +4 -2
- package/src/renderers/dom/desktop/select-field.tsx +4 -2
- package/src/renderers/dom/host/chart-surface.tsx +21 -0
- package/src/renderers/electrobun/bun/desktop/app-name.ts +222 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +29 -7
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +7 -0
- package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -0
- package/src/renderers/electrobun/bun/desktop/relaunch.ts +74 -25
- package/src/renderers/electrobun/bun/desktop/state-broadcaster.ts +1 -0
- package/src/renderers/electrobun/bun/desktop/update.ts +173 -5
- package/src/renderers/electrobun/bun/desktop/view-ids.ts +52 -0
- package/src/renderers/electrobun/bun/desktop/workspace/index.ts +2 -0
- package/src/renderers/electrobun/bun/index.ts +25 -1
- package/src/renderers/electrobun/shared/app-name.ts +30 -0
- package/src/renderers/electrobun/shared/protocol.ts +10 -0
- package/src/renderers/electrobun/view/backend-rpc.ts +6 -0
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +3 -3
- package/src/renderers/electrobun/view/desktop/window/snapshot.ts +1 -0
- package/src/renderers/electrobun/view/main.tsx +24 -1
- package/src/renderers/electrobun/view/news-source.ts +3 -1
- package/src/renderers/electrobun/view/remote/ticker-repository.ts +14 -7
- package/src/renderers/electrobun/view/view-ids.ts +85 -0
- package/src/renderers/opentui/start.tsx +5 -0
- package/src/renderers/opentui/toast-host.tsx +71 -43
- package/src/series/registry.ts +1 -0
- package/src/series/types.ts +6 -0
- package/src/series/validate.ts +1 -0
- package/src/sources/gloomberb-cloud/index.ts +1 -0
- package/src/sources/gloomberb-cloud/news.ts +47 -7
- package/src/sources/gloomberb-cloud/normalizers.ts +2 -0
- package/src/sources/provider-router/batches.ts +10 -2
- package/src/sources/provider-router/financial-routes.ts +3 -3
- package/src/sources/provider-router/financials.ts +15 -3
- package/src/sources/provider-router/history.ts +28 -7
- package/src/sources/provider-router/index.ts +149 -10
- package/src/sources/provider-router/search.ts +13 -2
- package/src/state/app/context/index.tsx +3 -0
- package/src/state/ticker-cleanup.ts +50 -0
- package/src/sync/auth-transition.ts +19 -9
- package/src/sync/baseline.ts +10 -4
- package/src/sync/controller.ts +70 -19
- package/src/sync/core-contributors.ts +90 -31
- package/src/sync/react.ts +4 -1
- package/src/sync/types.ts +3 -0
- package/src/telemetry/stall-reports-dom.ts +38 -0
- package/src/telemetry/stall-reports-node.ts +75 -0
- package/src/telemetry/stall-reports.ts +214 -0
- package/src/telemetry/usage-counts.ts +0 -18
- package/src/test-support/preload.ts +14 -0
- package/src/theme/colors.ts +8 -0
- package/src/theme/themes.ts +10 -0
- package/src/tickers/company-name.ts +103 -3
- package/src/tickers/listing-venues.ts +38 -3
- package/src/tickers/search/bare-symbol.ts +36 -0
- package/src/tickers/search/index.ts +36 -7
- package/src/tickers/search/ranking.ts +10 -1
- package/src/tickers/search/types.ts +5 -0
- package/src/tickers/terminal-codes.ts +19 -0
- package/src/time-series/alignment.ts +1 -1
- package/src/time-series/base-series.ts +13 -5
- package/src/time-series/daily-valuation.ts +62 -0
- package/src/time-series/economic.ts +18 -4
- package/src/time-series/field-catalog.ts +2 -4
- package/src/time-series/filed-trailing-eps.ts +197 -0
- package/src/time-series/forward-valuation.ts +32 -0
- package/src/time-series/fundamentals.ts +198 -7
- package/src/time-series/hooks.ts +1 -0
- package/src/time-series/ice-credit.ts +3 -0
- package/src/time-series/price-comparison.ts +30 -2
- package/src/time-series/price-units.ts +72 -2
- package/src/time-series/resolve-context.ts +7 -1
- package/src/time-series/resolve.ts +116 -15
- package/src/time-series/series-presentation.ts +40 -6
- package/src/time-series/session-bar.ts +11 -0
- package/src/time-series/spec.ts +5 -3
- package/src/time-series/studies.ts +278 -74
- package/src/time-series/total-return.ts +160 -0
- package/src/time-series/transforms.ts +3 -3
- package/src/time-series/types.ts +27 -1
- package/src/time-series/valuation-releases.ts +39 -0
- package/src/types/data-provider.ts +9 -1
- package/src/types/desktop-window.ts +2 -0
- package/src/types/financials.ts +73 -2
- package/src/types/headless.ts +61 -5
- package/src/types/instrument.ts +3 -0
- package/src/types/news-source.ts +1 -0
- package/src/types/plugin.ts +10 -1
- package/src/ui/host.tsx +3 -0
- package/src/updater/command-names.ts +12 -7
- package/src/updater/failure.ts +4 -1
- package/src/utils/cli-output.ts +42 -1
- package/src/utils/crypto-pair.ts +44 -0
- package/src/utils/financial-statements.ts +6 -1
- package/src/utils/forward-dividend.ts +2 -0
- package/src/utils/fundamentals.ts +24 -3
- package/src/utils/fx-market-hours.ts +26 -3
- package/src/utils/main-thread-stall.ts +35 -2
- package/src/utils/market-capitalization.ts +24 -1
- package/src/utils/network-failure.ts +9 -6
- package/src/utils/option-expiry.ts +48 -1
- package/src/utils/options.ts +10 -0
- package/src/utils/plugin-proxy-hosts.json +1 -0
- package/src/utils/price-history.ts +12 -1
- package/src/utils/shell-word.ts +8 -0
- package/src/utils/trailing-dividend.ts +53 -4
- package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +0 -17
- package/src/renderers/browser/first-screen.ts +0 -193
package/src/types/plugin.ts
CHANGED
|
@@ -20,6 +20,7 @@ export type {
|
|
|
20
20
|
HeadlessPaneOptionType,
|
|
21
21
|
HeadlessPaneOptionValue,
|
|
22
22
|
HeadlessPaneOptionValues,
|
|
23
|
+
HeadlessPaneReference,
|
|
23
24
|
HeadlessPaneResult,
|
|
24
25
|
HeadlessPaneResultByShape,
|
|
25
26
|
HeadlessPaneRow,
|
|
@@ -529,6 +530,14 @@ export interface PaneTemplateDef {
|
|
|
529
530
|
description: string;
|
|
530
531
|
keywords?: string[];
|
|
531
532
|
shortcut?: PaneTemplateShortcut;
|
|
533
|
+
/**
|
|
534
|
+
* False leaves the function out of every list and search of functions
|
|
535
|
+
* (command-bar browse, search and assistant, Help, `gloom catalog` and
|
|
536
|
+
* search, the plugin directory, chat suggestions) while typing its code
|
|
537
|
+
* still opens it, `fn` and `shot` still run it and its help still answers.
|
|
538
|
+
* ATTN until it publishes (attention/listing.ts).
|
|
539
|
+
*/
|
|
540
|
+
listed?: boolean;
|
|
532
541
|
/** Template-specific headless model. Takes precedence over the pane-level model. */
|
|
533
542
|
headless?: HeadlessPaneDefinition;
|
|
534
543
|
/**
|
|
@@ -945,7 +954,7 @@ export interface AppNotificationRequest {
|
|
|
945
954
|
/**
|
|
946
955
|
* What a built-in notice is about, so the Unread list can keep it after the
|
|
947
956
|
* toast is gone and open it again: `price:<alertId>`, `catalyst:<eventId>`,
|
|
948
|
-
* `econ:<eventId>` or `
|
|
957
|
+
* `econ:<eventId>`, `team:<cardId>` or `scan:<paneId>`. Other values are not kept.
|
|
949
958
|
*/
|
|
950
959
|
refId?: string;
|
|
951
960
|
/** Rendered next to `action`. Use for a dismissing counterpart such as snooze. */
|
package/src/ui/host.tsx
CHANGED
|
@@ -82,6 +82,8 @@ export interface ChartVectorShape {
|
|
|
82
82
|
gradient?: readonly string[];
|
|
83
83
|
/** Opacity of the whole shape, so others can recede behind a highlighted one. */
|
|
84
84
|
opacity?: number;
|
|
85
|
+
/** Text set just above the shape's first point, such as a retracement level's ratio and price. */
|
|
86
|
+
label?: string;
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
interface TextEditBuffer {
|
|
@@ -508,6 +510,7 @@ export interface HostCheckboxProps {
|
|
|
508
510
|
interface HostQueryBarOption {
|
|
509
511
|
value: string;
|
|
510
512
|
label: string;
|
|
513
|
+
group?: string;
|
|
511
514
|
description?: string;
|
|
512
515
|
disabled?: boolean;
|
|
513
516
|
selected: boolean;
|
|
@@ -3,7 +3,7 @@ import { lstat, readFile, readlink, stat, symlink, writeFile } from "fs/promises
|
|
|
3
3
|
import { basename, dirname, join, resolve } from "path";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* The terminal command is `gloom`. `gloomberb`, its name before 0.
|
|
6
|
+
* The terminal command is `gloom`. `gloomberb`, its name before 0.18.4, keeps
|
|
7
7
|
* working beside it, for scripts and habits.
|
|
8
8
|
*
|
|
9
9
|
* An install from before the rename has only `gloomberb`, and the ways it
|
|
@@ -58,17 +58,21 @@ export function linkStandaloneCommand(execPath: string): string | null {
|
|
|
58
58
|
return addSymlink(name, path);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
/** Homebrew's prefixes on Apple Silicon and on Intel. */
|
|
62
|
+
export const HOMEBREW_PREFIXES = ["/opt/homebrew", "/usr/local"];
|
|
63
|
+
|
|
61
64
|
/** Homebrew's command folders on Apple Silicon and on Intel. */
|
|
62
|
-
const HOMEBREW_BINS =
|
|
65
|
+
const HOMEBREW_BINS = HOMEBREW_PREFIXES.map((prefix) => join(prefix, "bin"));
|
|
63
66
|
|
|
64
67
|
/**
|
|
65
|
-
* Where a Mac keeps the desktop app's command: install.sh's folder,
|
|
66
|
-
* then the rest of PATH. A GUI app's PATH rarely has the first
|
|
67
|
-
* are named outright.
|
|
68
|
+
* Where a Mac keeps the desktop app's command: install.sh's folder, `~/bin`,
|
|
69
|
+
* Homebrew's, then the rest of PATH. A GUI app's PATH rarely has the first
|
|
70
|
+
* ones, so they are named outright.
|
|
68
71
|
*/
|
|
69
|
-
function macCommandFolders(homeDir: string, pathEnv: string, homebrewBins: readonly string[]): string[] {
|
|
72
|
+
export function macCommandFolders(homeDir: string, pathEnv: string, homebrewBins: readonly string[] = HOMEBREW_BINS): string[] {
|
|
70
73
|
return [...new Set([
|
|
71
74
|
homeDir ? join(homeDir, ".local", "bin") : "",
|
|
75
|
+
homeDir ? join(homeDir, "bin") : "",
|
|
72
76
|
...homebrewBins,
|
|
73
77
|
...pathEnv.split(":"),
|
|
74
78
|
].filter(Boolean))];
|
|
@@ -141,7 +145,7 @@ interface DesktopCommandOptions {
|
|
|
141
145
|
homeDir: string;
|
|
142
146
|
/** PATH as the app sees it. */
|
|
143
147
|
pathEnv: string;
|
|
144
|
-
/** `%LOCALAPPDATA%`, where the Windows installer puts the app by default. */
|
|
148
|
+
/** `%LOCALAPPDATA%`, where the Windows installer puts the app by default (`Programs\Gloom`, `Programs\Gloomberb` before the rename). */
|
|
145
149
|
localAppData?: string;
|
|
146
150
|
/** Homebrew's command folders; tests pass none. */
|
|
147
151
|
homebrewBins?: readonly string[];
|
|
@@ -166,6 +170,7 @@ export async function linkDesktopCommands({
|
|
|
166
170
|
added = await Promise.all(macCommandFolders(homeDir, pathEnv, homebrewBins).map(linkMacCommand));
|
|
167
171
|
} else if (platform === "win32") {
|
|
168
172
|
const folders = new Set([
|
|
173
|
+
localAppData ? join(localAppData, "Programs", "Gloom", "bin") : "",
|
|
169
174
|
localAppData ? join(localAppData, "Programs", "Gloomberb", "bin") : "",
|
|
170
175
|
...pathEnv.split(";"),
|
|
171
176
|
].filter(Boolean));
|
package/src/updater/failure.ts
CHANGED
|
@@ -24,7 +24,7 @@ const UPDATE_FAILURE_CODES = [
|
|
|
24
24
|
"no_build",
|
|
25
25
|
/** The download stopped before the whole file arrived. */
|
|
26
26
|
"interrupted",
|
|
27
|
-
/** The
|
|
27
|
+
/** The download does not match its checksum, or does not unpack (part of it is missing or damaged). */
|
|
28
28
|
"corrupt",
|
|
29
29
|
"permission_denied",
|
|
30
30
|
/** The macOS app runs from where it cannot be replaced: a disk image, App Translocation, another volume. */
|
|
@@ -112,6 +112,9 @@ export function classifyUpdateError(error: unknown): UpdateFailureCode {
|
|
|
112
112
|
if (status) return httpStatusFailureCode(Number(status));
|
|
113
113
|
if (/checksum mismatch|hash mismatch/i.test(message)) return "corrupt";
|
|
114
114
|
if (/zstd|decompress|gunzip|incorrect header|unexpected end of (?:file|data)/i.test(message)) return "corrupt";
|
|
115
|
+
// Bun.Archive on a tar that does not read: cut off, damaged, or none at all.
|
|
116
|
+
// Unpacking says only "ReadError", whatever stopped it.
|
|
117
|
+
if (/\bReadError\b|truncated tar|damaged tar|unrecognized archive format/i.test(message)) return "corrupt";
|
|
115
118
|
if (/timed? ?out/i.test(message)) return "timeout";
|
|
116
119
|
if (/rate limit/i.test(message)) return "rate_limited";
|
|
117
120
|
if (/read-only file system/i.test(message)) return "read_only";
|
package/src/utils/cli-output.ts
CHANGED
|
@@ -74,6 +74,47 @@ const PLAIN_EMPTY_CELL = "—";
|
|
|
74
74
|
let colorEnabledOverride: boolean | null = null;
|
|
75
75
|
let widthOverride: number | null = null;
|
|
76
76
|
let plainOverride: boolean | null = null;
|
|
77
|
+
/** Output is being rendered for a file (`renderForFile`), which has no terminal width. */
|
|
78
|
+
let renderingForFile = false;
|
|
79
|
+
|
|
80
|
+
/** Renders for a file from here on; the function returned puts the terminal's rendering back. */
|
|
81
|
+
function enterFileRendering(): () => void {
|
|
82
|
+
const saved = { color: colorEnabledOverride, plain: plainOverride, file: renderingForFile };
|
|
83
|
+
colorEnabledOverride = false;
|
|
84
|
+
plainOverride = true;
|
|
85
|
+
renderingForFile = true;
|
|
86
|
+
return () => {
|
|
87
|
+
colorEnabledOverride = saved.color;
|
|
88
|
+
plainOverride = saved.plain;
|
|
89
|
+
renderingForFile = saved.file;
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Output rendered for a file (`fn --output`) as a redirect gets it: plain,
|
|
95
|
+
* without colour, and fitted to no width but `--width`'s.
|
|
96
|
+
*/
|
|
97
|
+
export function renderForFile<T>(render: () => T): T {
|
|
98
|
+
const restore = enterFileRendering();
|
|
99
|
+
try {
|
|
100
|
+
return render();
|
|
101
|
+
} finally {
|
|
102
|
+
restore();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* `renderForFile` around work that renders as it loads: a report whose text is
|
|
108
|
+
* drawn while it is built is drawn for the file, though stdout is a terminal.
|
|
109
|
+
*/
|
|
110
|
+
export async function buildForFile<T>(build: () => Promise<T>): Promise<T> {
|
|
111
|
+
const restore = enterFileRendering();
|
|
112
|
+
try {
|
|
113
|
+
return await build();
|
|
114
|
+
} finally {
|
|
115
|
+
restore();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
77
118
|
|
|
78
119
|
function colorEnabled(): boolean {
|
|
79
120
|
if (colorEnabledOverride != null) return colorEnabledOverride;
|
|
@@ -176,7 +217,7 @@ export function setCliWidthOverride(value: number | null): void {
|
|
|
176
217
|
/** Columns the output is fitted to: `--width`, else the terminal's, or null when output is piped or redirected. */
|
|
177
218
|
export function cliTerminalWidth(): number | null {
|
|
178
219
|
if (widthOverride != null) return widthOverride;
|
|
179
|
-
if (!process.stdout.isTTY) return null;
|
|
220
|
+
if (renderingForFile || !process.stdout.isTTY) return null;
|
|
180
221
|
const columns = process.stdout.columns;
|
|
181
222
|
return typeof columns === "number" && columns > 0 ? columns : null;
|
|
182
223
|
}
|
package/src/utils/crypto-pair.ts
CHANGED
|
@@ -91,6 +91,50 @@ export const MAJOR_COIN_NAMES: ReadonlyMap<string, string> = new Map([
|
|
|
91
91
|
["BNB", "BNB"],
|
|
92
92
|
]);
|
|
93
93
|
|
|
94
|
+
/**
|
|
95
|
+
* The largest coins by market value, stablecoins and gold tokens left out, with
|
|
96
|
+
* how a note names each: the coins whose bare ticker a listed company or fund
|
|
97
|
+
* may hold instead (SOL is a stale Emeren Group, LINK is Interlink Electronics).
|
|
98
|
+
* A hint reads this list; `MAJOR_COIN_NAMES` stays the shorter one stories and
|
|
99
|
+
* company-name lookups use, so a word such as "stellar" is still a company's.
|
|
100
|
+
*/
|
|
101
|
+
export const TOP_COIN_NAMES: ReadonlyMap<string, string> = new Map([
|
|
102
|
+
...MAJOR_COIN_NAMES,
|
|
103
|
+
["TRX", "tron"],
|
|
104
|
+
["ZEC", "zcash"],
|
|
105
|
+
["HYPE", "hyperliquid"],
|
|
106
|
+
["XMR", "monero"],
|
|
107
|
+
["XLM", "stellar"],
|
|
108
|
+
["NEAR", "near protocol"],
|
|
109
|
+
["TON", "toncoin"],
|
|
110
|
+
["UNI", "uniswap"],
|
|
111
|
+
["SUI", "sui"],
|
|
112
|
+
["HBAR", "hedera"],
|
|
113
|
+
["TAO", "bittensor"],
|
|
114
|
+
["SHIB", "shiba inu"],
|
|
115
|
+
["ENA", "ethena"],
|
|
116
|
+
["CRO", "cronos"],
|
|
117
|
+
["AAVE", "aave"],
|
|
118
|
+
["ONDO", "ondo"],
|
|
119
|
+
["PEPE", "pepe"],
|
|
120
|
+
["ICP", "internet computer"],
|
|
121
|
+
["ETC", "ethereum classic"],
|
|
122
|
+
["ARB", "arbitrum"],
|
|
123
|
+
["ALGO", "algorand"],
|
|
124
|
+
["ATOM", "cosmos"],
|
|
125
|
+
["APT", "aptos"],
|
|
126
|
+
["FIL", "filecoin"],
|
|
127
|
+
["POL", "polygon"],
|
|
128
|
+
["OP", "optimism"],
|
|
129
|
+
["WLD", "worldcoin"],
|
|
130
|
+
["MNT", "mantle"],
|
|
131
|
+
["KAS", "kaspa"],
|
|
132
|
+
["QNT", "quant"],
|
|
133
|
+
["VET", "vechain"],
|
|
134
|
+
["INJ", "injective"],
|
|
135
|
+
["RENDER", "render"],
|
|
136
|
+
]);
|
|
137
|
+
|
|
94
138
|
const COIN_PAIR = /^([A-Z0-9]{1,15})[-/](?:USD|EUR|GBP|USDT|USDC|BTC)$/;
|
|
95
139
|
// What a pair's listing name adds after the coin's: its quote currency, an id in brackets.
|
|
96
140
|
const PAIR_NAME_SUFFIX = /(?:\s*\([^)]*\))+$|\s+(?:USD|EUR|GBP|USDT|USDC|BTC|US Dollars?)$/i;
|
|
@@ -116,11 +116,16 @@ export function statementFieldAvailability(row: FinancialStatement | undefined,
|
|
|
116
116
|
return value && Number.isFinite(Date.parse(value)) ? value : undefined;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
/** A date without a publication time is only known to be available after that day. */
|
|
120
|
+
export function financialAvailabilityTime(value: string): number {
|
|
121
|
+
return Date.parse(value) + (/^\d{4}-\d{2}-\d{2}$/.test(value) ? 86_400_000 : 0);
|
|
122
|
+
}
|
|
123
|
+
|
|
119
124
|
/** A derived value is dated only when every input's availability is known. */
|
|
120
125
|
export function completeAvailability(values: readonly (string | null | undefined)[]): string | undefined {
|
|
121
126
|
if (values.length === 0 || values.some((value) => !value || !Number.isFinite(Date.parse(value)))) return undefined;
|
|
122
127
|
return values.reduce<string | undefined>((latest, value) => (
|
|
123
|
-
!latest ||
|
|
128
|
+
!latest || financialAvailabilityTime(value!) > financialAvailabilityTime(latest) ? value! : latest
|
|
124
129
|
), undefined);
|
|
125
130
|
}
|
|
126
131
|
|
|
@@ -14,6 +14,8 @@ import { formatDistributionAmount } from "./format";
|
|
|
14
14
|
* the rate divided back.
|
|
15
15
|
*/
|
|
16
16
|
export const LATEST_DISTRIBUTION = "latest distribution annualized";
|
|
17
|
+
/** The basis of a forward rate that is the year's regular payments, which differ too widely for one to be annualized (unevenRegularPayments). */
|
|
18
|
+
export const UNEVEN_REGULAR_PAYMENTS = "trailing regular payments: uneven interims";
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
21
|
* What a trailing dividend yield is everywhere it shows (DVD, a fund's in
|
|
@@ -6,16 +6,19 @@ import { formatCompact } from "./format";
|
|
|
6
6
|
import { formatUtcTime } from "./utc-time";
|
|
7
7
|
|
|
8
8
|
export const RETRACTABLE_VALUATION_FIELDS = ["enterpriseValue", "enterpriseToRevenue"] as const;
|
|
9
|
+
/** Every field a source can retract: the valuation fields, and a receipt's market cap (`marketCapUnavailable`). */
|
|
10
|
+
export const RETRACTED_FUNDAMENTALS_FIELDS = [...RETRACTABLE_VALUATION_FIELDS, "marketCap"] as const;
|
|
9
11
|
|
|
10
|
-
/** A retraction survives serialization and overrides a contradictory cached number. */
|
|
12
|
+
/** A retraction survives serialization and overrides a contradictory cached number; its reason goes with it. */
|
|
11
13
|
export function redactUnavailableFundamentals(value: Fundamentals | undefined): Fundamentals | undefined {
|
|
12
|
-
if (!value || value.unavailableFields === undefined) return value;
|
|
14
|
+
if (!value || (value.unavailableFields === undefined && value.marketCapUnavailable === undefined)) return value;
|
|
13
15
|
const unavailableFields = Array.isArray(value.unavailableFields)
|
|
14
|
-
?
|
|
16
|
+
? RETRACTED_FUNDAMENTALS_FIELDS.filter((field) => value.unavailableFields!.includes(field)) : [];
|
|
15
17
|
const result = { ...value };
|
|
16
18
|
if (unavailableFields.length) result.unavailableFields = unavailableFields;
|
|
17
19
|
else delete result.unavailableFields;
|
|
18
20
|
for (const field of unavailableFields) delete result[field];
|
|
21
|
+
if (!unavailableFields.includes("marketCap")) delete result.marketCapUnavailable;
|
|
19
22
|
return result;
|
|
20
23
|
}
|
|
21
24
|
|
|
@@ -243,6 +246,24 @@ export function epsConversionNote(fundamentals: Pick<Fundamentals, "financialCur
|
|
|
243
246
|
return eps && amounts && eps !== amounts ? `EPS (TTM) in ${eps}, converted from ${amounts} at report-date rates.` : undefined;
|
|
244
247
|
}
|
|
245
248
|
|
|
249
|
+
/** What a trailing EPS that is not the filed quarters' is called where it is shown (EE's TTM row). */
|
|
250
|
+
export const SERVED_TRAILING_EPS = "Gloom Cloud's TTM";
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* "EPS (TTM) and P/E (TTM) are Gloom Cloud's trailing figures, not the last four filed quarters'.": the headline EPS
|
|
254
|
+
* and P/E are the filed quarters' (time-series/filed-trailing-eps), so served ones say so, naming those `shown`
|
|
255
|
+
* ("P/E (TTM) is Gloom Cloud's trailing figure, ..." for a fund's P/E with no EPS). Undefined otherwise.
|
|
256
|
+
*/
|
|
257
|
+
export function trailingEpsSourceNote(
|
|
258
|
+
fundamentals: Pick<Fundamentals, "trailingEpsSource"> | undefined,
|
|
259
|
+
shown: { eps: boolean; pe: boolean },
|
|
260
|
+
): string | undefined {
|
|
261
|
+
if (fundamentals?.trailingEpsSource !== "served" || (!shown.eps && !shown.pe)) return undefined;
|
|
262
|
+
const figures = shown.eps && shown.pe ? "EPS (TTM) and P/E (TTM) are Gloom Cloud's trailing figures"
|
|
263
|
+
: `${shown.eps ? "EPS (TTM)" : "P/E (TTM)"} is Gloom Cloud's trailing figure`;
|
|
264
|
+
return `${figures}, not the last four filed quarters'.`;
|
|
265
|
+
}
|
|
266
|
+
|
|
246
267
|
type PriceEarningsBasis = Pick<Fundamentals, "financialCurrency" | "ttmConversion" | "epsCurrency" | "trailingPEConversion">;
|
|
247
268
|
|
|
248
269
|
/** The trailing EPS in the price's currency: converted at the rate the served P/E used when it says so. */
|
|
@@ -30,12 +30,35 @@ export function isFxMarketOpen(time: number): boolean {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
* The FX trading day
|
|
34
|
-
* at 17:00 New York time, so Wednesday 18:00 New York is
|
|
33
|
+
* The FX trading day a print made at `time` belongs to, as "YYYY-MM-DD": the
|
|
34
|
+
* day rolls at 17:00 New York time, so Wednesday 18:00 New York is
|
|
35
|
+
* Thursday's. A print stamped exactly 17:00:00 is that day's close, so it is
|
|
36
|
+
* still that day's.
|
|
35
37
|
*/
|
|
36
38
|
export function fxTradingDay(time: number): string {
|
|
37
39
|
// The roll is 17:00, seven hours before New York's midnight, daylight saving or not.
|
|
38
|
-
return zonedDateKey(time + 7 * HOUR_MS, NEW_YORK);
|
|
40
|
+
return zonedDateKey(time - 1 + 7 * HOUR_MS, NEW_YORK);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The FX trading day of a print made at `time` (fxTradingDay), or null for a
|
|
45
|
+
* print made while the market is shut: from just after Friday's 17:00 New
|
|
46
|
+
* York close, whose own print still counts, through Sunday's 17:00 open. A
|
|
47
|
+
* tick over the weekend belongs to no trading day.
|
|
48
|
+
*/
|
|
49
|
+
export function fxPrintTradingDay(time: number): string | null {
|
|
50
|
+
return Number.isFinite(time) && isFxMarketOpen(time - 1) ? fxTradingDay(time) : null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The FX trading day the market is on at `time`: the day in progress while it
|
|
55
|
+
* trades, or the Friday that closed it while it is shut.
|
|
56
|
+
*/
|
|
57
|
+
export function fxTradingDayAt(time: number): string | null {
|
|
58
|
+
const day = fxPrintTradingDay(time);
|
|
59
|
+
if (day != null || !Number.isFinite(time)) return day;
|
|
60
|
+
const shut = currentFxClosureStart(time - 1);
|
|
61
|
+
return shut != null ? fxTradingDay(shut) : null;
|
|
39
62
|
}
|
|
40
63
|
|
|
41
64
|
/** The latest 17:00 New York on `weekday` (0 is Sunday) at or before `time`. */
|
|
@@ -9,13 +9,43 @@ const SAMPLE_INTERVAL_MS = 250;
|
|
|
9
9
|
*/
|
|
10
10
|
const STALL_THRESHOLD_MS = 400;
|
|
11
11
|
|
|
12
|
+
export interface StallEvent {
|
|
13
|
+
blockedMs: number;
|
|
14
|
+
/** The last measured section before the stall (perf-marks), if any. */
|
|
15
|
+
lastMeasured?: string;
|
|
16
|
+
/** How long before the stall was noticed that section ended. */
|
|
17
|
+
lastMeasuredEndedMsAgo?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let stallSink: ((event: StallEvent) => void) | null = null;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Where this process's stalls go besides the Debug Log: the stall log and its
|
|
24
|
+
* report (telemetry/stall-reports.ts), or, in the desktop window, the Bun
|
|
25
|
+
* process that keeps them.
|
|
26
|
+
*/
|
|
27
|
+
export function setStallSink(next: ((event: StallEvent) => void) | null): () => void {
|
|
28
|
+
stallSink = next;
|
|
29
|
+
return () => {
|
|
30
|
+
if (stallSink === next) stallSink = null;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function noteStall(event: StallEvent): void {
|
|
35
|
+
try {
|
|
36
|
+
stallSink?.(event);
|
|
37
|
+
} catch {
|
|
38
|
+
// Intentional ignore: reporting a freeze must never become one.
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
12
42
|
export interface MainThreadStallMonitorOptions {
|
|
13
43
|
intervalMs?: number;
|
|
14
44
|
thresholdMs?: number;
|
|
15
45
|
now?: () => number;
|
|
16
46
|
schedule?: (callback: () => void, delayMs: number) => unknown;
|
|
17
47
|
cancel?: (handle: unknown) => void;
|
|
18
|
-
report?: (blockedMs: number, context:
|
|
48
|
+
report?: (blockedMs: number, context: Omit<StallEvent, "blockedMs">) => void;
|
|
19
49
|
}
|
|
20
50
|
|
|
21
51
|
function defaultNow(): number {
|
|
@@ -41,7 +71,10 @@ export function startMainThreadStallMonitor(
|
|
|
41
71
|
const schedule = options.schedule ?? ((callback, delayMs) => setInterval(callback, delayMs));
|
|
42
72
|
const cancel = options.cancel ?? ((handle) => clearInterval(handle as ReturnType<typeof setInterval>));
|
|
43
73
|
const report = options.report
|
|
44
|
-
?? ((blockedMs, context) =>
|
|
74
|
+
?? ((blockedMs, context) => {
|
|
75
|
+
recordPerfSample("runtime.stall", blockedMs, context);
|
|
76
|
+
noteStall({ blockedMs, ...context });
|
|
77
|
+
});
|
|
45
78
|
|
|
46
79
|
let previous = now();
|
|
47
80
|
const handle = schedule(() => {
|
|
@@ -20,11 +20,34 @@ function explicitCurrency(currency: string | undefined): currency is string {
|
|
|
20
20
|
return currency != null && /^[A-Z]{3}$/.test(currency);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
/**
|
|
23
|
+
/** What every view says for a cap Gloom Cloud withheld, in the words its screener uses. */
|
|
24
|
+
const WITHHELD_MARKET_CAP: Record<NonNullable<Fundamentals["marketCapUnavailable"]>, { gap: string; note: string }> = {
|
|
25
|
+
"receipt-priced-as-ordinary": {
|
|
26
|
+
gap: "receipt, no ratio",
|
|
27
|
+
note: "No market cap: a depositary receipt with no known ratio, whose source's cap is the receipt price x the company's ordinary shares.",
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Why a listing has no market cap when Gloom Cloud withheld it: `gap` for a cell, `note` for a line under a
|
|
33
|
+
* report. Null when the cap was not withheld.
|
|
34
|
+
*/
|
|
35
|
+
export function withheldMarketCap(fundamentals: Pick<Fundamentals, "unavailableFields" | "marketCapUnavailable"> | undefined):
|
|
36
|
+
{ gap: string; note: string } | null {
|
|
37
|
+
if (!fundamentals?.unavailableFields?.includes("marketCap")) return null;
|
|
38
|
+
const reason = fundamentals.marketCapUnavailable ? WITHHELD_MARKET_CAP[fundamentals.marketCapUnavailable] : undefined;
|
|
39
|
+
return reason ?? { gap: "withheld", note: "No market cap: Gloom Cloud withheld it." };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* A lightweight quote can omit capitalization without invalidating the snapshot. A cap Gloom Cloud withheld
|
|
44
|
+
* (withheldMarketCap) is none, the quote's included.
|
|
45
|
+
*/
|
|
24
46
|
export function selectMarketCapitalization(
|
|
25
47
|
quote: Quote | undefined,
|
|
26
48
|
fundamentals: Fundamentals | undefined,
|
|
27
49
|
): MarketCapitalization | null {
|
|
50
|
+
if (withheldMarketCap(fundamentals)) return null;
|
|
28
51
|
if (usableValue(quote?.marketCap) && explicitCurrency(quote?.currency)) {
|
|
29
52
|
return { value: quote.marketCap, currency: quote.currency,
|
|
30
53
|
provenance: { kind: "quote", source: quote.providerId } };
|
|
@@ -3,9 +3,10 @@ export const DATA_SERVICE_UNREACHABLE_MESSAGE = "Gloom couldn't reach its data s
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* A request that never reached the data service: no connection, a proxy that
|
|
6
|
-
* refused it, a name that did not resolve
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* refused it, a name that did not resolve, or a connection that hung with
|
|
7
|
+
* nothing coming back before the request's deadline. The fetch's own error (or
|
|
8
|
+
* the deadline's) is the `cause`, and its `code` (Bun's `ConnectionRefused`,
|
|
9
|
+
* Node's `ENOTFOUND`) is kept for code that classifies failures by it.
|
|
9
10
|
*/
|
|
10
11
|
export class DataServiceUnreachableError extends Error {
|
|
11
12
|
readonly code?: string;
|
|
@@ -56,9 +57,11 @@ function cameFromServer(error: object): boolean {
|
|
|
56
57
|
|
|
57
58
|
/**
|
|
58
59
|
* Whether a request failed before any answer came back. A caller's abort and
|
|
59
|
-
* a timeout are not: the first is on purpose, and the second
|
|
60
|
-
* that did not answer in time.
|
|
61
|
-
*
|
|
60
|
+
* a bare timeout are not: the first is on purpose, and the second may have
|
|
61
|
+
* reached a server that did not answer in time. A Cloud request whose deadline
|
|
62
|
+
* passed with nothing back from the service is one: the client throws it as
|
|
63
|
+
* `DataServiceUnreachableError`, as it does a refused connection. Nor is
|
|
64
|
+
* anything the server answered, whatever its text or code says.
|
|
62
65
|
*/
|
|
63
66
|
export function isNetworkFailure(error: unknown): boolean {
|
|
64
67
|
if (typeof error === "string") return NO_CONNECTION_MESSAGES.has(error.trim());
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
import type { OptionsChain } from "../types/financials";
|
|
8
8
|
import { hasRegularCloseHour, latestRegularSessionClose, sessionCalendarTimeZone } from "../market-data/market/freshness";
|
|
9
|
+
import { listedCoinOptions } from "../market-data/options-alternatives";
|
|
9
10
|
import { dateOptionHint, readCalendarDate } from "./calendar-date";
|
|
11
|
+
import { isRoundTheClockCoin } from "./crypto-pair";
|
|
10
12
|
import { canonicalExchange, isUsListingExchange } from "./exchanges";
|
|
11
13
|
import { zonedWallClockToUtcMs } from "./zoned-date-time";
|
|
12
14
|
|
|
@@ -20,6 +22,23 @@ export const OPTION_EXPIRATION_FORMAT = "YYYY-MM-DD (2028-01-21), DD.MM.YYYY, Ja
|
|
|
20
22
|
/** The value's name in a catalog flag, `--expiration <date|unix>`. */
|
|
21
23
|
export const OPTION_EXPIRATION_PLACEHOLDER = "date|unix";
|
|
22
24
|
|
|
25
|
+
/** Seconds into its UTC day that Deribit stamps each expiry at: its 08:00 UTC settlement. */
|
|
26
|
+
const UTC_SETTLEMENT_SECONDS = 8 * 3600;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Whether an expiry stamp is the settlement instant itself, as Deribit stamps
|
|
30
|
+
* its BTC and ETH expiries (08:00 UTC), rather than a listed option's date. No
|
|
31
|
+
* US listing is stamped at that hour: they carry the date's midnight or its close.
|
|
32
|
+
*/
|
|
33
|
+
export function isSettlementStamp(seconds: number): boolean {
|
|
34
|
+
return Number.isFinite(seconds) && ((seconds % 86_400) + 86_400) % 86_400 === UTC_SETTLEMENT_SECONDS;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** `08:00 UTC` for a settlement stamp (`isSettlementStamp`); null for a dated one. */
|
|
38
|
+
export function settlementStampTime(seconds: number): string | null {
|
|
39
|
+
return isSettlementStamp(seconds) ? `${new Date(seconds * 1000).toISOString().slice(11, 16)} UTC` : null;
|
|
40
|
+
}
|
|
41
|
+
|
|
23
42
|
/** The expiry's calendar date, `2028-01-21`; empty for a stamp that is not a time. */
|
|
24
43
|
export function expiryIsoDate(seconds: number): string {
|
|
25
44
|
const date = new Date(seconds * 1000);
|
|
@@ -89,6 +108,9 @@ export function formatDaysToExpiry(expiration: number, asOfMs: number, exchange?
|
|
|
89
108
|
return isLiveOptionExpiry(expiration, asOfMs, exchange) ? `${Math.max(0, daysToExpiry(expiration, asOfMs))}d` : "expired";
|
|
90
109
|
}
|
|
91
110
|
|
|
111
|
+
/** The coin board's venue code, which a coin pair's listing carries. */
|
|
112
|
+
const COIN_OPTIONS_VENUE = "CCC";
|
|
113
|
+
|
|
92
114
|
/** Listed US options trade on the US equity calendar, NYSE's published one. */
|
|
93
115
|
const US_OPTIONS_CALENDAR = "NYSE";
|
|
94
116
|
const lastSessions = new Map<string, { date: string; close: number } | null>();
|
|
@@ -105,10 +127,33 @@ function expiryCalendarVenue(exchange: string | undefined): string {
|
|
|
105
127
|
? venue : US_OPTIONS_CALENDAR;
|
|
106
128
|
}
|
|
107
129
|
|
|
130
|
+
/**
|
|
131
|
+
* The venue to read an expiry's close on for a listing: the coin board for a
|
|
132
|
+
* coin whose options are listed (BTC-USD, ETH-USD, even when it carries no
|
|
133
|
+
* venue), else the listing's own.
|
|
134
|
+
*/
|
|
135
|
+
export function optionExpiryVenue(symbol: string | undefined, exchange: string | undefined): string | undefined {
|
|
136
|
+
return symbol && listedCoinOptions(symbol) ? COIN_OPTIONS_VENUE : exchange;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* When a settlement-priced expiry settles (Deribit's BTC and ETH options): its
|
|
141
|
+
* stamp when it carries the 08:00 UTC settlement, or 08:00 UTC on a typed
|
|
142
|
+
* date's day for a coin listing. Any day of the week, weekends included: the
|
|
143
|
+
* US calendar does not apply. Null for a listed US option, whatever its venue.
|
|
144
|
+
*/
|
|
145
|
+
function settlementCloseMs(expiration: number, exchange: string | undefined): number | null {
|
|
146
|
+
if (isSettlementStamp(expiration)) return expiration * 1000;
|
|
147
|
+
if (!isRoundTheClockCoin(undefined, exchange)) return null;
|
|
148
|
+
return Math.floor(expiration / 86_400) * 86_400_000 + UTC_SETTLEMENT_SECONDS * 1000;
|
|
149
|
+
}
|
|
150
|
+
|
|
108
151
|
/** The expiry's last trading session, on or before its date, on its venue's calendar: the date and when it closed. */
|
|
109
152
|
function expiryLastSession(expiration: number, exchange: string | undefined): { date: string; close: number } | null {
|
|
110
153
|
const date = expiryIsoDate(expiration);
|
|
111
154
|
if (!date) return null;
|
|
155
|
+
const settles = settlementCloseMs(expiration, exchange);
|
|
156
|
+
if (settles != null) return { date, close: settles };
|
|
112
157
|
const venue = expiryCalendarVenue(exchange);
|
|
113
158
|
const key = `${venue}:${date}`;
|
|
114
159
|
const known = lastSessions.get(key);
|
|
@@ -128,7 +173,9 @@ function expiryLastSession(expiration: number, exchange: string | undefined): {
|
|
|
128
173
|
* listing venue's last trading day on or before the expiry's date, on that
|
|
129
174
|
* venue's clock and calendar. A US expiry closes at 16:00 New York, at 13:00
|
|
130
175
|
* on a published early close, and one dated on a holiday or a weekend closed
|
|
131
|
-
* with the session before it.
|
|
176
|
+
* with the session before it. A Deribit expiry (BTC-USD, ETH-USD) settles at
|
|
177
|
+
* 08:00 UTC on its own date, a Saturday or Sunday too. Null for a stamp that
|
|
178
|
+
* is not a date.
|
|
132
179
|
*/
|
|
133
180
|
export function optionExpiryCloseMs(expiration: number, exchange?: string): number | null {
|
|
134
181
|
return expiryLastSession(expiration, exchange)?.close ?? null;
|
package/src/utils/options.ts
CHANGED
|
@@ -11,6 +11,16 @@ export function formatExpDate(ts: number): string {
|
|
|
11
11
|
return `${month} ${d.getUTCDate()} '${yy}`;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* A strike as every options pane writes it: grouped, with every listed
|
|
16
|
+
* decimal (`82,000`, `82.5`). 15 significant digits keep every listed decimal
|
|
17
|
+
* but drop binary noise from computed strikes such as spot * 0.9.
|
|
18
|
+
*/
|
|
19
|
+
export function formatStrikeLabel(strike: number): string {
|
|
20
|
+
return Number.isFinite(strike)
|
|
21
|
+
? strike.toLocaleString("en-US", { maximumSignificantDigits: 15 }) : "\u2014";
|
|
22
|
+
}
|
|
23
|
+
|
|
14
24
|
/**
|
|
15
25
|
* Parse IBKR option symbol like "UBER 260821C00090000" into components.
|
|
16
26
|
* Returns null if not a recognized option symbol.
|
|
@@ -2,7 +2,7 @@ import type { PricePoint, TickerFinancials } from "../types/financials";
|
|
|
2
2
|
import { canonicalExchange } from "./exchanges";
|
|
3
3
|
import { isRoundTheClockCoin } from "./crypto-pair";
|
|
4
4
|
import { isCurrencyPairListing, isFxMarketOpen, latestFxWeekClose, latestFxWeekOpen } from "./fx-market-hours";
|
|
5
|
-
import { hasPublishedSessionCalendar, historySourceWeekendDays, latestRegularSessionClose, latestRegularSessionOpen, sessionCalendarTimeZone } from "../market-data/market/freshness";
|
|
5
|
+
import { hasPublishedSessionCalendar, historySourceWeekendDays, isMiddayBreakPrint, latestRegularSessionClose, latestRegularSessionOpen, sessionCalendarTimeZone } from "../market-data/market/freshness";
|
|
6
6
|
import { zonedDateTimeParts } from "./zoned-date-time";
|
|
7
7
|
import { regularHistorySessionStaleness } from "../market-data/history-session";
|
|
8
8
|
import type { HistorySession } from "../types/price-history";
|
|
@@ -234,6 +234,12 @@ export function isPriceHistoryStaleForCurrentWindow(
|
|
|
234
234
|
const age = now - latestTime;
|
|
235
235
|
const allowedLag = allowedBarLagMs(intervalMs);
|
|
236
236
|
if (age <= allowedLag) return false;
|
|
237
|
+
// A venue paused at midday (SSE/SZSE/BSE, TKO, ...) holds the morning's last
|
|
238
|
+
// bar current through the break, as the quote freshness rule does. A bar is
|
|
239
|
+
// labelled by its start, so an hourly bar ending at the break is judged by
|
|
240
|
+
// when it ends.
|
|
241
|
+
const latestBarEnd = intervalMs != null ? Math.min(latestTime + intervalMs, now) : latestTime;
|
|
242
|
+
if (isMiddayBreakPrint(latestBarEnd, options.exchange, now, 0)) return false;
|
|
237
243
|
const sessions = listingSessionsAt(now, options);
|
|
238
244
|
if (!sessions) return age > UNSCHEDULED_HISTORY_MAX_AGE_MS;
|
|
239
245
|
const fetchedAt = options.fetchedAt ?? Number.NEGATIVE_INFINITY;
|
|
@@ -354,6 +360,11 @@ function barDate(time: number, timeZone: string): string {
|
|
|
354
360
|
return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
|
355
361
|
}
|
|
356
362
|
|
|
363
|
+
/** The venue date a daily bar at `time` names on `exchange`, read as calendarHistoryLastBarDate reads it. */
|
|
364
|
+
export function dailyBarDate(time: number, exchange: string): string {
|
|
365
|
+
return barDate(time, sessionCalendarTimeZone(exchange) ?? "UTC");
|
|
366
|
+
}
|
|
367
|
+
|
|
357
368
|
/**
|
|
358
369
|
* The venue date of the latest bar, read as calendarHistoryFetchState reads
|
|
359
370
|
* it, so copies whose sources label a session differently compare equal.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One word of a command line as a shell reads it back: as written when it
|
|
3
|
+
* holds nothing a shell treats specially (`NVDA`, `SAN:EPA`, `BRK.B`), else
|
|
4
|
+
* in single quotes (`'Altria Group'`, `'$nvda'`, `'AT&T'`).
|
|
5
|
+
*/
|
|
6
|
+
export function shellWord(word: string): string {
|
|
7
|
+
return /^[\p{L}\p{N}._:@%+,/][\p{L}\p{N}._:@%+,/=-]*$/u.test(word) ? word : `'${word.replaceAll("'", "'\\''")}'`;
|
|
8
|
+
}
|