gloomberb 0.17.1 → 0.17.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/{plugins/builtin/cloud → account}/auth-dialog.tsx +7 -7
- package/src/api-client/earnings.ts +4 -2
- package/src/app/global-shortcuts.ts +10 -0
- package/src/app/keybindings/actions.ts +16 -0
- package/src/app/runtime/desktop-deeplink.ts +1 -1
- package/src/app.tsx +1 -1
- package/src/architecture/core-builtin-allowlist.json +4 -9
- package/src/cli/commands/market.ts +34 -16
- package/src/cli/commands/options-chain.ts +29 -33
- package/src/cli/commands/options-leaps.ts +462 -63
- package/src/cli/commands/search.ts +10 -7
- package/src/cli/commands/ticker.ts +1 -1
- package/src/cli/known-gaps.ts +22 -0
- package/src/cli/pane-functions/catalog.ts +6 -3
- package/src/cli/pane-functions/dom.ts +17 -2
- package/src/cli/pane-functions/function-help.ts +1 -1
- package/src/cli/pane-functions/index.ts +5 -3
- package/src/cli/pane-functions/report-notices.ts +15 -0
- package/src/cli/symbol-args.ts +19 -0
- package/src/components/command-bar/workflow/builtin.ts +2 -2
- package/src/components/command-bar/workflow/collection-actions.ts +1 -1
- package/src/components/feedback-dialog.tsx +1 -1
- package/src/components/layout/shell/index.tsx +1 -1
- package/src/components/layout/status-bar-groups.ts +1 -1
- package/src/components/layout/status-bar.tsx +2 -2
- package/src/components/markdown-text.tsx +14 -2
- package/src/components/reader/article-reader.tsx +1 -1
- package/src/components/reader/detail-reader.tsx +10 -7
- package/src/components/reader/reader-text.tsx +32 -17
- package/src/layout-marketplace/gallery.tsx +2 -2
- package/src/layout-marketplace/linked-sync.ts +1 -1
- package/src/market-data/market/freshness.ts +3 -0
- package/src/market-data/published-apac-sessions.ts +12 -2
- package/src/plugins/builtin/chart-composer/index.tsx +1 -1
- package/src/plugins/builtin/chart-composer/presets.ts +33 -1
- package/src/plugins/builtin/chat/channel-labels.ts +2 -2
- package/src/plugins/builtin/chat/content/channel-navigation.ts +1 -1
- package/src/plugins/builtin/chat/content/index.tsx +2 -2
- package/src/plugins/builtin/chat/conversations.ts +1 -1
- package/src/plugins/builtin/chat/index.tsx +2 -2
- package/src/plugins/builtin/chat/share/flow.tsx +1 -1
- package/src/plugins/builtin/chat/sidebar-rows.ts +1 -1
- package/src/plugins/builtin/chat/sidebar.tsx +2 -2
- package/src/plugins/builtin/chat/unread-inbox-pane.tsx +2 -2
- package/src/plugins/builtin/cloud/auth-actions.tsx +1 -1
- package/src/plugins/builtin/cloud/auth-commands.ts +1 -1
- package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +1 -1
- package/src/plugins/builtin/cloud/team/acm-tab.tsx +3 -3
- package/src/plugins/builtin/cloud/team/capability.ts +2 -2
- package/src/plugins/builtin/cloud/team/command.ts +4 -4
- package/src/plugins/builtin/cloud/team/module.tsx +3 -3
- package/src/plugins/builtin/cloud/team/pane-model.ts +2 -2
- package/src/plugins/builtin/cloud/team/pane-sections.tsx +1 -1
- package/src/plugins/builtin/cloud/team/pane-ui.tsx +1 -1
- package/src/plugins/builtin/cloud/team/pane.tsx +3 -3
- package/src/plugins/builtin/cloud/team/status-widget.tsx +3 -3
- package/src/plugins/builtin/cloud/team/team-state-host.ts +1 -1
- package/src/plugins/builtin/cloud/team/views.ts +2 -2
- package/src/plugins/builtin/cloud/thesis/board-pane.tsx +1 -1
- package/src/plugins/builtin/cloud/thesis/detail.tsx +1 -1
- package/src/plugins/builtin/cloud/thesis/ticker-tab.tsx +1 -1
- package/src/plugins/builtin/cloud/upgrade-command.ts +1 -1
- package/src/plugins/builtin/custom-view/pane.tsx +2 -2
- package/src/plugins/builtin/dividend-yield/headless.ts +8 -2
- package/src/plugins/builtin/dividend-yield/pane.tsx +4 -2
- package/src/plugins/builtin/docs/blocks.tsx +13 -2
- package/src/plugins/builtin/docs/pane.tsx +6 -5
- package/src/plugins/builtin/earnings/board-model.ts +18 -1
- package/src/plugins/builtin/earnings/board-table.ts +18 -3
- package/src/plugins/builtin/earnings/headless.ts +13 -2
- package/src/plugins/builtin/earnings/history-model.ts +1 -1
- package/src/plugins/builtin/earnings/history-table.ts +2 -2
- package/src/plugins/builtin/help/feedback-tab.tsx +1 -1
- package/src/plugins/builtin/notes/index.tsx +1 -1
- package/src/plugins/builtin/notes/owner.tsx +2 -2
- package/src/plugins/builtin/options/carry.ts +36 -0
- package/src/plugins/builtin/options/open-interest-as-of.ts +16 -5
- package/src/plugins/builtin/options/view.tsx +19 -7
- package/src/plugins/builtin/options-calculator/pane.tsx +56 -1
- package/src/plugins/builtin/options-calculator/premium-history.ts +34 -0
- package/src/plugins/builtin/portfolio-list/mutations.ts +1 -1
- package/src/plugins/builtin/portfolio-list/pane/remove-ticker.ts +1 -1
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +4 -2
- package/src/plugins/builtin/research/event-model.ts +7 -4
- package/src/plugins/builtin/series-inventory.ts +1 -0
- package/src/plugins/builtin/shared/earnings-report.ts +10 -4
- package/src/renderers/dom/styles.css +4 -2
- package/src/sources/gloomberb-cloud/normalizers.ts +2 -0
- package/src/{plugins/builtin/cloud/team → team}/collections-sync.ts +6 -6
- package/src/{plugins/builtin/cloud/team → team}/collections.ts +3 -3
- package/src/{plugins/builtin/cloud/team → team}/model.ts +2 -2
- package/src/{plugins/builtin/cloud/team → team}/pane-request.ts +1 -1
- package/src/{plugins/builtin/cloud/team → team}/store.ts +3 -3
- package/src/types/data-provider.ts +3 -0
- package/src/types/financials.ts +6 -0
- package/src/utils/decimal-comma.ts +18 -0
- package/src/utils/exchanges.ts +7 -0
- package/src/utils/forward-dividend.ts +39 -9
- package/src/utils/option-expiry.ts +16 -0
- package/src/utils/sec.ts +2 -1
|
@@ -4,12 +4,12 @@ import {
|
|
|
4
4
|
type TeamCollection,
|
|
5
5
|
type TeamCollectionEvent,
|
|
6
6
|
type TeamCollectionItem,
|
|
7
|
-
} from "
|
|
8
|
-
import type { AppTickerRepositoryPort } from "
|
|
9
|
-
import type { AppAction, AppState } from "
|
|
10
|
-
import { useAppDispatch, useAppSelector, useAppStateRef } from "
|
|
11
|
-
import type { TickerRecord } from "
|
|
12
|
-
import { debugLog } from "
|
|
7
|
+
} from "../api-client";
|
|
8
|
+
import type { AppTickerRepositoryPort } from "../core/app-service-ports";
|
|
9
|
+
import type { AppAction, AppState } from "../core/state/app/types";
|
|
10
|
+
import { useAppDispatch, useAppSelector, useAppStateRef } from "../state/app/context";
|
|
11
|
+
import type { TickerRecord } from "../types/ticker";
|
|
12
|
+
import { debugLog } from "../utils/debug-log";
|
|
13
13
|
import {
|
|
14
14
|
applyMembership,
|
|
15
15
|
blankTickerRecord,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { TeamCollection, TeamCollectionItem } from "
|
|
2
|
-
import type { AppConfig } from "
|
|
3
|
-
import type { Portfolio, TickerRecord, Watchlist } from "
|
|
1
|
+
import type { TeamCollection, TeamCollectionItem } from "../api-client";
|
|
2
|
+
import type { AppConfig } from "../types/config";
|
|
3
|
+
import type { Portfolio, TickerRecord, Watchlist } from "../types/ticker";
|
|
4
4
|
|
|
5
5
|
const TEAM_COLLECTION_PREFIX = "team:";
|
|
6
6
|
|
|
@@ -4,8 +4,8 @@ import type {
|
|
|
4
4
|
TeamRole,
|
|
5
5
|
TeamSummary,
|
|
6
6
|
TeamUser,
|
|
7
|
-
} from "
|
|
8
|
-
import { blendHex, colors } from "
|
|
7
|
+
} from "../api-client";
|
|
8
|
+
import { blendHex, colors } from "../theme/colors";
|
|
9
9
|
|
|
10
10
|
const TEAM_CHANNEL_PREFIX = "team:";
|
|
11
11
|
|
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
type TeamReceivedInvitation,
|
|
5
5
|
type TeamSummary,
|
|
6
6
|
type TeamUpdatedEvent,
|
|
7
|
-
} from "
|
|
8
|
-
import type { AppNotificationDelivery, AppNotificationRequest, PluginPersistence } from "
|
|
9
|
-
import { markNotificationLogReadByRef } from "
|
|
7
|
+
} from "../api-client";
|
|
8
|
+
import type { AppNotificationDelivery, AppNotificationRequest, PluginPersistence } from "../types/plugin";
|
|
9
|
+
import { markNotificationLogReadByRef } from "../notifications/notification-log";
|
|
10
10
|
import { describeTeamNotification, findTeam, teamIdFromChannelId, teamNotificationRefId } from "./model";
|
|
11
11
|
|
|
12
12
|
export interface TeamStoreSnapshot {
|
|
@@ -2,6 +2,7 @@ import type { ExchangeRateSnapshot } from "./exchange-rate";
|
|
|
2
2
|
import type {
|
|
3
3
|
AnalystResearchData,
|
|
4
4
|
CorporateActionsData,
|
|
5
|
+
EarningsEpsBasis,
|
|
5
6
|
Quote,
|
|
6
7
|
QuoteMetadata,
|
|
7
8
|
TickerFinancials,
|
|
@@ -94,6 +95,8 @@ export interface EarningsEvent {
|
|
|
94
95
|
epsRevisionDown7d?: number | null;
|
|
95
96
|
epsRevisionDown30d?: number | null;
|
|
96
97
|
epsActual: number | null;
|
|
98
|
+
/** "adjusted" when the estimate is the consensus on the adjusted basis the company's reports are on (a REIT's FFO), not a GAAP forecast. */
|
|
99
|
+
epsBasis?: EarningsEpsBasis | null;
|
|
97
100
|
revenueEstimate: number | null;
|
|
98
101
|
revenueLow?: number | null;
|
|
99
102
|
revenueHigh?: number | null;
|
package/src/types/financials.ts
CHANGED
|
@@ -870,4 +870,10 @@ export interface OptionsChain {
|
|
|
870
870
|
realtimeEligible?: boolean;
|
|
871
871
|
/** ISO timestamp for the upstream options snapshot. */
|
|
872
872
|
asOf?: string;
|
|
873
|
+
/**
|
|
874
|
+
* The session the chain's open interest counts, YYYY-MM-DD, as Gloom Cloud
|
|
875
|
+
* states it; null when none of its counts is dated. Absent from a source
|
|
876
|
+
* that does not say (an older server, another provider).
|
|
877
|
+
*/
|
|
878
|
+
openInterestAsOf?: string | null;
|
|
873
879
|
}
|
|
@@ -18,6 +18,24 @@ export function numberErrorMessage(message: string, value: unknown): string {
|
|
|
18
18
|
return dotted == null ? message : `${message.replace(/\.$/, "")}; use a dot: ${dotted}`;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
const DECIMAL_COMMA_RANGE = /^([+-]?\d+(?:,\d+)?)\s*(-|to|\.\.)\s*([+-]?\d+(?:,\d+)?)$/i;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A range typed with decimal commas, `0,80-0,90`, as the dotted range to type
|
|
25
|
+
* instead (`0.80-0.90`); null when neither end has a decimal comma.
|
|
26
|
+
*/
|
|
27
|
+
function dottedDecimalRange(value: unknown): string | null {
|
|
28
|
+
const match = DECIMAL_COMMA_RANGE.exec(typeof value === "string" ? value.trim() : "");
|
|
29
|
+
if (!match || !`${match[1]}${match[3]}`.includes(",")) return null;
|
|
30
|
+
return `${match[1]!.replace(",", ".")}${match[2]}${match[3]!.replace(",", ".")}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** `numberErrorMessage` for a range of two numbers: "... got "0,80-0,90"; use a dot: 0.80-0.90". */
|
|
34
|
+
export function rangeErrorMessage(message: string, value: unknown): string {
|
|
35
|
+
const dotted = dottedDecimalRange(value);
|
|
36
|
+
return dotted == null ? message : `${message.replace(/\.$/, "")}; use a dot: ${dotted}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
21
39
|
/** What a number pasted from a sheet reads as. */
|
|
22
40
|
export type PastedNumber =
|
|
23
41
|
| { kind: "number"; value: number }
|
package/src/utils/exchanges.ts
CHANGED
|
@@ -104,6 +104,11 @@ export const CANONICAL_EXCHANGE_ALIASES: Record<string, string> = {
|
|
|
104
104
|
XPRA: "PSE",
|
|
105
105
|
VIE: "VIE",
|
|
106
106
|
XWBO: "VIE",
|
|
107
|
+
// The Vienna MTF, Wiener Boerse's multilateral trading facility, which Gloom
|
|
108
|
+
// Cloud names by its segment MIC. Its ETPs and notes are its own listings.
|
|
109
|
+
WBDM: "WBDM",
|
|
110
|
+
"VIENNA MTF": "WBDM",
|
|
111
|
+
VMTF: "WBDM",
|
|
107
112
|
TPE: "TWSE",
|
|
108
113
|
TWSE: "TWSE",
|
|
109
114
|
TAI: "TWSE",
|
|
@@ -276,6 +281,7 @@ export const EXCHANGE_TIME_ZONES: Record<string, string> = {
|
|
|
276
281
|
WSE: "Europe/Warsaw",
|
|
277
282
|
PSE: "Europe/Prague",
|
|
278
283
|
VIE: "Europe/Vienna",
|
|
284
|
+
WBDM: "Europe/Vienna",
|
|
279
285
|
TPEX: "Asia/Taipei",
|
|
280
286
|
TWSE: "Asia/Taipei",
|
|
281
287
|
NSE: "Asia/Kolkata",
|
|
@@ -347,6 +353,7 @@ const EXCHANGE_NAMES: Record<string, string> = {
|
|
|
347
353
|
WSE: "Warsaw Stock Exchange",
|
|
348
354
|
PSE: "Prague Stock Exchange",
|
|
349
355
|
VIE: "Vienna Stock Exchange",
|
|
356
|
+
WBDM: "Vienna MTF",
|
|
350
357
|
TWSE: "Taiwan Stock Exchange",
|
|
351
358
|
TPEX: "Taipei Exchange",
|
|
352
359
|
NSE: "National Stock Exchange of India",
|
|
@@ -1,14 +1,44 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* What a forward dividend yield is everywhere it shows (fundamentals, DVD):
|
|
3
|
-
* the indicated annual rate Gloom Cloud serves
|
|
4
|
-
*
|
|
5
|
-
* distribution
|
|
3
|
+
* the indicated annual rate Gloom Cloud serves over the price, dated by the
|
|
4
|
+
* ex-date of the distribution it annualizes. While no other is announced that
|
|
5
|
+
* is the latest distribution, whose ex-date has passed. Once the next one is
|
|
6
|
+
* declared the rate annualizes it, and its ex-date is still ahead: the basis
|
|
7
|
+
* then names the declared distribution by its ex-date and pay date, never a
|
|
8
|
+
* rate "as of" a day that has not come.
|
|
6
9
|
*/
|
|
7
|
-
const
|
|
10
|
+
const LATEST_DISTRIBUTION = "latest distribution annualized";
|
|
8
11
|
|
|
9
|
-
/** `
|
|
10
|
-
|
|
11
|
-
const text =
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
/** `2026-10-01` from a date or an ISO text; null when it is neither. */
|
|
13
|
+
function isoDay(value: string | Date | null | undefined): string | null {
|
|
14
|
+
const text = value instanceof Date ? (Number.isFinite(value.getTime()) ? value.toISOString() : "") : value ?? "";
|
|
15
|
+
return /^\d{4}-\d{2}-\d{2}/.test(text) ? text.slice(0, 10) : null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** A rate dated by an ex-date after today annualizes a distribution declared and not yet gone ex. */
|
|
19
|
+
function isDeclared(exDate: string | null, now: Date): exDate is string {
|
|
20
|
+
return exDate != null && exDate > now.toISOString().slice(0, 10);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* `latest distribution annualized, as of 2026-08-20`, or for a rate dated
|
|
25
|
+
* ahead, `annualized from the declared distribution payable 2026-12-10, ex
|
|
26
|
+
* 2026-11-19`; the basis alone when the date is unknown. `payDate` is the pay
|
|
27
|
+
* date stated beside that ex-date, for a source that pairs them.
|
|
28
|
+
*/
|
|
29
|
+
export function forwardDividendBasis(
|
|
30
|
+
asOf: string | Date | null | undefined,
|
|
31
|
+
options: { payDate?: string | Date | null; now?: Date } = {},
|
|
32
|
+
): string {
|
|
33
|
+
const exDate = isoDay(asOf);
|
|
34
|
+
if (!isDeclared(exDate, options.now ?? new Date())) return exDate ? `${LATEST_DISTRIBUTION}, as of ${exDate}` : LATEST_DISTRIBUTION;
|
|
35
|
+
const payDate = isoDay(options.payDate);
|
|
36
|
+
return `annualized from the declared distribution${payDate ? ` payable ${payDate}` : ""}, ex ${exDate}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** The same basis as a pane's short note under the figure: `as of 2026-08-20`, or `declared` beside the next ex-date it shows. */
|
|
40
|
+
export function forwardDividendNote(asOf: string | Date | null | undefined, now = new Date()): string | null {
|
|
41
|
+
const exDate = isoDay(asOf);
|
|
42
|
+
if (!exDate) return null;
|
|
43
|
+
return isDeclared(exDate, now) ? "declared" : `as of ${exDate}`;
|
|
14
44
|
}
|
|
@@ -124,3 +124,19 @@ export function missingExpiryText(requested: number, expirations: readonly numbe
|
|
|
124
124
|
? `no option contracts returned for${subject ? ` ${subject}` : ""} expiry ${date}; nearest others: ${choices}`
|
|
125
125
|
: `no expiry ${date}${of}; available: ${choices}`;
|
|
126
126
|
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* How a command fails on an expiry the chain cannot show: `options --expiration`
|
|
130
|
+
* and `fn OMON --expiration` print the same error, with the command that lists
|
|
131
|
+
* every expiry as its advice line.
|
|
132
|
+
*/
|
|
133
|
+
export function missingExpiryMessage(
|
|
134
|
+
symbol: string,
|
|
135
|
+
requested: number,
|
|
136
|
+
expirations: readonly number[],
|
|
137
|
+
): { message: string; details: string } {
|
|
138
|
+
return {
|
|
139
|
+
message: missingExpiryText(requested, expirations, symbol),
|
|
140
|
+
details: `Run gloomberb options ${symbol} to list every expiry (--json carries them too).`,
|
|
141
|
+
};
|
|
142
|
+
}
|
package/src/utils/sec.ts
CHANGED
|
@@ -37,7 +37,8 @@ function isEquityType(value?: string): boolean {
|
|
|
37
37
|
|
|
38
38
|
const FUND_TYPES = new Set(["ETF", "ETP", "FUND", "MUTUALFUND", "CEF", "CLOSEDEND", "CLOSEDENDFUND"]);
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
/** An instrument type that names a fund (ETF, closed-end fund), which reports no earnings of its own. */
|
|
41
|
+
export function isFundType(value?: string): boolean {
|
|
41
42
|
return FUND_TYPES.has(normalize(value).replace(/[\s_-]/g, ""));
|
|
42
43
|
}
|
|
43
44
|
|