gloomberb 0.19.0 → 0.19.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/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/package.json +2 -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/errors.ts +38 -0
- 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/app/runtime/startup.ts +3 -1
- package/src/architecture/core-builtin-allowlist.json +2 -2
- package/src/capabilities/chart-series.ts +2 -1
- package/src/cli/commands/market.ts +44 -16
- package/src/cli/commands/news-search.ts +22 -0
- package/src/cli/commands/overview.ts +84 -19
- package/src/cli/commands/search.ts +13 -13
- package/src/cli/commands/ticker.ts +32 -2
- package/src/cli/context.ts +1 -0
- package/src/cli/errors.ts +17 -2
- package/src/cli/glossary.ts +8 -1
- package/src/cli/history-rows.ts +35 -7
- package/src/cli/index-roots.ts +0 -7
- package/src/cli/known-gaps.ts +11 -0
- package/src/cli/listing-arg.ts +74 -11
- 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 +30 -7
- 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 +29 -8
- package/src/components/command-bar/selection-runtime.ts +64 -32
- package/src/components/command-bar/surface/index.tsx +2 -0
- package/src/components/layout/detached-pane-shell.tsx +2 -2
- package/src/components/layout/header.tsx +2 -2
- package/src/components/layout/pane/capture-stamp.ts +2 -2
- package/src/components/layout/pane/footer/index.tsx +23 -6
- package/src/components/layout/pane/footer/model.ts +116 -16
- package/src/components/layout/pane/header.tsx +2 -2
- package/src/components/layout/pane/status-footer.ts +37 -3
- package/src/components/layout/status-widget-space.ts +9 -0
- package/src/components/onboarding/onboarding-frame.tsx +2 -1
- package/src/components/onboarding/onboarding-wizard.tsx +6 -3
- package/src/components/ticker/list-table-view.tsx +4 -20
- package/src/components/ui/display.tsx +29 -3
- package/src/components/ui/icon.tsx +12 -3
- package/src/core/app-services.ts +11 -2
- package/src/data/app-persistence.ts +9 -7
- package/src/data/plugin-cache.ts +20 -3
- package/src/data/plugin-state-store.ts +81 -24
- package/src/data/resource-store.ts +130 -58
- package/src/data/saved-copies.ts +8 -0
- package/src/data/session-store.ts +31 -8
- package/src/data/sqlite/access.ts +313 -0
- package/src/data/sqlite/checkpointer.ts +198 -0
- package/src/data/sqlite/database.ts +47 -4
- package/src/data/sqlite/retry.ts +50 -9
- package/src/data/ticker-store.ts +57 -23
- 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/market-data/realized-volatility.ts +4 -2
- package/src/news/aggregator.ts +7 -1
- package/src/news/types.ts +6 -0
- package/src/plugins/auto-update-node.ts +10 -6
- 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/central-bank-rates/series.ts +2 -3
- package/src/plugins/builtin/chart-composer/cli-options.ts +16 -0
- package/src/plugins/builtin/chart-composer/follow-binding.ts +14 -2
- package/src/plugins/builtin/chart-composer/headless-schema.ts +5 -0
- package/src/plugins/builtin/chart-composer/index.tsx +4 -5
- package/src/plugins/builtin/chart-composer/pane.tsx +5 -1
- package/src/plugins/builtin/chart-composer/session-range.ts +5 -2
- 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/commodity-balances/client.ts +4 -1
- 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/cot/client.ts +28 -2
- package/src/plugins/builtin/cot/headless.ts +4 -1
- package/src/plugins/builtin/cot/index.tsx +4 -2
- package/src/plugins/builtin/cot/model.ts +58 -7
- package/src/plugins/builtin/cot/pane.tsx +6 -2
- package/src/plugins/builtin/cpi/client.ts +6 -5
- package/src/plugins/builtin/credit-boards/series.ts +3 -4
- package/src/plugins/builtin/credit-conditions/client.ts +22 -14
- package/src/plugins/builtin/credit-documents/headless.ts +3 -3
- package/src/plugins/builtin/crypto-board/client.ts +5 -5
- package/src/plugins/builtin/crypto-board/series.ts +4 -4
- package/src/plugins/builtin/debt-maturities/series.ts +3 -3
- package/src/plugins/builtin/doe/client.ts +6 -5
- package/src/plugins/builtin/doe/headless.ts +3 -2
- package/src/plugins/builtin/doe/pane.tsx +13 -3
- package/src/plugins/builtin/doe/prices.ts +2 -3
- package/src/plugins/builtin/doe/series.ts +4 -4
- package/src/plugins/builtin/earnings-calls/calendar.tsx +10 -2
- package/src/plugins/builtin/earnings-calls/data.ts +37 -17
- package/src/plugins/builtin/earnings-calls/headless.ts +13 -3
- package/src/plugins/builtin/earnings-calls/pane.tsx +34 -14
- 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 +18 -4
- 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/executives/data.ts +6 -1
- package/src/plugins/builtin/executives/pane.tsx +9 -21
- package/src/plugins/builtin/fear-greed/cache.ts +4 -0
- package/src/plugins/builtin/fear-greed/series.ts +6 -4
- package/src/plugins/builtin/gpu/client.ts +4 -1
- package/src/plugins/builtin/gpu/series.ts +2 -3
- 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 +4 -2
- 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/jodi/client.ts +4 -1
- 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 +3 -0
- package/src/plugins/builtin/market-movers/headless.ts +3 -1
- package/src/plugins/builtin/market-movers/index.tsx +10 -5
- package/src/plugins/builtin/market-movers/screener.ts +27 -6
- package/src/plugins/builtin/market-movers/session-body.tsx +2 -1
- package/src/plugins/builtin/mna/headless.ts +2 -0
- package/src/plugins/builtin/mna/pane.tsx +3 -1
- package/src/plugins/builtin/money-markets/series.ts +3 -5
- 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/power/gas-client.ts +2 -1
- package/src/plugins/builtin/power/prices-client.ts +3 -2
- 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 +12 -6
- package/src/plugins/builtin/risk-factors/headless.ts +5 -2
- package/src/plugins/builtin/risk-factors/index.tsx +3 -1
- package/src/plugins/builtin/risk-factors/pane.tsx +5 -8
- package/src/plugins/builtin/roadmap/index.tsx +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/scanner/lock-note.ts +26 -3
- 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 +20 -7
- package/src/plugins/builtin/shared/fred-points.ts +6 -1
- package/src/plugins/builtin/shared/headless-market-data.ts +2 -2
- package/src/plugins/builtin/shared/pro-lock-note.ts +23 -8
- 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/shared/series-warning.ts +13 -4
- package/src/plugins/builtin/short-volume/series.ts +2 -3
- package/src/plugins/builtin/social-mentions/client.ts +15 -10
- package/src/plugins/builtin/social-mentions/series.ts +2 -3
- package/src/plugins/builtin/thirteenf/api.ts +15 -9
- package/src/plugins/builtin/thirteenf/data.ts +39 -11
- package/src/plugins/builtin/thirteenf/headless.ts +31 -4
- package/src/plugins/builtin/thirteenf/overlap-pane.tsx +5 -1
- package/src/plugins/builtin/thirteenf/pane.tsx +21 -5
- package/src/plugins/builtin/thirteenf/types.ts +2 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +5 -2
- package/src/plugins/builtin/ticker-detail/financials/model.ts +35 -2
- package/src/plugins/builtin/ticker-detail/financials/ratios.ts +53 -18
- package/src/plugins/builtin/ticker-detail/headless.ts +59 -8
- 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/cache.ts +20 -8
- package/src/plugins/builtin/treasury-auctions/client.ts +3 -3
- package/src/plugins/builtin/treasury-auctions/headless.ts +24 -13
- package/src/plugins/builtin/treasury-auctions/pane.tsx +18 -6
- package/src/plugins/builtin/volatility/client.ts +43 -16
- package/src/plugins/builtin/volatility/headless.ts +5 -2
- package/src/plugins/builtin/volatility/model.ts +17 -6
- package/src/plugins/builtin/volatility/pane.tsx +11 -4
- package/src/plugins/builtin/volatility/series.ts +2 -1
- package/src/plugins/builtin/yield-curve/client.ts +59 -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/plugins/installer.ts +50 -39
- package/src/portfolio/column-values.ts +11 -7
- package/src/renderers/dom/desktop/icons.tsx +10 -2
- package/src/renderers/electrobun/bun/desktop/backend.ts +9 -10
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +23 -1
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +8 -0
- package/src/renderers/electrobun/bun/desktop/initialization.ts +9 -1
- 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/attention.ts +54 -0
- package/src/renderers/electrobun/bun/window/create.ts +45 -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/launcher/preload.ts +13 -0
- package/src/renderers/electrobun/launcher/windows-emulation.ts +50 -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 +16 -1
- package/src/series/resolve.ts +2 -1
- package/src/series/types.ts +5 -0
- package/src/sources/gloomberb-cloud/fred-series.ts +8 -4
- package/src/sources/gloomberb-cloud/index.ts +42 -8
- package/src/telemetry/stall-reports-node.ts +13 -2
- package/src/telemetry/stall-reports.ts +189 -13
- package/src/test-support/outage.ts +8 -0
- package/src/tickers/company-name-listing.ts +110 -40
- package/src/tickers/company-name.ts +71 -2
- package/src/tickers/index-roots.ts +7 -0
- package/src/tickers/listing-fate.ts +2 -2
- package/src/tickers/search/home-listing.ts +93 -8
- package/src/tickers/search/index.ts +7 -3
- 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/time-series/market.ts +5 -3
- package/src/time-series/price-comparison.ts +20 -2
- package/src/time-series/resolve.ts +20 -1
- package/src/time-series/types.ts +7 -0
- package/src/types/company-from.ts +40 -0
- package/src/types/data-provider.ts +7 -0
- package/src/types/financials.ts +45 -3
- package/src/types/headless.ts +6 -0
- package/src/ui/host.tsx +6 -1
- package/src/utils/crypto-pair.ts +121 -7
- package/src/utils/declared-dividends.ts +1 -1
- package/src/utils/financial-statements.ts +73 -16
- package/src/utils/fundamentals.ts +53 -10
- package/src/utils/lease-liabilities.ts +54 -0
- package/src/utils/main-thread-stall.ts +47 -2
- package/src/utils/perf-marks.ts +23 -11
- package/src/utils/price-history-integrity.ts +47 -1
- package/src/version.ts +2 -2
package/src/data/ticker-store.ts
CHANGED
|
@@ -1,27 +1,47 @@
|
|
|
1
1
|
import type { Database } from "bun:sqlite";
|
|
2
|
+
import { createSqliteAccess, type SqliteAccess } from "./sqlite/access";
|
|
2
3
|
import { serializeJson } from "./sqlite/json";
|
|
3
|
-
import { withSqliteBusyRetry } from "./sqlite/retry";
|
|
4
4
|
|
|
5
5
|
export interface StoredTickerRecord {
|
|
6
6
|
symbol: string;
|
|
7
7
|
metadata: string;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
/** A queued write's row (null metadata for a delete), one object per write. */
|
|
11
|
+
interface PendingTicker {
|
|
12
|
+
metadata: string | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
10
15
|
export class TickerStore {
|
|
11
|
-
|
|
16
|
+
/** Writes queued behind another program's lock, by symbol, read back until they land. */
|
|
17
|
+
private readonly pending = new Map<string, PendingTicker>();
|
|
18
|
+
|
|
19
|
+
constructor(
|
|
20
|
+
private readonly db: Database,
|
|
21
|
+
private readonly access: SqliteAccess = createSqliteAccess(db),
|
|
22
|
+
) {}
|
|
12
23
|
|
|
13
24
|
getAll(): StoredTickerRecord[] {
|
|
14
|
-
|
|
25
|
+
const rows = this.access.run("load tickers", () => (
|
|
15
26
|
this.db
|
|
16
27
|
.query<StoredTickerRecord, []>(
|
|
17
28
|
"SELECT symbol, metadata FROM tickers ORDER BY symbol",
|
|
18
29
|
)
|
|
19
30
|
.all()
|
|
20
31
|
));
|
|
32
|
+
if (this.pending.size === 0) return rows;
|
|
33
|
+
const bySymbol = new Map(rows.map((row) => [row.symbol, row]));
|
|
34
|
+
for (const [symbol, { metadata }] of this.pending) {
|
|
35
|
+
if (metadata == null) bySymbol.delete(symbol);
|
|
36
|
+
else bySymbol.set(symbol, { symbol, metadata });
|
|
37
|
+
}
|
|
38
|
+
return [...bySymbol.values()].sort((a, b) => (a.symbol < b.symbol ? -1 : a.symbol > b.symbol ? 1 : 0));
|
|
21
39
|
}
|
|
22
40
|
|
|
23
41
|
get(symbol: string): string | null {
|
|
24
|
-
const
|
|
42
|
+
const pending = this.pending.get(symbol);
|
|
43
|
+
if (pending) return pending.metadata;
|
|
44
|
+
const row = this.access.run("load ticker", () => (
|
|
25
45
|
this.db
|
|
26
46
|
.query<{ metadata: string }, [string]>(
|
|
27
47
|
"SELECT metadata FROM tickers WHERE symbol = ?",
|
|
@@ -32,34 +52,48 @@ export class TickerStore {
|
|
|
32
52
|
}
|
|
33
53
|
|
|
34
54
|
save(symbol: string, metadata: unknown): void {
|
|
35
|
-
|
|
36
|
-
this.db
|
|
37
|
-
.query(
|
|
38
|
-
`INSERT OR REPLACE INTO tickers (symbol, metadata, updated_at)
|
|
39
|
-
VALUES (?, ?, ?)`,
|
|
40
|
-
)
|
|
41
|
-
.run(symbol, serializeJson(metadata), Date.now());
|
|
42
|
-
});
|
|
55
|
+
this.saveMany([{ symbol, metadata }]);
|
|
43
56
|
}
|
|
44
57
|
|
|
45
58
|
/** Saves every record in one transaction: one write for a whole import, not one per ticker. */
|
|
46
59
|
saveMany(records: ReadonlyArray<{ symbol: string; metadata: unknown }>): void {
|
|
47
60
|
if (records.length === 0) return;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
61
|
+
const rows = records.map((record) => ({ symbol: record.symbol, metadata: serializeJson(record.metadata) }));
|
|
62
|
+
const now = Date.now();
|
|
63
|
+
this.write(
|
|
64
|
+
rows.length === 1 ? "save ticker" : "save tickers",
|
|
65
|
+
rows.map((row) => [row.symbol, { metadata: row.metadata }]),
|
|
66
|
+
() => {
|
|
67
|
+
const statement = this.db.query(
|
|
68
|
+
`INSERT OR REPLACE INTO tickers (symbol, metadata, updated_at)
|
|
69
|
+
VALUES (?, ?, ?)`,
|
|
70
|
+
);
|
|
71
|
+
this.db.transaction(() => {
|
|
72
|
+
for (const row of rows) statement.run(row.symbol, row.metadata, now);
|
|
73
|
+
})();
|
|
74
|
+
},
|
|
75
|
+
);
|
|
58
76
|
}
|
|
59
77
|
|
|
60
78
|
delete(symbol: string): void {
|
|
61
|
-
|
|
79
|
+
this.write("delete ticker", [[symbol, { metadata: null }]], () => {
|
|
62
80
|
this.db.query("DELETE FROM tickers WHERE symbol = ?").run(symbol);
|
|
63
81
|
});
|
|
64
82
|
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Runs `statement` through the write queue, reading `entries` back until it
|
|
86
|
+
* lands. A write of one row replaces a queued write of the same row.
|
|
87
|
+
*/
|
|
88
|
+
private write(operationName: string, entries: Array<[string, PendingTicker]>, statement: () => void): void {
|
|
89
|
+
for (const [symbol, entry] of entries) this.pending.set(symbol, entry);
|
|
90
|
+
this.access.write(operationName, statement, {
|
|
91
|
+
...(entries.length === 1 ? { key: `tickers\u0000${entries[0]![0]}` } : {}),
|
|
92
|
+
settled: () => {
|
|
93
|
+
for (const [symbol, entry] of entries) {
|
|
94
|
+
if (this.pending.get(symbol) === entry) this.pending.delete(symbol);
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
}
|
|
65
99
|
}
|
package/src/docs/snapshot.json
CHANGED
|
@@ -1684,6 +1684,13 @@
|
|
|
1684
1684
|
"category": "app",
|
|
1685
1685
|
"lesson": "/academy/terminal-and-workspace/how-the-terminal-works/help-cards"
|
|
1686
1686
|
},
|
|
1687
|
+
{
|
|
1688
|
+
"code": "ROADMAP",
|
|
1689
|
+
"name": "Roadmap",
|
|
1690
|
+
"description": "What is coming next",
|
|
1691
|
+
"detail": "What is being built, what is planned and what shipped, with each item's votes. Pro members vote on what is building or planned, once per item, and can take the vote back.",
|
|
1692
|
+
"category": "app"
|
|
1693
|
+
},
|
|
1687
1694
|
{
|
|
1688
1695
|
"code": "HELP",
|
|
1689
1696
|
"name": "Help",
|
|
@@ -1799,7 +1806,7 @@
|
|
|
1799
1806
|
},
|
|
1800
1807
|
{
|
|
1801
1808
|
"type": "code",
|
|
1802
|
-
"code": "bun install -g
|
|
1809
|
+
"code": "bun install -g @gloom-sh/terminal"
|
|
1803
1810
|
},
|
|
1804
1811
|
{
|
|
1805
1812
|
"type": "heading",
|
|
@@ -1853,10 +1860,14 @@
|
|
|
1853
1860
|
],
|
|
1854
1861
|
[
|
|
1855
1862
|
"Bun",
|
|
1856
|
-
"`bun install -g
|
|
1863
|
+
"`bun install -g @gloom-sh/terminal@latest`"
|
|
1857
1864
|
]
|
|
1858
1865
|
]
|
|
1859
1866
|
},
|
|
1867
|
+
{
|
|
1868
|
+
"type": "paragraph",
|
|
1869
|
+
"text": "An existing `gloomberb` install keeps updating as it is."
|
|
1870
|
+
},
|
|
1860
1871
|
{
|
|
1861
1872
|
"type": "paragraph",
|
|
1862
1873
|
"text": "Installed before 0.18.4, when the command was `gloomberb`? Updating adds `gloom` beside it and `gloomberb` keeps working, with nothing to reinstall."
|
|
@@ -5469,7 +5480,7 @@
|
|
|
5469
5480
|
"functions",
|
|
5470
5481
|
"screenshots"
|
|
5471
5482
|
],
|
|
5472
|
-
"updatedAt": "2026-10-
|
|
5483
|
+
"updatedAt": "2026-10-27",
|
|
5473
5484
|
"blocks": [
|
|
5474
5485
|
{
|
|
5475
5486
|
"type": "paragraph",
|
|
@@ -5641,8 +5652,8 @@
|
|
|
5641
5652
|
"Ticker and quick notes"
|
|
5642
5653
|
],
|
|
5643
5654
|
[
|
|
5644
|
-
"`alerts list`, `alerts add
|
|
5645
|
-
"Price alerts"
|
|
5655
|
+
"`alerts list`, `alerts add ...`, `alerts delete|rearm <id>`",
|
|
5656
|
+
"Price, valuation, daily technical and event alerts, every kind the `ALRT` pane offers; the forms are below"
|
|
5646
5657
|
]
|
|
5647
5658
|
]
|
|
5648
5659
|
},
|
|
@@ -5650,6 +5661,22 @@
|
|
|
5650
5661
|
"type": "paragraph",
|
|
5651
5662
|
"text": "[Portfolios and rebalancing](/docs/portfolio) walks through targets and the drift table. `CASH` in `portfolio target` is the cash line; `portfolio add` and `position set` refuse a bare `CASH` (the stock is `CASH:NASDAQ`). `portfolio` and `watchlist` write immediately and ignore `--dry-run`. Sign-in, account management and chat are app-only."
|
|
5652
5663
|
},
|
|
5664
|
+
{
|
|
5665
|
+
"type": "paragraph",
|
|
5666
|
+
"text": "The alerts commands, as `gloom help alerts` lists them:"
|
|
5667
|
+
},
|
|
5668
|
+
{
|
|
5669
|
+
"type": "code",
|
|
5670
|
+
"code": "gloom alerts list\ngloom alerts add <symbol> <above|below|crosses> <price>\ngloom alerts add <symbol> <pe|ps|rsi(14)> <above|below> <level>\ngloom alerts add <symbol> ma(50) crosses <above|below> ma(200)\ngloom alerts add <symbol> closes <above|below> ma(200)\ngloom alerts add <symbol>/<benchmark> <above|below|crosses> <ratio>\ngloom alerts add <symbol> rrg <leading|weakening|lagging|improving> [--benchmark <symbol>]\ngloom alerts add <symbol> earnings [--days <n> | results]\ngloom alerts add <calendar event> [--country <code>] [--days <n>]\ngloom alerts add [symbol] news <keyword>\ngloom alerts add [symbol] flow [premium] [calls|puts] [sweeps|blocks]\ngloom alerts add <symbol> <iv|rr> <above|below> <level>\ngloom alerts add <OCC contract> iv spike <points>\ngloom alerts add <symbol> 52-week <high|low>\ngloom alerts add <symbol> unusual volume [<multiple>x]\ngloom alerts add <symbol> filing [8-K|10-K|10-Q|S-1|13D|13D/A|13G|13G/A|6-K|20-F]\ngloom alerts add <symbol> insider [buy|sell]\ngloom alerts add <symbol> short interest [increase|decrease] [<percent>%]\ngloom alerts add <symbol> analyst [upgrade|downgrade]\ngloom alerts add <symbol> hiring [accelerating|slowing]\ngloom alerts add perps <market> <funding|oi|premium|closed-premium> <above|below> <percent>\ngloom alerts add catalyst [type <type> | agency <agency> | country <code>]\ngloom alerts add <symbol> catalyst\ngloom alerts add congress [member name]\ngloom alerts add 13f <fund CIK>\ngloom alerts delete <id>\ngloom alerts rearm <id>"
|
|
5671
|
+
},
|
|
5672
|
+
{
|
|
5673
|
+
"type": "paragraph",
|
|
5674
|
+
"text": "Words none of these forms read are refused with the list of kinds. Adding a rule that already exists names the existing alert's ID and adds nothing, and `rearm` on an alert that has not gone off says it is already active. An RSI or moving-average alert is always saved: it reads the same daily closes `history` shows as final and says when it is first checked."
|
|
5675
|
+
},
|
|
5676
|
+
{
|
|
5677
|
+
"type": "paragraph",
|
|
5678
|
+
"text": "`alerts list` shows each alert's listing with its currency, its last reading with when it is from (or `not checked yet`) and when it was created, in ISO 8601 UTC. `alerts list --csv` keeps its columns in order (`id,kind,target,trigger,eventDate,status,lastCheckedPrice,triggeredAt`) and adds `createdAt,listing,currency,lastReading,lastReadingAt` after them. Creating, re-arming and deleting an alert go in the app's alert log beside the alerts that fired (`gloom fn ALRT --tab history`)."
|
|
5679
|
+
},
|
|
5653
5680
|
{
|
|
5654
5681
|
"type": "heading",
|
|
5655
5682
|
"level": 2,
|
package/src/i18n/es.ts
CHANGED
|
@@ -506,10 +506,8 @@ export const es: Record<string, string> = {
|
|
|
506
506
|
"Pin Ticker": "Fijar ticker",
|
|
507
507
|
|
|
508
508
|
// ── Help pane ────────────────────────────────────────────────
|
|
509
|
-
"How To Use Gloom": "Cómo usar Gloom",
|
|
510
509
|
"Not sure of a code? Click the search bar at the top, or press {key}, and type what you want in plain words, like \"top news\". The Functions tab lists everything.": "¿No sabes el código? Haz clic en la barra de búsqueda de arriba, o pulsa {key}, y escribe lo que quieres con tus palabras, como \"top news\". La pestaña Funciones las lista todas.",
|
|
511
510
|
"Not sure of a code? Click the search bar at the top and type what you want in plain words, like \"top news\". The Functions tab lists everything.": "¿No sabes el código? Haz clic en la barra de búsqueda de arriba y escribe lo que quieres con tus palabras, como \"top news\". La pestaña Funciones las lista todas.",
|
|
512
|
-
"Click anything to use it; the keys shown beside actions are shortcuts.": "Haz clic en cualquier cosa para usarla; las teclas junto a las acciones son atajos.",
|
|
513
511
|
"Open Help": "Abrir la ayuda",
|
|
514
512
|
"Command Prefixes": "Prefijos de comandos",
|
|
515
513
|
"Window Templates": "Plantillas de ventana",
|
|
@@ -519,7 +517,6 @@ export const es: Record<string, string> = {
|
|
|
519
517
|
"Scrolling": "Desplazamiento",
|
|
520
518
|
"Open Debug Log": "Abrir registro de depuración",
|
|
521
519
|
"GitHub Issues": "GitHub Issues",
|
|
522
|
-
"Docked panes stay in the saved layout.": "Los paneles anclados permanecen en el diseño guardado.",
|
|
523
520
|
"Floating panes can be dragged by the title bar and resized from the lower-right corner.": "Los paneles flotantes se arrastran por la barra de título y se redimensionan desde la esquina inferior derecha.",
|
|
524
521
|
"Use Layout Actions for split, move, duplicate, close all floating panes, undo, redo, and layout presets.": "Usa Acciones de diseño para dividir, mover, duplicar, cerrar paneles flotantes, deshacer, rehacer y diseños predefinidos.",
|
|
525
522
|
"Move through focused table and list rows.": "Moverse por las filas de tablas y listas activas.",
|
|
@@ -564,7 +561,6 @@ export const es: Record<string, string> = {
|
|
|
564
561
|
"Go back from a nested command screen when the query is empty.": "Volver de una pantalla de comando anidada cuando la consulta está vacía.",
|
|
565
562
|
"Reorder ordered multi-select choices.": "Reordenar opciones de selección múltiple ordenadas.",
|
|
566
563
|
"Submit multiline command forms.": "Enviar formularios de comando multilínea.",
|
|
567
|
-
"Layout Basics": "Fundamentos del diseño",
|
|
568
564
|
|
|
569
565
|
// ── Onboarding ───────────────────────────────────────────────
|
|
570
566
|
"The open terminal for modern finance.": "La terminal abierta para las finanzas modernas.",
|
|
@@ -1672,6 +1668,8 @@ export const es: Record<string, string> = {
|
|
|
1672
1668
|
"Guides": "Guías",
|
|
1673
1669
|
"Academy": "Academia",
|
|
1674
1670
|
"offline, saved copy": "sin conexión, copia guardada",
|
|
1671
|
+
"company data from {listing}": "datos de la empresa de {listing}",
|
|
1672
|
+
"from {listing}": "de {listing}",
|
|
1675
1673
|
"Open in Browser": "Abrir en el navegador",
|
|
1676
1674
|
"No docs match \"{query}\".": "Nada en la documentación coincide con \"{query}\".",
|
|
1677
1675
|
"No docs for {name} yet.": "Aún no hay documentación para {name}.",
|
package/src/i18n/ja.ts
CHANGED
|
@@ -507,10 +507,8 @@ export const ja: Record<string, string> = {
|
|
|
507
507
|
"Pin Ticker": "銘柄を固定",
|
|
508
508
|
|
|
509
509
|
// ── Help pane ────────────────────────────────────────────────
|
|
510
|
-
"How To Use Gloom": "Gloom の使用方法",
|
|
511
510
|
"Not sure of a code? Click the search bar at the top, or press {key}, and type what you want in plain words, like \"top news\". The Functions tab lists everything.": "コードが分からない場合は、上部の検索バーをクリックするか {key} を押し、\"top news\" のように普段の言葉で入力してください。「関数」タブに全機能があります。",
|
|
512
511
|
"Not sure of a code? Click the search bar at the top and type what you want in plain words, like \"top news\". The Functions tab lists everything.": "コードが分からない場合は、上部の検索バーをクリックし、\"top news\" のように普段の言葉で入力してください。「関数」タブに全機能があります。",
|
|
513
|
-
"Click anything to use it; the keys shown beside actions are shortcuts.": "どこでもクリックして操作できます。操作の横に表示されるキーはショートカットです。",
|
|
514
512
|
"Open Help": "ヘルプを開く",
|
|
515
513
|
"Command Prefixes": "コマンド接頭辞",
|
|
516
514
|
"Window Templates": "ウィンドウ テンプレート",
|
|
@@ -520,7 +518,6 @@ export const ja: Record<string, string> = {
|
|
|
520
518
|
"Scrolling": "スクロール",
|
|
521
519
|
"Open Debug Log": "デバッグ ログを開く",
|
|
522
520
|
"GitHub Issues": "GitHub Issues",
|
|
523
|
-
"Docked panes stay in the saved layout.": "ドッキングされたペインは保存されたレイアウトに残ります。",
|
|
524
521
|
"Floating panes can be dragged by the title bar and resized from the lower-right corner.": "フローティング ペインは、タイトル バーをドラッグして、右下隅からサイズを変更できます。",
|
|
525
522
|
"Use Layout Actions for split, move, duplicate, close all floating panes, undo, redo, and layout presets.": "レイアウト アクションを使用して、分割、移動、複製、すべてのフローティング ペインを閉じる、元に戻す、やり直し、およびレイアウト プリセットを実行します。",
|
|
526
523
|
"Move through focused table and list rows.": "フォーカスされたテーブルとリストの行を移動します。",
|
|
@@ -565,7 +562,6 @@ export const ja: Record<string, string> = {
|
|
|
565
562
|
"Go back from a nested command screen when the query is empty.": "クエリが空の場合、ネストされたコマンド画面から戻ります。",
|
|
566
563
|
"Reorder ordered multi-select choices.": "順序付けされた複数選択の選択肢を並べ替えます。",
|
|
567
564
|
"Submit multiline command forms.": "複数行のコマンド フォームを送信します。",
|
|
568
|
-
"Layout Basics": "レイアウトの基本",
|
|
569
565
|
|
|
570
566
|
// ── Onboarding ───────────────────────────────────────────────
|
|
571
567
|
"The open terminal for modern finance.": "現代の金融に開かれたターミナル。",
|
|
@@ -1668,6 +1664,8 @@ export const ja: Record<string, string> = {
|
|
|
1668
1664
|
"Guides": "ガイド",
|
|
1669
1665
|
"Academy": "アカデミー",
|
|
1670
1666
|
"offline, saved copy": "オフライン、保存済みのコピー",
|
|
1667
|
+
"company data from {listing}": "{listing} の企業データ",
|
|
1668
|
+
"from {listing}": "{listing} から",
|
|
1671
1669
|
"Open in Browser": "ブラウザで開く",
|
|
1672
1670
|
"No docs match \"{query}\".": "「{query}」に一致するドキュメントはありません。",
|
|
1673
1671
|
"No docs for {name} yet.": "{name} のドキュメントはまだありません。",
|
package/src/i18n/ko.ts
CHANGED
|
@@ -505,10 +505,8 @@ export const ko: Record<string, string> = {
|
|
|
505
505
|
"Pin Ticker": "종목 고정",
|
|
506
506
|
|
|
507
507
|
// ── Help pane ────────────────────────────────────────────────
|
|
508
|
-
"How To Use Gloom": "Gloom 사용 방법",
|
|
509
508
|
"Not sure of a code? Click the search bar at the top, or press {key}, and type what you want in plain words, like \"top news\". The Functions tab lists everything.": "코드를 모르겠다면 위쪽 검색창을 클릭하거나 {key}을 누르고 \"top news\"처럼 원하는 것을 평범한 말로 입력하세요. 기능 탭에 전체 목록이 있습니다.",
|
|
510
509
|
"Not sure of a code? Click the search bar at the top and type what you want in plain words, like \"top news\". The Functions tab lists everything.": "코드를 모르겠다면 위쪽 검색창을 클릭하고 \"top news\"처럼 원하는 것을 평범한 말로 입력하세요. 기능 탭에 전체 목록이 있습니다.",
|
|
511
|
-
"Click anything to use it; the keys shown beside actions are shortcuts.": "무엇이든 클릭해서 사용하세요. 동작 옆에 표시된 키는 단축키입니다.",
|
|
512
510
|
"Open Help": "도움말 열기",
|
|
513
511
|
"Command Prefixes": "명령 접두사",
|
|
514
512
|
"Window Templates": "창 템플릿",
|
|
@@ -518,7 +516,6 @@ export const ko: Record<string, string> = {
|
|
|
518
516
|
"Scrolling": "스크롤",
|
|
519
517
|
"Open Debug Log": "디버그 로그 열기",
|
|
520
518
|
"GitHub Issues": "GitHub 이슈",
|
|
521
|
-
"Docked panes stay in the saved layout.": "도킹된 패널은 저장된 레이아웃에 유지됩니다.",
|
|
522
519
|
"Floating panes can be dragged by the title bar and resized from the lower-right corner.": "플로팅 패널은 제목 표시줄로 이동하고 오른쪽 아래에서 크기를 조절할 수 있습니다.",
|
|
523
520
|
"Use Layout Actions for split, move, duplicate, close all floating panes, undo, redo, and layout presets.": "레이아웃 작업에서 분할, 이동, 복제, 플로팅 패널 모두 닫기, 실행 취소, 다시 실행 및 프리셋을 관리합니다.",
|
|
524
521
|
"Move through focused table and list rows.": "포커스된 표와 목록의 행을 이동합니다.",
|
|
@@ -563,7 +560,6 @@ export const ko: Record<string, string> = {
|
|
|
563
560
|
"Go back from a nested command screen when the query is empty.": "쿼리가 비어 있으면 중첩된 명령 화면에서 돌아갑니다.",
|
|
564
561
|
"Reorder ordered multi-select choices.": "순서가 있는 다중 선택 항목을 재정렬합니다.",
|
|
565
562
|
"Submit multiline command forms.": "여러 줄 명령 양식을 제출합니다.",
|
|
566
|
-
"Layout Basics": "레이아웃 기본 사항",
|
|
567
563
|
|
|
568
564
|
// ── Onboarding ───────────────────────────────────────────────
|
|
569
565
|
"The open terminal for modern finance.": "현대 금융을 위한 오픈 소스 터미널.",
|
|
@@ -1666,6 +1662,8 @@ export const ko: Record<string, string> = {
|
|
|
1666
1662
|
"Guides": "가이드",
|
|
1667
1663
|
"Academy": "아카데미",
|
|
1668
1664
|
"offline, saved copy": "오프라인, 저장된 사본",
|
|
1665
|
+
"company data from {listing}": "{listing}의 기업 데이터",
|
|
1666
|
+
"from {listing}": "{listing}에서",
|
|
1669
1667
|
"Open in Browser": "브라우저에서 열기",
|
|
1670
1668
|
"No docs match \"{query}\".": "\"{query}\"와 일치하는 문서가 없습니다.",
|
|
1671
1669
|
"No docs for {name} yet.": "{name} 문서가 아직 없습니다.",
|
package/src/i18n/zh-cn.ts
CHANGED
|
@@ -507,10 +507,8 @@ export const zhCN: Record<string, string> = {
|
|
|
507
507
|
"Pin Ticker": "固定股票",
|
|
508
508
|
|
|
509
509
|
// ── Help pane ────────────────────────────────────────────────
|
|
510
|
-
"How To Use Gloom": "如何使用 Gloom",
|
|
511
510
|
"Not sure of a code? Click the search bar at the top, or press {key}, and type what you want in plain words, like \"top news\". The Functions tab lists everything.": "不知道代码?点击顶部的搜索栏,或按 {key},用日常语言输入你想要的,比如 \"top news\"。“功能”标签列出了全部功能。",
|
|
512
511
|
"Not sure of a code? Click the search bar at the top and type what you want in plain words, like \"top news\". The Functions tab lists everything.": "不知道代码?点击顶部的搜索栏,用日常语言输入你想要的,比如 \"top news\"。“功能”标签列出了全部功能。",
|
|
513
|
-
"Click anything to use it; the keys shown beside actions are shortcuts.": "点击任意内容即可使用;操作旁显示的按键是快捷键。",
|
|
514
512
|
"Open Help": "打开帮助",
|
|
515
513
|
"Command Prefixes": "命令前缀",
|
|
516
514
|
"Window Templates": "窗口模板",
|
|
@@ -520,7 +518,6 @@ export const zhCN: Record<string, string> = {
|
|
|
520
518
|
"Scrolling": "滚动",
|
|
521
519
|
"Open Debug Log": "打开调试日志",
|
|
522
520
|
"GitHub Issues": "GitHub 问题反馈",
|
|
523
|
-
"Docked panes stay in the saved layout.": "停靠面板会保留在已存布局中。",
|
|
524
521
|
"Floating panes can be dragged by the title bar and resized from the lower-right corner.": "浮动面板可拖动标题栏移动,右下角调整大小。",
|
|
525
522
|
"Use Layout Actions for split, move, duplicate, close all floating panes, undo, redo, and layout presets.": "用布局操作完成拆分、移动、复制、关闭全部浮动面板、撤销、重做与布局预设。",
|
|
526
523
|
"Move through focused table and list rows.": "在聚焦的表格与列表行间移动。",
|
|
@@ -565,7 +562,6 @@ export const zhCN: Record<string, string> = {
|
|
|
565
562
|
"Go back from a nested command screen when the query is empty.": "查询为空时从嵌套命令界面返回。",
|
|
566
563
|
"Reorder ordered multi-select choices.": "调整有序多选项的顺序。",
|
|
567
564
|
"Submit multiline command forms.": "提交多行命令表单。",
|
|
568
|
-
"Layout Basics": "布局基础",
|
|
569
565
|
|
|
570
566
|
// ── Onboarding ───────────────────────────────────────────────
|
|
571
567
|
"The open terminal for modern finance.": "面向现代金融的开源终端。",
|
|
@@ -1668,6 +1664,8 @@ export const zhCN: Record<string, string> = {
|
|
|
1668
1664
|
"Guides": "指南",
|
|
1669
1665
|
"Academy": "学院",
|
|
1670
1666
|
"offline, saved copy": "离线,已保存的副本",
|
|
1667
|
+
"company data from {listing}": "公司数据来自 {listing}",
|
|
1668
|
+
"from {listing}": "来自 {listing}",
|
|
1671
1669
|
"Open in Browser": "在浏览器中打开",
|
|
1672
1670
|
"No docs match \"{query}\".": "没有与“{query}”匹配的文档。",
|
|
1673
1671
|
"No docs for {name} yet.": "{name} 暂无文档。",
|
package/src/i18n/zh-tw.ts
CHANGED
|
@@ -507,10 +507,8 @@ export const zhTW: Record<string, string> = {
|
|
|
507
507
|
"Pin Ticker": "固定股票",
|
|
508
508
|
|
|
509
509
|
// ── Help pane ────────────────────────────────────────────────
|
|
510
|
-
"How To Use Gloom": "如何使用 Gloom",
|
|
511
510
|
"Not sure of a code? Click the search bar at the top, or press {key}, and type what you want in plain words, like \"top news\". The Functions tab lists everything.": "不知道代碼?點擊頂部的搜尋列,或按 {key},用日常用語輸入你想要的,例如 \"top news\"。「功能」標籤列出了全部功能。",
|
|
512
511
|
"Not sure of a code? Click the search bar at the top and type what you want in plain words, like \"top news\". The Functions tab lists everything.": "不知道代碼?點擊頂部的搜尋列,用日常用語輸入你想要的,例如 \"top news\"。「功能」標籤列出了全部功能。",
|
|
513
|
-
"Click anything to use it; the keys shown beside actions are shortcuts.": "點擊任何內容即可使用;動作旁顯示的按鍵是快捷鍵。",
|
|
514
512
|
"Open Help": "開啟說明",
|
|
515
513
|
"Command Prefixes": "命令字首",
|
|
516
514
|
"Window Templates": "視窗範本",
|
|
@@ -520,7 +518,6 @@ export const zhTW: Record<string, string> = {
|
|
|
520
518
|
"Scrolling": "捲動",
|
|
521
519
|
"Open Debug Log": "開啟除錯日誌",
|
|
522
520
|
"GitHub Issues": "GitHub 問題回報",
|
|
523
|
-
"Docked panes stay in the saved layout.": "停靠面板會保留在已儲存的版面設定中。",
|
|
524
521
|
"Floating panes can be dragged by the title bar and resized from the lower-right corner.": "拖曳標題列可移動浮動面板,從右下角可調整大小。",
|
|
525
522
|
"Use Layout Actions for split, move, duplicate, close all floating panes, undo, redo, and layout presets.": "用版面設定操作完成拆分、移動、複製、關閉全部浮動面板、撤銷、重做與版面設定預設。",
|
|
526
523
|
"Move through focused table and list rows.": "在目前表格與清單的各列之間移動。",
|
|
@@ -565,7 +562,6 @@ export const zhTW: Record<string, string> = {
|
|
|
565
562
|
"Go back from a nested command screen when the query is empty.": "查詢為空時,從巢狀命令畫面回到上一層。",
|
|
566
563
|
"Reorder ordered multi-select choices.": "調整有序多選項的順序。",
|
|
567
564
|
"Submit multiline command forms.": "提交多行命令表單。",
|
|
568
|
-
"Layout Basics": "版面設定基礎",
|
|
569
565
|
|
|
570
566
|
// ── Onboarding ───────────────────────────────────────────────
|
|
571
567
|
"The open terminal for modern finance.": "現代金融的開源終端機。",
|
|
@@ -1668,6 +1664,8 @@ export const zhTW: Record<string, string> = {
|
|
|
1668
1664
|
"Guides": "指南",
|
|
1669
1665
|
"Academy": "學院",
|
|
1670
1666
|
"offline, saved copy": "離線,已儲存的副本",
|
|
1667
|
+
"company data from {listing}": "公司資料來自 {listing}",
|
|
1668
|
+
"from {listing}": "來自 {listing}",
|
|
1671
1669
|
"Open in Browser": "在瀏覽器中開啟",
|
|
1672
1670
|
"No docs match \"{query}\".": "沒有符合「{query}」的文件。",
|
|
1673
1671
|
"No docs for {name} yet.": "{name} 尚無文件。",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DepositaryPair, Fundamentals, Quote } from "../types/financials";
|
|
1
|
+
import type { CedearRatio, DepositaryPair, Fundamentals, Quote } from "../types/financials";
|
|
2
2
|
import { canonicalExchange, parsePublicTickerKey } from "../utils/exchanges";
|
|
3
3
|
import { formatNumber } from "../utils/format";
|
|
4
4
|
import { formatUtcDayTime } from "../utils/utc-time";
|
|
@@ -41,6 +41,30 @@ export function ratioCount(ratio: number): string {
|
|
|
41
41
|
return Number.isInteger(ratio) ? String(ratio) : String(Number(ratio.toPrecision(6)));
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
type CedearRecords = { quote?: Pick<Quote, "cedearRatio"> | null; fundamentals?: Pick<Fundamentals, "cedearRatio"> | null };
|
|
45
|
+
|
|
46
|
+
const positiveCount = (value: unknown): value is number => typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
47
|
+
|
|
48
|
+
/** A served CEDEAR ratio, when it is whole. */
|
|
49
|
+
function readCedearRatio(value: unknown): CedearRatio | null {
|
|
50
|
+
if (!value || typeof value !== "object") return null;
|
|
51
|
+
const ratio = value as Partial<CedearRatio>;
|
|
52
|
+
if (typeof ratio.listing !== "string" || !ratio.listing.trim()) return null;
|
|
53
|
+
if (typeof ratio.company !== "string" || !ratio.company.trim()) return null;
|
|
54
|
+
if (!positiveCount(ratio.receipts) || !positiveCount(ratio.shares)) return null;
|
|
55
|
+
return ratio as CedearRatio;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** The CEDEAR ratio a listing's records state: the quote's, else the fundamentals'. */
|
|
59
|
+
export function listingCedearRatio(records: CedearRecords | null | undefined): CedearRatio | null {
|
|
60
|
+
return readCedearRatio(records?.quote?.cedearRatio) ?? readCedearRatio(records?.fundamentals?.cedearRatio);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** A CEDEAR's ratio in its company's shares: `20 AAPL:BYMA = 1 Apple Inc. share`. */
|
|
64
|
+
export function cedearRatioText(ratio: CedearRatio): string {
|
|
65
|
+
return `${ratioCount(ratio.receipts)} ${ratio.listing} = ${ratioCount(ratio.shares)} ${ratio.company.trim()} share${ratio.shares === 1 ? "" : "s"}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
44
68
|
/** What a home line says of its receipt: `1 GGAL ADR = 10 of these shares`, and `1 of these shares` for one. */
|
|
45
69
|
function homeLineRatioText(pair: DepositaryPair): string {
|
|
46
70
|
return `1 ${pair.receipt} ADR = ${ratioCount(pair.ratio)} of these shares`;
|
|
@@ -2,6 +2,7 @@ import type { Quote, QuoteMetadata } from "../../types/financials";
|
|
|
2
2
|
import { canonicalExchange, parsePublicTickerKey } from "../../utils/exchanges";
|
|
3
3
|
import { getListingSymbolsToTry } from "../../sources/listing-symbols";
|
|
4
4
|
import { currencyPairCode } from "../../utils/currency-pair";
|
|
5
|
+
import { exchangeLineCoinListing } from "../../utils/crypto-pair";
|
|
5
6
|
|
|
6
7
|
export function quoteMetadataFromQuote(quote: Quote): QuoteMetadata {
|
|
7
8
|
return {
|
|
@@ -44,6 +45,12 @@ export function mergeQuoteMetadata(known: QuoteMetadata | null | undefined, load
|
|
|
44
45
|
|
|
45
46
|
/** Qualified listings must agree; provider suffix spellings use the existing exact-listing normalizer. */
|
|
46
47
|
export function quoteMetadataMatchesTarget(metadata: QuoteMetadata, symbol: string, exchange?: string): boolean {
|
|
48
|
+
// A crypto exchange's line of a pair (BTC/GBP on COINBASE PRO) is priced as the crypto venue's listing, BTC-GBP on
|
|
49
|
+
// CCC, and a quote kept under the line's key is that listing's.
|
|
50
|
+
const line = exchangeLineCoinListing(symbol, exchange);
|
|
51
|
+
if (line) return quoteMetadataMatchesTarget(metadata, line.symbol, line.exchange);
|
|
52
|
+
const quotedLine = exchangeLineCoinListing(metadata.symbol, parsePublicTickerKey(metadata.symbol).exchange ? undefined : metadata.listingExchangeName);
|
|
53
|
+
if (quotedLine) metadata = { ...metadata, symbol: quotedLine.symbol, listingExchangeName: quotedLine.exchange };
|
|
47
54
|
const target = parsePublicTickerKey(symbol);
|
|
48
55
|
const actual = parsePublicTickerKey(metadata.symbol);
|
|
49
56
|
// An index is one series whatever its venue is called: search files ^VIX under CXI and ^RUT under WCB, while
|
|
@@ -3,6 +3,7 @@ import { barsPerYear } from "./bars-per-year";
|
|
|
3
3
|
import {
|
|
4
4
|
mergePriceHistoryIntegrity,
|
|
5
5
|
pricePointIntegrity,
|
|
6
|
+
pricePointWicks,
|
|
6
7
|
type PriceHistoryIntegrity,
|
|
7
8
|
} from "../utils/price-history-integrity";
|
|
8
9
|
|
|
@@ -115,8 +116,9 @@ function observations(points: readonly PricePoint[]): Observation[] | null {
|
|
|
115
116
|
time,
|
|
116
117
|
close: positiveLog(point.close),
|
|
117
118
|
open: positiveLog(point.open),
|
|
118
|
-
|
|
119
|
-
|
|
119
|
+
// A wick too far from the bar's body to have traded is missing, not a range.
|
|
120
|
+
high: positiveLog(pricePointWicks(point).high),
|
|
121
|
+
low: positiveLog(pricePointWicks(point).low),
|
|
120
122
|
integrity: pricePointIntegrity(point),
|
|
121
123
|
}));
|
|
122
124
|
}
|
package/src/news/aggregator.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CompanyFrom } from "../types/company-from";
|
|
1
2
|
import { logFailure } from "../utils/log-failure";
|
|
2
3
|
import type { NewsCapability } from "../capabilities";
|
|
3
4
|
import type { ConnectionHealthRegistry } from "../core/connection-health";
|
|
@@ -63,6 +64,7 @@ interface SourceFetchResult {
|
|
|
63
64
|
errors: string[];
|
|
64
65
|
nextCursor: string | null;
|
|
65
66
|
access: NewsAccess | null;
|
|
67
|
+
companyFrom?: CompanyFrom | null;
|
|
66
68
|
}
|
|
67
69
|
|
|
68
70
|
interface NewsQueryEntry {
|
|
@@ -451,6 +453,7 @@ export class NewsService {
|
|
|
451
453
|
loadingMore: entry.state.loadingMore,
|
|
452
454
|
// A page that does not say keeps what this session's earlier answer said.
|
|
453
455
|
access: result.access ?? (sameSession ? entry.state.access ?? null : null),
|
|
456
|
+
companyFrom: result.companyFrom ?? null,
|
|
454
457
|
};
|
|
455
458
|
entry.state = state;
|
|
456
459
|
entry.generation = generation;
|
|
@@ -550,7 +553,7 @@ export class NewsService {
|
|
|
550
553
|
private async readSourcePage(
|
|
551
554
|
source: NewsCapability,
|
|
552
555
|
query: NewsQuery,
|
|
553
|
-
): Promise<{ articles: NewsArticle[]; nextCursor: string | null; error?: string | null; access?: NewsAccess | null }> {
|
|
556
|
+
): Promise<{ articles: NewsArticle[]; nextCursor: string | null; error?: string | null; access?: NewsAccess | null; companyFrom?: CompanyFrom | null }> {
|
|
554
557
|
if (source.provider.fetchNewsPage) {
|
|
555
558
|
const page = await this.trackSourceRequest(
|
|
556
559
|
source,
|
|
@@ -562,6 +565,7 @@ export class NewsService {
|
|
|
562
565
|
nextCursor: page.nextCursor ?? null,
|
|
563
566
|
error: page.error,
|
|
564
567
|
access: page.access,
|
|
568
|
+
companyFrom: page.companyFrom ?? null,
|
|
565
569
|
};
|
|
566
570
|
}
|
|
567
571
|
const articles = (await this.trackSourceRequest(
|
|
@@ -585,6 +589,7 @@ export class NewsService {
|
|
|
585
589
|
errors: page.error ? [page.error] : [],
|
|
586
590
|
nextCursor: page.nextCursor,
|
|
587
591
|
access: page.access ?? null,
|
|
592
|
+
companyFrom: page.companyFrom ?? null,
|
|
588
593
|
};
|
|
589
594
|
if (page.articles.length > 0) return result;
|
|
590
595
|
firstEmpty ??= result;
|
|
@@ -654,6 +659,7 @@ export class NewsService {
|
|
|
654
659
|
nextCursor: entry.state.nextCursor,
|
|
655
660
|
loadingMore: false,
|
|
656
661
|
access: entry.state.access ?? null,
|
|
662
|
+
companyFrom: entry.state.companyFrom ?? null,
|
|
657
663
|
};
|
|
658
664
|
changed = true;
|
|
659
665
|
}
|
package/src/news/types.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { CompanyFrom } from "../types/company-from";
|
|
2
|
+
|
|
1
3
|
type NewsQueryScope = "global" | "ticker";
|
|
2
4
|
export type NewsFeed = "latest" | "top" | "breaking" | "ticker" | "sector" | "topic";
|
|
3
5
|
type NewsSentiment = "positive" | "neutral" | "negative";
|
|
@@ -95,6 +97,8 @@ export interface NewsPage {
|
|
|
95
97
|
nextCursor?: string | null;
|
|
96
98
|
/** Which news the source answered with; null or absent when the answer does not say. */
|
|
97
99
|
access?: NewsAccess | null;
|
|
100
|
+
/** The company's home line the stories are read from, when not the listing asked (a receipt, a foreign line). */
|
|
101
|
+
companyFrom?: CompanyFrom | null;
|
|
98
102
|
}
|
|
99
103
|
|
|
100
104
|
export interface NewsQueryState {
|
|
@@ -107,4 +111,6 @@ export interface NewsQueryState {
|
|
|
107
111
|
loadingMore: boolean;
|
|
108
112
|
/** Which news the stories are, from the last answer; null or absent when it did not say. */
|
|
109
113
|
access?: NewsAccess | null;
|
|
114
|
+
/** The company's home line the stories are read from, when not the listing asked. */
|
|
115
|
+
companyFrom?: CompanyFrom | null;
|
|
110
116
|
}
|
|
@@ -37,24 +37,28 @@ function readJson(path: string): Record<string, unknown> | null {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
async function readCheckouts(): Promise<PluginCheckout[]> {
|
|
40
|
-
const { installedPluginDirectories,
|
|
40
|
+
const { installedPluginDirectories, readPluginRemoteAsync } = await installer();
|
|
41
41
|
const pluginsDir = getPluginsDir();
|
|
42
|
-
|
|
42
|
+
const checkouts: PluginCheckout[] = [];
|
|
43
|
+
// One git at a time: starting a process holds the thread for a moment, and
|
|
44
|
+
// starting them all at once adds those moments up into one pause.
|
|
45
|
+
for (const directory of installedPluginDirectories()) {
|
|
43
46
|
const dir = join(pluginsDir, directory);
|
|
44
47
|
const pkg = readJson(join(dir, "package.json"));
|
|
45
48
|
const dependencies = pkg?.dependencies;
|
|
46
|
-
|
|
49
|
+
checkouts.push({
|
|
47
50
|
directory,
|
|
48
51
|
id: readPluginManifest(dir).id,
|
|
49
|
-
repo: existsSync(join(dir, ".git")) ?
|
|
52
|
+
repo: existsSync(join(dir, ".git")) ? await readPluginRemoteAsync(dir) : null,
|
|
50
53
|
commit: readPluginCommit(dir),
|
|
51
54
|
version: typeof pkg?.version === "string" ? pkg.version : null,
|
|
52
55
|
linked: lstatSync(dir, { throwIfNoEntry: false })?.isSymbolicLink() === true,
|
|
53
56
|
needsGloomberb: checkPluginCompatibility(dir)?.needsGloomberb ?? null,
|
|
54
57
|
peers: installedPeerPlugins(dir, pluginsDir).map((peer) => peer.directory),
|
|
55
58
|
hasDependencies: !!dependencies && typeof dependencies === "object" && Object.keys(dependencies).length > 0,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return checkouts;
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
function createNodeAutoUpdateDeps(manager: PluginManager): PluginAutoUpdateDeps {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// release's rows as the calendar's feeds name it from week to week, and the
|
|
4
4
|
// notifications sent before it and once its figures are out. CPI and FOMC are
|
|
5
5
|
// two cases of the same alert, whose dates come from their own calendars.
|
|
6
|
-
import { dateKey, eventCountry, matchesCountry, type CountryFilter } from "../econ/calendar-model";
|
|
6
|
+
import { dateKey, econEventName, eventCountry, matchesCountry, type CountryFilter } from "../econ/calendar-model";
|
|
7
7
|
import { isAllDayEvent, hasNoReleaseTime, type EconEvent, type EconImpact } from "../econ/types";
|
|
8
8
|
import { RENAMED_RELEASES } from "../shared/macro-releases";
|
|
9
9
|
import { MACRO_EVENT_NAMES } from "./research-builder";
|
|
@@ -126,7 +126,11 @@ export interface CalendarEventChoice {
|
|
|
126
126
|
|
|
127
127
|
const IMPACT_RANK: Record<EconImpact, number> = { high: 0, medium: 1, low: 2 };
|
|
128
128
|
|
|
129
|
-
type RankedChoice = CalendarEventChoice & {
|
|
129
|
+
type RankedChoice = CalendarEventChoice & {
|
|
130
|
+
words: string[];
|
|
131
|
+
/** The words of the name `econ` shows it under, when that is not the feed's (the Fed's rate as its upper bound). */
|
|
132
|
+
shownWords: string[];
|
|
133
|
+
};
|
|
130
134
|
|
|
131
135
|
/**
|
|
132
136
|
* The calendar's releases, one per country and name, each with its next row
|
|
@@ -150,6 +154,7 @@ function calendarChoices(events: readonly EconEvent[], now: number): RankedChoic
|
|
|
150
154
|
impact: rows.reduce<EconImpact>((best, event) => IMPACT_RANK[event.impact] < IMPACT_RANK[best] ? event.impact : best, "low"),
|
|
151
155
|
next,
|
|
152
156
|
words: calendarNameWords(named.event),
|
|
157
|
+
shownWords: calendarNameWords(econEventName(named)),
|
|
153
158
|
};
|
|
154
159
|
});
|
|
155
160
|
}
|
|
@@ -246,7 +251,8 @@ function matchCalendarWords(
|
|
|
246
251
|
now: number,
|
|
247
252
|
): CalendarEventMatch {
|
|
248
253
|
const choices = calendarChoices(country ? events.filter((event) => matchesCountry(event, country)) : events, now);
|
|
249
|
-
|
|
254
|
+
// The name as the feed gives it, or as `econ` shows it: the alert keeps the feed's, which the calendar's rows carry.
|
|
255
|
+
const exact = choices.filter((choice) => [choice.words, choice.shownWords].some((name) => name.join(" ") === words.join(" ")));
|
|
250
256
|
const naming = (typed: readonly string[], loose: boolean) => typed.length === 0 ? [] : choices.filter((choice) =>
|
|
251
257
|
typed.every((word) => loose ? wordFound(word, choice.words) : choice.words.includes(word)));
|
|
252
258
|
// CPI by the name one feed gives it everywhere but the US (China's Inflation Rate YoY).
|
|
@@ -278,7 +284,7 @@ function matchCalendarWords(
|
|
|
278
284
|
return { kind: "match", choice: strip(ranked[0]!), others: ranked.slice(1).map(strip) };
|
|
279
285
|
}
|
|
280
286
|
|
|
281
|
-
function strip({ words: _words, ...choice }: RankedChoice): CalendarEventChoice {
|
|
287
|
+
function strip({ words: _words, shownWords: _shown, ...choice }: RankedChoice): CalendarEventChoice {
|
|
282
288
|
return choice;
|
|
283
289
|
}
|
|
284
290
|
|