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/src/types/trading.ts
CHANGED
|
@@ -3,6 +3,36 @@ import type { BrokerContractRef } from "./instrument";
|
|
|
3
3
|
type BrokerOrderAction = "BUY" | "SELL";
|
|
4
4
|
export type BrokerOrderType = "MKT" | "LMT" | "STP" | "STP LMT";
|
|
5
5
|
|
|
6
|
+
/** Explicit account classification for order confirmation. Missing values are treated as unknown. */
|
|
7
|
+
export type BrokerTradingMode = "simulation" | "live" | "unknown";
|
|
8
|
+
|
|
9
|
+
/** Synchronous ticket metadata. Adapters may vary this by contract and order type. */
|
|
10
|
+
export interface BrokerTradingCapabilities {
|
|
11
|
+
enabled: boolean;
|
|
12
|
+
disabledReason?: string;
|
|
13
|
+
orderTypes: BrokerOrderType[];
|
|
14
|
+
tif: string[];
|
|
15
|
+
extendedHours?: boolean;
|
|
16
|
+
/** When set, extended hours are available only for these time-in-force values. */
|
|
17
|
+
extendedHoursTif?: string[];
|
|
18
|
+
fractionalQuantity?: boolean;
|
|
19
|
+
/** Explicitly permits sells beyond a known long position. Omission blocks short sales. */
|
|
20
|
+
shortSelling?: boolean;
|
|
21
|
+
minQuantity?: number;
|
|
22
|
+
quantityStep?: number;
|
|
23
|
+
priceDecimals?: number;
|
|
24
|
+
/** Broker-reported price increment for this instrument/order. Omit if unknown. */
|
|
25
|
+
priceStep?: number;
|
|
26
|
+
modify?: boolean;
|
|
27
|
+
cancel?: boolean;
|
|
28
|
+
executionKind?: "fills" | "order-summaries";
|
|
29
|
+
/**
|
|
30
|
+
* Multi-leg option orders take up to this many legs (at least 2). Declared
|
|
31
|
+
* for a combo contract (`secType: "BAG"`); omit when the broker takes none.
|
|
32
|
+
*/
|
|
33
|
+
maxLegs?: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
6
36
|
export interface BrokerCashBalance {
|
|
7
37
|
currency: string;
|
|
8
38
|
quantity: number;
|
|
@@ -13,6 +43,9 @@ export interface BrokerCashBalance {
|
|
|
13
43
|
export interface BrokerAccount {
|
|
14
44
|
accountId: string;
|
|
15
45
|
name: string;
|
|
46
|
+
tradingMode?: BrokerTradingMode;
|
|
47
|
+
/** Broker-reported account classification, such as Cash or Margin. Omit when unavailable. */
|
|
48
|
+
accountType?: string;
|
|
16
49
|
currency?: string;
|
|
17
50
|
/** "cloud" is a connection held by the user's Gloom Cloud account. */
|
|
18
51
|
source?: "gateway" | "flex" | "cloud";
|
|
@@ -64,10 +97,25 @@ export interface BrokerPortfolioPerformance {
|
|
|
64
97
|
points: BrokerPortfolioPerformancePoint[];
|
|
65
98
|
}
|
|
66
99
|
|
|
100
|
+
/**
|
|
101
|
+
* One leg of a multi-leg option order. The action is what happens to this
|
|
102
|
+
* contract when the order fills; the ratio is its contracts per spread.
|
|
103
|
+
*/
|
|
104
|
+
export interface BrokerOrderLeg {
|
|
105
|
+
contract: BrokerContractRef;
|
|
106
|
+
action: BrokerOrderAction;
|
|
107
|
+
ratio: number;
|
|
108
|
+
}
|
|
109
|
+
|
|
67
110
|
export interface BrokerOrderRequest {
|
|
68
111
|
brokerInstanceId?: string;
|
|
69
112
|
accountId?: string;
|
|
113
|
+
/** A combo contract (`secType: "BAG"`, the underlying's symbol) when the order has legs. */
|
|
70
114
|
contract: BrokerContractRef;
|
|
115
|
+
/**
|
|
116
|
+
* BUY pays a net debit and SELL receives a net credit. With legs, the
|
|
117
|
+
* legs' own actions say which contracts are bought and sold.
|
|
118
|
+
*/
|
|
71
119
|
action: BrokerOrderAction;
|
|
72
120
|
orderType: BrokerOrderType;
|
|
73
121
|
quantity: number;
|
|
@@ -75,9 +123,23 @@ export interface BrokerOrderRequest {
|
|
|
75
123
|
stopPrice?: number;
|
|
76
124
|
tif?: string;
|
|
77
125
|
outsideRth?: boolean;
|
|
126
|
+
/**
|
|
127
|
+
* 2 or more option legs filled as one order. `quantity` counts spreads and
|
|
128
|
+
* `limitPrice` is the positive net price of one spread.
|
|
129
|
+
*/
|
|
130
|
+
legs?: BrokerOrderLeg[];
|
|
78
131
|
}
|
|
79
132
|
|
|
80
133
|
export interface BrokerOrderPreview {
|
|
134
|
+
currency?: string;
|
|
135
|
+
estimatedCost?: number;
|
|
136
|
+
fees?: number;
|
|
137
|
+
buyingPowerBefore?: number;
|
|
138
|
+
buyingPowerAfter?: number;
|
|
139
|
+
buyingPowerImpact?: number;
|
|
140
|
+
warnings?: string[];
|
|
141
|
+
/** Blocking broker validation errors. A ticket must not submit when these are present. */
|
|
142
|
+
errors?: string[];
|
|
81
143
|
initMarginBefore?: number;
|
|
82
144
|
initMarginAfter?: number;
|
|
83
145
|
maintMarginBefore?: number;
|
|
@@ -91,6 +153,8 @@ export interface BrokerOrderPreview {
|
|
|
91
153
|
|
|
92
154
|
export interface BrokerOrder {
|
|
93
155
|
orderId: number;
|
|
156
|
+
/** Broker-native identity, scoped to profile and account. Numeric orderId remains the mutation handle. */
|
|
157
|
+
brokerOrderId?: string;
|
|
94
158
|
brokerInstanceId?: string;
|
|
95
159
|
accountId?: string;
|
|
96
160
|
status: string;
|
|
@@ -108,12 +172,15 @@ export interface BrokerOrder {
|
|
|
108
172
|
reviewUrl?: string;
|
|
109
173
|
updatedAt: number;
|
|
110
174
|
contract: BrokerContractRef;
|
|
175
|
+
/** A multi-leg order's legs, as on its request. */
|
|
176
|
+
legs?: BrokerOrderLeg[];
|
|
111
177
|
}
|
|
112
178
|
|
|
113
179
|
export interface BrokerExecution {
|
|
114
180
|
execId: string;
|
|
115
181
|
brokerInstanceId?: string;
|
|
116
182
|
orderId?: number;
|
|
183
|
+
brokerOrderId?: string;
|
|
117
184
|
accountId?: string;
|
|
118
185
|
side: string;
|
|
119
186
|
shares: number;
|
package/src/ui/host.tsx
CHANGED
|
@@ -447,6 +447,8 @@ export interface AsciiTextProps extends BoxProps {
|
|
|
447
447
|
interface HostTabItem {
|
|
448
448
|
label: string;
|
|
449
449
|
value: string;
|
|
450
|
+
/** Artwork before the label, such as a logo; decoration only. */
|
|
451
|
+
leading?: ReactNode;
|
|
450
452
|
disabled?: boolean;
|
|
451
453
|
reorderable?: boolean;
|
|
452
454
|
onClose?: (value: string) => void;
|
|
@@ -611,6 +613,8 @@ export interface HostMenuItem {
|
|
|
611
613
|
checked?: boolean;
|
|
612
614
|
/** Tints the label, e.g. a status in its tone; the words carry the meaning. */
|
|
613
615
|
color?: string;
|
|
616
|
+
/** Artwork before the label, such as a logo; decoration only. */
|
|
617
|
+
leading?: ReactNode;
|
|
614
618
|
}
|
|
615
619
|
|
|
616
620
|
export interface HostMenuProps {
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { currenciesNamed } from "./currency-names";
|
|
2
|
+
import { isCurrencyCode } from "./currency-pair";
|
|
3
|
+
import { isIsoCurrencyCode } from "./crypto-pair";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Signs people write for a currency, as they read them: C$ and US$ as
|
|
7
|
+
* Canadians and Americans write them, S$, NZ$, R$. These settle a sign the
|
|
8
|
+
* runtime gives another currency too (C$ is also the cordoba's). The runtime
|
|
9
|
+
* adds CA$, A$, HK$, €, £, ₹ and the rest, so a sign several currencies use
|
|
10
|
+
* ($, ¥) names all of them.
|
|
11
|
+
*/
|
|
12
|
+
const EXTRA_SIGNS: ReadonlyArray<readonly [sign: string, code: string]> = [
|
|
13
|
+
["US$", "USD"], ["U$S", "USD"], ["C$", "CAD"], ["CAN$", "CAD"], ["AU$", "AUD"], ["S$", "SGD"], ["SG$", "SGD"],
|
|
14
|
+
["NZ$", "NZD"], ["R$", "BRL"], ["NT$", "TWD"], ["RMB", "CNY"], ["Fr", "CHF"], ["SFr", "CHF"], ["zł", "PLN"],
|
|
15
|
+
["kr", "SEK"], ["kr", "NOK"], ["kr", "DKK"], ["kr", "ISK"], ["Kč", "CZK"], ["Ft", "HUF"], ["RM", "MYR"],
|
|
16
|
+
["£", "GBP"], ["¥", "JPY"], ["¥", "CNY"],
|
|
17
|
+
["$", "USD"], ["$", "CAD"], ["$", "AUD"], ["$", "NZD"], ["$", "HKD"], ["$", "SGD"], ["$", "MXN"],
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
/** The most traded currencies, first among those a shared sign ($, ¥, kr) names. */
|
|
21
|
+
const SIGN_ORDER = ["USD", "EUR", "JPY", "GBP", "CNY", "CAD", "AUD", "CHF", "HKD", "SGD", "NZD", "MXN", "SEK", "NOK", "DKK"];
|
|
22
|
+
|
|
23
|
+
let signIndex: ReadonlyMap<string, readonly string[]> | undefined;
|
|
24
|
+
|
|
25
|
+
function signKey(sign: string): string {
|
|
26
|
+
return sign.normalize("NFC").replace(/\s+/g, "").toUpperCase();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function signs(): ReadonlyMap<string, readonly string[]> {
|
|
30
|
+
if (signIndex) return signIndex;
|
|
31
|
+
const built = new Map<string, string[]>();
|
|
32
|
+
const curated = new Set(EXTRA_SIGNS.map(([sign]) => signKey(sign)));
|
|
33
|
+
const add = (sign: string, code: string, extra = false) => {
|
|
34
|
+
const key = signKey(sign);
|
|
35
|
+
// A code is its own spelling, not a sign: CHF reads as the code.
|
|
36
|
+
if (!key || key === code || (!extra && curated.has(key))) return;
|
|
37
|
+
const codes = built.get(key) ?? [];
|
|
38
|
+
if (!codes.includes(code)) codes.push(code);
|
|
39
|
+
built.set(key, codes);
|
|
40
|
+
};
|
|
41
|
+
const codes = typeof Intl.supportedValuesOf === "function" ? Intl.supportedValuesOf("currency") : [];
|
|
42
|
+
for (const code of codes) {
|
|
43
|
+
if (!isCurrencyCode(code)) continue;
|
|
44
|
+
for (const currencyDisplay of ["symbol", "narrowSymbol"] as const) {
|
|
45
|
+
try {
|
|
46
|
+
const sign = new Intl.NumberFormat("en-US", { style: "currency", currency: code, currencyDisplay })
|
|
47
|
+
.formatToParts(0).find((part) => part.type === "currency")?.value;
|
|
48
|
+
if (sign) add(sign, code);
|
|
49
|
+
} catch {
|
|
50
|
+
// Intentional ignore: a code the runtime lists but cannot format has no sign to read.
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
for (const [sign, code] of EXTRA_SIGNS) add(sign, code, true);
|
|
55
|
+
const rank = (code: string) => {
|
|
56
|
+
const at = SIGN_ORDER.indexOf(code);
|
|
57
|
+
return at < 0 ? SIGN_ORDER.length : at;
|
|
58
|
+
};
|
|
59
|
+
for (const codesForSign of built.values()) codesForSign.sort((left, right) => rank(left) - rank(right));
|
|
60
|
+
signIndex = built;
|
|
61
|
+
return built;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** The currencies a name (`Canadian dollar`, `yen`) or a sign (`CA$`, `C$`, `€`) stands for, most traded first. */
|
|
65
|
+
function currenciesForNameOrSign(typed: string): string[] {
|
|
66
|
+
const named = currenciesNamed(typed).map(({ code }) => code);
|
|
67
|
+
if (named.length > 0) return named;
|
|
68
|
+
return [...signs().get(signKey(typed.trim())) ?? []];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** What a typed base currency is: its ISO 4217 code, or why it is none and the codes it may have meant. */
|
|
72
|
+
export type BaseCurrencyReading =
|
|
73
|
+
| { code: string }
|
|
74
|
+
| { error: string; suggestions: string[] };
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* A base currency as `config set baseCurrency` takes it: an ISO 4217 code in
|
|
78
|
+
* any case (`cad` is CAD). A currency's name or sign (`Canadian dollar`,
|
|
79
|
+
* `CA$`) is refused with the code it stands for, so the setting is always a
|
|
80
|
+
* code the conversions can price; so is a code that is no currency (XAU, XYZ).
|
|
81
|
+
*/
|
|
82
|
+
export function readBaseCurrency(typed: string): BaseCurrencyReading {
|
|
83
|
+
const text = typed.trim();
|
|
84
|
+
const upper = text.toUpperCase();
|
|
85
|
+
if (/^[A-Z]{3}$/.test(upper) && isCurrencyCode(upper)) return { code: upper };
|
|
86
|
+
if (/^[A-Z]{3}$/.test(upper) && isIsoCurrencyCode(upper)) {
|
|
87
|
+
return { error: `${upper} is a metal, drawing-right or test code, not a currency.`, suggestions: [] };
|
|
88
|
+
}
|
|
89
|
+
const suggestions = text ? currenciesForNameOrSign(text) : [];
|
|
90
|
+
const shown = text ? JSON.stringify(text) : "An empty value";
|
|
91
|
+
if (suggestions.length === 1) return { error: `${shown} is not a currency code. Did you mean ${suggestions[0]}?`, suggestions };
|
|
92
|
+
if (suggestions.length > 1) {
|
|
93
|
+
return { error: `${shown} is not a currency code; it can be ${suggestions.slice(0, 6).join(", ")}.`, suggestions };
|
|
94
|
+
}
|
|
95
|
+
return { error: `${shown} is not an ISO 4217 currency code.`, suggestions };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* A base currency as it was saved, as the setting reads it now: a code in
|
|
100
|
+
* capitals, and a name or sign an older version stored (`Canadian dollar`,
|
|
101
|
+
* `CA$`, `cad`) as the one code it stands for. Anything else stays as saved,
|
|
102
|
+
* for `doctor` and `config get` to flag, rather than turning into USD.
|
|
103
|
+
*/
|
|
104
|
+
export function normalizeStoredBaseCurrency(value: string): string {
|
|
105
|
+
const reading = readBaseCurrency(value);
|
|
106
|
+
if ("code" in reading) return reading.code;
|
|
107
|
+
return reading.suggestions.length === 1 ? reading.suggestions[0]! : value.trim();
|
|
108
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Currencies by the names people give them (`peso`, `Swiss franc`, `rand`),
|
|
3
|
+
* for `fx`, which takes ISO codes. Each currency lists its names, the first
|
|
4
|
+
* one saying whose it is. The last word of every name is also the generic
|
|
5
|
+
* word for it (`peso` for the Mexican peso), shared by every currency that
|
|
6
|
+
* uses it, so a word several currencies carry names all of them, most traded
|
|
7
|
+
* first.
|
|
8
|
+
*/
|
|
9
|
+
const CURRENCY_NAMES: ReadonlyArray<readonly [code: string, ...names: string[]]> = [
|
|
10
|
+
["MXN", "Mexican peso"],
|
|
11
|
+
["ARS", "Argentine peso"],
|
|
12
|
+
["COP", "Colombian peso"],
|
|
13
|
+
["CLP", "Chilean peso"],
|
|
14
|
+
["PHP", "Philippine peso"],
|
|
15
|
+
["UYU", "Uruguayan peso"],
|
|
16
|
+
["DOP", "Dominican peso"],
|
|
17
|
+
["USD", "US dollar", "United States dollar", "American dollar"],
|
|
18
|
+
["CAD", "Canadian dollar"],
|
|
19
|
+
["AUD", "Australian dollar"],
|
|
20
|
+
["NZD", "New Zealand dollar"],
|
|
21
|
+
["HKD", "Hong Kong dollar"],
|
|
22
|
+
["SGD", "Singapore dollar"],
|
|
23
|
+
["TWD", "Taiwan dollar"],
|
|
24
|
+
["EUR", "euro"],
|
|
25
|
+
["GBP", "British pound", "pound sterling"],
|
|
26
|
+
["EGP", "Egyptian pound"],
|
|
27
|
+
["JPY", "Japanese yen", "yen"],
|
|
28
|
+
["CNY", "Chinese yuan", "yuan", "renminbi", "rmb"],
|
|
29
|
+
["CHF", "Swiss franc"],
|
|
30
|
+
["XOF", "West African CFA franc"],
|
|
31
|
+
["XAF", "Central African CFA franc"],
|
|
32
|
+
["INR", "Indian rupee"],
|
|
33
|
+
["PKR", "Pakistani rupee"],
|
|
34
|
+
["LKR", "Sri Lankan rupee"],
|
|
35
|
+
["NPR", "Nepalese rupee"],
|
|
36
|
+
["IDR", "Indonesian rupiah"],
|
|
37
|
+
["KRW", "South Korean won", "Korean won", "won"],
|
|
38
|
+
["BRL", "Brazilian real", "Brazilian reais", "reais"],
|
|
39
|
+
["ZAR", "South African rand"],
|
|
40
|
+
["TRY", "Turkish lira"],
|
|
41
|
+
["NOK", "Norwegian krone", "Norwegian kroner"],
|
|
42
|
+
["DKK", "Danish krone", "Danish kroner"],
|
|
43
|
+
["SEK", "Swedish krona", "Swedish kronor"],
|
|
44
|
+
["ISK", "Icelandic krona", "Icelandic kronur"],
|
|
45
|
+
["CZK", "Czech koruna", "Czech crown"],
|
|
46
|
+
["PLN", "Polish zloty", "Polish zlotych"],
|
|
47
|
+
["HUF", "Hungarian forint"],
|
|
48
|
+
["RON", "Romanian leu", "Romanian lei"],
|
|
49
|
+
["BGN", "Bulgarian lev", "Bulgarian leva"],
|
|
50
|
+
["RUB", "Russian ruble", "Russian rouble"],
|
|
51
|
+
["UAH", "Ukrainian hryvnia"],
|
|
52
|
+
["ILS", "Israeli shekel", "new shekel"],
|
|
53
|
+
["THB", "Thai baht"],
|
|
54
|
+
["VND", "Vietnamese dong"],
|
|
55
|
+
["MYR", "Malaysian ringgit"],
|
|
56
|
+
["BDT", "Bangladeshi taka"],
|
|
57
|
+
["NGN", "Nigerian naira"],
|
|
58
|
+
["GHS", "Ghanaian cedi"],
|
|
59
|
+
["KES", "Kenyan shilling"],
|
|
60
|
+
["UGX", "Ugandan shilling"],
|
|
61
|
+
["TZS", "Tanzanian shilling"],
|
|
62
|
+
["AED", "UAE dirham", "Emirati dirham"],
|
|
63
|
+
["MAD", "Moroccan dirham"],
|
|
64
|
+
["SAR", "Saudi riyal", "Saudi rial"],
|
|
65
|
+
["QAR", "Qatari riyal", "Qatari rial"],
|
|
66
|
+
["OMR", "Omani rial", "Omani riyal"],
|
|
67
|
+
["IRR", "Iranian rial", "Iranian riyal"],
|
|
68
|
+
["KWD", "Kuwaiti dinar"],
|
|
69
|
+
["BHD", "Bahraini dinar"],
|
|
70
|
+
["JOD", "Jordanian dinar"],
|
|
71
|
+
["IQD", "Iraqi dinar"],
|
|
72
|
+
["RSD", "Serbian dinar"],
|
|
73
|
+
["DZD", "Algerian dinar"],
|
|
74
|
+
["TND", "Tunisian dinar"],
|
|
75
|
+
["LYD", "Libyan dinar"],
|
|
76
|
+
["KZT", "Kazakhstani tenge"],
|
|
77
|
+
["PEN", "Peruvian sol"],
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
/** One currency a name stands for. */
|
|
81
|
+
export interface NamedCurrency {
|
|
82
|
+
code: string;
|
|
83
|
+
/** What tells it from the others that share the word: "Mexican" for peso. Empty when the name is the whole name. */
|
|
84
|
+
qualifier: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** The text of a name as it is looked up: lower case, without accents, punctuation or "the". */
|
|
88
|
+
function normalize(text: string): string {
|
|
89
|
+
return text.normalize("NFD").replace(/\p{M}/gu, "").toLowerCase()
|
|
90
|
+
.replace(/[^a-z0-9]+/g, " ").trim()
|
|
91
|
+
.replace(/^the /, "");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
let index: ReadonlyMap<string, readonly NamedCurrency[]> | undefined;
|
|
95
|
+
|
|
96
|
+
function nameIndex(): ReadonlyMap<string, readonly NamedCurrency[]> {
|
|
97
|
+
if (index) return index;
|
|
98
|
+
const built = new Map<string, NamedCurrency[]>();
|
|
99
|
+
const add = (key: string, entry: NamedCurrency) => {
|
|
100
|
+
const found = built.get(key);
|
|
101
|
+
if (!found) built.set(key, [entry]);
|
|
102
|
+
else if (!found.some((other) => other.code === entry.code)) found.push(entry);
|
|
103
|
+
};
|
|
104
|
+
for (const [code, ...names] of CURRENCY_NAMES) {
|
|
105
|
+
for (const name of names) {
|
|
106
|
+
const words = normalize(name).split(" ");
|
|
107
|
+
const generic = words.at(-1)!;
|
|
108
|
+
// "Mexican" for "Mexican peso"; the whole name when it is one word, which says no more than the word.
|
|
109
|
+
const qualifier = words.length > 1 ? name.slice(0, name.length - generic.length).trim() : "";
|
|
110
|
+
add(normalize(name), { code, qualifier: "" });
|
|
111
|
+
add(generic, { code, qualifier });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
index = built;
|
|
115
|
+
return built;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* The currencies a name stands for: `Swiss franc` is CHF alone, `peso` is
|
|
120
|
+
* MXN, ARS, COP, CLP, PHP and more. A plural is its singular (`pesos`). Empty
|
|
121
|
+
* for text that names no currency.
|
|
122
|
+
*/
|
|
123
|
+
export function currenciesNamed(text: string): readonly NamedCurrency[] {
|
|
124
|
+
const key = normalize(text);
|
|
125
|
+
const names = nameIndex();
|
|
126
|
+
if (!key) return [];
|
|
127
|
+
return names.get(key) ?? (key.endsWith("s") ? names.get(key.slice(0, -1)) : undefined) ?? [];
|
|
128
|
+
}
|
|
@@ -26,7 +26,8 @@ const NON_CURRENCY_CODES = new Set([
|
|
|
26
26
|
"XAU", "XAG", "XPT", "XPD", "XDR", "XSU", "XUA", "XBA", "XBB", "XBC", "XBD", "XTS", "XXX", "XEU", "XFO", "XFU", "XRE",
|
|
27
27
|
]);
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
/** Whether `code` is a currency code a pair can be written with: ISO 4217, less metals, drawing rights and testing codes. */
|
|
30
|
+
export function isCurrencyCode(code: string): boolean {
|
|
30
31
|
return !NON_CURRENCY_CODES.has(code) && isIsoCurrencyCode(code);
|
|
31
32
|
}
|
|
32
33
|
|
|
@@ -15,10 +15,13 @@ const SUB_UNIT_NAMES: Record<string, string> = {
|
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* A currency code as a reader should see it; a sub-unit says which one,
|
|
18
|
-
* "GBp (pence)", and with `ofMajor` what it divides:
|
|
18
|
+
* "GBp (pence)", "US¢ (US cents)", and with `ofMajor` what it divides:
|
|
19
|
+
* "ILA (agorot, 1/100 ILS)".
|
|
19
20
|
*/
|
|
20
21
|
export function currencyUnitLabel(code?: string | null, { ofMajor = false }: { ofMajor?: boolean } = {}): string {
|
|
21
22
|
const raw = (code ?? "").trim();
|
|
23
|
+
// US cents have no standard code; the one quotes carry (USX) is shown as US¢.
|
|
24
|
+
if (raw.toUpperCase() === US_CENTS) return ofMajor ? "US¢ (US cents, 1/100 USD)" : "US¢ (US cents)";
|
|
22
25
|
const unit = SUB_UNIT_NAMES[raw];
|
|
23
26
|
const major = SUB_UNIT_CURRENCIES[raw];
|
|
24
27
|
if (!unit) return raw;
|
|
@@ -50,6 +53,34 @@ const SUB_UNIT_EXCHANGE_RULES = [
|
|
|
50
53
|
*/
|
|
51
54
|
export const US_CENTS = "USX";
|
|
52
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Minor units with a sign of their own, by upper-cased code; GBp is read in
|
|
58
|
+
* its own case, as GBP is pounds. Agorot (ILA) have none in common use and
|
|
59
|
+
* keep their code.
|
|
60
|
+
*/
|
|
61
|
+
const MINOR_UNIT_SIGNS: Readonly<Record<string, string>> = { USX: "¢", GBX: "p", ZAC: "c" };
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The sign a price in a minor unit is written with, after the amount, where
|
|
65
|
+
* a major currency's symbol goes before it: US cents 314.95¢ (grains and
|
|
66
|
+
* softs), pence 412.50p, South African cents 1,250.00c. Null for a major
|
|
67
|
+
* currency, or a minor unit without one.
|
|
68
|
+
*/
|
|
69
|
+
export function minorUnitSign(code: string | null | undefined): string | null {
|
|
70
|
+
const raw = (code ?? "").trim();
|
|
71
|
+
if (raw === "GBp") return "p";
|
|
72
|
+
return MINOR_UNIT_SIGNS[raw.toUpperCase()] ?? null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* A quote currency's code as a column of codes shows it: US cents, a code no
|
|
77
|
+
* standard has, as US¢; every other code as it is (USD, GBp).
|
|
78
|
+
*/
|
|
79
|
+
export function currencyCodeLabel(code: string | null | undefined): string {
|
|
80
|
+
const raw = (code ?? "").trim();
|
|
81
|
+
return raw.toUpperCase() === US_CENTS ? "US¢" : raw;
|
|
82
|
+
}
|
|
83
|
+
|
|
53
84
|
/**
|
|
54
85
|
* A currency's rate to USD where it is fixed rather than quoted: the dollar
|
|
55
86
|
* itself, and US cents. Undefined for any other, whose rate the market sets.
|
|
@@ -64,6 +95,15 @@ export interface CurrencyUnitInfo {
|
|
|
64
95
|
divisor: number;
|
|
65
96
|
}
|
|
66
97
|
|
|
98
|
+
/**
|
|
99
|
+
* The currency money held in a code is counted in, and how many of the code
|
|
100
|
+
* make one of it: resolveCurrencyUnit's, and US cents as a hundredth of a
|
|
101
|
+
* dollar, which a lot's cost in USX is.
|
|
102
|
+
*/
|
|
103
|
+
export function heldCurrencyUnit(currency?: string | null): CurrencyUnitInfo {
|
|
104
|
+
return currency?.trim().toUpperCase() === US_CENTS ? { currency: "USD", divisor: 100 } : resolveCurrencyUnit(currency);
|
|
105
|
+
}
|
|
106
|
+
|
|
67
107
|
interface ExchangeSubUnitOptions {
|
|
68
108
|
allowDefaultCurrency?: boolean;
|
|
69
109
|
allowMissingCurrency?: boolean;
|
|
@@ -469,11 +469,16 @@ function drawCanvasElement(
|
|
|
469
469
|
}
|
|
470
470
|
}
|
|
471
471
|
|
|
472
|
+
/** Inputs whose value is not text on screen. A button's value is its label, so it is painted. */
|
|
473
|
+
const NON_TEXT_INPUTS = new Set(["checkbox", "radio", "range", "color", "file", "hidden", "image"]);
|
|
474
|
+
|
|
472
475
|
function drawInputElement(
|
|
473
476
|
context: CanvasRenderingContext2D,
|
|
474
477
|
element: HTMLInputElement | HTMLTextAreaElement,
|
|
475
478
|
origin: CaptureOrigin,
|
|
476
479
|
): void {
|
|
480
|
+
// A checkbox's value ("on" unless set) is not on screen; its box is painted from its CSS.
|
|
481
|
+
if (element instanceof HTMLInputElement && NON_TEXT_INPUTS.has(element.type)) return;
|
|
477
482
|
// Paint what the screen shows: a password field is dots, never its value.
|
|
478
483
|
const typed = element instanceof HTMLInputElement && element.type === "password"
|
|
479
484
|
? "\u2022".repeat(element.value.length)
|
|
@@ -593,6 +598,12 @@ function drawElement(pass: PaintPass, element: Element): void {
|
|
|
593
598
|
|
|
594
599
|
const style = getComputedStyle(element);
|
|
595
600
|
if (!isVisible(style)) return;
|
|
601
|
+
// A `display: contents` element (a ColumnGrid row) has no box of its own: its children are laid
|
|
602
|
+
// out in its parent's, so its empty rect must not leave them out.
|
|
603
|
+
if (style.display === "contents") {
|
|
604
|
+
drawChildren(pass, element);
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
596
607
|
|
|
597
608
|
const rect = localRect(element.getBoundingClientRect(), origin);
|
|
598
609
|
if (rect.width <= 0 || rect.height <= 0) return;
|
|
@@ -624,19 +635,21 @@ function drawElement(pass: PaintPass, element: Element): void {
|
|
|
624
635
|
}
|
|
625
636
|
|
|
626
637
|
// An SVG's shapes and text are in its raster; they are not boxes to walk.
|
|
627
|
-
if (!(element instanceof SVGElement))
|
|
628
|
-
for (const child of paintOrder(element)) {
|
|
629
|
-
if (child.nodeType === Node.TEXT_NODE) {
|
|
630
|
-
drawTextNode(context, child as Text, origin);
|
|
631
|
-
} else {
|
|
632
|
-
drawElement(pass, child as Element);
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
}
|
|
638
|
+
if (!(element instanceof SVGElement)) drawChildren(pass, element);
|
|
636
639
|
|
|
637
640
|
context.restore();
|
|
638
641
|
}
|
|
639
642
|
|
|
643
|
+
function drawChildren(pass: PaintPass, element: Element): void {
|
|
644
|
+
for (const child of paintOrder(element)) {
|
|
645
|
+
if (child.nodeType === Node.TEXT_NODE) {
|
|
646
|
+
drawTextNode(pass.context, child as Text, pass.origin);
|
|
647
|
+
} else {
|
|
648
|
+
drawElement(pass, child as Element);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
640
653
|
/** Where a child falls in its parent's paint: below the flow, in it, or above it at its z-index. */
|
|
641
654
|
function paintLayer(child: Element): number {
|
|
642
655
|
const style = getComputedStyle(child);
|