gloomberb 0.18.0 → 0.18.2
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/package.json +1 -1
- package/src/api-client/commodity-balances.ts +6 -0
- package/src/api-client/company-kpis.ts +9 -0
- package/src/api-client/crypto-markets.ts +9 -0
- package/src/api-client/data.ts +6 -5
- package/src/api-client/equity-screener.ts +2 -0
- package/src/api-client/market-movers.ts +7 -0
- package/src/api-client/types.ts +14 -0
- package/src/app/pane-runtime/plugin-bindings.ts +3 -1
- package/src/app/pane-runtime/ticker-open-runtime.ts +17 -5
- package/src/app/runtime/plugin-bindings.ts +6 -2
- package/src/brokers/logos.ts +66 -0
- package/src/brokers/profile-form.ts +3 -0
- package/src/brokers/remote-broker-adapter.ts +13 -3
- package/src/capabilities/index.ts +1 -1
- package/src/capabilities/service-capabilities.ts +7 -1
- package/src/cli/base-converter.ts +60 -18
- package/src/cli/commands/fred-series.ts +15 -5
- package/src/cli/commands/market.ts +290 -159
- package/src/cli/commands/news-search.ts +35 -8
- package/src/cli/commands/overview.ts +31 -6
- package/src/cli/commands/system.ts +35 -1
- package/src/cli/commands/ticker.ts +105 -52
- package/src/cli/currency-hints.ts +27 -0
- package/src/cli/fx-pair.ts +41 -4
- package/src/cli/glossary.ts +57 -4
- package/src/cli/helpers.ts +36 -3
- package/src/cli/index.ts +4 -1
- package/src/cli/known-gaps.ts +37 -1
- package/src/cli/listing-arg.ts +37 -2
- package/src/cli/pane-functions/catalog.ts +3 -1
- package/src/cli/pane-functions/discovery.ts +15 -1
- package/src/cli/pane-functions/dom.ts +9 -4
- package/src/cli/pane-functions/freshness.ts +4 -4
- package/src/cli/pane-functions/function-help.ts +31 -7
- package/src/cli/pane-functions/headless.ts +6 -5
- package/src/cli/pane-functions/index.ts +3 -2
- package/src/cli/pane-functions/lock-note.ts +7 -4
- package/src/cli/pane-functions/resolver.ts +2 -1
- package/src/cli/quote-answer.ts +179 -0
- package/src/cli/series-search.ts +2 -1
- package/src/cli/symbol-list.ts +51 -16
- package/src/cli/types.ts +4 -0
- package/src/components/chart/composite/composite-chart.tsx +22 -7
- package/src/components/chart/composite/format.ts +13 -1
- package/src/components/chart/composite/level-labels.ts +30 -0
- package/src/components/chart/composite/levels.ts +17 -6
- package/src/components/chart/composite/panel-surface.tsx +64 -16
- package/src/components/chart/composite/price-axis-labels.tsx +2 -1
- package/src/components/chart/composite/types.ts +4 -0
- package/src/components/command-bar/routes/ticker-search/actions.ts +6 -0
- package/src/components/command-bar/workflow/collection-actions.ts +4 -0
- package/src/components/index.ts +2 -0
- package/src/components/layout/pane/content.tsx +16 -14
- package/src/components/layout/pane/footer/index.tsx +22 -3
- package/src/components/layout/pane/footer/model.ts +99 -4
- package/src/components/layout/pane/header-tabs.tsx +15 -1
- package/src/components/onboarding/onboarding-frame.tsx +9 -11
- package/src/components/onboarding/use-onboarding-broker-form.ts +5 -2
- package/src/components/onboarding/wizard-model.ts +10 -3
- package/src/components/onboarding/wizard-positions.ts +8 -0
- package/src/components/ui/button.tsx +11 -4
- package/src/components/ui/choice-dialog.tsx +8 -5
- package/src/components/ui/display.tsx +11 -6
- package/src/components/ui/fields.tsx +100 -20
- package/src/components/ui/icon.tsx +6 -1
- package/src/components/ui/list-row-lines.tsx +87 -0
- package/src/components/ui/list-view.tsx +14 -0
- package/src/components/ui/logo-mark.tsx +64 -0
- package/src/components/ui/number-step.ts +54 -0
- package/src/components/ui/select-button.tsx +5 -4
- package/src/components/ui/select-field.tsx +3 -3
- package/src/components/ui/status.tsx +17 -3
- package/src/components/ui/tabs.tsx +9 -1
- package/src/components/ui/toggle.tsx +17 -3
- package/src/core/state/app/instrument.ts +8 -3
- package/src/data/config/store/normalize.ts +4 -1
- package/src/data/plugin-cache.ts +32 -6
- package/src/docs/snapshot.json +57 -22
- package/src/i18n/es.ts +9 -3
- package/src/i18n/ja.ts +9 -3
- package/src/i18n/ko.ts +9 -3
- package/src/i18n/zh-cn.ts +10 -4
- package/src/i18n/zh-tw.ts +10 -4
- package/src/market-data/commodity-names.ts +80 -0
- package/src/market-data/coordinator/auxiliary.ts +3 -1
- package/src/market-data/coordinator/chart.ts +3 -1
- package/src/market-data/futures-board.ts +38 -1
- package/src/market-data/futures-contract.ts +91 -0
- package/src/market-data/fx-closes.ts +78 -1
- package/src/market-data/market/change-basis.ts +219 -0
- package/src/market-data/market/format.ts +28 -12
- package/src/market-data/market/freshness.ts +38 -0
- package/src/market-data/market/status.ts +55 -9
- package/src/market-data/market/year-to-date.ts +46 -0
- package/src/market-data/quotes/contributions.ts +12 -0
- package/src/market-data/quotes/delisting.ts +34 -0
- package/src/market-data/quotes/live-valuation.ts +23 -0
- package/src/market-data/quotes/resolution.ts +8 -2
- package/src/market-data/tax-equivalent.ts +10 -2
- package/src/notifications/app-notifier.ts +2 -2
- package/src/notifications/notification-log.ts +8 -6
- package/src/plugins/builtin/alerts/cli.ts +26 -18
- package/src/plugins/builtin/alerts/headless.ts +1 -1
- package/src/plugins/builtin/alerts/index.tsx +13 -4
- package/src/plugins/builtin/analytics/index.tsx +1 -1
- package/src/plugins/builtin/analytics/risk-client.ts +44 -11
- package/src/plugins/builtin/analytics/risk-fx.ts +61 -0
- package/src/plugins/builtin/analytics/risk-headless.ts +10 -1
- package/src/plugins/builtin/analytics/risk-model.ts +79 -16
- package/src/plugins/builtin/analytics/risk-pane.tsx +8 -2
- package/src/plugins/builtin/analytics/risk-test-data.ts +3 -0
- package/src/plugins/builtin/attention/trending.tsx +8 -6
- package/src/plugins/builtin/backtest/client.ts +5 -2
- package/src/plugins/builtin/backtest/window.ts +16 -3
- package/src/plugins/builtin/broker-manager/add-flow.tsx +40 -8
- package/src/plugins/builtin/broker-manager/detail.tsx +26 -1
- package/src/plugins/builtin/broker-manager/index.tsx +20 -9
- package/src/plugins/builtin/broker-manager/model.ts +5 -0
- package/src/plugins/builtin/broker-manager/pane-actions.tsx +8 -1
- package/src/plugins/builtin/broker-manager/table.ts +5 -1
- package/src/plugins/builtin/broker-trading/account-picker.tsx +91 -0
- package/src/plugins/builtin/broker-trading/chart-levels.ts +54 -0
- package/src/plugins/builtin/broker-trading/command.ts +103 -0
- package/src/plugins/builtin/broker-trading/controller.ts +688 -0
- package/src/plugins/builtin/broker-trading/dock.tsx +182 -0
- package/src/plugins/builtin/broker-trading/headless.ts +76 -0
- package/src/plugins/builtin/broker-trading/index.tsx +77 -0
- package/src/plugins/builtin/broker-trading/order-feed.ts +383 -0
- package/src/plugins/builtin/broker-trading/orders-data.ts +133 -0
- package/src/plugins/builtin/broker-trading/orders.tsx +437 -0
- package/src/plugins/builtin/broker-trading/overview-orders.tsx +121 -0
- package/src/plugins/builtin/broker-trading/pane-model.ts +207 -0
- package/src/plugins/builtin/broker-trading/pane.tsx +505 -0
- package/src/plugins/builtin/broker-trading/strategy.ts +153 -0
- package/src/plugins/builtin/broker-trading/ticket-parts.tsx +117 -0
- package/src/plugins/builtin/broker-trading/ticket.tsx +573 -0
- package/src/plugins/builtin/buildout/data-runtime.ts +1 -1
- package/src/plugins/builtin/buildout/format.ts +1 -0
- package/src/plugins/builtin/buildout/model/index.ts +16 -7
- package/src/plugins/builtin/buildout/pane/index.tsx +3 -2
- package/src/plugins/builtin/buildout/pane/status.tsx +3 -3
- package/src/plugins/builtin/chart-composer/cli-options.ts +19 -0
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
- package/src/plugins/builtin/chart-composer/headless-schema.ts +3 -3
- package/src/plugins/builtin/chart-composer/headless.ts +2 -1
- package/src/plugins/builtin/chart-composer/option-range.ts +39 -0
- package/src/plugins/builtin/chart-composer/pane.tsx +31 -11
- package/src/plugins/builtin/chart-composer/presets.ts +2 -2
- package/src/plugins/builtin/chart-composer/series-catalog.ts +4 -2
- package/src/plugins/builtin/chart-composer/shortcuts.ts +3 -3
- package/src/plugins/builtin/chart-composer/viewport-labels.ts +5 -2
- package/src/plugins/builtin/chat/index.tsx +1 -1
- package/src/plugins/builtin/chat/status-widget.tsx +1 -1
- package/src/plugins/builtin/chat/unread-inbox-pane.tsx +6 -1
- package/src/plugins/builtin/chat/unread-inbox.ts +1 -1
- package/src/plugins/builtin/cloud/team/pane-sections.tsx +10 -3
- package/src/plugins/builtin/cloud/team/pane.tsx +30 -9
- package/src/plugins/builtin/commodity-balances/client.ts +6 -4
- package/src/plugins/builtin/commodity-balances/headless.ts +41 -7
- package/src/plugins/builtin/commodity-balances/index.tsx +19 -4
- package/src/plugins/builtin/commodity-balances/model.ts +22 -0
- package/src/plugins/builtin/commodity-balances/pane.tsx +36 -5
- package/src/plugins/builtin/company-kpis/client.ts +3 -2
- package/src/plugins/builtin/company-kpis/headless.ts +5 -7
- package/src/plugins/builtin/company-kpis/model.ts +85 -2
- package/src/plugins/builtin/company-kpis/pane.tsx +26 -12
- package/src/plugins/builtin/composite-plugins.ts +3 -2
- package/src/plugins/builtin/cot/headless.ts +1 -1
- package/src/plugins/builtin/cot/index.tsx +1 -1
- package/src/plugins/builtin/cot/model.ts +35 -12
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +2 -1
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +2 -1
- package/src/plugins/builtin/credit-conditions/index.tsx +2 -1
- package/src/plugins/builtin/crypto-board/client.ts +33 -2
- package/src/plugins/builtin/crypto-board/headless.ts +5 -2
- package/src/plugins/builtin/crypto-board/model.ts +28 -8
- package/src/plugins/builtin/custom-view/loader.ts +3 -2
- package/src/plugins/builtin/custom-view/pane.tsx +5 -4
- package/src/plugins/builtin/custom-view/view-spec.ts +1 -0
- package/src/plugins/builtin/dividend-yield/headless.ts +30 -8
- package/src/plugins/builtin/dividend-yield/provider-client.ts +3 -1
- package/src/plugins/builtin/earnings-calls/headless.ts +4 -4
- package/src/plugins/builtin/earnings-calls/lock-note.ts +12 -3
- package/src/plugins/builtin/econ/calendar-model.ts +38 -2
- package/src/plugins/builtin/econ/fred-catalog.ts +6 -2
- package/src/plugins/builtin/econ/fred-series-map.ts +12 -1
- package/src/plugins/builtin/econ/index.tsx +31 -4
- package/src/plugins/builtin/econ/print-watch.ts +279 -0
- package/src/plugins/builtin/equity-screener/headless.ts +20 -5
- package/src/plugins/builtin/equity-screener/model.ts +40 -2
- package/src/plugins/builtin/equity-screener/pane.tsx +24 -21
- package/src/plugins/builtin/estimate-revisions/headless.ts +3 -2
- package/src/plugins/builtin/estimate-revisions/lock-note.ts +29 -7
- package/src/plugins/builtin/executives/data.ts +24 -8
- package/src/plugins/builtin/executives/index.tsx +2 -18
- package/src/plugins/builtin/executives/pane.tsx +34 -10
- package/src/plugins/builtin/exposure/client.ts +4 -1
- package/src/plugins/builtin/exposure/editor.tsx +3 -3
- package/src/plugins/builtin/exposure/evidence.ts +4 -1
- package/src/plugins/builtin/exposure/holdings.ts +3 -1
- package/src/plugins/builtin/exposure/pane.tsx +37 -16
- package/src/plugins/builtin/filing-events/index.tsx +9 -3
- package/src/plugins/builtin/futures/table.tsx +6 -3
- package/src/plugins/builtin/futures-curve/pane.tsx +2 -2
- package/src/plugins/builtin/insider/base-values.ts +72 -0
- package/src/plugins/builtin/insider/headless.ts +29 -4
- package/src/plugins/builtin/jobs/headless.ts +2 -2
- package/src/plugins/builtin/jobs/lock-note.ts +14 -3
- package/src/plugins/builtin/market-halts/model.ts +31 -6
- package/src/plugins/builtin/market-halts/pane.tsx +3 -0
- package/src/plugins/builtin/market-movers/client.ts +2 -2
- package/src/plugins/builtin/market-movers/index.tsx +0 -3
- package/src/plugins/builtin/market-movers/session-body.tsx +27 -11
- package/src/plugins/builtin/market-movers/session.ts +25 -10
- package/src/plugins/builtin/market-valuation/pane.tsx +2 -1
- package/src/plugins/builtin/members/pane.tsx +8 -3
- package/src/plugins/builtin/news/wire/feed-config.ts +33 -13
- package/src/plugins/builtin/news/wire/index.tsx +7 -2
- package/src/plugins/builtin/news/wire/letters/client.ts +1 -0
- package/src/plugins/builtin/news/wire/news/command-bar-search.ts +6 -3
- package/src/plugins/builtin/news/wire/news/detail-view.tsx +2 -1
- package/src/plugins/builtin/news/wire/news/preset-pane.tsx +11 -3
- package/src/plugins/builtin/news/wire/news/table.tsx +2 -1
- package/src/plugins/builtin/news/wire/rss/cli.ts +3 -2
- package/src/plugins/builtin/news/wire/rss/feed-xml.ts +6 -1
- package/src/plugins/builtin/news/wire/rss/managed-feed.ts +1 -0
- package/src/plugins/builtin/news/wire/rss/source.ts +13 -4
- package/src/plugins/builtin/notes/cli.ts +33 -8
- package/src/plugins/builtin/notes/export.ts +49 -3
- package/src/plugins/builtin/notes/files.ts +14 -3
- package/src/plugins/builtin/notes/index.tsx +3 -3
- package/src/plugins/builtin/notes/quick-notes-pane.tsx +45 -10
- package/src/plugins/builtin/notes/store.ts +13 -3
- package/src/plugins/builtin/options/footer.ts +25 -20
- package/src/plugins/builtin/options/live-quotes.ts +33 -18
- package/src/plugins/builtin/options/view.tsx +77 -22
- package/src/plugins/builtin/options-calculator/pane.tsx +4 -2
- package/src/plugins/builtin/options-scenario/pane.tsx +41 -6
- package/src/plugins/builtin/portfolio-list/account-metrics.ts +3 -0
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +8 -7
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +166 -15
- package/src/plugins/builtin/portfolio-list/cli/render.ts +69 -15
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +2 -2
- package/src/plugins/builtin/portfolio-list/headless.ts +3 -1
- package/src/plugins/builtin/portfolio-list/pane/data.ts +23 -1
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +44 -17
- package/src/plugins/builtin/portfolio-list/settings.ts +20 -2
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +22 -1
- package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +42 -7
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +24 -3
- package/src/plugins/builtin/primary-dealers/client.ts +137 -62
- package/src/plugins/builtin/primary-dealers/headless.ts +30 -5
- package/src/plugins/builtin/primary-dealers/index.tsx +3 -2
- package/src/plugins/builtin/primary-dealers/model.ts +179 -129
- package/src/plugins/builtin/primary-dealers/pane.tsx +135 -15
- package/src/plugins/builtin/research/analyst-model.ts +5 -1
- package/src/plugins/builtin/risk-factors/index.tsx +12 -3
- package/src/plugins/builtin/scanner/feed.ts +6 -1
- package/src/plugins/builtin/scanner/headless.ts +1 -1
- package/src/plugins/builtin/scanner/lock-note.ts +3 -2
- package/src/plugins/builtin/series-inventory.ts +1 -0
- package/src/plugins/builtin/shared/broker-reconnect.ts +105 -0
- package/src/plugins/builtin/shared/cloud-denied.ts +7 -6
- package/src/plugins/builtin/shared/cloud-upgrade.ts +10 -11
- package/src/plugins/builtin/shared/free-routes.ts +24 -0
- package/src/plugins/builtin/shared/headless-options.ts +11 -0
- package/src/plugins/builtin/shared/pro-feature-wall.tsx +9 -4
- package/src/plugins/builtin/shared/pro-lock-note.ts +89 -7
- package/src/plugins/builtin/shared/research-trading.tsx +62 -0
- package/src/plugins/builtin/social-mentions/headless.ts +1 -1
- package/src/plugins/builtin/social-mentions/lock-note.ts +1 -1
- package/src/plugins/builtin/themes/headless.ts +8 -2
- package/src/plugins/builtin/themes/model.ts +43 -10
- package/src/plugins/builtin/themes/pane.tsx +8 -6
- package/src/plugins/builtin/thirteenf/api.ts +4 -1
- package/src/plugins/builtin/thirteenf/data.ts +5 -1
- package/src/plugins/builtin/thirteenf/headless.ts +3 -1
- package/src/plugins/builtin/thirteenf/pane.tsx +8 -3
- package/src/plugins/builtin/ticker-detail/overview/model.ts +44 -10
- package/src/plugins/builtin/ticker-detail/overview/option-contract.ts +64 -0
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +82 -21
- package/src/plugins/builtin/ticker-detail/pane.tsx +21 -14
- package/src/plugins/builtin/ticker-detail/quote-footer.ts +5 -1
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +37 -8
- package/src/plugins/builtin/time-sales/pane.tsx +2 -2
- package/src/plugins/builtin/trace-bonds/client.ts +14 -3
- package/src/plugins/builtin/trace-bonds/headless.ts +1 -1
- package/src/plugins/builtin/vol-surface/pane.tsx +2 -2
- package/src/plugins/builtin-editorial.ts +1 -1
- package/src/plugins/compat.ts +3 -0
- package/src/plugins/external-runtime.ts +5 -0
- package/src/plugins/loader.ts +6 -0
- package/src/plugins/plugin-icon.ts +61 -0
- package/src/plugins/registry/host-actions.ts +2 -1
- package/src/plugins/registry/index.ts +9 -1
- package/src/plugins/runtime/context.tsx +5 -0
- package/src/plugins/runtime/index.tsx +3 -0
- package/src/portfolio/column-values.ts +13 -4
- package/src/portfolio/cost-fx.ts +61 -0
- package/src/portfolio/mutations.ts +16 -2
- package/src/portfolio/position-metrics.ts +45 -4
- package/src/portfolio/position-quantity.ts +43 -0
- package/src/public/__snapshots__/public-api.test.ts.snap +5 -0
- package/src/public/broker.ts +8 -0
- package/src/public/market-data.ts +5 -0
- package/src/renderers/dom/desktop/control-styles.ts +7 -1
- package/src/renderers/dom/desktop/controls.tsx +39 -7
- package/src/renderers/dom/desktop/icons.tsx +14 -0
- package/src/renderers/dom/desktop/list-view.tsx +51 -19
- package/src/renderers/dom/desktop/menu.tsx +10 -1
- package/src/renderers/dom/desktop/select-field.tsx +8 -6
- package/src/renderers/dom/host/style.ts +6 -1
- package/src/renderers/dom/host/tabs.tsx +6 -0
- package/src/renderers/dom/styles.css +12 -5
- package/src/renderers/electrobun/bun/core-capabilities.ts +12 -0
- package/src/renderers/electrobun/bun/external-plugins.ts +3 -0
- package/src/renderers/electrobun/shared/protocol.ts +2 -0
- package/src/renderers/electrobun/view/broker-remote-client.ts +16 -0
- package/src/renderers/electrobun/view/external-plugins.ts +1 -0
- package/src/series/validate.ts +2 -2
- package/src/sources/gloomberb-cloud/fred-series.ts +27 -2
- package/src/sources/gloomberb-cloud/index.ts +50 -17
- package/src/sources/gloomberb-cloud/normalizers.ts +4 -0
- package/src/sources/history-result.ts +3 -0
- package/src/sources/provider-errors.ts +3 -1
- package/src/sources/provider-router/history.ts +49 -6
- package/src/sources/provider-router/index.ts +2 -1
- package/src/state/app/activity.ts +13 -0
- package/src/sync/controller.ts +4 -0
- package/src/sync/core-contributors.ts +63 -11
- package/src/sync/local-only.ts +121 -0
- package/src/sync/react.ts +6 -0
- package/src/sync/types.ts +3 -0
- package/src/team/collections.ts +2 -0
- package/src/tickers/listing-fate.ts +27 -8
- package/src/tickers/metadata.ts +10 -0
- package/src/tickers/search/index.ts +24 -3
- package/src/time-series/price-comparison.ts +35 -0
- package/src/time-series/resolve.ts +52 -11
- package/src/time-series/spec.ts +1 -1
- package/src/time-series/types.ts +5 -0
- package/src/types/broker.ts +56 -1
- package/src/types/config.ts +6 -0
- package/src/types/data-provider.ts +5 -1
- package/src/types/financials.ts +23 -0
- package/src/types/headless.ts +12 -2
- package/src/types/instrument.ts +4 -0
- package/src/types/plugin.ts +24 -6
- package/src/types/price-history.ts +6 -1
- package/src/types/ticker.ts +9 -0
- package/src/types/trading.ts +67 -0
- package/src/ui/host.tsx +4 -0
- package/src/utils/base-currency.ts +108 -0
- package/src/utils/currency-names.ts +128 -0
- package/src/utils/currency-pair.ts +2 -1
- package/src/utils/currency-units.ts +41 -1
- package/src/utils/dom-screenshot.ts +22 -9
- package/src/utils/exchange-notation.generated.ts +360 -0
- package/src/utils/exchanges.ts +15 -322
- package/src/utils/format.ts +31 -1
- package/src/utils/instrument-identity.ts +38 -1
- package/src/utils/options.ts +46 -1
- package/src/utils/price-history.ts +4 -0
- package/src/utils/reported-money.ts +8 -4
package/package.json
CHANGED
|
@@ -44,6 +44,12 @@ export interface PsdBalanceRow {
|
|
|
44
44
|
unit: string;
|
|
45
45
|
/** Market year, 2026/27. */
|
|
46
46
|
year: string;
|
|
47
|
+
/**
|
|
48
|
+
* YYYY-MM of the crop's newest estimate: the WASDE for grains, oilseeds and
|
|
49
|
+
* cotton, USDA's semiannual report for coffee and sugar. Absent from boards
|
|
50
|
+
* served before it was sent.
|
|
51
|
+
*/
|
|
52
|
+
month?: string | null;
|
|
47
53
|
cropOrder: number;
|
|
48
54
|
countryOrder: number;
|
|
49
55
|
attributeOrder: number;
|
|
@@ -83,6 +83,10 @@ export interface KpiObservation extends Omit<KpiObservationInput, "quote" | "sca
|
|
|
83
83
|
conflict: boolean
|
|
84
84
|
contested?: boolean
|
|
85
85
|
evidence: KpiEvidence[]
|
|
86
|
+
/** Stored facts shown as this one: the same figure under other labels or periods. */
|
|
87
|
+
merged?: string[]
|
|
88
|
+
/** The labels that tell its series apart, the same on each of its facts; the stored ones stay in `dimensions`. */
|
|
89
|
+
seriesLabels?: Record<string, string>
|
|
86
90
|
}
|
|
87
91
|
export interface KpiGuidance extends Omit<KpiGuidanceInput, "quote" | "scale"> {
|
|
88
92
|
id: string
|
|
@@ -97,6 +101,10 @@ export interface KpiGuidance extends Omit<KpiGuidanceInput, "quote" | "scale"> {
|
|
|
97
101
|
direction: GuidanceDirection
|
|
98
102
|
previousId: string | null
|
|
99
103
|
midpointChangePct: number | null
|
|
104
|
+
/** Stored guides shown as this one. */
|
|
105
|
+
merged?: string[]
|
|
106
|
+
/** The labels that tell its series apart, as on its actuals. */
|
|
107
|
+
seriesLabels?: Record<string, string>
|
|
100
108
|
actual: { observationId: string; value: number; outcome: "above" | "below" | "within"; favorable: "beat" | "miss" | "in_line" | "neutral"; difference: number; differencePct: number | null } | null
|
|
101
109
|
}
|
|
102
110
|
interface KpiCoverage {
|
|
@@ -118,6 +126,7 @@ export interface KpiSeries {
|
|
|
118
126
|
currency: string | null
|
|
119
127
|
basis: KpiBasis
|
|
120
128
|
dimensions: Record<string, string>
|
|
129
|
+
seriesLabels?: Record<string, string>
|
|
121
130
|
latest: KpiObservation
|
|
122
131
|
observations: KpiObservation[]
|
|
123
132
|
}
|
|
@@ -38,9 +38,16 @@ export interface CryptoMarketAsset {
|
|
|
38
38
|
/** Market-cap rank within its kind. */
|
|
39
39
|
rank: number;
|
|
40
40
|
price: number;
|
|
41
|
+
/**
|
|
42
|
+
* The day's move as `quote` gives the coin: from the previous UTC day's
|
|
43
|
+
* close, the price at 00:00 UTC. A coin whose close Gloom Cloud cannot date
|
|
44
|
+
* to the last two days moves over 24 hours (`changeBasis` "24h") or not at
|
|
45
|
+
* all ("none"), its previousClose null.
|
|
46
|
+
*/
|
|
41
47
|
previousClose: number | null;
|
|
42
48
|
change: number | null;
|
|
43
49
|
changePercent: number | null;
|
|
50
|
+
changeBasis?: "24h" | "none";
|
|
44
51
|
dayHigh: number | null;
|
|
45
52
|
dayLow: number | null;
|
|
46
53
|
volume24h: number | null;
|
|
@@ -62,6 +69,8 @@ export interface CryptoMarketAsset {
|
|
|
62
69
|
export interface CryptoMarketsPayload {
|
|
63
70
|
version: 1;
|
|
64
71
|
generatedAt: string;
|
|
72
|
+
/** Each asset's change is since 00:00 UTC; a server before it sent the screener's 24-hour move. */
|
|
73
|
+
dayChangeBasis?: "utc-day";
|
|
65
74
|
asOf: string | null;
|
|
66
75
|
status: "available" | "partial" | "unavailable";
|
|
67
76
|
source: {
|
package/src/api-client/data.ts
CHANGED
|
@@ -610,12 +610,12 @@ export class CloudDataApi {
|
|
|
610
610
|
}
|
|
611
611
|
|
|
612
612
|
/** `listing` names a listing abroad's venue and company; a US listing needs neither. */
|
|
613
|
-
async getCloudCompanyKpis(symbol: string, options: KpiQueryOptions = {}, listing: IssuerListingParams = {}): Promise<KpisPayload> {
|
|
614
|
-
return this.request<KpisPayload>(companyDisclosurePath("kpis", symbol, options, listing));
|
|
613
|
+
async getCloudCompanyKpis(symbol: string, options: KpiQueryOptions = {}, listing: IssuerListingParams = {}, request?: { signal?: AbortSignal }): Promise<KpisPayload> {
|
|
614
|
+
return this.request<KpisPayload>(companyDisclosurePath("kpis", symbol, options, listing), request);
|
|
615
615
|
}
|
|
616
616
|
|
|
617
|
-
async getCloudCompanyGuidance(symbol: string, options: KpiQueryOptions = {}, listing: IssuerListingParams = {}): Promise<GuidancePayload> {
|
|
618
|
-
return this.request<GuidancePayload>(companyDisclosurePath("guidance", symbol, options, listing));
|
|
617
|
+
async getCloudCompanyGuidance(symbol: string, options: KpiQueryOptions = {}, listing: IssuerListingParams = {}, request?: { signal?: AbortSignal }): Promise<GuidancePayload> {
|
|
618
|
+
return this.request<GuidancePayload>(companyDisclosurePath("guidance", symbol, options, listing), request);
|
|
619
619
|
}
|
|
620
620
|
async getCloudPerpsBoard(query: PerpBoardQuery = {}): Promise<PerpBoardPayload> {
|
|
621
621
|
return this.request(`/cloud/perps/board?${new URLSearchParams(Object.entries(query).filter(([, value]) => value !== undefined).map(([key, value]) => [key, String(value)]))}`);
|
|
@@ -1040,8 +1040,9 @@ export class CloudDataApi {
|
|
|
1040
1040
|
|
|
1041
1041
|
async getCloudSecFilings(
|
|
1042
1042
|
params: CloudSecFilingsParams,
|
|
1043
|
+
options?: { signal?: AbortSignal },
|
|
1043
1044
|
): Promise<CloudSecFilingsResponse> {
|
|
1044
|
-
return this.request<CloudSecFilingsResponse>(cloudSecFilingsPath(params));
|
|
1045
|
+
return this.request<CloudSecFilingsResponse>(cloudSecFilingsPath(params), options);
|
|
1045
1046
|
}
|
|
1046
1047
|
|
|
1047
1048
|
/** Schedule 13D/13G reports about an issuer. Unknown tickers answer 404; no reports is an empty `owners`. */
|
|
@@ -110,6 +110,8 @@ export interface ScreenMetric {
|
|
|
110
110
|
scope: "reported" | "derived" | "observed-subset";
|
|
111
111
|
reason: string | null;
|
|
112
112
|
sourceUrl: string | null;
|
|
113
|
+
/** Set by the client on a Pro field the server left out for a caller without Gloom Pro; never sent. */
|
|
114
|
+
access?: "pro";
|
|
113
115
|
percentile: {
|
|
114
116
|
value: number | null;
|
|
115
117
|
sampleCount: number;
|
|
@@ -50,6 +50,13 @@ export interface CloudSessionMoversPayload {
|
|
|
50
50
|
phase: CloudSessionPhase;
|
|
51
51
|
asOf: string;
|
|
52
52
|
stale?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* `delayed` for an account without Pro: the list as it was built at least
|
|
55
|
+
* `delayMinutes` before it was served, as old as that account's quotes,
|
|
56
|
+
* and `asOf` that time. Absent on Pro's live list.
|
|
57
|
+
*/
|
|
58
|
+
access?: "delayed";
|
|
59
|
+
delayMinutes?: number;
|
|
53
60
|
items: CloudSessionMoverItem[];
|
|
54
61
|
}
|
|
55
62
|
|
package/src/api-client/types.ts
CHANGED
|
@@ -1005,6 +1005,13 @@ interface CloudProxyStatementSummaryPayload {
|
|
|
1005
1005
|
}
|
|
1006
1006
|
|
|
1007
1007
|
export interface CloudProxyStatementPayload extends CloudProxyStatementSummaryPayload {
|
|
1008
|
+
/**
|
|
1009
|
+
* `preview` for an account without Pro: each executive's total pay from
|
|
1010
|
+
* the latest proxy, with the breakdown, the year before, the pay ratio,
|
|
1011
|
+
* say-on-pay, highlights, key figures and other years null or empty.
|
|
1012
|
+
* Absent on Pro's full statement.
|
|
1013
|
+
*/
|
|
1014
|
+
access?: "preview";
|
|
1008
1015
|
docUrl: string;
|
|
1009
1016
|
ceo: (CloudExecutiveRowPayload & { priorYearTotal: number | null }) | null;
|
|
1010
1017
|
namedExecutives: CloudExecutiveRowPayload[];
|
|
@@ -1126,6 +1133,8 @@ export interface CloudProxyStatementListPayload {
|
|
|
1126
1133
|
shortName: string;
|
|
1127
1134
|
};
|
|
1128
1135
|
proxies: CloudProxyStatementSummaryPayload[];
|
|
1136
|
+
/** `preview` for an account without Pro: the latest proxy alone, without the year before or the pay ratio. */
|
|
1137
|
+
access?: "preview";
|
|
1129
1138
|
}
|
|
1130
1139
|
|
|
1131
1140
|
export interface CloudTranscriptTurnPayload {
|
|
@@ -1554,6 +1563,11 @@ export interface CloudMarketResponse<T> {
|
|
|
1554
1563
|
omittedSessions?: unknown;
|
|
1555
1564
|
/** Untrusted until the history adapter validates its boundary dates. */
|
|
1556
1565
|
coverage?: CloudHistoryCoverage;
|
|
1566
|
+
/**
|
|
1567
|
+
* Untrusted: a US listing that no longer trades, `{ status, lastTradeDate,
|
|
1568
|
+
* historyStart }`. Its history ends on `lastTradeDate`. Read by parseListingDelisting.
|
|
1569
|
+
*/
|
|
1570
|
+
delisting?: unknown;
|
|
1557
1571
|
providerMeta?: {
|
|
1558
1572
|
provider?: string;
|
|
1559
1573
|
upstream?: string;
|
|
@@ -479,9 +479,11 @@ export function bindAppPanePluginRegistry({
|
|
|
479
479
|
throw error;
|
|
480
480
|
}
|
|
481
481
|
}
|
|
482
|
+
// Recorded before it registers: what redraws as its contributions land
|
|
483
|
+
// (a broker list and its logo) reads the entry this checkout now is.
|
|
484
|
+
upsertExternalPlugin(entry);
|
|
482
485
|
try {
|
|
483
486
|
await pluginRegistry.register(entry.plugin);
|
|
484
|
-
upsertExternalPlugin(entry);
|
|
485
487
|
} catch (error) {
|
|
486
488
|
upsertExternalPlugin({ ...entry, error: error instanceof Error ? error.message : String(error) });
|
|
487
489
|
reportCrash(error, { kind: "plugin", plugin: pluginId });
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
tickerOpenFailureMessage,
|
|
25
25
|
type TickerOpenTarget,
|
|
26
26
|
} from "../../tickers/open-target";
|
|
27
|
-
import { findExactTickerSearchMatch } from "../../tickers/search";
|
|
27
|
+
import { findExactTickerSearchMatch, upsertTickerFromSearchResult } from "../../tickers/search";
|
|
28
28
|
import { offerTickerListings, publishTickerOpenTarget as publishOpenTarget } from "./ticker-open-target";
|
|
29
29
|
import { parsePublicTickerKey, publicTickerKey } from "../../utils/exchanges";
|
|
30
30
|
import { attentionActionForPane, captureAttentionAction } from "../../telemetry/attention-counts";
|
|
@@ -158,7 +158,7 @@ export function useAppTickerOpenRuntime({
|
|
|
158
158
|
persistLayout(nextLayout);
|
|
159
159
|
}
|
|
160
160
|
if (paneType === TICKER_RESEARCH_PANE_ID && options?.tabId) {
|
|
161
|
-
dispatch({ type: "UPDATE_PANE_STATE", paneId: existing.instanceId, patch: { activeTabId: options.tabId } });
|
|
161
|
+
dispatch({ type: "UPDATE_PANE_STATE", paneId: existing.instanceId, patch: { ...options.tabState, activeTabId: options.tabId } });
|
|
162
162
|
}
|
|
163
163
|
focusVisiblePane(existing.instanceId, nextLayout);
|
|
164
164
|
return;
|
|
@@ -186,7 +186,7 @@ export function useAppTickerOpenRuntime({
|
|
|
186
186
|
);
|
|
187
187
|
persistLayout(nextLayout);
|
|
188
188
|
if (paneType === TICKER_RESEARCH_PANE_ID && options?.tabId) {
|
|
189
|
-
dispatch({ type: "UPDATE_PANE_STATE", paneId: instance.instanceId, patch: { activeTabId: options.tabId } });
|
|
189
|
+
dispatch({ type: "UPDATE_PANE_STATE", paneId: instance.instanceId, patch: { ...options.tabState, activeTabId: options.tabId } });
|
|
190
190
|
}
|
|
191
191
|
activatePane(instance.instanceId);
|
|
192
192
|
}, [
|
|
@@ -205,9 +205,21 @@ export function useAppTickerOpenRuntime({
|
|
|
205
205
|
// Before resolving, so a refused open adds no ticker either.
|
|
206
206
|
if (refuseWhileOwnerOff(rawSymbol, options, () => { void openPinnedTicker(rawSymbol, options); })) return;
|
|
207
207
|
const recordAttention = captureAttentionAction();
|
|
208
|
-
|
|
208
|
+
let selected = options?.instrument !== undefined && (options.instrument || options.listing)
|
|
209
|
+
? { ticker: await tickerRepository.loadTicker(rawSymbol), created: false } : null;
|
|
210
|
+
// A listing the caller chose, such as one contract of an options chain,
|
|
211
|
+
// opens as given: no search could name it better than its own chain.
|
|
212
|
+
if (selected && !selected.ticker && options?.listing) {
|
|
213
|
+
const { listing, instrument } = options;
|
|
214
|
+
selected = await upsertTickerFromSearchResult(tickerRepository, {
|
|
215
|
+
providerId: instrument?.brokerId ?? "", ...(instrument?.brokerInstanceId ? { brokerInstanceId: instrument.brokerInstanceId } : {}),
|
|
216
|
+
symbol: rawSymbol, name: listing.name, exchange: listing.exchange, type: listing.type,
|
|
217
|
+
...(listing.currency ? { currency: listing.currency } : {}), ...(instrument ? { brokerContract: instrument } : {}),
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
const selectedTicker = selected?.ticker;
|
|
209
221
|
const target = selectedTicker
|
|
210
|
-
? { symbol: selectedTicker.metadata.ticker, ticker: selectedTicker, created:
|
|
222
|
+
? { symbol: selectedTicker.metadata.ticker, ticker: selectedTicker, created: selected!.created, instrument: options?.instrument, listing: options?.listing }
|
|
211
223
|
: await resolveOpenTickerTarget(rawSymbol, options?.instrument === null);
|
|
212
224
|
if (!target) return;
|
|
213
225
|
placePinnedTickerTarget(target, options, rawSymbol);
|
|
@@ -105,7 +105,7 @@ export function bindPluginRegistryRuntimeAccess({
|
|
|
105
105
|
pluginRegistry.events.emit("config:changed", { config: nextConfig });
|
|
106
106
|
},
|
|
107
107
|
|
|
108
|
-
createBrokerInstance: async (brokerType, label, values) => {
|
|
108
|
+
createBrokerInstance: async (brokerType, label, values, options = {}) => {
|
|
109
109
|
const instanceId = createBrokerInstanceId(
|
|
110
110
|
brokerType,
|
|
111
111
|
label,
|
|
@@ -118,6 +118,7 @@ export function bindPluginRegistryRuntimeAccess({
|
|
|
118
118
|
connectionMode: typeof values.connectionMode === "string" ? values.connectionMode : undefined,
|
|
119
119
|
config: values,
|
|
120
120
|
enabled: true,
|
|
121
|
+
...(options.localOnly ? { localOnly: true } : {}),
|
|
121
122
|
};
|
|
122
123
|
const nextConfig = {
|
|
123
124
|
...stateRef.current.config,
|
|
@@ -153,12 +154,15 @@ export function bindPluginRegistryRuntimeAccess({
|
|
|
153
154
|
instance.id === instanceId
|
|
154
155
|
? (() => {
|
|
155
156
|
const nextValues = options.replaceConfig ? values : { ...instance.config, ...values };
|
|
157
|
+
const { localOnly: wasLocalOnly, ...rest } = instance;
|
|
158
|
+
const localOnly = options.localOnly ?? wasLocalOnly === true;
|
|
156
159
|
return {
|
|
157
|
-
...
|
|
160
|
+
...rest,
|
|
158
161
|
label: options.label ?? instance.label,
|
|
159
162
|
enabled: options.enabled ?? instance.enabled,
|
|
160
163
|
connectionMode: typeof nextValues.connectionMode === "string" ? nextValues.connectionMode : instance.connectionMode,
|
|
161
164
|
config: nextValues,
|
|
165
|
+
...(localOnly ? { localOnly: true } : {}),
|
|
162
166
|
};
|
|
163
167
|
})()
|
|
164
168
|
: instance,
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The logo a broker is listed with on the desktop and the web: the icon of the
|
|
3
|
+
* plugin that registered it (its gloom.json `icon`), else the app's own for a
|
|
4
|
+
* broker Gloom connects for you (a signed-in broker, which no plugin owns),
|
|
5
|
+
* else none, and the list draws the broker's initial instead (LogoMark).
|
|
6
|
+
*/
|
|
7
|
+
import type { BrokerAdapter } from "../types/broker";
|
|
8
|
+
import type { BrokerInstanceConfig } from "../types/config";
|
|
9
|
+
import type { Portfolio } from "../types/ticker";
|
|
10
|
+
import type { BrokerDirectoryEntry } from "./directory";
|
|
11
|
+
|
|
12
|
+
function svg(markup: string): string {
|
|
13
|
+
return `data:image/svg+xml,${encodeURIComponent(markup)}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The marks the official plugins ship as their icon, for the same brokers
|
|
18
|
+
* when Gloom connects them, keyed by the backend's broker id.
|
|
19
|
+
*/
|
|
20
|
+
const SIGNED_IN_BROKER_LOGOS: Readonly<Record<string, string>> = {
|
|
21
|
+
ibkr: svg('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><linearGradient id="t" x1="0" y1="0" x2="0" y2="64" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#262626"/><stop offset="1" stop-color="#0F0F0F"/></linearGradient><linearGradient id="m" gradientUnits="userSpaceOnUse" x1="3633.335" y1="66.0445" x2="3671.0737" y2="66.0445" gradientTransform="matrix(-1 0 0 1 3673.7529 0)"><stop offset="0" stop-color="#D71F27"/><stop offset="1" stop-color="#971B1E"/></linearGradient></defs><rect width="64" height="64" fill="url(#t)"/><g transform="translate(20.4 8.2) scale(0.539)"><polygon points="40.4,86.8 2.7,86.8 2.7,45.3" fill="url(#m)"/><polygon points="40.4,1.5 2.7,45.3 2.7,86.8" fill="#D71F27"/><circle cx="35.2" cy="55.5" r="11.3" fill="#D71F27"/></g></svg>'),
|
|
22
|
+
robinhood: svg('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" fill="#CCFF00"/><path transform="translate(14 14) scale(1.5)" d="M2.84 24h.53c.096 0 .192-.048.224-.128C7.591 13.696 11.94 8.656 14.67 5.638c.112-.128.064-.225-.096-.225h-4.88a.55.55 0 0 0-.45.225L5.746 9.972c-.514.642-.642 1.236-.642 2.086v4.43c-1.14 3.194-1.862 5.361-2.392 7.32-.032.125.016.192.129.192M20.447.646c-.754-.802-4.157-.834-5.73-.224a3 3 0 0 0-.786.465 41 41 0 0 0-3.323 3.178c-.112.113-.064.225.097.225h5.409c.497 0 .786.289.786.786v6.1c0 .16.128.208.225.064l3.258-4.254c.53-.69.69-.898.835-1.861.192-1.413.08-3.58-.77-4.479m-6.982 16.18 2.231-3.676a.7.7 0 0 0 .064-.29V6.73c0-.16-.112-.225-.224-.097-3.355 3.74-5.971 7.672-8.395 12.407-.06.12.016.225.16.177l5.009-1.54c.565-.174.882-.402 1.155-.852" fill="#1A1A1A"/></svg>'),
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/** The plugin icon of a broker adapter (`getBrokerLogo` on the plugin runtime). */
|
|
26
|
+
export type BrokerPluginLogo = (brokerType: string) => string | null;
|
|
27
|
+
|
|
28
|
+
function logoFor(brokerKey: string, pluginIcon: string | null): string | null {
|
|
29
|
+
return pluginIcon ?? SIGNED_IN_BROKER_LOGOS[brokerKey] ?? null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** A broker in Add Broker's list: the icon of the plugin that connects it on this device, else Gloom's own. */
|
|
33
|
+
export function brokerDirectoryLogo(entry: BrokerDirectoryEntry, pluginLogo: BrokerPluginLogo): string | null {
|
|
34
|
+
const device = entry.methods.find((method) => method.kind === "device");
|
|
35
|
+
return logoFor(entry.key, device ? pluginLogo(device.adapter.id) : null);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** A broker profile: its adapter's plugin icon, or the logo of the broker a signed-in profile connects. */
|
|
39
|
+
export function brokerProfileLogo(
|
|
40
|
+
instance: BrokerInstanceConfig,
|
|
41
|
+
adapter: BrokerAdapter | null,
|
|
42
|
+
pluginLogo: BrokerPluginLogo,
|
|
43
|
+
): string | null {
|
|
44
|
+
const brokerKey = adapter?.portfolioBrokerId?.(instance) || instance.brokerType;
|
|
45
|
+
return logoFor(brokerKey, pluginLogo(instance.brokerType));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The broker a portfolio's account is at, for its tab: the logo and the name
|
|
50
|
+
* its initial stands in for. Null for a portfolio no broker fills.
|
|
51
|
+
*/
|
|
52
|
+
export function brokerPortfolioLogo(
|
|
53
|
+
portfolio: Pick<Portfolio, "brokerId" | "brokerInstanceId">,
|
|
54
|
+
instances: readonly BrokerInstanceConfig[],
|
|
55
|
+
getAdapter: (brokerType: string) => BrokerAdapter | null,
|
|
56
|
+
pluginLogo: BrokerPluginLogo,
|
|
57
|
+
): { src: string | null; name: string } | null {
|
|
58
|
+
if (!portfolio.brokerInstanceId) return null;
|
|
59
|
+
const instance = instances.find((candidate) => candidate.id === portfolio.brokerInstanceId);
|
|
60
|
+
if (!instance) {
|
|
61
|
+
return portfolio.brokerId ? { src: logoFor(portfolio.brokerId, null), name: portfolio.brokerId } : null;
|
|
62
|
+
}
|
|
63
|
+
const adapter = getAdapter(instance.brokerType);
|
|
64
|
+
const name = adapter?.describeInstance?.(instance).brokerName ?? adapter?.name ?? instance.label;
|
|
65
|
+
return { src: brokerProfileLogo(instance, adapter, pluginLogo), name };
|
|
66
|
+
}
|
|
@@ -6,6 +6,8 @@ import { t, tf } from "../i18n";
|
|
|
6
6
|
export interface BrokerProfileDraft {
|
|
7
7
|
label: string;
|
|
8
8
|
enabled: boolean;
|
|
9
|
+
/** Keep the connection's data on this device, out of Gloom Cloud sync. */
|
|
10
|
+
localOnly: boolean;
|
|
9
11
|
values: Record<string, string>;
|
|
10
12
|
}
|
|
11
13
|
|
|
@@ -47,6 +49,7 @@ export function createBrokerProfileDraft(
|
|
|
47
49
|
return {
|
|
48
50
|
label: instance?.label || adapter.name,
|
|
49
51
|
enabled: instance?.enabled !== false,
|
|
52
|
+
localOnly: instance?.localOnly === true,
|
|
50
53
|
values: flattenBrokerConfigValues(adapter, instance),
|
|
51
54
|
};
|
|
52
55
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { TimeRange } from "../time-series/range";
|
|
2
2
|
import type { ManualChartResolution } from "../time-series/resolution";
|
|
3
|
-
import type { BrokerAdapter, BrokerConnectionStatus } from "../types/broker";
|
|
3
|
+
import type { BrokerAdapter, BrokerConnectionStatus, BrokerHistoryOptions, BrokerOrderListener } from "../types/broker";
|
|
4
4
|
import type { BrokerInstanceConfig } from "../types/config";
|
|
5
5
|
import type { QuoteSubscriptionTarget } from "../types/data-provider";
|
|
6
6
|
import type { BrokerContractRef } from "../types/instrument";
|
|
@@ -15,6 +15,7 @@ export interface BrokerRemoteClient {
|
|
|
15
15
|
targets: QuoteSubscriptionTarget[],
|
|
16
16
|
onQuote: (target: QuoteSubscriptionTarget, quote: any) => void,
|
|
17
17
|
): () => void;
|
|
18
|
+
subscribeOrders(instanceId: string, listener: BrokerOrderListener): () => void;
|
|
18
19
|
removeInstance(instanceId: string): Promise<void>;
|
|
19
20
|
destroyAll(): Promise<void>;
|
|
20
21
|
}
|
|
@@ -73,7 +74,8 @@ export function createRemoteBrokerAdapter(adapter: BrokerAdapter): BrokerAdapter
|
|
|
73
74
|
bufferRange: TimeRange,
|
|
74
75
|
resolution: ManualChartResolution,
|
|
75
76
|
instrument?: BrokerContractRef | null,
|
|
76
|
-
|
|
77
|
+
options?: BrokerHistoryOptions,
|
|
78
|
+
) => invoke(instance, "getPriceHistoryForResolution", [ticker, exchange, bufferRange, resolution, instrument, ...(options ? [options] : [])]),
|
|
77
79
|
getDetailedPriceHistory: (
|
|
78
80
|
ticker,
|
|
79
81
|
instance,
|
|
@@ -82,7 +84,8 @@ export function createRemoteBrokerAdapter(adapter: BrokerAdapter): BrokerAdapter
|
|
|
82
84
|
endDate: Date,
|
|
83
85
|
barSize: string,
|
|
84
86
|
instrument?: BrokerContractRef | null,
|
|
85
|
-
|
|
87
|
+
options?: BrokerHistoryOptions,
|
|
88
|
+
) => invoke(instance, "getDetailedPriceHistory", [ticker, exchange, startDate, endDate, barSize, instrument, ...(options ? [options] : [])]),
|
|
86
89
|
getChartResolutionSupport: (ticker, instance, exchange?: string, instrument?: BrokerContractRef | null) =>
|
|
87
90
|
invoke(instance, "getChartResolutionSupport", [ticker, exchange, instrument]),
|
|
88
91
|
getChartResolutionCapabilities: (ticker, instance, exchange?: string, instrument?: BrokerContractRef | null) =>
|
|
@@ -95,7 +98,14 @@ export function createRemoteBrokerAdapter(adapter: BrokerAdapter): BrokerAdapter
|
|
|
95
98
|
subscribeQuotes: adapter.subscribeQuotes
|
|
96
99
|
? (instance, targets, onQuote) => getBrokerRemoteClient()?.subscribeQuotes(instance.id, targets, onQuote) ?? (() => {})
|
|
97
100
|
: undefined,
|
|
101
|
+
subscribeOrders: adapter.subscribeOrders
|
|
102
|
+
? (instance, listener) => getBrokerRemoteClient()?.subscribeOrders(instance.id, listener) ?? (() => {})
|
|
103
|
+
: undefined,
|
|
98
104
|
listOpenOrders: (instance) => invoke(instance, "listOpenOrders"),
|
|
105
|
+
// The view's own adapter has no session: a ticket confirming an order must ask the one that placed it.
|
|
106
|
+
getOrderStatus: adapter.getOrderStatus
|
|
107
|
+
? (instance, orderId: number) => invoke(instance, "getOrderStatus", [orderId])
|
|
108
|
+
: undefined,
|
|
99
109
|
listExecutions: (instance) => invoke(instance, "listExecutions"),
|
|
100
110
|
previewOrder: (instance, request: BrokerOrderRequest) => invoke(instance, "previewOrder", [request]),
|
|
101
111
|
placeOrder: (instance, request: BrokerOrderRequest) => invoke(instance, "placeOrder", [request]),
|
|
@@ -25,7 +25,7 @@ export {
|
|
|
25
25
|
AI_RUNNER_CAPABILITY_ID, BROKER_CAPABILITY_ID, NOTES_FILES_CAPABILITY_ID,
|
|
26
26
|
} from "./service-capabilities";
|
|
27
27
|
export type {
|
|
28
|
-
AiAuthProgressEvent, AiRunnerAgentMessage, AiRunnerEvent, BrokerQuoteEvent, BrokerRemoteEvent,
|
|
28
|
+
AiAuthProgressEvent, AiRunnerAgentMessage, AiRunnerEvent, BrokerOrderEvent, BrokerQuoteEvent, BrokerRemoteEvent,
|
|
29
29
|
BrokerStatusEvent,
|
|
30
30
|
} from "./service-capabilities";
|
|
31
31
|
export {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { BrokerConnectionStatus } from "../types/broker";
|
|
2
2
|
import type { QuoteSubscriptionTarget } from "../types/data-provider";
|
|
3
3
|
import type { Quote } from "../types/financials";
|
|
4
|
+
import type { BrokerOrder } from "../types/trading";
|
|
4
5
|
|
|
5
6
|
export const BROKER_CAPABILITY_ID = "broker.core";
|
|
6
7
|
export const NOTES_FILES_CAPABILITY_ID = "notes.files";
|
|
@@ -18,7 +19,12 @@ export type BrokerQuoteEvent = {
|
|
|
18
19
|
quote: Quote;
|
|
19
20
|
};
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
/** An order change, or the order stream going live or quiet, from `BrokerAdapter.subscribeOrders`. */
|
|
23
|
+
export type BrokerOrderEvent =
|
|
24
|
+
| { kind: "order"; order: BrokerOrder }
|
|
25
|
+
| { kind: "orders-live"; live: boolean };
|
|
26
|
+
|
|
27
|
+
export type BrokerRemoteEvent = BrokerStatusEvent | BrokerQuoteEvent | BrokerOrderEvent;
|
|
22
28
|
|
|
23
29
|
/**
|
|
24
30
|
* What an AI runtime reports while it signs an account in.
|
|
@@ -2,34 +2,76 @@ import type { DataProvider } from "../types/data-provider";
|
|
|
2
2
|
import { fixedUsdRate } from "../utils/currency-units";
|
|
3
3
|
import { logFailure } from "../utils/log-failure";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/** One rate a converter used: units of `baseCurrency` per unit of `currency`, and when it was observed. */
|
|
6
|
+
export interface BaseConversion {
|
|
7
|
+
currency: string;
|
|
8
|
+
baseCurrency: string;
|
|
9
|
+
rate: number;
|
|
10
|
+
/** Epoch ms of the older leg's observation; null when the source did not date it. */
|
|
11
|
+
asOf: number | null;
|
|
12
|
+
}
|
|
7
13
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
/** Converts an amount into the base currency, and lists the rates it used so a report can state them. */
|
|
15
|
+
export type BaseConverter = ((value: number, fromCurrency: string) => Promise<number>) & {
|
|
16
|
+
conversions(): BaseConversion[];
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
interface UsdRate {
|
|
20
|
+
rate: number;
|
|
21
|
+
asOf: number | null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function createBaseConverter(
|
|
25
|
+
dataProvider: Pick<DataProvider, "getExchangeRate" | "getCachedQuery" | "revalidatesInBackground">,
|
|
26
|
+
baseCurrency: string,
|
|
27
|
+
): BaseConverter {
|
|
28
|
+
const rateCache = new Map<string, Promise<UsdRate>>();
|
|
29
|
+
const used = new Map<string, BaseConversion>();
|
|
30
|
+
|
|
31
|
+
/** USD per unit, dated when the cached query says when it was observed (as `fx` dates it). */
|
|
32
|
+
const loadRate = async (currency: string): Promise<UsdRate> => {
|
|
33
|
+
const fixed = fixedUsdRate(currency);
|
|
34
|
+
if (fixed != null) return { rate: fixed, asOf: null };
|
|
12
35
|
try {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
36
|
+
if (dataProvider.getCachedQuery) {
|
|
37
|
+
const entry = await dataProvider.getCachedQuery("getExchangeRate", [currency])
|
|
38
|
+
.load({ background: dataProvider.revalidatesInBackground });
|
|
39
|
+
return { rate: Number.isFinite(entry.value) && entry.value > 0 ? entry.value : Number.NaN, asOf: entry.asOf ?? null };
|
|
40
|
+
}
|
|
41
|
+
const rate = await dataProvider.getExchangeRate(currency);
|
|
42
|
+
return { rate: Number.isFinite(rate) && rate > 0 ? rate : Number.NaN, asOf: null };
|
|
17
43
|
} catch (error) {
|
|
18
44
|
logFailure("cli-base-converter", "Could not load base conversion exchange rate")(error);
|
|
19
|
-
return Number.NaN;
|
|
45
|
+
return { rate: Number.NaN, asOf: null };
|
|
20
46
|
}
|
|
21
47
|
};
|
|
22
48
|
|
|
23
|
-
|
|
49
|
+
const getRate = (currency: string): Promise<UsdRate> => {
|
|
50
|
+
const normalizedCurrency = currency.toUpperCase();
|
|
51
|
+
let pending = rateCache.get(normalizedCurrency);
|
|
52
|
+
if (!pending) {
|
|
53
|
+
pending = loadRate(normalizedCurrency);
|
|
54
|
+
rateCache.set(normalizedCurrency, pending);
|
|
55
|
+
}
|
|
56
|
+
return pending;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const convert = async (value: number, fromCurrency: string): Promise<number> => {
|
|
24
60
|
const normalizedFrom = fromCurrency.toUpperCase();
|
|
25
61
|
const normalizedBase = baseCurrency.toUpperCase();
|
|
26
62
|
if (normalizedFrom === normalizedBase) return value;
|
|
27
63
|
|
|
28
|
-
const [
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
64
|
+
const [from, base] = await Promise.all([getRate(normalizedFrom), getRate(normalizedBase)]);
|
|
65
|
+
if (!Number.isFinite(from.rate) || !Number.isFinite(base.rate) || base.rate <= 0) return Number.NaN;
|
|
66
|
+
const dates = [from.asOf, base.asOf].filter((time): time is number => time != null);
|
|
67
|
+
used.set(normalizedFrom, {
|
|
68
|
+
currency: normalizedFrom,
|
|
69
|
+
baseCurrency: normalizedBase,
|
|
70
|
+
rate: from.rate / base.rate,
|
|
71
|
+
asOf: dates.length > 0 ? Math.min(...dates) : null,
|
|
72
|
+
});
|
|
73
|
+
return (value * from.rate) / base.rate;
|
|
34
74
|
};
|
|
75
|
+
|
|
76
|
+
return Object.assign(convert, { conversions: () => [...used.values()] });
|
|
35
77
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { seriesMoves, type MoveHorizon } from "../../plugins/builtin/shared/move-rank";
|
|
2
|
+
import { seriesNotOnFred } from "../../sources/gloomberb-cloud/fred-series";
|
|
2
3
|
import { ICE_SPREAD_SERIES } from "../../time-series/ice-credit";
|
|
3
4
|
import { toBasisPoints } from "../../utils/basis-points";
|
|
4
5
|
import { parseReportTime } from "../../utils/utc-time";
|
|
@@ -138,7 +139,10 @@ export interface FredProvenance {
|
|
|
138
139
|
* looking for the figure in FRED's own data knows it is not there yet:
|
|
139
140
|
* `U.S. Treasury via FRED, published 2026-10-09`. Null for FRED's own.
|
|
140
141
|
*/
|
|
141
|
-
export function fredProvenance(
|
|
142
|
+
export function fredProvenance(
|
|
143
|
+
observations: ReadonlyArray<{ date: string; publisher?: string; publishedAt?: string }>,
|
|
144
|
+
seriesId?: string,
|
|
145
|
+
): FredProvenance | null {
|
|
142
146
|
const ahead = observations.filter((observation) => observation.publisher?.trim());
|
|
143
147
|
if (ahead.length === 0) return null;
|
|
144
148
|
const publishers = [...new Set(ahead.map((observation) => observation.publisher!.trim()))];
|
|
@@ -149,7 +153,8 @@ export function fredProvenance(observations: ReadonlyArray<{ date: string; publi
|
|
|
149
153
|
const publishedAt = times.at(-1);
|
|
150
154
|
const publisher = publishers.join(" and ");
|
|
151
155
|
return {
|
|
152
|
-
|
|
156
|
+
// A series FRED does not carry names whose publication it is read from instead (TurkStat via the CBRT).
|
|
157
|
+
source: `${publisher} via ${(seriesId ? seriesNotOnFred(seriesId)?.via : null) ?? "FRED"}${publishedAt ? `, published ${publishedAt.slice(0, 10)}` : ""}`,
|
|
153
158
|
publisher,
|
|
154
159
|
...(publishedAt ? { publishedAt } : {}),
|
|
155
160
|
};
|
|
@@ -275,6 +280,11 @@ export interface FredListRow {
|
|
|
275
280
|
group: string;
|
|
276
281
|
}
|
|
277
282
|
|
|
283
|
+
/** Lower case without accents, so `turk` and `turkiye` find Türkiye. */
|
|
284
|
+
function foldAccents(text: string): string {
|
|
285
|
+
return text.normalize("NFD").replace(/\p{M}/gu, "").toLowerCase();
|
|
286
|
+
}
|
|
287
|
+
|
|
278
288
|
/** How well a word of the filter matches a series, best first: its id or group name, a word of its group or title, the start of its id, then any text. */
|
|
279
289
|
function matchTier(term: string, row: FredListRow, words: readonly string[]): number {
|
|
280
290
|
if (row.id.toLowerCase() === term || row.group.toLowerCase() === term) return 0;
|
|
@@ -290,11 +300,11 @@ function matchTier(term: string, row: FredListRow, words: readonly string[]): nu
|
|
|
290
300
|
* Catalog order breaks ties; an empty filter keeps the catalog as it is.
|
|
291
301
|
*/
|
|
292
302
|
export function filterFredSeries(rows: readonly FredListRow[], filter: string): FredListRow[] {
|
|
293
|
-
const terms = filter
|
|
303
|
+
const terms = foldAccents(filter).split(/\s+/).filter(Boolean);
|
|
294
304
|
const ranked = rows.flatMap((row, index) => {
|
|
295
|
-
const text = `${row.id} ${row.title} ${row.group}
|
|
305
|
+
const text = foldAccents(`${row.id} ${row.title} ${row.group}`);
|
|
296
306
|
if (!terms.every((term) => text.includes(term))) return [];
|
|
297
|
-
const words = `${row.title} ${row.group}
|
|
307
|
+
const words = foldAccents(`${row.title} ${row.group}`).split(/[^a-z0-9]+/).filter(Boolean);
|
|
298
308
|
const tiers = terms.map((term) => matchTier(term, row, words));
|
|
299
309
|
return [{ row, index, worst: Math.max(0, ...tiers), total: tiers.reduce((sum, tier) => sum + tier, 0) }];
|
|
300
310
|
});
|