@gloom-sh/terminal 0.19.1 → 0.19.3
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 +7 -1
- package/package.json +2 -1
- package/patches/electrobun@1.18.1.patch +108 -1
- package/src/account/upgrade-dialog.tsx +4 -23
- package/src/api-client/coalesce.ts +118 -0
- package/src/api-client/credit-boards.ts +13 -0
- package/src/api-client/crypto-etf-flows.ts +6 -0
- package/src/api-client/crypto-markets.ts +40 -0
- package/src/api-client/data.ts +201 -14
- package/src/api-client/equity-screener.ts +10 -0
- package/src/api-client/errors.ts +58 -0
- package/src/api-client/gpu.ts +29 -0
- package/src/api-client/index.ts +5 -2
- package/src/api-client/plan-access.ts +10 -1
- package/src/api-client/plan-rules.ts +35 -0
- package/src/api-client/research-activity.ts +1 -32
- package/src/api-client/types.ts +21 -1
- package/src/app/attention-notice.tsx +94 -0
- package/src/app/runtime/startup.ts +3 -1
- package/src/app.tsx +23 -1
- package/src/architecture/core-builtin-allowlist.json +2 -1
- package/src/capabilities/chart-series.ts +2 -1
- package/src/capabilities/factories.ts +1 -0
- package/src/cli/ascii-output.ts +42 -0
- package/src/cli/base-converter.ts +10 -2
- package/src/cli/command-options.ts +16 -1
- package/src/cli/commands/crypto-hints.ts +23 -4
- package/src/cli/commands/market.ts +101 -27
- package/src/cli/commands/news-search.ts +24 -5
- package/src/cli/commands/overview.ts +14 -10
- package/src/cli/commands/search.ts +84 -25
- package/src/cli/commands/system.ts +22 -30
- package/src/cli/commands/ticker.ts +49 -9
- package/src/cli/commands/version.ts +33 -0
- package/src/cli/context.ts +6 -9
- package/src/cli/data-dir.ts +7 -0
- package/src/cli/desktop-pane-shot-api-policy.ts +85 -0
- package/src/cli/desktop-pane-shot-browser.ts +320 -0
- package/src/cli/desktop-pane-shot-routes.ts +26 -1
- package/src/cli/desktop-pane-shot.ts +196 -256
- package/src/cli/early-command.ts +42 -0
- package/src/cli/earnings-calendar.ts +9 -0
- package/src/cli/entry.ts +19 -13
- package/src/cli/errors.ts +12 -2
- package/src/cli/glossary.ts +2 -1
- package/src/cli/help.ts +1 -1
- package/src/cli/history-export.ts +22 -2
- package/src/cli/history-rows.ts +189 -11
- package/src/cli/index.ts +18 -1
- package/src/cli/known-gaps.ts +51 -5
- package/src/cli/listing-arg.ts +63 -10
- package/src/cli/options.ts +1 -1
- package/src/cli/output-file.ts +60 -13
- package/src/cli/pane-functions/catalog.ts +14 -3
- package/src/cli/pane-functions/data.ts +1 -1
- package/src/cli/pane-functions/dom.ts +45 -0
- package/src/cli/pane-functions/freshness.ts +46 -9
- package/src/cli/pane-functions/function-help.ts +17 -9
- package/src/cli/pane-functions/headless.ts +22 -14
- package/src/cli/pane-functions/index.ts +6 -2
- package/src/cli/pane-functions/options.ts +6 -2
- package/src/cli/pane-functions/resolver.ts +27 -5
- package/src/cli/pane-functions/screenshot-assessment.ts +33 -0
- package/src/cli/pane-functions/screenshot-bridge.ts +94 -13
- package/src/cli/pane-functions/screenshot-http.ts +70 -0
- package/src/cli/pane-functions/screenshot-render.ts +19 -5
- package/src/cli/quote-answer.ts +49 -6
- package/src/cli/registry.ts +41 -13
- package/src/cli/result.ts +12 -6
- package/src/cli/ticker-resolution.ts +2 -1
- package/src/cli/types.ts +2 -0
- package/src/components/chart/composite/format.ts +3 -0
- package/src/components/chart-table/header.tsx +1 -1
- package/src/components/chart-table/layout.ts +28 -11
- package/src/components/command-bar/action-runtime.ts +4 -0
- package/src/components/command-bar/commands/direct/index.ts +18 -33
- package/src/components/command-bar/commands/direct/runtime.ts +5 -0
- package/src/components/command-bar/commands/registry.ts +10 -1
- package/src/components/command-bar/routes/root/command-items.ts +9 -4
- package/src/components/command-bar/routes/root/runtime.ts +51 -6
- package/src/components/command-bar/selection-runtime.ts +12 -29
- package/src/components/command-bar/surface/index.tsx +9 -3
- package/src/components/company-logo.tsx +2 -1
- package/src/components/layout/detached-pane-shell.tsx +2 -2
- package/src/components/layout/header.tsx +10 -5
- package/src/components/layout/market-summary.ts +25 -7
- package/src/components/layout/pane/footer/index.tsx +8 -2
- package/src/components/layout/pane/footer/model.ts +73 -6
- package/src/components/layout/pane/header.tsx +2 -2
- package/src/components/layout/pane/status-footer.ts +2 -1
- package/src/components/market-board/index.tsx +3 -2
- package/src/components/onboarding/desks-step.tsx +12 -4
- package/src/components/onboarding/first-run-workspace.ts +81 -4
- package/src/components/onboarding/onboarding-frame.tsx +4 -2
- package/src/components/onboarding/onboarding-keyboard.ts +8 -5
- package/src/components/onboarding/onboarding-wizard.tsx +60 -26
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +7 -2
- package/src/components/onboarding/run-setup-again.ts +24 -0
- package/src/components/onboarding/use-onboarding-progress.ts +33 -15
- package/src/components/onboarding/use-onboarding-upgrade.ts +2 -6
- package/src/components/onboarding/wizard-model.ts +57 -3
- package/src/components/onboarding/wizard-positions.ts +1 -1
- package/src/components/ui/delayed-mark.tsx +56 -0
- package/src/components/ui/display.tsx +16 -5
- package/src/components/ui/external-link.tsx +3 -6
- package/src/components/ui/icon.tsx +16 -3
- package/src/components/ui/logo-mark.tsx +8 -5
- package/src/components/ui/stat-grid.tsx +263 -19
- package/src/core/app-services.ts +11 -2
- package/src/data/app-persistence.ts +9 -7
- package/src/data/config/store/node.ts +11 -5
- package/src/data/config/store/normalize.ts +16 -3
- package/src/data/plugin-cache.ts +15 -0
- package/src/data/plugin-state-store.ts +81 -24
- package/src/data/profile-permissions.ts +47 -0
- package/src/data/resource-store.ts +165 -90
- package/src/data/session-store.ts +31 -8
- package/src/data/sqlite/access.ts +324 -0
- package/src/data/sqlite/checkpointer.ts +285 -0
- package/src/data/sqlite/database.ts +80 -4
- package/src/data/sqlite/retry.ts +50 -9
- package/src/data/ticker-store.ts +57 -23
- package/src/docs/snapshot.json +191 -78
- package/src/i18n/es.ts +18 -2
- package/src/i18n/ja.ts +18 -2
- package/src/i18n/ko.ts +18 -2
- package/src/i18n/zh-cn.ts +18 -2
- package/src/i18n/zh-tw.ts +18 -2
- package/src/layout/desk-keys.ts +4 -1
- package/src/layout/desks.ts +38 -5
- package/src/layout-marketplace/gallery-desktop.tsx +45 -16
- package/src/market-data/batched-reads.ts +16 -0
- package/src/market-data/coordinator/auxiliary.ts +4 -2
- package/src/market-data/coordinator/index.ts +11 -2
- package/src/market-data/futures-board.ts +1 -1
- package/src/market-data/futures-contract.ts +3 -1
- package/src/market-data/market/index-level.ts +6 -4
- package/src/market-data/published-apac-sessions.ts +6 -0
- package/src/market-data/realized-volatility.ts +4 -2
- package/src/news/aggregator.ts +7 -4
- package/src/news/news-model.ts +11 -0
- package/src/news/story-id.ts +22 -0
- package/src/news/ticker-symbols.ts +17 -1
- package/src/notifications/app-notifier.ts +35 -14
- package/src/plugins/auto-update-node.ts +10 -6
- package/src/plugins/builtin/account-management/form-components.tsx +1 -1
- package/src/plugins/builtin/account-management/index.tsx +2 -3
- package/src/plugins/builtin/account-management/model.ts +1 -1
- package/src/plugins/builtin/alerts/cli-forms.ts +15 -1
- package/src/plugins/builtin/alerts/events-pane.tsx +7 -5
- package/src/plugins/builtin/alerts/events.ts +10 -2
- package/src/plugins/builtin/alerts/index.tsx +5 -5
- package/src/plugins/builtin/alerts/research-builder.ts +5 -1
- package/src/plugins/builtin/alerts/research-rules.ts +18 -0
- package/src/plugins/builtin/alerts/targets.ts +4 -1
- package/src/plugins/builtin/attention/headless.ts +1 -1
- package/src/plugins/builtin/attention/index.tsx +2 -4
- package/src/plugins/builtin/attention/listing.ts +1 -1
- package/src/plugins/builtin/attention/series.ts +1 -1
- package/src/plugins/builtin/awards/index.tsx +1 -2
- package/src/plugins/builtin/backtest/client.ts +1 -0
- package/src/plugins/builtin/backtest/index.tsx +1 -2
- package/src/plugins/builtin/backtest/rules.ts +3 -1
- package/src/plugins/builtin/backtest/window.ts +8 -7
- package/src/plugins/builtin/broker-manager/detail.tsx +16 -3
- package/src/plugins/builtin/broker-manager/index.tsx +1 -1
- package/src/plugins/builtin/buildout/cells.tsx +5 -0
- package/src/plugins/builtin/buildout/company/flow.tsx +367 -0
- package/src/plugins/builtin/buildout/company/id.ts +2 -0
- package/src/plugins/builtin/buildout/company/model.ts +247 -0
- package/src/plugins/builtin/buildout/company/pane.tsx +317 -0
- package/src/plugins/builtin/buildout/data-runtime.ts +31 -10
- package/src/plugins/builtin/buildout/facilities.ts +309 -0
- package/src/plugins/builtin/buildout/format.ts +9 -0
- package/src/plugins/builtin/buildout/index.tsx +51 -5
- package/src/plugins/builtin/buildout/model/index.ts +62 -10
- package/src/plugins/builtin/buildout/model/normalizers.ts +5 -0
- package/src/plugins/builtin/buildout/model/types.ts +11 -2
- package/src/plugins/builtin/buildout/pane/index.tsx +91 -20
- package/src/plugins/builtin/buildout/pane/status.tsx +1 -1
- package/src/plugins/builtin/buildout/pane/themes.tsx +110 -0
- package/src/plugins/builtin/buildout/table-model.ts +26 -2
- package/src/plugins/builtin/builtin-plugin-meta.ts +16 -0
- package/src/plugins/builtin/cds/headless.ts +10 -2
- package/src/plugins/builtin/cds/model.ts +7 -3
- package/src/plugins/builtin/central-bank-rates/index.tsx +1 -2
- package/src/plugins/builtin/central-bank-rates/pane.tsx +2 -1
- package/src/plugins/builtin/central-bank-rates/series.ts +2 -3
- package/src/plugins/builtin/changelog/index.tsx +3 -2
- package/src/plugins/builtin/chart-composer/cli-options.ts +16 -0
- package/src/plugins/builtin/chart-composer/headless-schema.ts +10 -0
- package/src/plugins/builtin/chart-composer/headless.ts +88 -21
- package/src/plugins/builtin/chart-composer/index.tsx +2 -3
- package/src/plugins/builtin/chart-composer/pane.tsx +30 -2
- package/src/plugins/builtin/chart-composer/series-expression.ts +3 -2
- package/src/plugins/builtin/chart-composer/session-range.ts +5 -2
- package/src/plugins/builtin/chart-composer/studies.ts +1 -1
- package/src/plugins/builtin/chat/controller/index.ts +1 -1
- package/src/plugins/builtin/chat/controller/messages.ts +15 -4
- package/src/plugins/builtin/chat/ghost-user.ts +8 -0
- package/src/plugins/builtin/chat/index.tsx +5 -5
- package/src/plugins/builtin/clinical-trials/index.tsx +1 -2
- package/src/plugins/builtin/cloud/company-picker.tsx +1 -1
- package/src/plugins/builtin/cloud/index.tsx +1 -2
- package/src/plugins/builtin/cloud/plugin.tsx +6 -4
- package/src/plugins/builtin/cloud/team/module.tsx +1 -1
- package/src/plugins/builtin/cloud/thesis/module.tsx +1 -1
- package/src/plugins/builtin/cloud/trial-offer-status-widget.tsx +24 -1
- package/src/plugins/builtin/cloud/upgrade-status-widget.tsx +39 -15
- package/src/plugins/builtin/comment-letters/index.tsx +1 -2
- package/src/plugins/builtin/commodity-balances/client.ts +4 -1
- package/src/plugins/builtin/commodity-balances/index.tsx +3 -3
- package/src/plugins/builtin/commodity-balances/pane.tsx +2 -2
- package/src/plugins/builtin/congress-trades/aggregates.ts +13 -2
- package/src/plugins/builtin/congress-trades/detail.tsx +20 -4
- package/src/plugins/builtin/congress-trades/headless.ts +2 -0
- package/src/plugins/builtin/congress-trades/model.ts +92 -64
- package/src/plugins/builtin/congress-trades/table.tsx +14 -2
- package/src/plugins/builtin/connections/index.ts +2 -3
- package/src/plugins/builtin/cot/client.ts +28 -2
- package/src/plugins/builtin/cot/headless.ts +4 -1
- package/src/plugins/builtin/cot/index.tsx +5 -4
- package/src/plugins/builtin/cot/model.ts +58 -7
- package/src/plugins/builtin/cot/pane.tsx +6 -2
- package/src/plugins/builtin/cpi/client.ts +6 -5
- package/src/plugins/builtin/cpi/index.tsx +1 -2
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +2 -1
- package/src/plugins/builtin/credit-boards/client.ts +7 -2
- package/src/plugins/builtin/credit-boards/headless.ts +25 -12
- package/src/plugins/builtin/credit-boards/model.ts +29 -0
- package/src/plugins/builtin/credit-boards/series.ts +3 -4
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +9 -4
- package/src/plugins/builtin/credit-conditions/client.ts +22 -14
- package/src/plugins/builtin/crypto-board/bitcoin-network.ts +143 -0
- package/src/plugins/builtin/crypto-board/client.ts +5 -5
- package/src/plugins/builtin/crypto-board/headless.ts +4 -3
- package/src/plugins/builtin/crypto-board/index.tsx +4 -2
- package/src/plugins/builtin/crypto-board/series.ts +6 -4
- package/src/plugins/builtin/crypto-etf-flows/client.ts +9 -2
- package/src/plugins/builtin/crypto-etf-flows/headless.ts +61 -6
- package/src/plugins/builtin/crypto-etf-flows/index.tsx +1 -2
- package/src/plugins/builtin/crypto-etf-flows/model.ts +14 -1
- package/src/plugins/builtin/crypto-etf-flows/pane.tsx +8 -5
- package/src/plugins/builtin/debt-maturities/headless.ts +4 -3
- package/src/plugins/builtin/debt-maturities/model.ts +17 -1
- package/src/plugins/builtin/debt-maturities/pane.tsx +18 -4
- package/src/plugins/builtin/debt-maturities/series.ts +3 -3
- package/src/plugins/builtin/debug/index.tsx +1 -1
- package/src/plugins/builtin/dividend-yield/client.ts +32 -2
- package/src/plugins/builtin/dividend-yield/headless.ts +58 -33
- package/src/plugins/builtin/dividend-yield/index.tsx +37 -2
- package/src/plugins/builtin/dividend-yield/pane.tsx +32 -13
- package/src/plugins/builtin/dividend-yield/ranking-reads.ts +73 -0
- package/src/plugins/builtin/dividend-yield/ranking-view.tsx +163 -0
- package/src/plugins/builtin/dividend-yield/ranking.ts +1 -1
- package/src/plugins/builtin/dividend-yield/view.ts +21 -0
- package/src/plugins/builtin/docs/index.tsx +2 -3
- package/src/plugins/builtin/doe/client.ts +6 -5
- package/src/plugins/builtin/doe/headless.ts +16 -3
- package/src/plugins/builtin/doe/index.tsx +5 -4
- package/src/plugins/builtin/doe/prices.ts +2 -3
- package/src/plugins/builtin/doe/series.ts +4 -4
- package/src/plugins/builtin/earnings/board.tsx +2 -1
- package/src/plugins/builtin/earnings/history.tsx +2 -1
- package/src/plugins/builtin/earnings-calls/calendar.tsx +10 -2
- package/src/plugins/builtin/earnings-calls/data.ts +19 -11
- package/src/plugins/builtin/earnings-calls/pane.tsx +27 -14
- package/src/plugins/builtin/earnings-ripple/client.ts +32 -7
- package/src/plugins/builtin/earnings-ripple/index.tsx +1 -2
- package/src/plugins/builtin/econ/calendar-model.ts +29 -6
- package/src/plugins/builtin/econ/detail-view.tsx +16 -2
- package/src/plugins/builtin/econ-statistics/index.tsx +1 -2
- package/src/plugins/builtin/equity-screener/client.ts +1 -1
- package/src/plugins/builtin/equity-screener/headless.ts +1 -0
- package/src/plugins/builtin/equity-screener/ideas.ts +30 -1
- package/src/plugins/builtin/equity-screener/index.tsx +1 -2
- package/src/plugins/builtin/equity-screener/model.ts +28 -4
- package/src/plugins/builtin/equity-screener/pane.tsx +5 -0
- package/src/plugins/builtin/equity-screener/screen-check.ts +23 -1
- package/src/plugins/builtin/estimate-revisions/index.tsx +1 -2
- package/src/plugins/builtin/executives/data.ts +6 -1
- package/src/plugins/builtin/executives/pane.tsx +9 -21
- package/src/plugins/builtin/exposure/holdings.ts +35 -13
- package/src/plugins/builtin/exposure/index.tsx +1 -2
- package/src/plugins/builtin/fear-greed/cache.ts +4 -0
- package/src/plugins/builtin/fear-greed/cli.ts +44 -0
- package/src/plugins/builtin/fear-greed/index.tsx +5 -53
- package/src/plugins/builtin/fear-greed/pane.tsx +2 -1
- package/src/plugins/builtin/fear-greed/series.ts +6 -4
- package/src/plugins/builtin/fixed-income/index.tsx +1 -2
- package/src/plugins/builtin/futures/board-reads.ts +25 -0
- package/src/plugins/builtin/futures/coalesced-bump.ts +44 -0
- package/src/plugins/builtin/futures/index.tsx +15 -0
- package/src/plugins/builtin/futures/model.ts +14 -0
- package/src/plugins/builtin/futures/use-board-terms.ts +22 -15
- package/src/plugins/builtin/futures/use-front-returns.ts +20 -14
- package/src/plugins/builtin/futures-curve/headless.ts +6 -1
- package/src/plugins/builtin/futures-curve/index.tsx +1 -2
- package/src/plugins/builtin/fx-matrix/index.tsx +2 -2
- package/src/plugins/builtin/gpu/board.tsx +51 -12
- package/src/plugins/builtin/gpu/client.ts +19 -3
- package/src/plugins/builtin/gpu/equities.tsx +5 -2
- package/src/plugins/builtin/gpu/headless.ts +14 -2
- package/src/plugins/builtin/gpu/index.tsx +1 -2
- package/src/plugins/builtin/gpu/model.ts +20 -2
- package/src/plugins/builtin/gpu/pane.tsx +1 -1
- package/src/plugins/builtin/gpu/series.ts +2 -3
- package/src/plugins/builtin/help/index.tsx +1 -1
- package/src/plugins/builtin/holders/beneficial-view.tsx +1 -2
- package/src/plugins/builtin/holders/index-holders.ts +24 -12
- package/src/plugins/builtin/holders/index.tsx +2 -3
- package/src/plugins/builtin/ipo-calendar/index.tsx +1 -2
- package/src/plugins/builtin/iv-history/index.tsx +1 -2
- package/src/plugins/builtin/jodi/client.ts +4 -1
- package/src/plugins/builtin/jodi/index.tsx +1 -2
- package/src/plugins/builtin/kelly-sizer/index.tsx +1 -2
- package/src/plugins/builtin/layout-manager/index.tsx +9 -8
- package/src/plugins/builtin/macro-day/pane.tsx +4 -2
- package/src/plugins/builtin/market-halts/index.tsx +1 -2
- package/src/plugins/builtin/market-heatmap/index.tsx +11 -2
- package/src/plugins/builtin/market-movers/client.ts +1 -0
- package/src/plugins/builtin/market-movers/index.tsx +16 -5
- package/src/plugins/builtin/market-movers/screener.ts +23 -6
- package/src/plugins/builtin/market-movers/session-body.tsx +6 -2
- package/src/plugins/builtin/market-valuation/index.tsx +1 -2
- package/src/plugins/builtin/members/index.tsx +1 -2
- package/src/plugins/builtin/money-markets/index.tsx +1 -2
- package/src/plugins/builtin/money-markets/pane.tsx +2 -1
- package/src/plugins/builtin/money-markets/series.ts +3 -5
- package/src/plugins/builtin/news/headless.ts +7 -0
- package/src/plugins/builtin/news/wire/index.tsx +1 -1
- package/src/plugins/builtin/news/wire/news/pop-out.tsx +9 -3
- package/src/plugins/builtin/notes/index.tsx +3 -6
- package/src/plugins/builtin/openfda/index.tsx +1 -2
- package/src/plugins/builtin/options/view.tsx +6 -5
- package/src/plugins/builtin/options-calculator/index.tsx +1 -2
- package/src/plugins/builtin/options-positioning/index.tsx +1 -2
- package/src/plugins/builtin/options-scenario/index.tsx +2 -4
- package/src/plugins/builtin/perps/index.tsx +1 -2
- package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -3
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +2 -1
- package/src/plugins/builtin/plugin-module.ts +16 -2
- package/src/plugins/builtin/portfolio-list/cli/render.ts +53 -3
- package/src/plugins/builtin/portfolio-list/index.tsx +1 -2
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +11 -0
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +2 -2
- package/src/plugins/builtin/power/gas-client.ts +2 -1
- package/src/plugins/builtin/power/index.tsx +1 -2
- package/src/plugins/builtin/power/prices-client.ts +3 -2
- package/src/plugins/builtin/rate-path/index.tsx +1 -2
- package/src/plugins/builtin/realized-vol/headless.ts +2 -0
- package/src/plugins/builtin/realized-vol/index.tsx +1 -2
- package/src/plugins/builtin/realized-vol/model.ts +16 -2
- package/src/plugins/builtin/realized-vol/pane.tsx +3 -3
- package/src/plugins/builtin/relative-rotation/index.tsx +1 -2
- package/src/plugins/builtin/research/analyst-headless.ts +33 -6
- package/src/plugins/builtin/research/analyst-model.ts +37 -2
- package/src/plugins/builtin/research/analyst-pane.tsx +25 -5
- package/src/plugins/builtin/research/index.tsx +5 -8
- package/src/plugins/builtin/research-search/index.tsx +1 -2
- package/src/plugins/builtin/revenue-breakdown/headless.ts +22 -8
- package/src/plugins/builtin/revenue-breakdown/model.ts +23 -0
- package/src/plugins/builtin/reverse-dcf/pane.tsx +4 -2
- package/src/plugins/builtin/risk-factors/data.ts +8 -4
- package/src/plugins/builtin/risk-factors/index.tsx +3 -1
- package/src/plugins/builtin/risk-factors/pane.tsx +5 -8
- package/src/plugins/builtin/roadmap/index.tsx +2 -3
- package/src/plugins/builtin/roadmap/pane.tsx +49 -2
- package/src/plugins/builtin/scanner/hilo-model.ts +18 -1
- package/src/plugins/builtin/scanner/hilo-pane.tsx +12 -2
- package/src/plugins/builtin/scanner/live-pane.tsx +7 -4
- package/src/plugins/builtin/scanner/lock-note.ts +26 -3
- package/src/plugins/builtin/sec/filing-content.ts +38 -6
- package/src/plugins/builtin/sec/headless.ts +5 -1
- package/src/plugins/builtin/sec/index.tsx +4 -2
- package/src/plugins/builtin/sec/model.ts +2 -0
- package/src/plugins/builtin/sectors/index.tsx +11 -5
- package/src/plugins/builtin/series-inventory.ts +2 -0
- package/src/plugins/builtin/shared/cloud-resource.ts +73 -8
- package/src/plugins/builtin/shared/cloud-upgrade.ts +24 -1
- package/src/plugins/builtin/shared/forming-bars.ts +29 -0
- package/src/plugins/builtin/shared/fred-points.ts +6 -1
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +17 -0
- package/src/plugins/builtin/shared/pro-lock-note.ts +23 -8
- package/src/plugins/builtin/shared/series-detail-chart.tsx +4 -2
- package/src/plugins/builtin/shared/series-warning.ts +13 -4
- package/src/plugins/builtin/shared/use-quote-board.ts +5 -0
- package/src/plugins/builtin/short-interest/publications-pane.tsx +2 -1
- package/src/plugins/builtin/short-volume/pane.tsx +2 -1
- package/src/plugins/builtin/short-volume/series.ts +2 -3
- package/src/plugins/builtin/social-mentions/client.ts +15 -10
- package/src/plugins/builtin/social-mentions/index.tsx +1 -2
- package/src/plugins/builtin/social-mentions/pane.tsx +2 -1
- package/src/plugins/builtin/social-mentions/series.ts +2 -3
- package/src/plugins/builtin/supply-chain/client.ts +22 -1
- package/src/plugins/builtin/supply-chain/graph-client.ts +22 -1
- package/src/plugins/builtin/supply-chain/index.tsx +1 -2
- package/src/plugins/builtin/thirteenf/api.ts +127 -29
- package/src/plugins/builtin/thirteenf/data.ts +165 -35
- package/src/plugins/builtin/thirteenf/index.tsx +2 -4
- package/src/plugins/builtin/thirteenf/model.ts +2 -0
- package/src/plugins/builtin/thirteenf/overlap-pane.tsx +5 -1
- package/src/plugins/builtin/thirteenf/pane.tsx +41 -16
- package/src/plugins/builtin/thirteenf/types.ts +14 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +22 -6
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +81 -11
- package/src/plugins/builtin/ticker-detail/financials/model.ts +35 -2
- package/src/plugins/builtin/ticker-detail/financials/ratios.ts +53 -18
- package/src/plugins/builtin/ticker-detail/headless.ts +70 -11
- package/src/plugins/builtin/ticker-detail/index.tsx +5 -10
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +16 -6
- package/src/plugins/builtin/time-sales/index.tsx +1 -2
- package/src/plugins/builtin/time-sales/pane.tsx +3 -1
- package/src/plugins/builtin/trace-bonds/headless.ts +11 -2
- package/src/plugins/builtin/trace-bonds/model.ts +44 -10
- package/src/plugins/builtin/trace-bonds/pane.tsx +12 -7
- package/src/plugins/builtin/treasury-auctions/cache.ts +20 -8
- package/src/plugins/builtin/treasury-auctions/client.ts +3 -3
- package/src/plugins/builtin/treasury-auctions/headless.ts +3 -1
- package/src/plugins/builtin/treasury-auctions/pane.tsx +10 -4
- package/src/plugins/builtin/vol-surface/client.ts +18 -3
- package/src/plugins/builtin/vol-surface/index.tsx +1 -2
- package/src/plugins/builtin/volatility/client.ts +43 -16
- package/src/plugins/builtin/volatility/headless.ts +5 -2
- package/src/plugins/builtin/volatility/index.tsx +1 -2
- package/src/plugins/builtin/volatility/model.ts +17 -6
- package/src/plugins/builtin/volatility/pane.tsx +6 -2
- package/src/plugins/builtin/volatility/series.ts +2 -1
- package/src/plugins/builtin/world-indices/footer.ts +6 -1
- package/src/plugins/builtin/world-venue-map/client.ts +10 -1
- package/src/plugins/builtin/world-venue-map/index.ts +6 -2
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +48 -7
- package/src/plugins/builtin/world-venue-map/layers.ts +17 -0
- package/src/plugins/builtin/world-venue-map/local-layers.ts +141 -0
- package/src/plugins/builtin/world-venue-map/map-symbols.ts +18 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +4 -2
- package/src/plugins/builtin/world-venue-map/scope.ts +63 -0
- package/src/plugins/builtin/yield-curve/client.ts +4 -6
- package/src/plugins/builtin/yield-curve/curves.ts +16 -2
- package/src/plugins/builtin/yield-curve/headless.ts +3 -3
- package/src/plugins/bundle.ts +52 -2
- package/src/plugins/catalog-browser.ts +2 -2
- package/src/plugins/catalog-cli.ts +20 -0
- package/src/plugins/host-link.ts +13 -1
- package/src/plugins/installer.ts +64 -42
- package/src/plugins/loader.ts +43 -11
- package/src/plugins/peer-imports.ts +201 -0
- package/src/plugins/peer-retry.ts +26 -29
- package/src/plugins/plugin-process.ts +128 -0
- package/src/plugins/redirection-guard.ts +45 -0
- package/src/remote/endpoint.ts +16 -3
- package/src/renderers/browser/main.tsx +3 -2
- package/src/renderers/cloudflare/http-proxy.ts +7 -123
- package/src/renderers/dom/desktop/icons.tsx +5 -2
- package/src/renderers/dom/host/image-surface.tsx +46 -21
- package/src/renderers/dom/styles.css +7 -0
- package/src/renderers/dom/toast-host.tsx +2 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +7 -1
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +23 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +12 -3
- package/src/renderers/electrobun/bun/desktop/rpc-timing.ts +88 -0
- package/src/renderers/electrobun/bun/desktop/update.ts +20 -4
- package/src/renderers/electrobun/bun/desktop/view-ids.ts +8 -4
- package/src/renderers/electrobun/bun/external-plugins.ts +4 -0
- package/src/renderers/electrobun/bun/window/attention.ts +54 -0
- package/src/renderers/electrobun/bun/window/create.ts +6 -2
- package/src/renderers/electrobun/bun/window/native-timing.ts +48 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +82 -4
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +13 -5
- package/src/renderers/electrobun/view/desktop/window/snapshot.ts +3 -0
- package/src/renderers/electrobun/view/main.tsx +7 -2
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -0
- package/src/renderers/electrobun/view/ui-host.tsx +9 -2
- package/src/renderers/opentui/browser-open.ts +10 -4
- package/src/renderers/opentui/image/surface.tsx +1 -1
- package/src/renderers/opentui/start.tsx +12 -6
- package/src/renderers/opentui/toast-host.tsx +2 -1
- package/src/series/registry.ts +18 -0
- package/src/series/resolve.ts +2 -1
- package/src/series/standalone.ts +10 -1
- package/src/series/types.ts +12 -0
- package/src/series/validate.ts +11 -2
- package/src/sources/gloomberb-cloud/fred-series.ts +5 -3
- package/src/sources/gloomberb-cloud/index.ts +28 -5
- package/src/sources/gloomberb-cloud/news.ts +24 -3
- package/src/sources/gloomberb-cloud/normalizers.ts +17 -2
- package/src/sources/provider-errors.ts +26 -3
- package/src/sources/provider-router/history.ts +5 -0
- package/src/sources/provider-router/index.ts +13 -0
- package/src/sync/core-contributors.ts +32 -0
- package/src/telemetry/attention-counts.ts +64 -6
- package/src/telemetry/attention-setting.ts +33 -0
- package/src/telemetry/crash-reports-node.ts +3 -1
- package/src/telemetry/stall-clocks.ts +93 -0
- package/src/telemetry/stall-reports-node.ts +25 -9
- package/src/telemetry/stall-reports.ts +218 -13
- package/src/test-support/outage.ts +8 -0
- package/src/test-support/preload.ts +9 -0
- package/src/tickers/company-name-listing.ts +59 -29
- package/src/tickers/company-name.ts +84 -1
- package/src/tickers/listing-fate.ts +14 -3
- package/src/tickers/saved-instrument.ts +17 -0
- package/src/tickers/search/home-listing.ts +104 -8
- package/src/tickers/search/index.ts +5 -2
- package/src/tickers/search/types.ts +6 -1
- package/src/time-series/bar-aggregation.ts +7 -1
- package/src/time-series/base-series.ts +3 -3
- package/src/time-series/chart-bounds.ts +1 -1
- package/src/time-series/chart-data.ts +5 -2
- package/src/time-series/chart-seed.ts +1 -1
- package/src/time-series/coin-session-close.ts +211 -0
- package/src/time-series/live-bars.ts +13 -2
- package/src/time-series/live-quotes.ts +1 -1
- package/src/time-series/market.ts +5 -3
- package/src/time-series/official-close.ts +159 -0
- package/src/time-series/price-comparison.ts +75 -8
- package/src/time-series/resolve.ts +32 -4
- package/src/time-series/series-presentation.ts +1 -1
- package/src/time-series/studies/formula.ts +205 -0
- package/src/time-series/studies/indicators.ts +299 -0
- package/src/time-series/studies/leverage.ts +75 -0
- package/src/time-series/studies/pair.ts +138 -0
- package/src/time-series/studies/resolve.ts +333 -0
- package/src/time-series/studies/shared.ts +141 -0
- package/src/time-series/studies/units.ts +243 -0
- package/src/time-series/studies/vwap.ts +274 -0
- package/src/time-series/types.ts +7 -0
- package/src/types/config.ts +18 -2
- package/src/types/data-provider.ts +23 -0
- package/src/types/financials.ts +40 -3
- package/src/types/headless.ts +42 -3
- package/src/types/plugin.ts +32 -3
- package/src/ui/host.tsx +17 -1
- package/src/ui/toast.tsx +26 -1
- package/src/utils/ascii-text.ts +140 -0
- package/src/utils/cli-output.ts +91 -18
- package/src/utils/concurrency.ts +24 -0
- package/src/utils/exchanges.ts +6 -0
- package/src/utils/external-url.ts +20 -7
- package/src/utils/financial-statements.ts +73 -16
- package/src/utils/fundamentals.ts +17 -5
- package/src/utils/futures-generic.ts +4 -4
- package/src/utils/http-proxy-upstream.ts +124 -0
- package/src/utils/lease-liabilities.ts +54 -0
- package/src/utils/main-thread-stall.ts +122 -5
- package/src/utils/perf-marks.ts +58 -12
- package/src/utils/price-history-integrity.ts +47 -1
- package/src/utils/private-files.ts +141 -0
- package/src/utils/public-address.ts +99 -0
- package/src/account/upgrade-personalization.ts +0 -57
- package/src/account/upgrade-tickers.ts +0 -124
- package/src/api-client/upgrade-experiment.ts +0 -91
- package/src/plugins/builtin/cloud/browser.tsx +0 -3
- package/src/time-series/studies.ts +0 -1628
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { scalarPointValue } from "../alignment";
|
|
2
|
+
import { resolveCurrencyUnit, US_CENTS } from "../../utils/currency-units";
|
|
3
|
+
import { isCurrencyCode } from "../../utils/currency-pair";
|
|
4
|
+
import { stablePriceFractionDigits } from "../../market-data/market/format";
|
|
5
|
+
import type { ResolvedSeries, TimeSeriesPoint } from "../types";
|
|
6
|
+
import {
|
|
7
|
+
GALLONS_PER_BARREL,
|
|
8
|
+
isPerBarrelUnit,
|
|
9
|
+
isPerGallonUnit,
|
|
10
|
+
quantityIdentity,
|
|
11
|
+
unitCurrencyToken,
|
|
12
|
+
} from "../price-units";
|
|
13
|
+
|
|
14
|
+
export function seriesCurrency(series: ResolvedSeries): string | null {
|
|
15
|
+
const grouped = series.unitGroup.match(/:([A-Z]{3})$/i)?.[1];
|
|
16
|
+
if (grouped) return grouped.toUpperCase();
|
|
17
|
+
if (!/^(?:price|currency-total|per-share)$/.test(series.unitGroup)) return null;
|
|
18
|
+
return series.unit.match(/^([A-Z]{3})(?:$|\/)/i)?.[1]?.toUpperCase() ?? null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function unitFactorIdentity(value: string): string {
|
|
22
|
+
// "US cents", as futures terms word a grain's quote, is the USX the quote names.
|
|
23
|
+
const token = unitCurrencyToken(value) ?? value.trim();
|
|
24
|
+
// Three letters are a currency unless they spell a quantity: "bbl" is a barrel.
|
|
25
|
+
if (/^[A-Za-z]{3}$/.test(token) && quantityIdentity(token) === token.toLowerCase()) {
|
|
26
|
+
const { currency, divisor } = resolveCurrencyUnit(token);
|
|
27
|
+
return `${currency}:${divisor}`;
|
|
28
|
+
}
|
|
29
|
+
return quantityIdentity(token);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Whether a unit's factor is money (USD, GBp, US cents) rather than a quantity it buys. */
|
|
33
|
+
function isCurrencyFactor(value: string): boolean {
|
|
34
|
+
const currency = /^([A-Z]{3}):\d+$/.exec(unitFactorIdentity(value))?.[1];
|
|
35
|
+
return !!currency && (currency === US_CENTS || isCurrencyCode(currency));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function knownUnitSignature(series: Pick<ResolvedSeries, "unit" | "unitGroup">): string | null {
|
|
39
|
+
const unit = series.unit.trim();
|
|
40
|
+
if (!unit || /(?:^|\W)(?:currency|unknown|unspecified|n\/a)(?:$|\W)/i.test(unit)
|
|
41
|
+
|| /^(?:units?|[-?]+)$/i.test(unit)) return null;
|
|
42
|
+
const parts = unit.split("/");
|
|
43
|
+
if (parts.some((part) => !part.trim() || /^[-?]+$/.test(part.trim()))) return null;
|
|
44
|
+
|
|
45
|
+
const monetary = series.unitGroup.match(/^(price|currency-total|per-share)(?::([^:]+))?$/);
|
|
46
|
+
// A futures contract writes its unit spaced ("USD / gallon"); a catalog series does not ("USD/gallon").
|
|
47
|
+
const currency = unitCurrencyToken(parts[0]!);
|
|
48
|
+
if (monetary && (!currency || (monetary[2] && unitFactorIdentity(monetary[2]) !== unitFactorIdentity(currency)))) return null;
|
|
49
|
+
|
|
50
|
+
// Currency alone does not establish a price's physical/share basis. A scalar
|
|
51
|
+
// multiplier cannot establish it either. Explicit USD/share price and EPS
|
|
52
|
+
// units, however, match despite different groups.
|
|
53
|
+
if (monetary?.[1] === "price" && !unit.includes("/")) return null;
|
|
54
|
+
const basis = monetary && !unit.includes("/") ? monetary[1] : "";
|
|
55
|
+
// Keep currency scale and compound order: GBp/GBX are pence, not pounds;
|
|
56
|
+
// USD/EUR cannot subtract EUR/USD.
|
|
57
|
+
return `${basis ?? ""}|${parts.map(unitFactorIdentity).join("/")}`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** A leg as an error names it: its ticker (HO=F), else its label. */
|
|
61
|
+
export function legName(series: ResolvedSeries): string {
|
|
62
|
+
return series.listing?.symbol || series.label;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** What a leg's unit is, in words: "is USD / gallon", "is in %", "is in USD per an unknown quantity". */
|
|
66
|
+
function unitPhrase(series: ResolvedSeries, unit: string): string {
|
|
67
|
+
const text = unit.trim();
|
|
68
|
+
// A rate reads as itself (HO=F is USD / gallon); an amount or a scale is what a leg is in (REVENUE is in USD).
|
|
69
|
+
if (knownUnitSignature({ unit: text, unitGroup: series.unitGroup }) !== null) return text.includes("/") ? `is ${text}` : `is in ${text}`;
|
|
70
|
+
if (unitCurrencyToken(text) && /^price(?::|$)/.test(series.unitGroup)) return `is in ${text} per an unknown quantity`;
|
|
71
|
+
return "has no known unit";
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function unitCurrency(series: ResolvedSeries, unit: string): string | null {
|
|
75
|
+
const token = unitCurrencyToken(unit.split("/")[0] ?? "");
|
|
76
|
+
return token ? unitFactorIdentity(token) : seriesCurrency(series);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Why two legs cannot be added or subtracted, naming each one's unit and the
|
|
81
|
+
* fix: a per-gallon leg beside a per-barrel one is 42 gallons short of it.
|
|
82
|
+
*/
|
|
83
|
+
export function unitMismatchMessage(
|
|
84
|
+
kind: "spread" | "formula",
|
|
85
|
+
left: { series: ResolvedSeries; unit: string },
|
|
86
|
+
right: { series: ResolvedSeries; unit: string },
|
|
87
|
+
): string {
|
|
88
|
+
// Two fields of one listing are told apart by their labels.
|
|
89
|
+
const [leftName, rightName] = legName(left.series) === legName(right.series)
|
|
90
|
+
? [left.series.label, right.series.label]
|
|
91
|
+
: [legName(left.series), legName(right.series)];
|
|
92
|
+
const named = `${leftName} ${unitPhrase(left.series, left.unit)} and ${rightName} ${unitPhrase(right.series, right.unit)}`;
|
|
93
|
+
const leftCurrency = unitCurrency(left.series, left.unit);
|
|
94
|
+
const rightCurrency = unitCurrency(right.series, right.unit);
|
|
95
|
+
const gallons = isPerGallonUnit(left.unit) && isPerBarrelUnit(right.unit) ? leftName
|
|
96
|
+
: isPerBarrelUnit(left.unit) && isPerGallonUnit(right.unit) ? rightName : null;
|
|
97
|
+
if (gallons && leftCurrency === rightCurrency) {
|
|
98
|
+
return `${named}: write ${GALLONS_PER_BARREL}*${gallons} to compare per barrel.`;
|
|
99
|
+
}
|
|
100
|
+
const subject = kind === "spread" ? "a spread" : "a formula";
|
|
101
|
+
if (leftCurrency && rightCurrency && leftCurrency !== rightCurrency) return `${named}: ${subject} does not convert currencies.`;
|
|
102
|
+
const known = knownUnitSignature({ unit: left.unit, unitGroup: left.series.unitGroup }) !== null
|
|
103
|
+
&& knownUnitSignature({ unit: right.unit, unitGroup: right.series.unitGroup }) !== null;
|
|
104
|
+
return `${named}: ${subject} needs ${kind === "spread" ? "both" : "every leg"} in one${known ? "" : " known"} unit.`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function unitFactors(unit: string): { numerator: string[]; denominator: string[] } {
|
|
108
|
+
const [numerator = "", ...denominator] = unit.split("/");
|
|
109
|
+
const factor = (value: string) => value.split("·").flatMap((part) => {
|
|
110
|
+
const normalized = part.trim();
|
|
111
|
+
if (!normalized || normalized === "1") return [];
|
|
112
|
+
return [normalized.toLowerCase() === "shares" ? "share" : normalized];
|
|
113
|
+
});
|
|
114
|
+
return {
|
|
115
|
+
numerator: factor(numerator),
|
|
116
|
+
denominator: denominator.flatMap(factor),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface SeriesUnit {
|
|
121
|
+
unit: string;
|
|
122
|
+
unitGroup: string;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const UNKNOWN_UNIT: SeriesUnit = { unit: "unknown", unitGroup: "derived-unit:unknown" };
|
|
126
|
+
|
|
127
|
+
export function isPriceGroup(unitGroup: string): boolean {
|
|
128
|
+
return /^price(?::|$)/.test(unitGroup);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* The unit of `left` times (`power` 1) or over (-1) `right`, the factors they
|
|
133
|
+
* share cancelling: USD / barrel over an FX rate's USD / EUR is EUR / barrel.
|
|
134
|
+
* Units are spaced as either side writes them ("USD / gallon"). A price over
|
|
135
|
+
* or times a price that leaves one currency per one quantity is a price in
|
|
136
|
+
* that currency; anything else is a derived unit, or a plain ratio.
|
|
137
|
+
*/
|
|
138
|
+
export function combinedUnit(left: SeriesUnit, right: SeriesUnit, power: 1 | -1): SeriesUnit {
|
|
139
|
+
if (!knownUnitSignature(left) || !knownUnitSignature(right)) return UNKNOWN_UNIT;
|
|
140
|
+
const leftFactors = unitFactors(left.unit);
|
|
141
|
+
const rightFactors = unitFactors(right.unit);
|
|
142
|
+
const numerator = [...leftFactors.numerator, ...(power < 0 ? rightFactors.denominator : rightFactors.numerator)];
|
|
143
|
+
const denominator = [...leftFactors.denominator, ...(power < 0 ? rightFactors.numerator : rightFactors.denominator)];
|
|
144
|
+
for (let index = numerator.length - 1; index >= 0; index -= 1) {
|
|
145
|
+
const match = denominator.findIndex((factor) => (
|
|
146
|
+
unitFactorIdentity(factor) === unitFactorIdentity(numerator[index]!)
|
|
147
|
+
));
|
|
148
|
+
if (match < 0) continue;
|
|
149
|
+
numerator.splice(index, 1);
|
|
150
|
+
denominator.splice(match, 1);
|
|
151
|
+
}
|
|
152
|
+
const slash = [left.unit, right.unit].some((unit) => /\s\/\s/.test(unit)) ? " / " : "/";
|
|
153
|
+
const unit = denominator.length === 0
|
|
154
|
+
? numerator.join("·") || "x"
|
|
155
|
+
: `${numerator.join("·") || "1"}${slash}${denominator.join("·")}`;
|
|
156
|
+
if (isPriceGroup(left.unitGroup) && isPriceGroup(right.unitGroup) && numerator.length === 1 && isCurrencyFactor(numerator[0]!)
|
|
157
|
+
&& (denominator.length === 0 || (denominator.length === 1 && !isCurrencyFactor(denominator[0]!)))) {
|
|
158
|
+
return { unit, unitGroup: `price:${unitCurrencyToken(numerator[0]!) ?? numerator[0]!}` };
|
|
159
|
+
}
|
|
160
|
+
const groupFactor = (value: string) => {
|
|
161
|
+
const identity = unitFactorIdentity(value);
|
|
162
|
+
return (/^[A-Za-z]{3}$/.test(value.trim()) ? identity.replace(/:1$/, "") : identity).toLowerCase();
|
|
163
|
+
};
|
|
164
|
+
const groupNumerator = numerator.map(groupFactor).join("·");
|
|
165
|
+
const groupDenominator = denominator.map(groupFactor).join("·");
|
|
166
|
+
const group = groupDenominator ? `${groupNumerator || "1"}/${groupDenominator}` : groupNumerator;
|
|
167
|
+
return {
|
|
168
|
+
unit,
|
|
169
|
+
unitGroup: unit === "x" ? "ratio" : `derived-unit:${group}`,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function ratioUnit(left: SeriesUnit, right: SeriesUnit): SeriesUnit {
|
|
174
|
+
return combinedUnit(left, right, -1);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** An FX rate's unit: one currency per another, as USD / EUR. */
|
|
178
|
+
function isRateUnit(unit: string): boolean {
|
|
179
|
+
const { numerator, denominator } = unitFactors(unit);
|
|
180
|
+
return numerator.length === 1 && denominator.length === 1 && isCurrencyFactor(numerator[0]!) && isCurrencyFactor(denominator[0]!);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Why a price times (`power` 1) or over (-1) an FX rate is no price, with how
|
|
185
|
+
* to convert it instead: a crack in USD / barrel over USDJPY=X (JPY / USD) is
|
|
186
|
+
* USD·USD / barrel·JPY, and times it JPY / barrel. A ratio, which cannot
|
|
187
|
+
* multiply, names the formula to write (`priceName` its numerator). Null when
|
|
188
|
+
* the rate converts the price, or either is not what this asks about.
|
|
189
|
+
*/
|
|
190
|
+
export function fxConversionIssue(price: SeriesUnit, rate: ResolvedSeries, power: 1 | -1, result: SeriesUnit, priceName?: string): string | null {
|
|
191
|
+
if (!isPriceGroup(price.unitGroup) || !isPriceGroup(rate.unitGroup) || !isRateUnit(rate.unit) || isPriceGroup(result.unitGroup)) {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
const name = legName(rate);
|
|
195
|
+
const done = `${power < 0 ? "Dividing" : "Multiplying"} by ${name} (${rate.unit}) leaves ${result.unit}`;
|
|
196
|
+
const other = combinedUnit(price, rate, power < 0 ? 1 : -1);
|
|
197
|
+
if (isPriceGroup(other.unitGroup)) {
|
|
198
|
+
const fix = priceName ? `write (${priceName})${power < 0 ? "*" : "/"}${name}` : `${power < 0 ? "multiply" : "divide"} by ${name}`;
|
|
199
|
+
return `${done}; ${fix} instead to get ${other.unit}.`;
|
|
200
|
+
}
|
|
201
|
+
const currency = price.unitGroup.slice("price:".length) || "its currency";
|
|
202
|
+
return `${done}; ${price.unit} converts only with a rate that has ${currency} on one side.`;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** The distinct currencies a unit still counts, once its factors cancel. */
|
|
206
|
+
export function unitCurrencies(unit: string): Set<string> {
|
|
207
|
+
const { numerator, denominator } = unitFactors(unit);
|
|
208
|
+
return new Set([...numerator, ...denominator].filter(isCurrencyFactor).map((factor) => unitFactorIdentity(factor).split(":")[0]!));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* The decimals a value worked out from prices prints at: the most its legs
|
|
213
|
+
* print, from two to four, and no more than a value of its own size needs:
|
|
214
|
+
* four under 10, two from 10. A crack of 4.9842 USD / gallon heating oil and
|
|
215
|
+
* 116.72 USD / barrel Brent reads 92.62; a gasoline-heating oil spread reads
|
|
216
|
+
* 1.7726. Undefined when a leg is not a price or the value has none yet.
|
|
217
|
+
*/
|
|
218
|
+
export function derivedValueDecimals(inputs: readonly ResolvedSeries[], points: readonly TimeSeriesPoint[]): number | undefined {
|
|
219
|
+
let digits = 0;
|
|
220
|
+
for (const input of inputs) {
|
|
221
|
+
if (!isPriceGroup(input.unitGroup) || input.transform !== "raw") return undefined;
|
|
222
|
+
const reference = latestScalarValue(input.points);
|
|
223
|
+
if (reference === undefined) return undefined;
|
|
224
|
+
digits = Math.max(digits, stablePriceFractionDigits({
|
|
225
|
+
assetCategory: input.priceAssetCategory,
|
|
226
|
+
currency: unitCurrencyToken(input.unit.split("/")[0] ?? "") ?? undefined,
|
|
227
|
+
referencePrice: reference,
|
|
228
|
+
sessionPrices: [reference],
|
|
229
|
+
}));
|
|
230
|
+
}
|
|
231
|
+
const size = latestScalarValue(points);
|
|
232
|
+
if (size === undefined) return undefined;
|
|
233
|
+
return Math.min(size < 10 ? 4 : 2, Math.max(2, digits));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** The size of a series' last nonzero value, which its decimals are read from. */
|
|
237
|
+
function latestScalarValue(points: readonly TimeSeriesPoint[]): number | undefined {
|
|
238
|
+
for (let index = points.length - 1; index >= 0; index -= 1) {
|
|
239
|
+
const value = scalarPointValue(points[index]!);
|
|
240
|
+
if (value !== null && Number.isFinite(value) && value !== 0) return Math.abs(value);
|
|
241
|
+
}
|
|
242
|
+
return undefined;
|
|
243
|
+
}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { latestTradingSessionOpen } from "../../market-data/market/trading-sessions";
|
|
2
|
+
import { CHART_RESOLUTION_STEP_MS, isIntradayResolution, type ManualChartResolution } from "../resolution";
|
|
3
|
+
import { anchoredVwap, sessionVwap, type StudyBar, type VwapValue } from "../trader-studies";
|
|
4
|
+
import { zonedDateTimeParts } from "../../utils/zoned-date-time";
|
|
5
|
+
import type { ChartStudySpec, ResolvedSeries } from "../types";
|
|
6
|
+
import { isFiniteNumber } from "../../utils/guards";
|
|
7
|
+
import { ANCHOR_COLORS, derivedPoint, outputSeries, studyBars, type NumericSample } from "./shared";
|
|
8
|
+
|
|
9
|
+
const DAY_MS = 86_400_000;
|
|
10
|
+
/** Most anchors one anchored VWAP keeps; each draws its own line. */
|
|
11
|
+
const MAX_VWAP_ANCHORS = 8;
|
|
12
|
+
export const DEFAULT_PROFILE_ROWS = 24;
|
|
13
|
+
|
|
14
|
+
/** Anchor times of an anchored VWAP, kept as `anchor1`, `anchor2`, ... so the spec stays numeric. */
|
|
15
|
+
export function vwapAnchors(spec: Pick<ChartStudySpec, "parameters">): number[] {
|
|
16
|
+
return [...new Set(Object.entries(spec.parameters)
|
|
17
|
+
.filter(([key, value]) => /^anchor\d+$/.test(key) && isFiniteNumber(value))
|
|
18
|
+
.map(([, value]) => value as number))]
|
|
19
|
+
.sort((left, right) => left - right)
|
|
20
|
+
.slice(0, MAX_VWAP_ANCHORS);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function withVwapAnchors(
|
|
24
|
+
parameters: ChartStudySpec["parameters"],
|
|
25
|
+
anchors: readonly number[],
|
|
26
|
+
): ChartStudySpec["parameters"] {
|
|
27
|
+
const kept = Object.fromEntries(Object.entries(parameters).filter(([key]) => !/^anchor\d+$/.test(key)));
|
|
28
|
+
const sorted = [...new Set(anchors.filter(Number.isFinite))].sort((left, right) => left - right).slice(-MAX_VWAP_ANCHORS);
|
|
29
|
+
return { ...kept, ...Object.fromEntries(sorted.map((anchor, index) => [`anchor${index + 1}`, anchor])) };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isIntradayInput(input: ResolvedSeries, marketResolution?: ManualChartResolution): boolean {
|
|
33
|
+
const resolution = input.historyResolution === undefined ? marketResolution : input.historyResolution;
|
|
34
|
+
if (resolution) return isIntradayResolution(resolution);
|
|
35
|
+
const cadence = input.timeBasis?.cadenceMs;
|
|
36
|
+
return cadence !== undefined && cadence < DAY_MS;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function localDay(time: number, timeZone: string | undefined): number {
|
|
40
|
+
if (!timeZone) return Math.floor(time / DAY_MS);
|
|
41
|
+
const { year, month, day } = zonedDateTimeParts(time, timeZone);
|
|
42
|
+
return Date.UTC(year, month - 1, day) / DAY_MS;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* `step` at each of `times` (ascending) for a step function that never falls
|
|
47
|
+
* as time moves on, such as a session's open or a local day. It is asked at
|
|
48
|
+
* both ends of a run and a run whose ends agree takes that value throughout,
|
|
49
|
+
* so a few calendar lookups per session cover every bar. The live chart
|
|
50
|
+
* resolves on every quote, and a lookup per 1-minute bar took tens of
|
|
51
|
+
* milliseconds over a week.
|
|
52
|
+
*/
|
|
53
|
+
function risingSteps<T>(times: readonly number[], step: (time: number) => T): T[] {
|
|
54
|
+
const values = new Array<T>(times.length);
|
|
55
|
+
if (times.length === 0) return values;
|
|
56
|
+
const last = times.length - 1;
|
|
57
|
+
values[0] = step(times[0]!);
|
|
58
|
+
values[last] = step(times[last]!);
|
|
59
|
+
const fill = (from: number, to: number): void => {
|
|
60
|
+
if (to - from < 2) return;
|
|
61
|
+
if (values[from] === values[to]) {
|
|
62
|
+
values.fill(values[from]!, from + 1, to);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const middle = (from + to) >> 1;
|
|
66
|
+
values[middle] = step(times[middle]!);
|
|
67
|
+
fill(from, middle);
|
|
68
|
+
fill(middle, to);
|
|
69
|
+
};
|
|
70
|
+
fill(0, last);
|
|
71
|
+
return values;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** When the session holding `time` opened on the input's listing, or null for a venue without known hours. */
|
|
75
|
+
function sessionOpenOf(input: ResolvedSeries): (time: number) => number | null {
|
|
76
|
+
const symbol = input.listing?.symbol;
|
|
77
|
+
const exchange = input.listing?.exchange || input.timeBasis?.exchange;
|
|
78
|
+
return (time) => latestTradingSessionOpen(symbol, exchange, time);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** The bar spacing: the requested cadence, else the history's resolution, else a minute. */
|
|
82
|
+
function barStep(input: ResolvedSeries): number {
|
|
83
|
+
return input.timeBasis?.cadenceMs
|
|
84
|
+
?? (input.historyResolution ? CHART_RESOLUTION_STEP_MS[input.historyResolution] : undefined)
|
|
85
|
+
?? 60_000;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Each bar's session, named by the open it follows, so the sums restart at
|
|
90
|
+
* the open and a bar before it continues the previous session: the regular
|
|
91
|
+
* open for stocks, the venue's published session open for futures (17:00
|
|
92
|
+
* Central on CME Globex). A venue without known hours starts over with each
|
|
93
|
+
* local day. The first session is left out when the history begins after its
|
|
94
|
+
* open, since its sums would be missing the bars before.
|
|
95
|
+
*/
|
|
96
|
+
function regularSessionKeys(bars: readonly StudyBar[], input: ResolvedSeries): Array<number | null> {
|
|
97
|
+
const step = barStep(input);
|
|
98
|
+
const times = bars.map((bar) => bar.time);
|
|
99
|
+
const opens = risingSteps(times, sessionOpenOf(input));
|
|
100
|
+
const days = opens.includes(null) ? risingSteps(times, (time) => localDay(time, input.timeBasis?.timeZone)) : [];
|
|
101
|
+
const keys = opens.map((open, index) => open ?? -1 - days[index]!);
|
|
102
|
+
const first = keys[0];
|
|
103
|
+
if (first !== undefined && first >= 0 && bars[0]!.time >= first + step) {
|
|
104
|
+
return keys.map((key) => key === first ? null : key);
|
|
105
|
+
}
|
|
106
|
+
return keys;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function vwapOutputs(
|
|
110
|
+
spec: ChartStudySpec,
|
|
111
|
+
input: ResolvedSeries,
|
|
112
|
+
bars: ReadonlyArray<{ sample: NumericSample }>,
|
|
113
|
+
values: readonly VwapValue[],
|
|
114
|
+
options: { id: string; label: string; color: string; bands: number; sessionOf?: (index: number) => number | null },
|
|
115
|
+
): ResolvedSeries[] {
|
|
116
|
+
// A value opening a new session follows a missing one just before it, so
|
|
117
|
+
// the line restarts there instead of joining the sessions with a diagonal.
|
|
118
|
+
const at = (pick: (value: VwapValue) => number) => values.flatMap((value, position) => {
|
|
119
|
+
const bar = bars[value.index];
|
|
120
|
+
if (!bar) return [];
|
|
121
|
+
const point = derivedPoint(bar.sample, pick(value));
|
|
122
|
+
const previous = values[position - 1];
|
|
123
|
+
if (!previous || !options.sessionOf || options.sessionOf(previous.index) === options.sessionOf(value.index)) return [point];
|
|
124
|
+
const before = new Date(point.date.getTime() - 1);
|
|
125
|
+
return [{ ...derivedPoint(bar.sample, null), date: before, observedAt: before }, point];
|
|
126
|
+
});
|
|
127
|
+
const outputs = [outputSeries(spec, input, {
|
|
128
|
+
id: options.id,
|
|
129
|
+
label: options.label,
|
|
130
|
+
points: at((value) => value.value),
|
|
131
|
+
color: options.color,
|
|
132
|
+
})];
|
|
133
|
+
if (options.bands > 0) {
|
|
134
|
+
outputs.push(
|
|
135
|
+
outputSeries(spec, input, {
|
|
136
|
+
id: `${options.id}:upper`,
|
|
137
|
+
label: `${options.label} +${options.bands}σ`,
|
|
138
|
+
points: at((value) => value.value + value.deviation * options.bands),
|
|
139
|
+
color: options.color,
|
|
140
|
+
}),
|
|
141
|
+
outputSeries(spec, input, {
|
|
142
|
+
id: `${options.id}:lower`,
|
|
143
|
+
label: `${options.label} -${options.bands}σ`,
|
|
144
|
+
points: at((value) => value.value - value.deviation * options.bands),
|
|
145
|
+
color: options.color,
|
|
146
|
+
}),
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
return outputs;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function hasVolume(bars: readonly StudyBar[]): boolean {
|
|
153
|
+
return bars.some((bar) => bar.volume > 0);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function resolveVwap(
|
|
157
|
+
spec: ChartStudySpec,
|
|
158
|
+
input: ResolvedSeries,
|
|
159
|
+
color: string,
|
|
160
|
+
nameInput: boolean,
|
|
161
|
+
marketResolution: ManualChartResolution | undefined,
|
|
162
|
+
warnings: string[],
|
|
163
|
+
): ResolvedSeries[] {
|
|
164
|
+
const label = nameInput ? `VWAP ${input.label}` : "VWAP";
|
|
165
|
+
if (!isIntradayInput(input, marketResolution)) {
|
|
166
|
+
warnings.push(`${label} needs intraday bars: choose 1D or 1W, or a minute timeframe.`);
|
|
167
|
+
return [];
|
|
168
|
+
}
|
|
169
|
+
const bars = studyBars(input);
|
|
170
|
+
if (!hasVolume(bars)) {
|
|
171
|
+
warnings.push(`${label} needs traded volume, which ${input.label} does not report.`);
|
|
172
|
+
return [];
|
|
173
|
+
}
|
|
174
|
+
const keys = regularSessionKeys(bars, input);
|
|
175
|
+
const bands = Math.min(3, Math.max(0, Math.round(isFiniteNumber(spec.parameters.bands) ? spec.parameters.bands : 0)));
|
|
176
|
+
return vwapOutputs(spec, input, bars, sessionVwap(bars, (_bar, index) => keys[index] ?? null), {
|
|
177
|
+
id: spec.id,
|
|
178
|
+
label,
|
|
179
|
+
color,
|
|
180
|
+
bands,
|
|
181
|
+
sessionOf: (index) => keys[index] ?? null,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
186
|
+
|
|
187
|
+
/** `Sep 30 09:30` on intraday bars, in the exchange's time; `Sep 30 2025` on daily ones. */
|
|
188
|
+
function formatAnchor(anchor: number, input: ResolvedSeries, intraday: boolean): string {
|
|
189
|
+
const parts = zonedDateTimeParts(anchor, intraday ? input.timeBasis?.timeZone ?? "UTC" : "UTC");
|
|
190
|
+
const date = `${MONTHS[parts.month - 1]} ${parts.day}`;
|
|
191
|
+
return intraday
|
|
192
|
+
? `${date} ${String(parts.hour).padStart(2, "0")}:${String(parts.minute).padStart(2, "0")}`
|
|
193
|
+
: `${date} ${parts.year}`;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Whether the loaded bars reach back to an anchor: a bar at or before it, or
|
|
198
|
+
* the first bar opening the same local day the anchor names.
|
|
199
|
+
*/
|
|
200
|
+
function historyReaches(bars: readonly StudyBar[], anchor: number, input: ResolvedSeries): boolean {
|
|
201
|
+
const first = bars[0];
|
|
202
|
+
if (!first) return false;
|
|
203
|
+
if (first.time <= anchor) return true;
|
|
204
|
+
const timeZone = input.timeBasis?.timeZone;
|
|
205
|
+
if (localDay(first.time, timeZone) !== localDay(anchor, timeZone)) return false;
|
|
206
|
+
const open = sessionOpenOf(input)(first.time);
|
|
207
|
+
return open === null || first.time < open + barStep(input);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function resolveAnchoredVwap(
|
|
211
|
+
spec: ChartStudySpec,
|
|
212
|
+
input: ResolvedSeries,
|
|
213
|
+
color: string,
|
|
214
|
+
marketResolution: ManualChartResolution | undefined,
|
|
215
|
+
warnings: string[],
|
|
216
|
+
): ResolvedSeries[] {
|
|
217
|
+
const anchors = vwapAnchors(spec);
|
|
218
|
+
if (anchors.length === 0) return [];
|
|
219
|
+
const bars = studyBars(input);
|
|
220
|
+
if (!hasVolume(bars)) {
|
|
221
|
+
warnings.push(`Anchored VWAP needs traded volume, which ${input.label} does not report.`);
|
|
222
|
+
return [];
|
|
223
|
+
}
|
|
224
|
+
const intraday = isIntradayInput(input, marketResolution);
|
|
225
|
+
const resolution = input.historyResolution ?? marketResolution;
|
|
226
|
+
const barMs = input.timeBasis?.cadenceMs ?? (resolution ? CHART_RESOLUTION_STEP_MS[resolution] : 0);
|
|
227
|
+
return anchors.flatMap((anchor, offset) => {
|
|
228
|
+
const label = `AVWAP ${formatAnchor(anchor, input, intraday)}`;
|
|
229
|
+
if (!historyReaches(bars, anchor, input)) {
|
|
230
|
+
warnings.push(`${label} starts before the loaded history; choose a longer range.`);
|
|
231
|
+
return [];
|
|
232
|
+
}
|
|
233
|
+
return vwapOutputs(spec, input, bars, anchoredVwap(bars, anchor, barMs), {
|
|
234
|
+
id: `${spec.id}:${anchor}`,
|
|
235
|
+
label,
|
|
236
|
+
color: offset === 0 ? color : ANCHOR_COLORS[offset % ANCHOR_COLORS.length]!,
|
|
237
|
+
bands: 0,
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** The input's bars, passed through for the chart to profile over what is in view. */
|
|
243
|
+
export function resolveVolumeProfile(
|
|
244
|
+
spec: ChartStudySpec,
|
|
245
|
+
input: ResolvedSeries,
|
|
246
|
+
color: string,
|
|
247
|
+
warnings: string[],
|
|
248
|
+
): ResolvedSeries[] {
|
|
249
|
+
if (input.transform !== "raw") {
|
|
250
|
+
warnings.push("Volume profile needs prices; switch the price series back to its own values.");
|
|
251
|
+
return [];
|
|
252
|
+
}
|
|
253
|
+
const bars = studyBars(input);
|
|
254
|
+
if (!hasVolume(bars)) {
|
|
255
|
+
warnings.push(`Volume profile needs traded volume, which ${input.label} does not report.`);
|
|
256
|
+
return [];
|
|
257
|
+
}
|
|
258
|
+
const rows = Math.min(100, Math.max(4, Math.round(isFiniteNumber(spec.parameters.rows) ? spec.parameters.rows : DEFAULT_PROFILE_ROWS)));
|
|
259
|
+
return [{
|
|
260
|
+
...outputSeries(spec, input, {
|
|
261
|
+
label: "VP POC",
|
|
262
|
+
points: bars.map(({ sample }) => ({
|
|
263
|
+
...derivedPoint(sample, sample.value),
|
|
264
|
+
open: sample.point.open,
|
|
265
|
+
high: sample.point.high,
|
|
266
|
+
low: sample.point.low,
|
|
267
|
+
close: sample.point.close,
|
|
268
|
+
volume: sample.point.volume,
|
|
269
|
+
})),
|
|
270
|
+
color,
|
|
271
|
+
}),
|
|
272
|
+
profile: { rows },
|
|
273
|
+
}];
|
|
274
|
+
}
|
package/src/time-series/types.ts
CHANGED
|
@@ -265,6 +265,8 @@ export interface ResolvedSeries {
|
|
|
265
265
|
/** Rejected valuation price inputs, retained independently of usable observations. */
|
|
266
266
|
valuationPriceIssues?: import("./valuation-price").ValuationPriceIssue[];
|
|
267
267
|
warning?: string;
|
|
268
|
+
/** When the copy the points came from was saved (ms), when its refresh failed and that copy answered. */
|
|
269
|
+
savedAt?: number;
|
|
268
270
|
/** Listed in the legend so it can be restored, but not drawn. */
|
|
269
271
|
hidden?: boolean;
|
|
270
272
|
/**
|
|
@@ -324,6 +326,11 @@ export interface ChartResolutionResult {
|
|
|
324
326
|
loading: boolean;
|
|
325
327
|
errors: string[];
|
|
326
328
|
warnings: string[];
|
|
329
|
+
/**
|
|
330
|
+
* The oldest saved copy a shown series answered from after its refresh
|
|
331
|
+
* failed (ms), which the chart's footer dates: "saved copy from …".
|
|
332
|
+
*/
|
|
333
|
+
savedAt?: number;
|
|
327
334
|
/**
|
|
328
335
|
* Where a series' source starts after the range asked for, and why (a
|
|
329
336
|
* publisher's cap on history), as `warnings` also carries it, so a report
|
package/src/types/config.ts
CHANGED
|
@@ -193,8 +193,13 @@ export interface OnboardingProgress {
|
|
|
193
193
|
positionsImported?: number;
|
|
194
194
|
accountStatus?: "signed-in" | "skipped";
|
|
195
195
|
checkoutOpenedAt?: string;
|
|
196
|
-
/** Desks picked at "What do you trade?", in the order picked; empty when skipped. */
|
|
196
|
+
/** Desks picked at "What do you trade most?", in the order picked; empty when skipped. */
|
|
197
197
|
desks?: string[];
|
|
198
|
+
/**
|
|
199
|
+
* Opened again from Settings (Run Setup Again) after setup was done: every
|
|
200
|
+
* step can be left, and the layouts are rebuilt in place.
|
|
201
|
+
*/
|
|
202
|
+
rerun?: boolean;
|
|
198
203
|
}
|
|
199
204
|
|
|
200
205
|
/**
|
|
@@ -231,8 +236,19 @@ export interface TelemetryConfig {
|
|
|
231
236
|
* both off; absent means on.
|
|
232
237
|
*/
|
|
233
238
|
usage?: boolean;
|
|
234
|
-
/**
|
|
239
|
+
/**
|
|
240
|
+
* Ticker-level research counts (Attention Counts). On by default: `false`
|
|
241
|
+
* turns them off and `true` is an explicit on. While unset, an account is
|
|
242
|
+
* counted only once this installation has shown it the one-time notice.
|
|
243
|
+
* Cloud sync carries only whether it is off, so an off reaches the
|
|
244
|
+
* account's other devices.
|
|
245
|
+
*/
|
|
235
246
|
attention?: boolean;
|
|
247
|
+
/**
|
|
248
|
+
* The accounts this installation has shown the Attention Counts notice to,
|
|
249
|
+
* oldest first. Kept on this device; never synced or sent.
|
|
250
|
+
*/
|
|
251
|
+
attentionNoticeShownTo?: string[];
|
|
236
252
|
}
|
|
237
253
|
|
|
238
254
|
/**
|
|
@@ -68,6 +68,11 @@ export interface SecFilingItem {
|
|
|
68
68
|
* Frankfurt reads SK hynix's). Absent on the listing's own filings.
|
|
69
69
|
*/
|
|
70
70
|
companyFrom?: CompanyFrom;
|
|
71
|
+
/**
|
|
72
|
+
* A current report's press release (its EX-99.1), when its index names one:
|
|
73
|
+
* the page the results or the news are on, not the cover page.
|
|
74
|
+
*/
|
|
75
|
+
pressReleaseUrl?: string;
|
|
71
76
|
}
|
|
72
77
|
|
|
73
78
|
export interface SecFilingDocument {
|
|
@@ -137,6 +142,9 @@ export interface EarningsEvent {
|
|
|
137
142
|
timing: "BMO" | "AMC" | "TNS" | "";
|
|
138
143
|
}
|
|
139
144
|
|
|
145
|
+
/** The reads a provider may send in batches (`DataProvider.batchesReads`). */
|
|
146
|
+
export type BatchedReadMethod = "getPriceHistory" | "getOptionsChain";
|
|
147
|
+
|
|
140
148
|
export interface MarketDataRequestContext {
|
|
141
149
|
brokerId?: string;
|
|
142
150
|
brokerInstanceId?: string;
|
|
@@ -155,6 +163,12 @@ export interface MarketDataRequestContext {
|
|
|
155
163
|
historySession?: "extended";
|
|
156
164
|
/** The listing's company, from its own quote: an SEC lookup for a non-US listing checks the registrant against it. */
|
|
157
165
|
listingName?: string;
|
|
166
|
+
/**
|
|
167
|
+
* The caller asks many reads like this one in the same moment (a board's
|
|
168
|
+
* rows), having checked `batchesReads`: a provider that batches them may
|
|
169
|
+
* hold this one a moment to send it with the others.
|
|
170
|
+
*/
|
|
171
|
+
batch?: boolean;
|
|
158
172
|
/**
|
|
159
173
|
* The caller prints what the quote's move is from: a short-lived process
|
|
160
174
|
* (the CLI) waits briefly for the daily closes that date a previous close
|
|
@@ -259,6 +273,15 @@ export interface AssetDataProvider {
|
|
|
259
273
|
primaryMarketSourceName?(): string | null | Promise<string | null>;
|
|
260
274
|
getCachedFinancialsForTargets?(targets: CachedFinancialsTarget[], options?: { allowExpired?: boolean; includeStaleQuotes?: boolean }): Map<string, TickerFinancials> | Promise<Map<string, TickerFinancials>>;
|
|
261
275
|
getQuotesBatch?(targets: QuoteSubscriptionTarget[], options?: QuoteBatchOptions): Promise<QuoteBatchResult[]>;
|
|
276
|
+
/**
|
|
277
|
+
* Whether reads of `method` asked with others in one moment (context
|
|
278
|
+
* `batch`) go out as batch requests (trailing history, dated option
|
|
279
|
+
* expiries), so a caller that otherwise keeps a few in flight may ask them
|
|
280
|
+
* all at once. A router answers true only when every source it could ask
|
|
281
|
+
* for them does; a remote transport asks the process that owns the router.
|
|
282
|
+
* Absent or false: ask a few at a time, without `batch`.
|
|
283
|
+
*/
|
|
284
|
+
batchesReads?(method: BatchedReadMethod): boolean | Promise<boolean>;
|
|
262
285
|
getTickerFinancialsBatch?(targets: CachedFinancialsTarget[], options?: { forceRefresh?: boolean; datesChangeBasis?: boolean }): Promise<TickerFinancialsBatchResult[]>;
|
|
263
286
|
getTickerFinancials(ticker: string, exchange?: string, context?: MarketDataRequestContext): Promise<TickerFinancials>;
|
|
264
287
|
getQuote(ticker: string, exchange?: string, context?: MarketDataRequestContext): Promise<Quote>;
|