gloomberb 0.18.1 → 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/types.ts +5 -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/market.ts +281 -154
- package/src/cli/commands/news-search.ts +35 -8
- package/src/cli/commands/system.ts +35 -1
- package/src/cli/commands/ticker.ts +100 -50
- 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 +27 -3
- 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/types.ts +4 -0
- package/src/components/chart/composite/composite-chart.tsx +11 -2
- 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 +58 -8
- package/src/components/command-bar/routes/ticker-search/actions.ts +6 -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/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 +5 -5
- 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/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/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/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 +35 -0
- 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/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-valuation/pane.tsx +2 -1
- package/src/plugins/builtin/members/pane.tsx +8 -3
- package/src/plugins/builtin/news/wire/feed-config.ts +29 -12
- package/src/plugins/builtin/news/wire/index.tsx +7 -2
- package/src/plugins/builtin/news/wire/news/preset-pane.tsx +11 -3
- package/src/plugins/builtin/news/wire/rss/cli.ts +3 -2
- package/src/plugins/builtin/news/wire/rss/source.ts +13 -4
- 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/render.ts +34 -10
- package/src/plugins/builtin/portfolio-list/headless.ts +1 -1
- package/src/plugins/builtin/portfolio-list/pane/data.ts +23 -1
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +33 -14
- package/src/plugins/builtin/portfolio-list/settings.ts +20 -2
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +12 -0
- 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/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-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/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 +5 -28
- 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/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 +62 -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/tickers/listing-fate.ts +27 -8
- 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/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 +32 -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/src/cli/glossary.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { cliStyles, cliTerminalWidth, renderDefinitions, renderSection, wrapText
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Plain-words meanings of the rates, auction, credit and bond yield, energy, perpetual-futures, portfolio,
|
|
5
|
-
* fund, bond fund (SEC yield, tax-equivalent yield, muni/Treasury ratio), short interest, quote-board, futures (basis, contango, roll yield), VIX curve (term structure, 3M/30D, VVIX) and economic-calendar terms the functions
|
|
5
|
+
* fund, bond fund (SEC yield, tax-equivalent yield, muni/Treasury ratio), short interest, quote-board, futures (basis, contango, roll yield), VIX curve (term structure, 3M/30D, VVIX), CFTC positioning (COT trader classes, net % of open interest) and economic-calendar terms the functions
|
|
6
6
|
* show in their rows, headers and footers.
|
|
7
7
|
* `catalog glossary` lists them, `catalog explain <term>` prints one, and
|
|
8
8
|
* `fn <function> --explain` and `portfolio show --explain` follow a report with
|
|
@@ -242,7 +242,7 @@ export const GLOSSARY: readonly GlossaryEntry[] = [
|
|
|
242
242
|
definition: "The first date the new rate level appears in the data, not necessarily the announcement or effective date.",
|
|
243
243
|
},
|
|
244
244
|
{
|
|
245
|
-
term: "Pctl 1Y", aliases: ["percentile", "1y percentile", "pctl"], functions: ["BTMM", "WIRP", "CBR", "CDX", "SOVR"],
|
|
245
|
+
term: "Pctl 1Y", aliases: ["percentile", "1y percentile", "1-year percentile", "pctl"], functions: ["BTMM", "WIRP", "CBR", "CDX", "SOVR", "COT"],
|
|
246
246
|
definition: "Where today's value ranks against the past year of the same series: 100 is the highest, 0 the lowest.",
|
|
247
247
|
},
|
|
248
248
|
{
|
|
@@ -360,8 +360,8 @@ export const GLOSSARY: readonly GlossaryEntry[] = [
|
|
|
360
360
|
+ "a simple annualisation of the rate now, not funding actually paid.",
|
|
361
361
|
},
|
|
362
362
|
{
|
|
363
|
-
term: "Open interest", short: "OI", aliases: ["open interest usd"], functions: ["PERP"],
|
|
364
|
-
definition: "The
|
|
363
|
+
term: "Open interest", short: "OI", aliases: ["open interest usd"], functions: ["PERP", "COT"],
|
|
364
|
+
definition: "The contracts that are open and not yet closed, counting each buyer and seller pair once: COT counts them, PERP gives their value, usually in dollars. "
|
|
365
365
|
+ "It rises as new positions open and falls as they close.",
|
|
366
366
|
},
|
|
367
367
|
{
|
|
@@ -631,6 +631,59 @@ export const GLOSSARY: readonly GlossaryEntry[] = [
|
|
|
631
631
|
definition: "A futures contract's official price for the day, set by its exchange from trading near the close. "
|
|
632
632
|
+ "The day's change and margin are measured from it, and it can differ from the last trade. FUT's PREV is the previous one.",
|
|
633
633
|
},
|
|
634
|
+
// CFTC positioning (COT): the legacy report's trader classes, then the disaggregated report's.
|
|
635
|
+
{
|
|
636
|
+
term: "Commitments of Traders", short: "COT", aliases: ["cot report", "commitment of traders", "cftc", "cftc report", "cftc positioning", "positioning"],
|
|
637
|
+
functions: ["COT"], shown: ["CFTC", "COT"],
|
|
638
|
+
definition: "The CFTC's weekly count of who holds each US futures market: open contracts split by type of trader, as of Tuesday and published that Friday. "
|
|
639
|
+
+ "It shows whether speculators or hedgers are net long or short, and how that moved since the week before.",
|
|
640
|
+
},
|
|
641
|
+
{
|
|
642
|
+
term: "Noncommercial", aliases: ["non-commercial", "noncommercials", "large speculators", "speculators", "large specs"], functions: ["COT"],
|
|
643
|
+
definition: "Large traders who do not hedge a business with the contract, such as funds and other speculators. "
|
|
644
|
+
+ "Their net position is the one most often read as the market's bet.",
|
|
645
|
+
},
|
|
646
|
+
{
|
|
647
|
+
term: "Commercial", aliases: ["commercials", "hedgers", "commercial hedgers"], functions: ["COT"],
|
|
648
|
+
definition: "Large traders who use the contract to hedge a business: producers, processors, merchants and dealers. "
|
|
649
|
+
+ "In a commodity they are usually net short, selling ahead what they will grow, mine or deliver.",
|
|
650
|
+
},
|
|
651
|
+
{
|
|
652
|
+
term: "Nonreportable", aliases: ["non-reportable", "nonreportables", "small traders", "small speculators"], functions: ["COT"],
|
|
653
|
+
definition: "Traders too small to report their positions to the CFTC, counted as open interest less every reported position. Mostly smaller speculators.",
|
|
654
|
+
},
|
|
655
|
+
{
|
|
656
|
+
term: "Net position", short: "Net", aliases: ["net long", "net short", "net positioning", "net spec"], functions: ["COT"], shown: ["Net"],
|
|
657
|
+
definition: "A group's long contracts less its short ones: positive is net long, negative net short.",
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
term: "Net % of open interest", short: "Net % OI", aliases: ["% of open interest", "percent of open interest", "net percent of open interest"], functions: ["COT"],
|
|
661
|
+
definition: "A group's net position as a share of all open contracts, so markets of different sizes compare: +8.3% means its longs exceed its shorts by 8.3% of open interest.",
|
|
662
|
+
},
|
|
663
|
+
{
|
|
664
|
+
term: "Weekly change", short: "1W Δ", aliases: ["1w change", "week change", "weekly net change"], functions: ["COT"],
|
|
665
|
+
definition: "How far a group's net position moved since the previous weekly report, in contracts.",
|
|
666
|
+
},
|
|
667
|
+
{
|
|
668
|
+
term: "Pctl 3Y", aliases: ["3y percentile", "3-year percentile", "three-year percentile"], functions: ["COT"],
|
|
669
|
+
definition: "Where this week's net position ranks against the past three years of weekly reports: 100 is the most net long it has been, 0 the most net short.",
|
|
670
|
+
},
|
|
671
|
+
{
|
|
672
|
+
term: "Managed money", aliases: ["money managers", "managed money traders", "hedge funds", "ctas"], functions: ["COT"], shown: ["Managed Money"],
|
|
673
|
+
definition: "The disaggregated report's funds that trade futures for clients, such as hedge funds and CTAs: the speculators most often watched.",
|
|
674
|
+
},
|
|
675
|
+
{
|
|
676
|
+
term: "Producer/merchant", aliases: ["producers", "merchants", "producer merchant", "processors"], functions: ["COT"], shown: ["Producer/Merchant"],
|
|
677
|
+
definition: "The disaggregated report's growers, miners, processors and merchants that hedge the physical commodity they produce or handle.",
|
|
678
|
+
},
|
|
679
|
+
{
|
|
680
|
+
term: "Swap dealers", aliases: ["swap dealer", "swaps dealers"], functions: ["COT"], shown: ["Swap Dealers"],
|
|
681
|
+
definition: "The disaggregated report's banks and dealers that hedge the commodity swaps they sell to clients, often index investors.",
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
term: "Other reportables", aliases: ["other reportable", "other reportable traders"], functions: ["COT"], shown: ["Other Reportables"],
|
|
685
|
+
definition: "The disaggregated report's large traders that fit none of its other classes, such as proprietary traders and family offices.",
|
|
686
|
+
},
|
|
634
687
|
// Futures basis and curve shape (CTM, FUT, PERP).
|
|
635
688
|
{
|
|
636
689
|
term: "Futures basis", aliases: ["basis", "basis trade", "cash and carry", "cash-and-carry", "vs spot", "spot spread"],
|
package/src/cli/helpers.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
formatCompact,
|
|
3
3
|
formatCurrency,
|
|
4
|
+
formatCurrencyCode,
|
|
4
5
|
formatNumber,
|
|
5
6
|
formatPercentRaw,
|
|
6
7
|
} from "../utils/format";
|
|
7
|
-
import { formatMarketPriceWithCurrency, type MarketFormatOptions } from "../market-data/market/format";
|
|
8
|
+
import { formatMarketChangeWithCurrency, formatMarketPriceWithCurrency, type MarketFormatOptions } from "../market-data/market/format";
|
|
9
|
+
import { changeBasisLabel, changeBasisNote, quoteChangeBasis } from "../market-data/market/change-basis";
|
|
10
|
+
import type { FuturesContractTermsPayload } from "../api-client/futures-curve";
|
|
11
|
+
import type { ActiveQuoteDisplay } from "../market-data/market/status";
|
|
12
|
+
import type { Quote } from "../types/financials";
|
|
8
13
|
import { cliStyles, colorBySign } from "../utils/cli-output";
|
|
9
14
|
import type { AppConfig } from "../types/config";
|
|
10
15
|
import type { Watchlist, TickerRecord } from "../types/ticker";
|
|
@@ -12,8 +17,36 @@ import { isFiniteNumber } from "../utils/guards";
|
|
|
12
17
|
import { formatUtcTime } from "../utils/utc-time";
|
|
13
18
|
import { findNamedCollection } from "../portfolio/collection-name";
|
|
14
19
|
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
/** A signed amount with its sign ($), or with `code` its code (+12.50 CAD) as a report for another base currency writes it. */
|
|
21
|
+
export function formatSignedCurrency(value: number, currency: string, code = false): string {
|
|
22
|
+
const text = (code ? formatCurrencyCode : formatCurrency)(value, currency);
|
|
23
|
+
return value > 0 ? `+${text}` : text;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The Change line of `ticker` and of `quote`'s futures block: the regular
|
|
28
|
+
* session's move and its percent, colored by sign, and what the move is
|
|
29
|
+
* measured from, "-HK$0.10 (-1.05%) vs Fri 16 Oct close" (a future's from
|
|
30
|
+
* its terms, "vs Fri 16 Oct settle"), with the venue's holidays since that
|
|
31
|
+
* close on the line under it ("HKEX closed Mon 19 Oct, holiday").
|
|
32
|
+
*/
|
|
33
|
+
export function quoteChangeText(
|
|
34
|
+
quote: Quote,
|
|
35
|
+
session: Pick<ActiveQuoteDisplay, "price" | "change" | "changePercent">,
|
|
36
|
+
options: MarketFormatOptions,
|
|
37
|
+
terms?: Pick<FuturesContractTermsPayload, "settlement" | "spec"> | null,
|
|
38
|
+
now = Date.now(),
|
|
39
|
+
): string {
|
|
40
|
+
// A listing that no longer trades: its last close moves no more.
|
|
41
|
+
if (quote.delisting) return "—";
|
|
42
|
+
const move = colorBySign(
|
|
43
|
+
`${formatMarketChangeWithCurrency(session.change, quote.currency ?? "USD", options, session.price)} (${formatPercentRaw(session.changePercent)})`,
|
|
44
|
+
session.change,
|
|
45
|
+
);
|
|
46
|
+
const basis = quoteChangeBasis(quote, { terms });
|
|
47
|
+
if (!basis) return move;
|
|
48
|
+
const note = changeBasisNote(basis, now);
|
|
49
|
+
return `${move} ${cliStyles.muted(changeBasisLabel(basis, now))}${note ? `\n${cliStyles.muted(note)}` : ""}`;
|
|
17
50
|
}
|
|
18
51
|
|
|
19
52
|
// Text-table cell formats. They leave missing values blank; CSV and JSON keep the raw numbers.
|
package/src/cli/index.ts
CHANGED
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
runPaneScreenshot,
|
|
48
48
|
} from "./pane-functions";
|
|
49
49
|
import { catalogPointer, tickerPointer, type CatalogCommandHit } from "./unknown-command";
|
|
50
|
+
import { exportCommandPointer } from "./known-gaps";
|
|
50
51
|
import { catalogFredSeriesIds } from "./series-search";
|
|
51
52
|
import { primeBoardCoins } from "./board-coins";
|
|
52
53
|
|
|
@@ -382,7 +383,9 @@ function failUnknownCommand(token: string, commands: CliCommandDef[], pointers:
|
|
|
382
383
|
[`Run: ${pointers.nearFn.command}`, ticker].filter(Boolean).join("\n"),
|
|
383
384
|
);
|
|
384
385
|
}
|
|
385
|
-
|
|
386
|
+
// Exporting is a flag, not a command: `export LMT` says how, rather than listing functions that mention exports.
|
|
387
|
+
const exported = suggestion ? null : exportCommandPointer(token, pointers.args);
|
|
388
|
+
const catalog = suggestion ? null : exported ?? catalogPointer(token, pointers.hits, pointers.args);
|
|
386
389
|
const help = suggestion
|
|
387
390
|
? `Did you mean ${suggestion}? Run gloomberb help to see every command.`
|
|
388
391
|
: catalog ? `${catalog}\nRun gloomberb help to see every command.` : "Run gloomberb help to see every command.";
|
package/src/cli/known-gaps.ts
CHANGED
|
@@ -109,6 +109,23 @@ const BANK_FIGURES_TOPIC = {
|
|
|
109
109
|
closest: [["EQS", "NIM%, Pro: gloomberb fn EQS --metric kpiNimPercent"]],
|
|
110
110
|
} as const;
|
|
111
111
|
|
|
112
|
+
/**
|
|
113
|
+
* How to export: a flag on every command, which `export LMT`, `catalog export` and `catalog csv` look for as a
|
|
114
|
+
* command or a function. One example, writing a file.
|
|
115
|
+
*/
|
|
116
|
+
function exportLine(symbol = "LMT"): string {
|
|
117
|
+
return `Export: add --csv or --json to any command to print its result as CSV or JSON, e.g. gloomberb history ${symbol} --csv > ${
|
|
118
|
+
symbol.toLowerCase().replace(/[^a-z0-9]+/g, "-")}.csv`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const EXPORT_POINTER = {
|
|
122
|
+
names: ["export", "exporting", "csv", "json", "excel", "spreadsheet", "xlsx"],
|
|
123
|
+
words: ["data", "to", "as", "a", "an", "the", "in", "into", "file", "files", "table", "tables", "result", "results", "output",
|
|
124
|
+
"format", "save", "how", "can", "i", "my", "report", "reports", "command", "commands"],
|
|
125
|
+
line: exportLine(),
|
|
126
|
+
leads: true,
|
|
127
|
+
} as const;
|
|
128
|
+
|
|
112
129
|
/** "bank", "bank figures": beside the functions a bank's name finds (CBR), where its figures are. */
|
|
113
130
|
const BANK_FIGURES_POINTER = {
|
|
114
131
|
names: ["bank", "banks", "banking"],
|
|
@@ -193,8 +210,9 @@ export function topicPointer(query: string): { message: string; codes: string[]
|
|
|
193
210
|
* "dark pool"; "drip", "dividend income", but not "income statement" or "net income"; "tether", "depeg",
|
|
194
211
|
* "usdc peg", but not "peg ratio".
|
|
195
212
|
*/
|
|
196
|
-
const COMMAND_POINTERS: ReadonlyArray<{ names: readonly string[]; words: readonly string[]; line: string }> = [
|
|
213
|
+
const COMMAND_POINTERS: ReadonlyArray<{ names: readonly string[]; words: readonly string[]; line: string; leads?: true }> = [
|
|
197
214
|
BANK_FIGURES_POINTER,
|
|
215
|
+
EXPORT_POINTER,
|
|
198
216
|
{
|
|
199
217
|
names: ["theme", "themes", "light", "dark", "colorblind", "colourblind", "blind"],
|
|
200
218
|
words: ["mode", "color", "colour", "colors", "colours", "high", "contrast", "change", "switch", "set", "setting", "settings"],
|
|
@@ -218,6 +236,24 @@ export function commandPointer(query: string): string | null {
|
|
|
218
236
|
return findCommandPointer(query)?.line ?? null;
|
|
219
237
|
}
|
|
220
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Whether the query's command line answers it ahead of the functions its words find: "csv" is the flag, not
|
|
241
|
+
* CDS, whose description happens to mention it.
|
|
242
|
+
*/
|
|
243
|
+
export function commandPointerLeads(query: string): boolean {
|
|
244
|
+
return findCommandPointer(query)?.leads === true;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* The line for a command word typed as `gloomberb export LMT`: exporting is a flag every command takes, not a
|
|
249
|
+
* command, so the example runs on the symbol typed. Null for any other word.
|
|
250
|
+
*/
|
|
251
|
+
export function exportCommandPointer(token: string, args: readonly string[]): string | null {
|
|
252
|
+
if (findCommandPointer(token) !== EXPORT_POINTER) return null;
|
|
253
|
+
const symbol = args.find((arg) => /^\^?[A-Z0-9][A-Z0-9.=-]{0,11}(?::[A-Z0-9]{1,8})?$/.test(arg) && /[A-Z]/.test(arg));
|
|
254
|
+
return exportLine(symbol);
|
|
255
|
+
}
|
|
256
|
+
|
|
221
257
|
function findCommandPointer(query: string): (typeof COMMAND_POINTERS)[number] | null {
|
|
222
258
|
const asked = words(query);
|
|
223
259
|
if (asked.length === 0) return null;
|
package/src/cli/listing-arg.ts
CHANGED
|
@@ -42,6 +42,7 @@ import { classifyInstrumentType, kindFromListingSyntax } from "../tickers/instru
|
|
|
42
42
|
import type { InstrumentOfKind } from "../tickers/instrument-coverage";
|
|
43
43
|
import { brokerIndexCode, brokerIndexReadAs } from "./index-roots";
|
|
44
44
|
import { readTerminalListingCode, terminalCodeReadAs } from "../tickers/terminal-codes";
|
|
45
|
+
import { listingAbroadVenue } from "../utils/sec";
|
|
45
46
|
|
|
46
47
|
/** The `--exchange` option of every command that takes a ticker. */
|
|
47
48
|
export const EXCHANGE_OPTION = {
|
|
@@ -342,7 +343,7 @@ export function listingChoiceNote(
|
|
|
342
343
|
}
|
|
343
344
|
|
|
344
345
|
// Quotes of these never name a company's listing, so they are never a choice between companies.
|
|
345
|
-
const UNLISTED_TYPES = new Set(["FUTURE", "INDEX", "CURRENCY", "CRYPTOCURRENCY", "OPTION"]);
|
|
346
|
+
export const UNLISTED_TYPES = new Set(["FUTURE", "INDEX", "CURRENCY", "CRYPTOCURRENCY", "OPTION"]);
|
|
346
347
|
|
|
347
348
|
/** Whether the data service chose the listing: a bare symbol, with no venue named and none saved. */
|
|
348
349
|
function isBareListing(listing: Pick<CliListing, "exchange" | "saved">): boolean {
|
|
@@ -860,11 +861,43 @@ async function builderDexMarket(listing: ListingArg, deps: ListingDeps): Promise
|
|
|
860
861
|
: null;
|
|
861
862
|
}
|
|
862
863
|
|
|
864
|
+
/** A symbol written with a venue's suffix, as data vendors write a listing abroad: RY.TO, 7203.T, VOD.L, 0700.HK. */
|
|
865
|
+
const VENUE_SUFFIX = /^([A-Z0-9][A-Z0-9&-]*)\.([A-Z]{1,3})$/;
|
|
866
|
+
|
|
867
|
+
/**
|
|
868
|
+
* RY.TO, 7203.T, VOD.L: a listing abroad written with a data vendor's venue
|
|
869
|
+
* suffix, read as the listing its own quote names (RY:TSX, 7203:JPX,
|
|
870
|
+
* VOD:LSE), the way `quote` names it, so data that is read by venue (a
|
|
871
|
+
* company's SEC filings, data that covers US listings only) finds the same
|
|
872
|
+
* listing the quote is for. A US share class (BRK.B, quoted on NYSE), a
|
|
873
|
+
* suffix no quote answers and a named venue stay as typed.
|
|
874
|
+
*/
|
|
875
|
+
async function readVenueSuffix(listing: ListingArg, deps: Pick<ListingDeps, "dataProvider">): Promise<ListingArg | null> {
|
|
876
|
+
const match = listing.exchange ? null : VENUE_SUFFIX.exec(listing.symbol);
|
|
877
|
+
if (!match) return null;
|
|
878
|
+
let quote: Quote | null;
|
|
879
|
+
try {
|
|
880
|
+
quote = await deps.dataProvider.getQuote(listing.symbol, "");
|
|
881
|
+
} catch (error) {
|
|
882
|
+
// The command's own request then says what is wrong with the symbol.
|
|
883
|
+
if (!isNoProviderError(error)) logFailure("cli.listing-arg", "Quote venue suffix failed")(error);
|
|
884
|
+
return null;
|
|
885
|
+
}
|
|
886
|
+
const venue = canonicalExchange(quote?.listingExchangeName || quote?.exchangeName);
|
|
887
|
+
const key = `${match[1]}:${venue}`;
|
|
888
|
+
if (!venue || !isKnownExchangeCode(venue) || !listingAbroadVenue(key)) return null;
|
|
889
|
+
return { symbol: match[1]!, exchange: venue, key, readAs: `Read ${listing.symbol} as ${key}.` };
|
|
890
|
+
}
|
|
891
|
+
|
|
863
892
|
export async function resolveCliListing(
|
|
864
893
|
raw: string,
|
|
865
894
|
exchangeOption: string | null | undefined,
|
|
866
895
|
deps: ListingDeps,
|
|
867
|
-
options: {
|
|
896
|
+
options: {
|
|
897
|
+
ownExchangeWins?: boolean;
|
|
898
|
+
/** Read a venue suffix (RY.TO) as the listing its quote names (RY:TSX): `fn` and `shot`, whose functions read data by venue. */
|
|
899
|
+
venueSuffix?: boolean;
|
|
900
|
+
} = {},
|
|
868
901
|
): Promise<CliListing> {
|
|
869
902
|
// "JPM US Equity" is Bloomberg's code for JPM; "Putnam US Equity", whose root is no US ticker, is a name.
|
|
870
903
|
const typed = stripStrayEdges(raw).text || raw;
|
|
@@ -879,6 +912,8 @@ export async function resolveCliListing(
|
|
|
879
912
|
// USD-NGN and USDNGN are the pair USDNGN=X unless a security is listed under those letters.
|
|
880
913
|
const pair = parsed.exchange ? null : await readAmbiguousCurrencyPair(parsed.symbol, deps);
|
|
881
914
|
if (pair) parsed = { symbol: pair, exchange: "", key: pair };
|
|
915
|
+
const suffixed = pair || named || !options.venueSuffix ? null : await readVenueSuffix(parsed, deps);
|
|
916
|
+
if (suffixed) parsed = parsed.readAs ? { ...suffixed, readAs: `${parsed.readAs} ${suffixed.readAs}` } : suffixed;
|
|
882
917
|
try {
|
|
883
918
|
await checkListingExchange(parsed, deps);
|
|
884
919
|
} catch (error) {
|
|
@@ -694,13 +694,15 @@ export function renderPaneCatalogReport(
|
|
|
694
694
|
series: readonly SeriesMatch[] = [],
|
|
695
695
|
/** The `config` command a query names a setting of ("light theme"), printed last, beside the functions. */
|
|
696
696
|
setting: string | null = null,
|
|
697
|
+
/** The setting answers the query ahead of the functions its words find (`csv` is the flag, not CDS): printed first. */
|
|
698
|
+
settingFirst = false,
|
|
697
699
|
): string {
|
|
698
700
|
const query = args.query.trim().toLowerCase();
|
|
699
701
|
const exact = query
|
|
700
702
|
? entries.find((entry) => entry.token.toLowerCase() === query)
|
|
701
703
|
?? entries.find((entry) => entry.aliases.some((alias) => alias.toLowerCase() === query))
|
|
702
704
|
: undefined;
|
|
703
|
-
const withSetting = (text: string) => [text, setting ?? ""].filter(Boolean).join("\n\n");
|
|
705
|
+
const withSetting = (text: string) => (settingFirst ? [setting ?? "", text] : [text, setting ?? ""]).filter(Boolean).join("\n\n");
|
|
704
706
|
if (exact) return withSetting([renderCatalogEntry(exact), renderAlsoMatches(exact, entries, query)].filter(Boolean).join("\n\n"));
|
|
705
707
|
|
|
706
708
|
const width = Math.min(cliTerminalWidth() ?? CATALOG_TEXT_WIDTH, CATALOG_TEXT_WIDTH);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ConnectionHealthRegistry } from "../../core/connection-health";
|
|
2
2
|
import type { TickerRepository } from "../../data/ticker-repository";
|
|
3
3
|
import type { AppConfig } from "../../types/config";
|
|
4
|
+
import type { BrokerAdapter } from "../../types/broker";
|
|
4
5
|
import type { DataProvider } from "../../types/data-provider";
|
|
5
6
|
import type { PersistedResourceValue } from "../../types/persistence";
|
|
6
7
|
import type {
|
|
@@ -20,6 +21,7 @@ export interface PaneDiscoveryOptions {
|
|
|
20
21
|
tickerRepository?: TickerRepository;
|
|
21
22
|
panes?: Map<string, PaneDef>;
|
|
22
23
|
paneTemplates?: Map<string, PaneTemplateDef>;
|
|
24
|
+
brokers?: Map<string, BrokerAdapter>;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
/** Throws only if a plugin actually reaches for a dependency discovery has no answer for. */
|
|
@@ -43,10 +45,12 @@ export function createPaneDiscoveryContext(options: PaneDiscoveryOptions): Gloom
|
|
|
43
45
|
} {
|
|
44
46
|
const panes = options.panes ?? new Map<string, PaneDef>();
|
|
45
47
|
const paneTemplates = options.paneTemplates ?? new Map<string, PaneTemplateDef>();
|
|
48
|
+
const brokers = options.brokers ?? new Map<string, BrokerAdapter>();
|
|
46
49
|
return {
|
|
47
50
|
...buildDiscoveryContext({
|
|
48
51
|
panes,
|
|
49
52
|
paneTemplates,
|
|
53
|
+
brokers,
|
|
50
54
|
getConfig: options.getConfig,
|
|
51
55
|
marketData: options.marketData ?? unavailable<DataProvider>("Market data"),
|
|
52
56
|
tickerRepository: options.tickerRepository ?? unavailable<TickerRepository>("The ticker repository"),
|
|
@@ -60,6 +64,7 @@ export function createPaneDiscoveryContext(options: PaneDiscoveryOptions): Gloom
|
|
|
60
64
|
function buildDiscoveryContext({
|
|
61
65
|
panes,
|
|
62
66
|
paneTemplates,
|
|
67
|
+
brokers,
|
|
63
68
|
getConfig,
|
|
64
69
|
marketData,
|
|
65
70
|
tickerRepository,
|
|
@@ -67,6 +72,7 @@ function buildDiscoveryContext({
|
|
|
67
72
|
}: {
|
|
68
73
|
panes: Map<string, PaneDef>;
|
|
69
74
|
paneTemplates: Map<string, PaneTemplateDef>;
|
|
75
|
+
brokers: Map<string, BrokerAdapter>;
|
|
70
76
|
getConfig: () => AppConfig;
|
|
71
77
|
marketData: DataProvider;
|
|
72
78
|
tickerRepository: TickerRepository;
|
|
@@ -84,7 +90,8 @@ function buildDiscoveryContext({
|
|
|
84
90
|
registerCommand: () => {},
|
|
85
91
|
registerCommandBarSearchProvider: () => () => {},
|
|
86
92
|
registerColumn: () => {},
|
|
87
|
-
registerBroker: () => {},
|
|
93
|
+
registerBroker: (broker) => { brokers.set(broker.id, broker); },
|
|
94
|
+
getBrokerAdapter: (brokerType) => brokers.get(brokerType) ?? null,
|
|
88
95
|
registerCapability: () => {},
|
|
89
96
|
registerTickerResearchTab: () => {},
|
|
90
97
|
registerShortcut: () => {},
|
|
@@ -155,10 +162,15 @@ function buildDiscoveryContext({
|
|
|
155
162
|
|
|
156
163
|
export async function createPaneCatalog(context: MarketContext, plugins: GloomPlugin[]): Promise<PaneFunctionCatalog> {
|
|
157
164
|
const setupPlugins: GloomPlugin[] = [];
|
|
165
|
+
const brokers = new Map<string, BrokerAdapter>();
|
|
166
|
+
const previousResolver = context.resolveBroker;
|
|
167
|
+
const resolveBroker = (brokerType: string) => brokers.get(brokerType) ?? null;
|
|
168
|
+
context.resolveBroker = resolveBroker;
|
|
158
169
|
const { panes, paneTemplates, ...discoveryContext } = createPaneDiscoveryContext({
|
|
159
170
|
getConfig: () => context.config,
|
|
160
171
|
marketData: context.dataProvider,
|
|
161
172
|
tickerRepository: context.store,
|
|
173
|
+
brokers,
|
|
162
174
|
});
|
|
163
175
|
|
|
164
176
|
const destroy = () => {
|
|
@@ -166,6 +178,8 @@ export async function createPaneCatalog(context: MarketContext, plugins: GloomPl
|
|
|
166
178
|
for (const plugin of setupPlugins.splice(0).reverse()) {
|
|
167
179
|
try { plugin.dispose?.(); } catch (error) { failure ??= error; }
|
|
168
180
|
}
|
|
181
|
+
brokers.clear();
|
|
182
|
+
if (context.resolveBroker === resolveBroker) context.resolveBroker = previousResolver;
|
|
169
183
|
if (failure) throw failure;
|
|
170
184
|
};
|
|
171
185
|
|
|
@@ -6,6 +6,8 @@ import type { PaneFunctionReport } from "./report";
|
|
|
6
6
|
import type { ResolvedPaneFunction } from "./resolver";
|
|
7
7
|
import { collectShotSymbols } from "./data";
|
|
8
8
|
import { lockNoteLines } from "./lock-note";
|
|
9
|
+
import { createHeadlessPaneContext } from "./headless";
|
|
10
|
+
import type { HeadlessPaneContext } from "../../types/headless";
|
|
9
11
|
import { lockNoteReason } from "../../plugins/builtin/shared/pro-lock-note";
|
|
10
12
|
import { renderDesktopShot, type PaneScreenshotResult } from "./screenshot";
|
|
11
13
|
import { deriveRenderedFreshness, formatFreshnessLine, type ReportFreshness } from "./freshness";
|
|
@@ -204,10 +206,12 @@ function reportRows(result: PaneScreenshotResult): DesktopPaneShotRenderedRow[]
|
|
|
204
206
|
}];
|
|
205
207
|
}
|
|
206
208
|
|
|
207
|
-
export function buildDomPaneReportFromRender(
|
|
209
|
+
export async function buildDomPaneReportFromRender(
|
|
208
210
|
resolved: ResolvedPaneFunction,
|
|
209
211
|
result: PaneScreenshotResult,
|
|
210
|
-
|
|
212
|
+
/** Reads data for the lock note, which names a free route only when it has data for the symbol. */
|
|
213
|
+
context?: HeadlessPaneContext,
|
|
214
|
+
): Promise<PaneFunctionReport> {
|
|
211
215
|
const rows = reportRows(result);
|
|
212
216
|
const hasStructuredRows = (result.render.reportRows ?? result.render.rows).length > 0;
|
|
213
217
|
// A table that reported every row is whole, whatever the viewport cut from the capture.
|
|
@@ -227,11 +231,12 @@ export function buildDomPaneReportFromRender(
|
|
|
227
231
|
// what is locked and how to reach it, and cites no source.
|
|
228
232
|
const gate = !hasStructuredRows ? result.render.accessGate ?? null : null;
|
|
229
233
|
const lockNote = gate
|
|
230
|
-
? resolved.pane.reportLockNote?.({
|
|
234
|
+
? await resolved.pane.reportLockNote?.({
|
|
231
235
|
gate,
|
|
232
236
|
symbol: result.symbols[0] ?? null,
|
|
233
237
|
token: resolved.token,
|
|
234
238
|
...gate === "sign-in" && asksToVerifyEmail(result.render.visibleText ?? "") ? { verifyEmail: true } : {},
|
|
239
|
+
...context ? { context } : {},
|
|
235
240
|
}) ?? null
|
|
236
241
|
: null;
|
|
237
242
|
const locked = gate === "sign-in" || lockNote ? gate : null;
|
|
@@ -399,7 +404,7 @@ export async function buildDomFunctionReport(
|
|
|
399
404
|
const failure = renderedReportFailure(result.render.semanticUi ?? []);
|
|
400
405
|
if (failure) throw new RenderedReportFailure(failure.message, failure.details);
|
|
401
406
|
try {
|
|
402
|
-
return buildDomPaneReportFromRender(resolved, result);
|
|
407
|
+
return await buildDomPaneReportFromRender(resolved, result, createHeadlessPaneContext(resolved, context, new AbortController().signal));
|
|
403
408
|
} catch (error) {
|
|
404
409
|
return failedDomReport(resolved, rawArg, error);
|
|
405
410
|
}
|
|
@@ -43,7 +43,7 @@ export interface ReportFreshness {
|
|
|
43
43
|
feed?: "live" | "delayed";
|
|
44
44
|
basis?: string;
|
|
45
45
|
/** Set when the dates are the start of a period: the status line then reads `Sep 2026 (monthly)`. */
|
|
46
|
-
periodicity?: "monthly" | "quarterly" | "annual";
|
|
46
|
+
periodicity?: "monthly" | "quarterly" | "semiannual" | "annual";
|
|
47
47
|
/**
|
|
48
48
|
* The newest bar's week or month had not ended, and the last day it covers
|
|
49
49
|
* so far (`asOf`, when known): the status line reads `month to date, through
|
|
@@ -335,7 +335,7 @@ function datasetLagDays(observed: ReportTime, periodicity: ReportFreshness["peri
|
|
|
335
335
|
const month = day.getUTCMonth();
|
|
336
336
|
const through = !periodicity ? Date.UTC(year, month, day.getUTCDate())
|
|
337
337
|
// Day 0 of the month after the period is its last day.
|
|
338
|
-
: periodicity === "monthly" ? Date.UTC(year, month + 1, 0)
|
|
338
|
+
: periodicity === "monthly" || periodicity === "semiannual" ? Date.UTC(year, month + 1, 0)
|
|
339
339
|
: periodicity === "quarterly" ? Date.UTC(year, month - (month % 3) + 3, 0)
|
|
340
340
|
: Date.UTC(year, 12, 0);
|
|
341
341
|
const today = new Date(now);
|
|
@@ -589,13 +589,13 @@ function tradingDayText(date: string, market: string | undefined): string {
|
|
|
589
589
|
return market ? `${market} trading day ${dayText(date)}` : dayText(date);
|
|
590
590
|
}
|
|
591
591
|
|
|
592
|
-
/** `Sep 2026`, `Q2 2026` or `2026` for the period a date starts. */
|
|
592
|
+
/** `Sep 2026`, `Q2 2026` or `2026` for the period a date starts; a semiannual estimate's month. */
|
|
593
593
|
function periodText(date: string, periodicity: NonNullable<ReportFreshness["periodicity"]>): string {
|
|
594
594
|
const day = new Date(`${date.slice(0, 10)}T00:00:00Z`);
|
|
595
595
|
if (!Number.isFinite(day.getTime())) return date;
|
|
596
596
|
const year = day.getUTCFullYear();
|
|
597
597
|
const month = day.getUTCMonth();
|
|
598
|
-
return periodicity === "monthly" ? `${MONTHS[month]} ${year}`
|
|
598
|
+
return periodicity === "monthly" || periodicity === "semiannual" ? `${MONTHS[month]} ${year}`
|
|
599
599
|
: periodicity === "quarterly" ? `Q${Math.floor(month / 3) + 1} ${year}`
|
|
600
600
|
: `${year}`;
|
|
601
601
|
}
|
|
@@ -93,7 +93,7 @@ const POP_OUT = key("p", "op out");
|
|
|
93
93
|
const STEP = key("←/→", " step");
|
|
94
94
|
/** THEM and MEMB members: open them in RRG, CORR, SIW or RIPL, or save them as a watchlist. */
|
|
95
95
|
const MEMBERS_MENU = key(".", " open members in, save as watchlist");
|
|
96
|
-
const CHART_KEYS = [key("s", "eries"), key("i", "ndicators"), key("
|
|
96
|
+
const CHART_KEYS = [key("s", "eries"), key("i", "ndicators"), key("b", "ars"), key("f", "ormulas")];
|
|
97
97
|
|
|
98
98
|
export const FUNCTION_HELP: Readonly<Record<string, FunctionHelp>> = {
|
|
99
99
|
// Research companies
|
|
@@ -971,7 +971,7 @@ export const FUNCTION_HELP: Readonly<Record<string, FunctionHelp>> = {
|
|
|
971
971
|
bloomberg: [],
|
|
972
972
|
},
|
|
973
973
|
PDLR: {
|
|
974
|
-
summary: "Weekly primary dealer net positions and
|
|
974
|
+
summary: "Weekly primary dealer net positions with history, by sector and Treasury tenor (bills, coupons, TIPS, FRN), and settlement fails.",
|
|
975
975
|
usage: ["PDLR"],
|
|
976
976
|
keys: [TABS],
|
|
977
977
|
data: same("Weekly, as published"),
|
|
@@ -1110,7 +1110,7 @@ export const FUNCTION_HELP: Readonly<Record<string, FunctionHelp>> = {
|
|
|
1110
1110
|
docs: "PORT",
|
|
1111
1111
|
},
|
|
1112
1112
|
ALRT: {
|
|
1113
|
-
summary: "Your price alerts with current price, distance to target and trigger state, plus alerts
|
|
1113
|
+
summary: "Your price alerts with current price, distance to target and trigger state, plus alerts on earnings, CPI and FOMC dates, filings and 13F, news keywords, analyst changes, 52-week highs and lows, unusual volume, short interest, insider and congress trades, catalysts, IV spikes, options flow and perps.",
|
|
1114
1114
|
usage: ["ALRT"],
|
|
1115
1115
|
keys: [key("a", "dd alert"), key("e", "dit"), key("d", "elete"), key("m", "re-arm")],
|
|
1116
1116
|
data: QUOTES,
|
|
@@ -1238,6 +1238,30 @@ export const FUNCTION_HELP: Readonly<Record<string, FunctionHelp>> = {
|
|
|
1238
1238
|
data: null,
|
|
1239
1239
|
bloomberg: [],
|
|
1240
1240
|
},
|
|
1241
|
+
BUY: {
|
|
1242
|
+
summary: "Open the shared Trade ticket with a buy quantity and optional limit price. Focus starts on Review; choose an account and review the broker preview before confirming.",
|
|
1243
|
+
usage: ["BUY AAPL 10", "BUY AAPL 10 150.25"],
|
|
1244
|
+
keys: [key("r", "eview"), key("o", "rders")],
|
|
1245
|
+
data: same("Broker account and quote"),
|
|
1246
|
+
bloomberg: [],
|
|
1247
|
+
docs: "BR",
|
|
1248
|
+
},
|
|
1249
|
+
SELL: {
|
|
1250
|
+
summary: "Open the shared Trade ticket with a sell quantity and optional limit price. Focus starts on Review; holdings and broker capabilities are checked before confirmation.",
|
|
1251
|
+
usage: ["SELL AAPL 10", "SELL AAPL 10 350.25"],
|
|
1252
|
+
keys: [key("r", "eview"), key("o", "rders")],
|
|
1253
|
+
data: same("Broker account and quote"),
|
|
1254
|
+
bloomberg: [],
|
|
1255
|
+
docs: "BR",
|
|
1256
|
+
},
|
|
1257
|
+
ORD: {
|
|
1258
|
+
summary: "Open orders and recent activity for a selected broker profile and account. Review a modification or confirm cancellation from an open order; uncertain outcomes require reconciliation before another action.",
|
|
1259
|
+
usage: ["ORD"],
|
|
1260
|
+
keys: [key("m", "odify"), key("c", "ancel")],
|
|
1261
|
+
data: same("Broker account snapshot"),
|
|
1262
|
+
bloomberg: [],
|
|
1263
|
+
docs: "BR",
|
|
1264
|
+
},
|
|
1241
1265
|
|
|
1242
1266
|
// Layouts and settings
|
|
1243
1267
|
GL: {
|
|
@@ -168,12 +168,12 @@ async function loadHeadlessPaneModel(
|
|
|
168
168
|
return result;
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
type HeadlessMarketContext = Pick<MarketContext, "config" | "store" | "refresh"> & Partial<Pick<MarketContext, "persistence" | "seriesCapabilities">> & {
|
|
171
|
+
type HeadlessMarketContext = Pick<MarketContext, "config" | "store" | "refresh" | "resolveBroker"> & Partial<Pick<MarketContext, "persistence" | "seriesCapabilities">> & {
|
|
172
172
|
dataProvider: HeadlessPaneContext["marketData"];
|
|
173
173
|
};
|
|
174
174
|
|
|
175
175
|
/** What a headless loader reads the market, the account and the saved collections through. */
|
|
176
|
-
function createHeadlessPaneContext(
|
|
176
|
+
export function createHeadlessPaneContext(
|
|
177
177
|
resolved: ResolvedPaneFunction,
|
|
178
178
|
context: HeadlessMarketContext,
|
|
179
179
|
signal: AbortSignal,
|
|
@@ -186,6 +186,7 @@ function createHeadlessPaneContext(
|
|
|
186
186
|
...(context.refresh ? { refresh: true } : {}),
|
|
187
187
|
settings: resolved.instance.settings,
|
|
188
188
|
capabilities: getSharedRegistry() ?? context.seriesCapabilities,
|
|
189
|
+
resolveBroker: context.resolveBroker,
|
|
189
190
|
async resolvePortfolio(id) {
|
|
190
191
|
const portfolio = findNamedCollection(context.config.portfolios, id);
|
|
191
192
|
if (!portfolio) return null;
|
|
@@ -498,7 +499,7 @@ function renderRows(
|
|
|
498
499
|
};
|
|
499
500
|
return renderTable(
|
|
500
501
|
columns.map((column) => ({
|
|
501
|
-
header: displayedHeader(column),
|
|
502
|
+
header: column.textHeader ?? displayedHeader(column),
|
|
502
503
|
align: column.align,
|
|
503
504
|
width: column.width,
|
|
504
505
|
shrink: column.shrink,
|
|
@@ -939,9 +940,9 @@ export async function buildHeadlessFunctionReport(
|
|
|
939
940
|
loaded = await loadResolvedHeadlessPaneModel(resolved, context, rawArgument);
|
|
940
941
|
} catch (error) {
|
|
941
942
|
// A Pro pane the server refused reports what its wall covers, as its rendered view does.
|
|
942
|
-
const locked = lockedHeadlessReport(resolved, error, () => (
|
|
943
|
+
const locked = await lockedHeadlessReport(resolved, error, () => (
|
|
943
944
|
buildHeadlessPaneLoadArgs(resolved.headless!, resolved.token, rawArgument, resolved.options).symbols
|
|
944
|
-
));
|
|
945
|
+
), createHeadlessPaneContext(resolved, context, new AbortController().signal));
|
|
945
946
|
if (locked) return locked;
|
|
946
947
|
throw error;
|
|
947
948
|
}
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
import { isNotATickerMessage } from "../not-a-ticker";
|
|
37
37
|
import { isCliFailure } from "../errors";
|
|
38
38
|
import { isTickerLinkPeer } from "../../layout/ticker-navigation";
|
|
39
|
-
import { knownGapMessage, commandPointer, topicPointer } from "../known-gaps";
|
|
39
|
+
import { knownGapMessage, commandPointer, commandPointerLeads, topicPointer } from "../known-gaps";
|
|
40
40
|
import { selectReportTables } from "../report-tables";
|
|
41
41
|
import { cliOutputWritten } from "../result";
|
|
42
42
|
import type { CatalogCommandHit } from "../unknown-command";
|
|
@@ -486,6 +486,7 @@ export async function runPaneCatalog(args: string[], ctx: CliCommandContext) {
|
|
|
486
486
|
// A setting or a report can be a command, not a function: "light theme" names `config themes` beside THEM,
|
|
487
487
|
// "drip" names `portfolio show --drip` beside DVD.
|
|
488
488
|
const setting = commandPointer(parsed.query);
|
|
489
|
+
const settingLeads = commandPointerLeads(parsed.query);
|
|
489
490
|
// The data catalog series the query names, which `fn G` charts.
|
|
490
491
|
const series = findCatalogSeries(ctx.plugins, parsed.query);
|
|
491
492
|
const listed = pointer
|
|
@@ -496,7 +497,7 @@ export async function runPaneCatalog(args: string[], ctx: CliCommandContext) {
|
|
|
496
497
|
...series.length ? { metadata: { series } } : {},
|
|
497
498
|
...(gap || setting) && ctx.cliOptions.format !== "text" ? { warnings: [gap, setting].filter((note): note is string => !!note) } : {},
|
|
498
499
|
}, {
|
|
499
|
-
text: () => renderPaneCatalogReport(filtered, effectiveParsed, glossary, gap, series, setting),
|
|
500
|
+
text: () => renderPaneCatalogReport(filtered, effectiveParsed, glossary, gap, series, setting, settingLeads),
|
|
500
501
|
});
|
|
501
502
|
} finally {
|
|
502
503
|
registry.destroy();
|
|
@@ -2,6 +2,7 @@ import { refusedLock } from "../../plugins/builtin/shared/cloud-denied";
|
|
|
2
2
|
import { lockNoteReason } from "../../plugins/builtin/shared/pro-lock-note";
|
|
3
3
|
import { cliTerminalWidth, wrapText } from "../../utils/cli-output";
|
|
4
4
|
import { reportFooterLines } from "../report-tables";
|
|
5
|
+
import type { HeadlessPaneContext } from "../../types/headless";
|
|
5
6
|
import type { PaneFunctionReport } from "./report";
|
|
6
7
|
import type { ResolvedPaneFunction } from "./resolver";
|
|
7
8
|
|
|
@@ -22,19 +23,21 @@ export function lockNoteLines(note: string): string[] {
|
|
|
22
23
|
* `reportLockNote`, no source line and `locked` in JSON. The refusal may be
|
|
23
24
|
* the error itself or the cause of the one a headless read wrote for it
|
|
24
25
|
* (`explainRefusal`). Null when the error is no such refusal or the pane has
|
|
25
|
-
* no note, and the error stands.
|
|
26
|
+
* no note, and the error stands. The context lets the note check the free
|
|
27
|
+
* route it names.
|
|
26
28
|
*/
|
|
27
|
-
export function lockedHeadlessReport(
|
|
29
|
+
export async function lockedHeadlessReport(
|
|
28
30
|
resolved: ResolvedPaneFunction,
|
|
29
31
|
error: unknown,
|
|
30
32
|
/** The symbols the report was asked for, read once the error is known to be a refusal. */
|
|
31
33
|
symbolsOf: () => string[],
|
|
32
|
-
|
|
34
|
+
context?: HeadlessPaneContext,
|
|
35
|
+
): Promise<PaneFunctionReport | null> {
|
|
33
36
|
const refused = refusedLock(error);
|
|
34
37
|
if (!refused || !resolved.pane.reportLockNote) return null;
|
|
35
38
|
const gate = refused.gate;
|
|
36
39
|
const symbols = symbolsOf();
|
|
37
|
-
const note = resolved.pane.reportLockNote({ ...refused, symbol: symbols[0] ?? null, token: resolved.token });
|
|
40
|
+
const note = await resolved.pane.reportLockNote({ ...refused, symbol: symbols[0] ?? null, token: resolved.token, ...context ? { context } : {} });
|
|
38
41
|
const reason = lockNoteReason(note);
|
|
39
42
|
return {
|
|
40
43
|
data: {
|