@gloom-sh/terminal 0.19.0 → 0.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/package.json +1 -1
- package/patches/electrobun@1.18.1.patch +23 -1
- package/src/api-client/app-attention.ts +3 -0
- package/src/api-client/beneficial-owners.ts +3 -0
- package/src/api-client/company-kpis.ts +3 -0
- package/src/api-client/data.ts +2 -1
- package/src/api-client/hiring.ts +3 -0
- package/src/api-client/index.ts +4 -0
- package/src/api-client/ipo.ts +24 -1
- package/src/api-client/mna.ts +3 -0
- package/src/api-client/paths.ts +9 -1
- package/src/api-client/roadmap.ts +85 -0
- package/src/api-client/types.ts +12 -0
- package/src/architecture/core-builtin-allowlist.json +2 -2
- package/src/cli/commands/market.ts +35 -12
- package/src/cli/commands/news-search.ts +22 -0
- package/src/cli/commands/overview.ts +86 -20
- package/src/cli/commands/ticker.ts +32 -2
- package/src/cli/errors.ts +17 -2
- package/src/cli/glossary.ts +6 -0
- package/src/cli/index-roots.ts +0 -7
- package/src/cli/listing-arg.ts +57 -10
- package/src/cli/pane-functions/capabilities.ts +1 -0
- package/src/cli/pane-functions/discovery.ts +21 -1
- package/src/cli/pane-functions/freshness.ts +7 -1
- package/src/cli/pane-functions/function-help.ts +7 -0
- package/src/cli/pane-functions/index.ts +6 -3
- package/src/cli/quote-answer.ts +1 -1
- package/src/cli/saved-copy-persistence.ts +88 -0
- package/src/components/command-bar/list/model.ts +5 -0
- package/src/components/command-bar/routes/root/runtime.ts +6 -7
- package/src/components/command-bar/selection-runtime.ts +52 -3
- package/src/components/command-bar/surface/index.tsx +2 -0
- package/src/components/layout/pane/capture-stamp.ts +2 -2
- package/src/components/layout/pane/footer/index.tsx +22 -6
- package/src/components/layout/pane/footer/model.ts +83 -15
- package/src/components/layout/pane/status-footer.ts +35 -2
- package/src/components/layout/status-widget-space.ts +9 -0
- package/src/components/ticker/list-table-view.tsx +4 -20
- package/src/components/ui/display.tsx +18 -3
- package/src/components/ui/icon.tsx +4 -1
- package/src/data/plugin-cache.ts +5 -3
- package/src/data/saved-copies.ts +8 -0
- package/src/docs/snapshot.json +32 -5
- package/src/i18n/es.ts +2 -4
- package/src/i18n/ja.ts +2 -4
- package/src/i18n/ko.ts +2 -4
- package/src/i18n/zh-cn.ts +2 -4
- package/src/i18n/zh-tw.ts +2 -4
- package/src/market-data/depositary-pair.ts +25 -1
- package/src/market-data/quotes/metadata.ts +7 -0
- package/src/news/aggregator.ts +7 -1
- package/src/news/types.ts +6 -0
- package/src/plugins/builtin/alerts/calendar-events.ts +10 -4
- package/src/plugins/builtin/alerts/cli.ts +34 -11
- package/src/plugins/builtin/alerts/event-rows.ts +24 -3
- package/src/plugins/builtin/alerts/events-pane.tsx +15 -6
- package/src/plugins/builtin/alerts/headless.ts +10 -6
- package/src/plugins/builtin/cds/client.ts +142 -30
- package/src/plugins/builtin/cds/headless.ts +35 -8
- package/src/plugins/builtin/cds/model.ts +145 -18
- package/src/plugins/builtin/cds/pane.tsx +16 -5
- package/src/plugins/builtin/chart-composer/follow-binding.ts +14 -2
- package/src/plugins/builtin/chart-composer/index.tsx +4 -5
- package/src/plugins/builtin/chat/controller/index.ts +5 -1
- package/src/plugins/builtin/chat/controller/notifications.ts +33 -3
- package/src/plugins/builtin/chat/controller/state.ts +25 -2
- package/src/plugins/builtin/chat/controller/unread-people.ts +89 -23
- package/src/plugins/builtin/chat/controller/utils.ts +7 -2
- package/src/plugins/builtin/chat/status-preview.ts +79 -0
- package/src/plugins/builtin/chat/status-widget.tsx +147 -10
- package/src/plugins/builtin/chat/unread-badge.ts +51 -10
- package/src/plugins/builtin/clinical-trials/client.ts +49 -4
- package/src/plugins/builtin/clinical-trials/model.ts +86 -22
- package/src/plugins/builtin/clinical-trials/pane.tsx +46 -27
- package/src/plugins/builtin/clinical-trials/sponsor-listing.ts +90 -0
- package/src/plugins/builtin/clinical-trials/sponsor-tickers.ts +87 -9
- package/src/plugins/builtin/clinical-trials/trial-pages.ts +50 -0
- package/src/plugins/builtin/company-attention/headless.ts +2 -1
- package/src/plugins/builtin/company-attention/pane.tsx +3 -0
- package/src/plugins/builtin/company-kpis/headless.ts +8 -3
- package/src/plugins/builtin/company-kpis/model.ts +73 -5
- package/src/plugins/builtin/company-kpis/pane.tsx +15 -7
- package/src/plugins/builtin/composite-plugins.ts +2 -1
- package/src/plugins/builtin/credit-documents/headless.ts +3 -3
- package/src/plugins/builtin/doe/headless.ts +3 -2
- package/src/plugins/builtin/doe/pane.tsx +13 -3
- package/src/plugins/builtin/earnings-calls/data.ts +18 -6
- package/src/plugins/builtin/earnings-calls/headless.ts +13 -3
- package/src/plugins/builtin/earnings-calls/pane.tsx +7 -0
- package/src/plugins/builtin/econ/calendar-model.ts +48 -1
- package/src/plugins/builtin/econ/calendar-source.ts +4 -2
- package/src/plugins/builtin/econ/detail-view.tsx +2 -2
- package/src/plugins/builtin/econ/figures.ts +48 -0
- package/src/plugins/builtin/econ/index.tsx +14 -5
- package/src/plugins/builtin/econ/print-watch.ts +3 -1
- package/src/plugins/builtin/econ-statistics/client.ts +11 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +10 -2
- package/src/plugins/builtin/econ-statistics/pane.tsx +8 -4
- package/src/plugins/builtin/econ-statistics/stats.ts +3 -0
- package/src/plugins/builtin/help/index.tsx +61 -59
- package/src/plugins/builtin/help/shortcut-table.tsx +5 -6
- package/src/plugins/builtin/help/table-cells.tsx +13 -2
- package/src/plugins/builtin/holders/beneficial-client.ts +5 -1
- package/src/plugins/builtin/holders/beneficial-view.tsx +3 -0
- package/src/plugins/builtin/holders/headless.ts +4 -2
- package/src/plugins/builtin/holders/pane.tsx +3 -0
- package/src/plugins/builtin/holders/report-rows.ts +4 -1
- package/src/plugins/builtin/insider/headless.ts +2 -2
- package/src/plugins/builtin/ipo-calendar/client.ts +18 -2
- package/src/plugins/builtin/ipo-calendar/headless.ts +75 -11
- package/src/plugins/builtin/ipo-calendar/listing-ipo.ts +160 -0
- package/src/plugins/builtin/ipo-calendar/model.ts +98 -2
- package/src/plugins/builtin/macro-day/headless.ts +12 -5
- package/src/plugins/builtin/macro-day/index.tsx +1 -1
- package/src/plugins/builtin/macro-day/model.ts +39 -5
- package/src/plugins/builtin/macro-day/pane.tsx +27 -19
- package/src/plugins/builtin/market-movers/client.ts +2 -0
- package/src/plugins/builtin/market-movers/headless.ts +3 -1
- package/src/plugins/builtin/market-movers/screener.ts +8 -4
- package/src/plugins/builtin/mna/headless.ts +2 -0
- package/src/plugins/builtin/mna/pane.tsx +3 -1
- package/src/plugins/builtin/news/headless.ts +3 -1
- package/src/plugins/builtin/news/index.tsx +3 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +2 -6
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +0 -14
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +2 -1
- package/src/plugins/builtin/portfolio-list/table.tsx +4 -6
- package/src/plugins/builtin/realized-vol/client.ts +13 -5
- package/src/plugins/builtin/realized-vol/evidence.ts +29 -4
- package/src/plugins/builtin/realized-vol/headless.ts +8 -4
- package/src/plugins/builtin/realized-vol/model.ts +37 -6
- package/src/plugins/builtin/realized-vol/pane.tsx +9 -7
- package/src/plugins/builtin/research/event-model.ts +30 -4
- package/src/plugins/builtin/research/index.tsx +7 -3
- package/src/plugins/builtin/research/relative-valuation-headless.ts +8 -25
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +52 -15
- package/src/plugins/builtin/research/relative-valuation-peers.ts +217 -20
- package/src/plugins/builtin/research/relative-valuation-settings.ts +44 -0
- package/src/plugins/builtin/risk-factors/data.ts +4 -2
- package/src/plugins/builtin/risk-factors/headless.ts +5 -2
- package/src/plugins/builtin/roadmap/index.tsx +28 -0
- package/src/plugins/builtin/roadmap/model.ts +67 -0
- package/src/plugins/builtin/roadmap/pane.tsx +244 -0
- package/src/plugins/builtin/scanner/live-headless.ts +21 -2
- package/src/plugins/builtin/sec/headless.ts +2 -1
- package/src/plugins/builtin/sec/index.tsx +3 -0
- package/src/plugins/builtin/shared/cloud-resource.ts +13 -5
- package/src/plugins/builtin/shared/headless-market-data.ts +2 -2
- package/src/plugins/builtin/shared/report-freshness.ts +8 -0
- package/src/plugins/builtin/shared/research-cells.tsx +1 -1
- package/src/plugins/builtin/shared/series-cache.ts +4 -4
- package/src/plugins/builtin/thirteenf/api.ts +12 -1
- package/src/plugins/builtin/thirteenf/data.ts +7 -7
- package/src/plugins/builtin/thirteenf/headless.ts +31 -4
- package/src/plugins/builtin/ticker-detail/overview/model.ts +10 -2
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +2 -1
- package/src/plugins/builtin/ticker-detail/pane.tsx +11 -6
- package/src/plugins/builtin/treasury-auctions/headless.ts +21 -12
- package/src/plugins/builtin/treasury-auctions/pane.tsx +9 -3
- package/src/plugins/builtin/volatility/pane.tsx +5 -2
- package/src/plugins/builtin/yield-curve/client.ts +61 -1
- package/src/plugins/builtin/yield-curve/headless.ts +9 -6
- package/src/plugins/builtin/yield-curve/index.tsx +34 -10
- package/src/plugins/builtin/yield-curve/swaps.tsx +9 -5
- package/src/plugins/catalog-browser.ts +2 -1
- package/src/plugins/host-link.ts +1 -1
- package/src/portfolio/column-values.ts +11 -7
- package/src/renderers/dom/desktop/icons.tsx +7 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +9 -10
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +8 -0
- package/src/renderers/electrobun/bun/desktop/installer-folder.ts +731 -0
- package/src/renderers/electrobun/bun/desktop/relaunch.ts +102 -10
- package/src/renderers/electrobun/bun/desktop/windows-script.ts +92 -0
- package/src/renderers/electrobun/bun/index.ts +26 -2
- package/src/renderers/electrobun/bun/window/create.ts +43 -4
- package/src/renderers/electrobun/bun/window/events.ts +20 -0
- package/src/renderers/electrobun/bun/window/windows-custom-chrome.ts +9 -2
- package/src/renderers/electrobun/bun/window/windows-native.ts +78 -0
- package/src/renderers/electrobun/bun/window/windows-quit.ts +57 -0
- package/src/renderers/electrobun/shared/protocol.ts +2 -0
- package/src/renderers/electrobun/view/news-source.ts +2 -0
- package/src/renderers/electrobun/view/ui-host.tsx +8 -0
- package/src/sources/gloomberb-cloud/fred-series.ts +3 -1
- package/src/sources/gloomberb-cloud/index.ts +42 -8
- package/src/tickers/company-name-listing.ts +53 -13
- package/src/tickers/company-name.ts +6 -1
- package/src/tickers/index-roots.ts +7 -0
- package/src/tickers/listing-fate.ts +2 -2
- package/src/tickers/search/index.ts +6 -2
- package/src/tickers/search/ranking.ts +5 -1
- package/src/tickers/search/upsert.ts +13 -0
- package/src/tickers/ticker-changes.ts +8 -4
- package/src/types/company-from.ts +40 -0
- package/src/types/data-provider.ts +7 -0
- package/src/types/financials.ts +27 -0
- package/src/types/headless.ts +6 -0
- package/src/utils/crypto-pair.ts +121 -7
- package/src/utils/declared-dividends.ts +1 -1
- package/src/utils/fundamentals.ts +36 -5
- package/src/version.ts +2 -2
package/src/utils/crypto-pair.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { canonicalExchange, parsePublicTickerKey } from "./exchanges";
|
|
1
|
+
import { canonicalExchange, EXCHANGE_TIME_ZONES, isKnownExchangeCode, parsePublicTickerKey } from "./exchanges";
|
|
2
2
|
|
|
3
3
|
// The fiat codes a pair against USD is read as FX for, never as a coin. The
|
|
4
4
|
// list Cloud reads: it serves these pairs by the same rule, so a copy judged
|
|
@@ -9,8 +9,8 @@ const FIAT_CURRENCY_CODES = new Set([
|
|
|
9
9
|
]);
|
|
10
10
|
|
|
11
11
|
const USD_COIN_PAIR = /^([A-Z0-9]+)[-/]USD$/;
|
|
12
|
-
// The other currencies and coins the crypto venue quotes a coin in (BTC-EUR, ETH-BTC).
|
|
13
|
-
const QUOTED_COIN_PAIR = /^([A-Z0-9]+)[-/](?:USDT|USDC|EUR|GBP|BTC|ETH)$/;
|
|
12
|
+
// The other currencies and coins the crypto venue quotes a coin in (BTC-EUR, BTC-JPY, ETH-BTC).
|
|
13
|
+
const QUOTED_COIN_PAIR = /^([A-Z0-9]+)[-/](?:USDT|USDC|EUR|GBP|JPY|KRW|CAD|INR|CNY|AUD|BTC|ETH)$/;
|
|
14
14
|
|
|
15
15
|
/** A coin quoted in dollars (BTC-USD, ETH/USD). EUR-USD is spot FX, not a coin. */
|
|
16
16
|
function isUsdCoinPair(symbol: string): boolean {
|
|
@@ -35,10 +35,18 @@ export function isRoundTheClockCoin(symbol?: string, exchange?: string): boolean
|
|
|
35
35
|
const parsed = symbol ? parsePublicTickerKey(symbol) : null;
|
|
36
36
|
const venue = canonicalExchange(parsed?.exchange ?? exchange) || canonicalExchange(exchange);
|
|
37
37
|
if (venue === "CCC" || canonicalExchange(exchange) === "CCC") return true;
|
|
38
|
+
if (parsed && exchangeLineCoinListing(parsed.symbol, venue)) return true;
|
|
38
39
|
return !!parsed && (isUsdCoinPair(parsed.symbol) || (!venue && isQuotedCoinPair(parsed.symbol)));
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
const SLASH_COIN_PAIR = /^([A-Z0-9]{1,15})\/(USD|EUR|GBP|USDT|USDC|BTC)$/;
|
|
42
|
+
const SLASH_COIN_PAIR = /^([A-Z0-9]{1,15})\/(USD|EUR|GBP|JPY|KRW|CAD|INR|CNY|AUD|USDT|USDC|BTC|ETH)$/;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* What the crypto venue (CCC) quotes a coin in: BTC-GBP, BTC-KRW, LINK-ETH.
|
|
46
|
+
* It has no coin in a stablecoin (BTC-USDT) or in most other currencies
|
|
47
|
+
* (BTC-TRY, BTC-BRL).
|
|
48
|
+
*/
|
|
49
|
+
const VENUE_QUOTE_LEGS: ReadonlySet<string> = new Set(["USD", "EUR", "GBP", "JPY", "KRW", "CAD", "INR", "CNY", "AUD", "BTC", "ETH"]);
|
|
42
50
|
|
|
43
51
|
let isoCurrencyCodes: ReadonlySet<string> | null = null;
|
|
44
52
|
|
|
@@ -58,9 +66,114 @@ export function dashedCoinPair(symbol: string): string | null {
|
|
|
58
66
|
return `${match[1]}-${match[2]}`;
|
|
59
67
|
}
|
|
60
68
|
|
|
69
|
+
/**
|
|
70
|
+
* The crypto exchanges whose own lines of a coin pair search lists in a currency the crypto venue quotes coins in,
|
|
71
|
+
* and the venue itself. A slash pair saved on any other venue, or on none, is not read as a coin: on the commodity
|
|
72
|
+
* or currency venue it is spot crude, gold by the gram or a currency (WTI/USD, GAU/USD, RUB/USD).
|
|
73
|
+
*/
|
|
74
|
+
const COIN_EXCHANGES: ReadonlySet<string> = new Set([
|
|
75
|
+
"CCC", "BIGONE", "BINANCE", "BITBANK", "BITBNS", "BITFINEX", "BITFLYER", "BITHUMB", "BITMART", "BITRUE", "BITSTAMP",
|
|
76
|
+
"BTC MARKETS", "BYBIT", "CEX.IO", "COINBASE PRO", "COINONE", "CRYPTO.COM EXCHANGE", "FREIEXCHANGE", "GATE.IO", "HITBTC",
|
|
77
|
+
"HUOBI", "INDEPENDENT RESERVE", "KRAKEN", "KUCOIN", "LATOKEN", "MEXC", "MXC", "OKEX", "OKX", "POLONIEX", "SYNTHETIC",
|
|
78
|
+
"UNISWAP", "UPBIT", "WAZIRX", "XT.COM", "YOBIT", "ZAIF",
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
/** Venues whose slash pairs are commodities or currencies, never coins, whatever a row's type says. */
|
|
82
|
+
const NOT_COIN_VENUES: ReadonlySet<string> = new Set(["COMMODITY", "CCY", "FX", "FOREX", "CURRENCY", "PHYSICAL CURRENCY"]);
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Spot commodities written as a pair: gold, silver, platinum and palladium, gold and silver by the gram (GAU,
|
|
86
|
+
* XAGG), WTI, Brent (XBR) and Urals crude, and copper (HG1). Never a coin, though tokens share the letters
|
|
87
|
+
* (GAU-USD is Gamer Arena).
|
|
88
|
+
*/
|
|
89
|
+
const SPOT_COMMODITY_BASES: ReadonlySet<string> = new Set(["XAU", "GAU", "XAG", "XAGG", "XPT", "XPD", "WTI", "XBR", "URALS", "HG1"]);
|
|
90
|
+
|
|
91
|
+
/** A spot commodity's pair (WTI/USD, GAU/USD) or a pair on the commodity or currency venue, which no coin is. */
|
|
92
|
+
export function isSpotCommodityOrCurrencyPair(symbol: string, exchange?: string): boolean {
|
|
93
|
+
const parsed = parsePublicTickerKey(symbol.trim().toUpperCase());
|
|
94
|
+
const named = (parsed.exchange ?? exchange ?? "").trim().toUpperCase();
|
|
95
|
+
const base = /^([A-Z0-9]{1,15})\//.exec(parsed.symbol)?.[1];
|
|
96
|
+
return !!base && (SPOT_COMMODITY_BASES.has(base) || NOT_COIN_VENUES.has(named) || NOT_COIN_VENUES.has(canonicalExchange(named)));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** The crypto venue's listing of a coin pair written with a slash (BTC/GBP); null for a currency, a spot commodity or another leg. */
|
|
100
|
+
function slashCoinPairListing(symbol: string): { symbol: string; exchange: "CCC"; currency: string } | null {
|
|
101
|
+
const match = SLASH_COIN_PAIR.exec(symbol.trim().toUpperCase());
|
|
102
|
+
if (!match) return null;
|
|
103
|
+
const [, base, quote] = match as unknown as [string, string, string];
|
|
104
|
+
if (isIsoCurrencyCode(base) || SPOT_COMMODITY_BASES.has(base) || !VENUE_QUOTE_LEGS.has(quote)) return null;
|
|
105
|
+
return { symbol: `${base}-${quote}`, exchange: "CCC", currency: quote };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* A crypto exchange's own line of a coin pair (BTC/GBP on COINBASE PRO, LINK/EUR on KRAKEN, DOGE/BTC on BINANCE)
|
|
110
|
+
* as the crypto venue's listing of it, in the currency it is quoted in: BTC-GBP on CCC, in pounds. Search offers
|
|
111
|
+
* those lines, and no source quotes them.
|
|
112
|
+
*
|
|
113
|
+
* Only a pair on a crypto exchange (COIN_EXCHANGES) is one, or a search row whose type says it is a coin
|
|
114
|
+
* (`coinRow`) on a venue that is no stock, commodity or currency venue. Null for a currency pair (EUR/USD,
|
|
115
|
+
* RUB/USD), a spot commodity (XAU/USD, WTI/USD), a pair the venue quotes in no such currency (BTC/USDT), a pair
|
|
116
|
+
* with no venue, and a slash on a stock exchange, which is a share class (BRK/B).
|
|
117
|
+
*/
|
|
118
|
+
export function exchangeLineCoinListing(
|
|
119
|
+
symbol: string,
|
|
120
|
+
exchange?: string,
|
|
121
|
+
{ coinRow = false }: { coinRow?: boolean } = {},
|
|
122
|
+
): { symbol: string; exchange: "CCC"; currency: string } | null {
|
|
123
|
+
const parsed = parsePublicTickerKey(symbol);
|
|
124
|
+
const listing = slashCoinPairListing(parsed.symbol);
|
|
125
|
+
if (!listing) return null;
|
|
126
|
+
const named = (parsed.exchange ?? exchange ?? "").trim().toUpperCase();
|
|
127
|
+
const venue = canonicalExchange(named);
|
|
128
|
+
if (COIN_EXCHANGES.has(named) || COIN_EXCHANGES.has(venue)) return listing;
|
|
129
|
+
if (!coinRow || !venue || NOT_COIN_VENUES.has(named) || NOT_COIN_VENUES.has(venue)) return null;
|
|
130
|
+
// The crypto venues trade around the clock; a venue the app knows that does not is a stock exchange.
|
|
131
|
+
return isKnownExchangeCode(venue) && EXCHANGE_TIME_ZONES[venue] !== "UTC" ? null : listing;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* A coin pair typed with a slash (btc/gbp) as the crypto venue's listing of it, BTC-GBP on CCC; with a venue
|
|
136
|
+
* (BTC/GBP:KRAKEN), as that exchange's line reads (exchangeLineCoinListing). Null for a currency pair, a spot
|
|
137
|
+
* commodity (wti/usd) and a pair the venue quotes in no such currency.
|
|
138
|
+
*/
|
|
139
|
+
export function typedCoinPairListing(query: string): { symbol: string; exchange: "CCC"; currency: string } | null {
|
|
140
|
+
const parsed = parsePublicTickerKey(query.trim().toUpperCase());
|
|
141
|
+
return parsed.exchange ? exchangeLineCoinListing(parsed.symbol, parsed.exchange) : slashCoinPairListing(parsed.symbol);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Search rows with each crypto exchange's line of a coin pair (ETH/EUR on KRAKEN, COINBASE PRO, BITSTAMP and
|
|
146
|
+
* BINANCE) as the crypto venue's one listing of it, ETH-EUR on CCC in euros, where the first line stood. A pair
|
|
147
|
+
* already offered on the venue is not offered twice. Newer servers send the listing themselves.
|
|
148
|
+
*/
|
|
149
|
+
export function withExchangeLinesAsCoinListings<T extends { symbol: string; exchange: string; type: string; currency?: string; brokerContract?: unknown }>(rows: T[]): T[] {
|
|
150
|
+
const offered = new Set(rows.filter((row) => canonicalExchange(row.exchange) === "CCC").map((row) => row.symbol.trim().toUpperCase()));
|
|
151
|
+
let changed = false;
|
|
152
|
+
const mapped = rows.flatMap((row) => {
|
|
153
|
+
const coin = !row.brokerContract && isCoinRowType(row.type) ? exchangeLineCoinListing(row.symbol, row.exchange, { coinRow: true }) : null;
|
|
154
|
+
if (!coin) return [row];
|
|
155
|
+
changed = true;
|
|
156
|
+
if (offered.has(coin.symbol)) return [];
|
|
157
|
+
offered.add(coin.symbol);
|
|
158
|
+
return [{ ...row, symbol: coin.symbol, exchange: coin.exchange, currency: row.currency || coin.currency }];
|
|
159
|
+
});
|
|
160
|
+
return changed ? mapped : rows;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Whether a search row's type says it is a coin (CRYPTOCURRENCY, Digital Currency). */
|
|
164
|
+
export function isCoinRowType(type: string | undefined): boolean {
|
|
165
|
+
return /CRYPTO|DIGITAL|COIN/i.test(type ?? "");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** The currency or coin a pair on the crypto venue is quoted in: GBP for BTC-GBP; null for anything else. */
|
|
169
|
+
export function coinPairQuoteCurrency(symbol: string): string | null {
|
|
170
|
+
const match = /^([A-Z0-9]{1,15})-([A-Z]{3})$/.exec(parsePublicTickerKey(symbol).symbol);
|
|
171
|
+
return match && !isIsoCurrencyCode(match[1]!) && VENUE_QUOTE_LEGS.has(match[2]!) ? match[2]! : null;
|
|
172
|
+
}
|
|
173
|
+
|
|
61
174
|
// A base-quote pair such as BTC-USD or SOL-EUR. Equities with a share-class dash (BRK-B) and
|
|
62
175
|
// currency pairs (EURUSD=X) do not match.
|
|
63
|
-
const CRYPTO_PAIR = /^[A-Z0-9]{1,15}-(?:USD|EUR|GBP|USDT|USDC|BTC)$/;
|
|
176
|
+
const CRYPTO_PAIR = /^[A-Z0-9]{1,15}-(?:USD|EUR|GBP|JPY|KRW|CAD|INR|CNY|AUD|USDT|USDC|BTC|ETH)$/;
|
|
64
177
|
|
|
65
178
|
/**
|
|
66
179
|
* Wider than isUsdCoinPair, for the hint under a pair that will not load: it
|
|
@@ -135,9 +248,10 @@ export const TOP_COIN_NAMES: ReadonlyMap<string, string> = new Map([
|
|
|
135
248
|
["RENDER", "render"],
|
|
136
249
|
]);
|
|
137
250
|
|
|
138
|
-
const COIN_PAIR = /^([A-Z0-9]{1,15})[-/](?:USD|EUR|GBP|USDT|USDC|BTC)$/;
|
|
251
|
+
const COIN_PAIR = /^([A-Z0-9]{1,15})[-/](?:USD|EUR|GBP|JPY|KRW|CAD|INR|CNY|AUD|USDT|USDC|BTC|ETH)$/;
|
|
139
252
|
// What a pair's listing name adds after the coin's: its quote currency, an id in brackets.
|
|
140
|
-
|
|
253
|
+
// Not ETH, which ends coins' own names (Lido Staked ETH).
|
|
254
|
+
const PAIR_NAME_SUFFIX = /(?:\s*\([^)]*\))+$|\s+(?:USD|EUR|GBP|JPY|KRW|CAD|INR|CNY|AUD|USDT|USDC|BTC|US Dollars?)$/i;
|
|
141
255
|
|
|
142
256
|
/**
|
|
143
257
|
* The coin a crypto pair trades, as stories name it: "bitcoin" for BTC-USD
|
|
@@ -34,6 +34,6 @@ export function declaredDividends(
|
|
|
34
34
|
const at = Date.parse(`${exDate}T00:00:00Z`);
|
|
35
35
|
if (paid.some((time) => Math.abs(time - at) <= SAME_DISTRIBUTION_DAYS * DAY_MS)) return [];
|
|
36
36
|
return [{ exDate, amount: row.amount, ...declarationDate ? { declarationDate } : {},
|
|
37
|
-
...recordDate ? { recordDate } : {}, ...payDate ? { payDate } : {} }];
|
|
37
|
+
...recordDate ? { recordDate } : {}, ...payDate ? { payDate } : {}, ...row.special === true ? { special: true as const } : {} }];
|
|
38
38
|
}).sort((left, right) => left.exDate.localeCompare(right.exDate));
|
|
39
39
|
}
|
|
@@ -2,6 +2,7 @@ import { formatFxRate } from "../cli/fx-pair";
|
|
|
2
2
|
import type { EnterpriseValueCheck, Fundamentals, Quote, TickerFinancials } from "../types/financials";
|
|
3
3
|
import { quotedFxPair } from "./currency-pair";
|
|
4
4
|
import { resolveCurrencyUnit } from "./currency-units";
|
|
5
|
+
import { isUsListingExchange } from "./exchanges";
|
|
5
6
|
import { formatCompact } from "./format";
|
|
6
7
|
import { formatUtcTime } from "./utc-time";
|
|
7
8
|
|
|
@@ -119,24 +120,53 @@ export function computedEnterpriseValueNote(fundamentals: Parameters<typeof ente
|
|
|
119
120
|
}
|
|
120
121
|
|
|
121
122
|
/** What names the currency of the trailing figures: the fundamentals' own labels, else the statements' on a listing that trades in theirs. */
|
|
122
|
-
type FundamentalsCurrencies = Pick<TickerFinancials, "financialCurrency"> & {
|
|
123
|
+
type FundamentalsCurrencies = Pick<TickerFinancials, "financialCurrency" | "statementHistory"> & {
|
|
123
124
|
fundamentals?: Pick<Fundamentals, "financialCurrency" | "epsCurrency" | "marketCapCurrency"> | null;
|
|
124
|
-
quote?: Pick<Quote, "currency"> | null;
|
|
125
|
+
quote?: Pick<Quote, "currency" | "exchangeName" | "listingExchangeName" | "isDepositaryReceipt"> | null;
|
|
125
126
|
};
|
|
126
127
|
|
|
128
|
+
/** What a caller knows of the listing beyond its quote: the day it listed (its IPO's), when known. */
|
|
129
|
+
interface ListingAge {
|
|
130
|
+
listedSince?: string | null;
|
|
131
|
+
now?: Date;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** A listing that started within about a year: its statements may not be served yet. */
|
|
135
|
+
const RECENT_LISTING_DAYS = 372;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* The listing's own currency, standing in for figures with no statements to tell their currency by: only for a
|
|
139
|
+
* listing of the last year or so (a recent IPO such as HAWK) or a US listing in dollars that is no receipt, and
|
|
140
|
+
* never after a statements read that failed. A minor unit (GBp) does not say whether figures are pence or pounds.
|
|
141
|
+
*/
|
|
142
|
+
function listingCurrencyFallback(financials: FundamentalsCurrencies | null | undefined, listing: ListingAge): string | undefined {
|
|
143
|
+
const listed = financials?.fundamentals?.marketCapCurrency?.trim() || financials?.quote?.currency?.trim();
|
|
144
|
+
if (!listed || resolveCurrencyUnit(listed).divisor !== 1) return undefined;
|
|
145
|
+
if (financials?.statementHistory?.status === "retryable-failure") return undefined;
|
|
146
|
+
const currency = resolveCurrencyUnit(listed).currency;
|
|
147
|
+
const since = listing.listedSince ? Date.parse(`${listing.listedSince.slice(0, 10)}T00:00:00Z`) : NaN;
|
|
148
|
+
const recent = Number.isFinite(since) && (listing.now ?? new Date()).getTime() - since <= RECENT_LISTING_DAYS * 86_400_000;
|
|
149
|
+
const quote = financials?.quote;
|
|
150
|
+
const home = currency === "USD" && quote?.isDepositaryReceipt !== true
|
|
151
|
+
&& isUsListingExchange(quote?.listingExchangeName || quote?.exchangeName);
|
|
152
|
+
return recent || home ? currency : undefined;
|
|
153
|
+
}
|
|
154
|
+
|
|
127
155
|
/**
|
|
128
156
|
* The currency of the trailing EPS, revenue, income and cash flows: the one the fundamentals declare for themselves.
|
|
129
157
|
* A block that declares none is in the statements' currency only when the listing trades in it; on a listing quoted
|
|
130
158
|
* in another (a receipt in USD beside TWD books, YPFD in ARS beside USD statements) its currency is unknown, since
|
|
131
|
-
* Gloom Cloud labels every block whose currency it can tell.
|
|
159
|
+
* Gloom Cloud labels every block whose currency it can tell. With no statements to tell by, the listing's own
|
|
160
|
+
* currency where that is safe (listingCurrencyFallback).
|
|
132
161
|
*/
|
|
133
162
|
export function fundamentalsCurrency(
|
|
134
163
|
financials: FundamentalsCurrencies | null | undefined,
|
|
164
|
+
listing: ListingAge = {},
|
|
135
165
|
): string | undefined {
|
|
136
166
|
const declared = financials?.fundamentals?.financialCurrency?.trim();
|
|
137
167
|
if (declared) return declared;
|
|
138
168
|
const statements = financials?.financialCurrency?.trim();
|
|
139
|
-
if (!statements) return
|
|
169
|
+
if (!statements) return listingCurrencyFallback(financials, listing);
|
|
140
170
|
const listed = financials?.fundamentals?.marketCapCurrency?.trim() || financials?.quote?.currency?.trim();
|
|
141
171
|
return !listed || resolveCurrencyUnit(listed).currency === resolveCurrencyUnit(statements).currency ? statements : undefined;
|
|
142
172
|
}
|
|
@@ -147,8 +177,9 @@ export function fundamentalsCurrency(
|
|
|
147
177
|
*/
|
|
148
178
|
export function fundamentalsEpsCurrency(
|
|
149
179
|
financials: FundamentalsCurrencies | null | undefined,
|
|
180
|
+
listing: ListingAge = {},
|
|
150
181
|
): string | undefined {
|
|
151
|
-
return financials?.fundamentals?.epsCurrency?.trim() || fundamentalsCurrency(financials);
|
|
182
|
+
return financials?.fundamentals?.epsCurrency?.trim() || fundamentalsCurrency(financials, listing);
|
|
152
183
|
}
|
|
153
184
|
|
|
154
185
|
const ISO_DAY = /^\d{4}-\d{2}-\d{2}$/;
|
package/src/version.ts
CHANGED
|
@@ -3,7 +3,7 @@ import packageJson from "../package.json" with { type: "json" };
|
|
|
3
3
|
export const VERSION = packageJson.version;
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* The npm package this copy came from:
|
|
7
|
-
*
|
|
6
|
+
* The npm package this copy came from: `@gloom-sh/terminal` or `gloomberb`,
|
|
7
|
+
* which every release publishes with the same build.
|
|
8
8
|
*/
|
|
9
9
|
export const PACKAGE_NAME = packageJson.name;
|