gloomberb 0.17.1 → 0.17.3
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/api-client/futures-curve.ts +16 -0
- package/src/api-client/index.ts +18 -8
- package/src/api-client/types.ts +3 -1
- 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 +94 -25
- package/src/cli/commands/options-chain.ts +29 -33
- package/src/cli/commands/options-leaps.ts +462 -63
- package/src/cli/commands/search.ts +53 -9
- package/src/cli/commands/ticker.ts +100 -21
- package/src/cli/desktop-pane-shot.ts +34 -9
- package/src/cli/fx-pair.ts +17 -0
- package/src/cli/glossary.ts +134 -6
- package/src/cli/history-rows.ts +16 -4
- package/src/cli/index.ts +44 -12
- package/src/cli/known-gaps.ts +43 -2
- package/src/cli/listing-arg.ts +19 -4
- package/src/cli/listing-suggestion.ts +33 -2
- package/src/cli/pane-functions/catalog.ts +6 -3
- package/src/cli/pane-functions/dom.ts +56 -8
- package/src/cli/pane-functions/freshness.ts +48 -5
- package/src/cli/pane-functions/function-help.ts +2 -2
- package/src/cli/pane-functions/headless.ts +85 -19
- package/src/cli/pane-functions/index.ts +65 -7
- package/src/cli/pane-functions/market-session.ts +69 -6
- package/src/cli/pane-functions/report-notices.ts +15 -0
- package/src/cli/pane-functions/resolver.ts +4 -2
- package/src/cli/pane-functions/screenshot.ts +14 -1
- package/src/cli/scroll-truncation.ts +5 -1
- package/src/cli/symbol-args.ts +60 -3
- package/src/cli/symbol-list.ts +19 -7
- package/src/cli/unknown-command.ts +70 -0
- package/src/components/chart/native/surface/visibility.ts +37 -7
- 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/header.tsx +348 -102
- 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 +50 -64
- package/src/components/market-board/index.tsx +12 -6
- package/src/components/reader/article-reader.tsx +1 -1
- package/src/components/reader/detail-reader.tsx +37 -12
- package/src/components/reader/reader-text.tsx +32 -17
- package/src/components/ticker/badge/index.tsx +2 -0
- package/src/components/ui/display.tsx +6 -1
- package/src/components/ui/external-link.tsx +10 -2
- package/src/data/memory-resource-store.ts +1 -1
- package/src/data/resource-store.ts +13 -1
- package/src/docs/snapshot.json +13 -13
- package/src/i18n/es.ts +1 -0
- package/src/i18n/ja.ts +1 -0
- package/src/i18n/ko.ts +1 -0
- package/src/i18n/zh-cn.ts +1 -0
- package/src/i18n/zh-tw.ts +1 -0
- package/src/layout-marketplace/gallery.tsx +2 -2
- package/src/layout-marketplace/linked-sync.ts +1 -1
- package/src/market-data/futures-contract.ts +10 -0
- package/src/market-data/market/format.ts +7 -2
- package/src/market-data/market/freshness.ts +28 -1
- package/src/market-data/published-apac-sessions.ts +12 -2
- package/src/market-data/quotes/regular-session-valuation.ts +32 -1
- package/src/market-data/quotes/resolution.ts +2 -0
- package/src/plugins/builtin/account-management/pane.tsx +17 -13
- package/src/plugins/builtin/attention/headless.ts +19 -10
- package/src/plugins/builtin/attention/model.ts +22 -0
- package/src/plugins/builtin/bond-calculator/pane.tsx +2 -1
- package/src/plugins/builtin/changelog/index.tsx +11 -8
- package/src/plugins/builtin/chart-composer/editor/desktop-view.tsx +2 -0
- 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/attachments/desktop.tsx +2 -1
- package/src/plugins/builtin/chat/attachments/model.ts +5 -3
- 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/footer.tsx +6 -0
- package/src/plugins/builtin/chat/content/index.tsx +2 -2
- package/src/plugins/builtin/chat/content/open-targets.ts +13 -4
- package/src/plugins/builtin/chat/content/transcript.tsx +2 -0
- package/src/plugins/builtin/chat/content/whole-message-copy.ts +70 -0
- package/src/plugins/builtin/chat/conversations.ts +1 -1
- package/src/plugins/builtin/chat/index.tsx +2 -2
- package/src/plugins/builtin/chat/layout.ts +91 -31
- package/src/plugins/builtin/chat/markdown.ts +94 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +3 -2
- package/src/plugins/builtin/chat/message/inline-tokens.tsx +197 -80
- package/src/plugins/builtin/chat/message/render-state.ts +3 -0
- package/src/plugins/builtin/chat/message/terminal.tsx +4 -4
- 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/exposure.ts +18 -2
- 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/company-attention/headless.ts +8 -5
- package/src/plugins/builtin/company-attention/model.ts +53 -2
- package/src/plugins/builtin/company-attention/pane.tsx +1 -1
- package/src/plugins/builtin/congress-trades/detail.tsx +7 -4
- package/src/plugins/builtin/congress-trades/pane.tsx +3 -1
- package/src/plugins/builtin/correlation/relationship/pane.tsx +3 -7
- package/src/plugins/builtin/cot/client.ts +12 -4
- package/src/plugins/builtin/cot/pane.tsx +2 -2
- package/src/plugins/builtin/crypto-board/model.ts +7 -3
- package/src/plugins/builtin/custom-view/pane.tsx +2 -2
- package/src/plugins/builtin/debt-maturities/pane.tsx +1 -6
- package/src/plugins/builtin/debug/index.tsx +15 -15
- package/src/plugins/builtin/dividend-yield/client.ts +8 -1
- package/src/plugins/builtin/dividend-yield/headless.ts +11 -2
- package/src/plugins/builtin/dividend-yield/pane.tsx +8 -5
- package/src/plugins/builtin/docs/blocks.tsx +13 -2
- package/src/plugins/builtin/docs/index.tsx +5 -3
- package/src/plugins/builtin/docs/pane.tsx +24 -6
- package/src/plugins/builtin/docs/targets.ts +5 -3
- 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/earnings-calls/data.ts +22 -0
- package/src/plugins/builtin/earnings-calls/pane.tsx +24 -14
- package/src/plugins/builtin/equity-screener/headless.ts +4 -3
- package/src/plugins/builtin/equity-screener/live.ts +27 -1
- package/src/plugins/builtin/equity-screener/pane.tsx +21 -2
- package/src/plugins/builtin/fear-greed/charts.tsx +5 -1
- package/src/plugins/builtin/fear-greed/pane.tsx +1 -1
- package/src/plugins/builtin/futures/index.tsx +32 -4
- package/src/plugins/builtin/futures/model.ts +65 -3
- package/src/plugins/builtin/futures/table.tsx +31 -11
- package/src/plugins/builtin/futures/use-board-terms.ts +89 -0
- package/src/plugins/builtin/help/feedback-tab.tsx +1 -1
- package/src/plugins/builtin/holders/pane.tsx +6 -1
- package/src/plugins/builtin/mna/client.ts +12 -2
- package/src/plugins/builtin/mna/detail.tsx +2 -2
- package/src/plugins/builtin/mna/pane.tsx +2 -2
- package/src/plugins/builtin/notes/index.tsx +1 -1
- package/src/plugins/builtin/notes/owner.tsx +7 -6
- package/src/plugins/builtin/notes/ticker-notes-tab.tsx +2 -3
- 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 +58 -4
- package/src/plugins/builtin/options-calculator/premium-history.ts +34 -0
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +8 -5
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +4 -3
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +9 -0
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +6 -3
- 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/equity-diagnostic-pane.tsx +2 -9
- package/src/plugins/builtin/research/event-model.ts +21 -4
- package/src/plugins/builtin/research/headless-schema.ts +31 -1
- package/src/plugins/builtin/research/relative-valuation-columns.ts +289 -0
- package/src/plugins/builtin/research/relative-valuation-currency.ts +164 -0
- package/src/plugins/builtin/research/relative-valuation-headless.ts +94 -11
- package/src/plugins/builtin/research/relative-valuation-model.ts +4 -1
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +13 -4
- package/src/plugins/builtin/research/relative-valuation-peers.ts +302 -0
- package/src/plugins/builtin/research-search/data.ts +11 -0
- package/src/plugins/builtin/research-search/pane.tsx +13 -2
- package/src/plugins/builtin/scanner/hilo-pane.tsx +7 -17
- package/src/plugins/builtin/seasonality/client.ts +23 -0
- package/src/plugins/builtin/seasonality/pane.tsx +4 -2
- package/src/plugins/builtin/sectors/index.tsx +7 -3
- package/src/plugins/builtin/series-inventory.ts +1 -0
- package/src/plugins/builtin/shared/earnings-report.ts +10 -4
- package/src/plugins/builtin/shared/report-freshness.ts +6 -2
- package/src/plugins/builtin/short-interest/headless.ts +13 -3
- package/src/plugins/builtin/short-interest/index.tsx +1 -1
- package/src/plugins/builtin/short-interest/model.ts +62 -3
- package/src/plugins/builtin/short-interest/pane.tsx +2 -2
- package/src/plugins/builtin/short-interest/schedule.ts +107 -0
- package/src/plugins/builtin/short-interest/watch-client.ts +54 -8
- package/src/plugins/builtin/short-interest/watch-headless.ts +8 -3
- package/src/plugins/builtin/short-interest/watch-model.ts +52 -23
- package/src/plugins/builtin/short-interest/watch-pane.tsx +1 -1
- package/src/plugins/builtin/supply-chain/flow.tsx +14 -4
- package/src/plugins/builtin/themes/headless.ts +1 -1
- package/src/plugins/builtin/thirteenf/overlap-pane.tsx +23 -27
- package/src/plugins/builtin/ticker-detail/index.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/overview/model.ts +4 -3
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +4 -4
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +9 -4
- package/src/plugins/builtin/vol-surface/pane.tsx +16 -1
- package/src/plugins/builtin/volatility/chart-model.ts +1 -1
- package/src/plugins/builtin/volatility/charts.tsx +1 -1
- package/src/renderers/dom/styles.css +10 -2
- package/src/sources/gloomberb-cloud/normalizers.ts +3 -0
- package/src/sources/provider-router/batches.ts +2 -1
- package/src/sources/provider-router/cache.ts +3 -0
- package/src/sync/baseline.ts +19 -14
- package/src/sync/controller.ts +140 -40
- package/src/sync/core-contributors.ts +256 -32
- package/src/sync/types.ts +44 -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/time-series/resolve.ts +19 -2
- package/src/types/data-provider.ts +11 -0
- package/src/types/financials.ts +46 -4
- package/src/types/headless.ts +43 -0
- package/src/types/plugin.ts +7 -0
- package/src/utils/decimal-comma.ts +18 -0
- package/src/utils/declared-dividends.ts +39 -0
- package/src/utils/exchanges.ts +7 -0
- package/src/utils/forward-dividend.ts +62 -9
- package/src/utils/fundamentals.ts +13 -2
- package/src/utils/markdown.ts +180 -0
- package/src/utils/market-capitalization.ts +22 -0
- package/src/utils/option-expiry.ts +16 -0
- package/src/utils/sec.ts +2 -1
package/package.json
CHANGED
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
* hosted terminal's sign-in gate reuses.
|
|
7
7
|
*/
|
|
8
8
|
import { useEffect, useRef, useState } from "react";
|
|
9
|
-
import type { AuthUser } from "
|
|
10
|
-
import { DialogFrame } from "
|
|
11
|
-
import { useAppLanguage } from "
|
|
12
|
-
import { useDialog, type PromptContext } from "
|
|
13
|
-
import { AuthForm, authFormTitle } from "
|
|
14
|
-
import type { AccountMode } from "
|
|
15
|
-
import { CloudVerificationPanel } from "
|
|
9
|
+
import type { AuthUser } from "../api-client";
|
|
10
|
+
import { DialogFrame } from "../components/ui/frame";
|
|
11
|
+
import { useAppLanguage } from "../i18n/react";
|
|
12
|
+
import { useDialog, type PromptContext } from "../ui/dialog";
|
|
13
|
+
import { AuthForm, authFormTitle } from "./auth-form";
|
|
14
|
+
import type { AccountMode } from "./auth-model";
|
|
15
|
+
import { CloudVerificationPanel } from "./verification-panel";
|
|
16
16
|
|
|
17
17
|
function AuthDialog({
|
|
18
18
|
initialMode,
|
|
@@ -38,7 +38,9 @@ export interface EarningsReport {
|
|
|
38
38
|
reportedAt: string | null;
|
|
39
39
|
/** Fiscal quarter end month, YYYY-MM. */
|
|
40
40
|
fiscalPeriod: string | null;
|
|
41
|
+
/** The company's cap as RV reads it: its latest snapshot at the regular session's price. */
|
|
41
42
|
marketCap: number | null;
|
|
43
|
+
/** For an upcoming report, the consensus every earnings view shows, with `epsAnalysts` behind it. */
|
|
42
44
|
epsEstimate: number | null;
|
|
43
45
|
epsActual: number | null;
|
|
44
46
|
epsAnalysts: number | null;
|
|
@@ -48,6 +50,8 @@ export interface EarningsReport {
|
|
|
48
50
|
realized: EarningsRealizedMove | null;
|
|
49
51
|
/** Whether the date is out, announced or projected; absent from older servers. */
|
|
50
52
|
dateStatus?: EarningsDateStatus;
|
|
53
|
+
/** The reported figure's basis, null when it cannot be determined; absent from older servers. */
|
|
54
|
+
epsBasis?: EarningsEpsBasis | null;
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
export interface EarningsCalendarReport extends EarningsReport {
|
|
@@ -65,8 +69,6 @@ export interface EarningsCalendarPayload {
|
|
|
65
69
|
|
|
66
70
|
interface EarningsHistoryReport extends EarningsReport {
|
|
67
71
|
revenueActual: number | null;
|
|
68
|
-
/** Null when the basis cannot be determined; absent from older servers. */
|
|
69
|
-
epsBasis?: EarningsEpsBasis | null;
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
export interface EarningsHistoryPayload {
|
|
@@ -30,6 +30,22 @@ export interface FuturesContractTermsPayload {
|
|
|
30
30
|
inDelivery: boolean
|
|
31
31
|
/** The newest exchange settlement confirmed for the contract, with its session. */
|
|
32
32
|
settlement: { price: number; date: string } | null
|
|
33
|
+
/**
|
|
34
|
+
* For a continuous symbol (CL=F) or a front generic: the nearest contract
|
|
35
|
+
* still trading when the symbol has rolled past it to the most active one,
|
|
36
|
+
* with its last trade; null when it prices the nearest itself. Absent from
|
|
37
|
+
* servers that do not send it.
|
|
38
|
+
*/
|
|
39
|
+
nearest?: FuturesNearestContract | null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** The nearest contract still trading, which a continuous symbol has rolled past (CLX26 under CL=F on Dec). */
|
|
43
|
+
interface FuturesNearestContract {
|
|
44
|
+
contract: string
|
|
45
|
+
contractSymbol: string
|
|
46
|
+
/** YYYY-MM */
|
|
47
|
+
deliveryMonth: string
|
|
48
|
+
lastTrade: string | null
|
|
33
49
|
}
|
|
34
50
|
|
|
35
51
|
/** Gloom Cloud futures prices retain provider denomination and explicit quote units. */
|
package/src/api-client/index.ts
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
parseCloudLayoutEntry,
|
|
13
13
|
parseCloudLayoutList,
|
|
14
14
|
} from "../layout-marketplace/cloud";
|
|
15
|
-
import type
|
|
15
|
+
import { SyncRevisionConflictError, type SyncSnapshot } from "../sync/types";
|
|
16
16
|
import { withDeadline } from "../utils/async-deadline";
|
|
17
17
|
import { CloudASKGApi } from "./askg";
|
|
18
18
|
import { CloudAuthApi } from "./auth";
|
|
@@ -450,14 +450,24 @@ class GloomApiClient {
|
|
|
450
450
|
return this.request<CloudSyncSnapshotResponse>("/sync/snapshot", { method: "GET" });
|
|
451
451
|
}
|
|
452
452
|
|
|
453
|
+
/**
|
|
454
|
+
* `baseRevision` goes out as If-Match: the server ignores the body field and
|
|
455
|
+
* would replace a snapshot another device wrote since this one pulled. With
|
|
456
|
+
* the header it refuses that write (409), raised as SyncRevisionConflictError
|
|
457
|
+
* so the controller pulls again instead.
|
|
458
|
+
*/
|
|
453
459
|
async putSyncSnapshot(snapshot: SyncSnapshot, options?: { baseRevision?: number | null }): Promise<CloudSyncPushResponse> {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
baseRevision:
|
|
459
|
-
|
|
460
|
-
|
|
460
|
+
const baseRevision = options?.baseRevision ?? null;
|
|
461
|
+
try {
|
|
462
|
+
return await this.request<CloudSyncPushResponse>("/sync/snapshot", {
|
|
463
|
+
method: "PUT",
|
|
464
|
+
...(baseRevision !== null ? { headers: { "If-Match": String(baseRevision) } } : {}),
|
|
465
|
+
body: JSON.stringify({ snapshot, baseRevision }),
|
|
466
|
+
});
|
|
467
|
+
} catch (error) {
|
|
468
|
+
if (error instanceof ApiRequestError && error.status === 409) throw new SyncRevisionConflictError(error.message);
|
|
469
|
+
throw error;
|
|
470
|
+
}
|
|
461
471
|
}
|
|
462
472
|
|
|
463
473
|
async getMarketplaceLayout(
|
package/src/api-client/types.ts
CHANGED
|
@@ -459,10 +459,12 @@ export interface CloudPricePointPayload {
|
|
|
459
459
|
low?: number;
|
|
460
460
|
close: number;
|
|
461
461
|
volume?: number;
|
|
462
|
-
/** A
|
|
462
|
+
/** A daily bar still forming when served: a coin's UTC day, or the trade date a future is trading. */
|
|
463
463
|
partial?: boolean;
|
|
464
464
|
/** A coin's daily bar whose prices were rebuilt from hourly bars; a day the source left empty has no volume. */
|
|
465
465
|
filled?: boolean;
|
|
466
|
+
/** A future's closed session whose settlement is not confirmed yet: it closes on the last trade. */
|
|
467
|
+
unsettled?: boolean;
|
|
466
468
|
}
|
|
467
469
|
|
|
468
470
|
type CloudEconImpact = "high" | "medium" | "low";
|
|
@@ -212,6 +212,16 @@ export function useAppGlobalShortcuts({
|
|
|
212
212
|
return;
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
+
// Text fields keep Cmd+Z. Everywhere else it restores the previous layout.
|
|
216
|
+
// A detached window has no layout history of its own.
|
|
217
|
+
if (action === "layout-undo" || action === "layout-redo") {
|
|
218
|
+
if (isDetachedWindow || dialogOpen || state.commandBarOpen || state.inputCaptured || event.targetEditable === true) return;
|
|
219
|
+
event.preventDefault();
|
|
220
|
+
event.stopPropagation();
|
|
221
|
+
dispatch({ type: action === "layout-undo" ? "UNDO_LAYOUT" : "REDO_LAYOUT" });
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
215
225
|
if (dialogOpen) return;
|
|
216
226
|
|
|
217
227
|
if (!isDetachedWindow && action === "command-bar") {
|
|
@@ -30,6 +30,8 @@ export type CoreKeybindingActionId =
|
|
|
30
30
|
| "pane-share"
|
|
31
31
|
| "pane-ask"
|
|
32
32
|
| "layout-gallery"
|
|
33
|
+
| "layout-undo"
|
|
34
|
+
| "layout-redo"
|
|
33
35
|
| "tidy-windows"
|
|
34
36
|
| "window-move-mode"
|
|
35
37
|
| "window-resize-mode";
|
|
@@ -62,6 +64,8 @@ export const PANE_ACTION_IDS = new Set<CoreKeybindingActionId>([
|
|
|
62
64
|
"pane-share",
|
|
63
65
|
"pane-ask",
|
|
64
66
|
"layout-gallery",
|
|
67
|
+
"layout-undo",
|
|
68
|
+
"layout-redo",
|
|
65
69
|
"tidy-windows",
|
|
66
70
|
"window-move-mode",
|
|
67
71
|
"window-resize-mode",
|
|
@@ -245,6 +249,18 @@ export const KEYBINDING_ACTIONS: readonly KeybindingActionDef[] = [
|
|
|
245
249
|
description: "Open layout actions.",
|
|
246
250
|
defaults: ["CmdOrCtrl+Shift+L"],
|
|
247
251
|
},
|
|
252
|
+
{
|
|
253
|
+
id: "layout-undo",
|
|
254
|
+
category: "Pane Management",
|
|
255
|
+
description: "Undo the last layout change.",
|
|
256
|
+
defaults: ["CmdOrCtrl+Z"],
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
id: "layout-redo",
|
|
260
|
+
category: "Pane Management",
|
|
261
|
+
description: "Redo the last undone layout change.",
|
|
262
|
+
defaults: ["CmdOrCtrl+Shift+Z"],
|
|
263
|
+
},
|
|
248
264
|
{
|
|
249
265
|
id: "tidy-windows",
|
|
250
266
|
category: "Pane Management",
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
import type { DesktopDeepLinkBridge } from "../../types/desktop-deeplink";
|
|
12
12
|
import type { DesktopWindowBridge } from "../../types/desktop-window";
|
|
13
13
|
import { requestAccountManagementTab } from "../../plugins/builtin/account-management/navigation";
|
|
14
|
-
import { openTeamPane } from "../../
|
|
14
|
+
import { openTeamPane } from "../../team/pane-request";
|
|
15
15
|
import { chatController } from "../../plugins/builtin/chat/controller";
|
|
16
16
|
import { getShare, type ShareRecord } from "../../shares/api";
|
|
17
17
|
import { openShareLink, registerShareOpener } from "../../shares/open";
|
package/src/app.tsx
CHANGED
|
@@ -14,7 +14,7 @@ import { Header } from "./components/layout/header";
|
|
|
14
14
|
import { StatusBar } from "./components/layout/status-bar";
|
|
15
15
|
import { useAppChromeShown } from "./components/layout/presentation";
|
|
16
16
|
import { useLinkedLayoutSync } from "./layout-marketplace/linked-sync";
|
|
17
|
-
import { useTeamCollectionsSync } from "./
|
|
17
|
+
import { useTeamCollectionsSync } from "./team/collections-sync";
|
|
18
18
|
import { Shell } from "./components/layout/shell";
|
|
19
19
|
import { DetachedPaneShell } from "./components/layout/detached-pane-shell";
|
|
20
20
|
import { TransientLayoutProvider } from "./components/layout/transient-layout";
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
"src/app/global-shortcuts.ts": ["help"],
|
|
5
5
|
"src/app/pane-runtime/plugin-bindings.ts": ["broker-manager","layout-manager"],
|
|
6
6
|
"src/app/runtime/broker-import.ts": ["portfolio-list"],
|
|
7
|
-
"src/app/runtime/desktop-deeplink.ts": ["account-management","chat"
|
|
7
|
+
"src/app/runtime/desktop-deeplink.ts": ["account-management","chat"],
|
|
8
8
|
"src/app/runtime/startup.ts": ["chat"],
|
|
9
9
|
"src/cli/commands/market.ts": ["holders","insider","research","sec"],
|
|
10
10
|
"src/cli/commands/options-chain.ts": ["options","options-calculator"],
|
|
11
|
-
"src/cli/commands/options-leaps.ts": ["options","vol-surface"],
|
|
11
|
+
"src/cli/commands/options-leaps.ts": ["iv-history","options","vol-surface"],
|
|
12
12
|
"src/cli/commands/overview.ts": ["correlation","econ","market-movers","sectors","world-indices"],
|
|
13
13
|
"src/cli/commands/ticker.ts": ["notes"],
|
|
14
14
|
"src/cli/desktop-pane-shot.ts": ["market-valuation","time-sales"],
|
|
@@ -24,21 +24,16 @@
|
|
|
24
24
|
"src/components/command-bar/routes/root/command-items.ts": ["portfolio-list"],
|
|
25
25
|
"src/components/command-bar/routes/root/help-items.ts": ["help"],
|
|
26
26
|
"src/components/command-bar/routes/root/shortcut-items.ts": ["portfolio-list"],
|
|
27
|
-
"src/components/command-bar/workflow/builtin.ts": ["
|
|
28
|
-
"src/components/command-bar/workflow/collection-actions.ts": ["
|
|
27
|
+
"src/components/command-bar/workflow/builtin.ts": ["portfolio-list"],
|
|
28
|
+
"src/components/command-bar/workflow/collection-actions.ts": ["portfolio-list"],
|
|
29
29
|
"src/components/command-bar/workflow/ops.ts": ["correlation","portfolio-list","ticker-detail"],
|
|
30
30
|
"src/components/command-bar/workflow/tickers.ts": ["portfolio-list"],
|
|
31
|
-
"src/components/feedback-dialog.tsx": ["cloud"],
|
|
32
31
|
"src/components/form-modal/routes.ts": ["portfolio-list"],
|
|
33
32
|
"src/components/index.ts": ["portfolio-list"],
|
|
34
33
|
"src/components/layout/shell/index.tsx": ["cloud"],
|
|
35
|
-
"src/components/layout/status-bar-groups.ts": ["cloud"],
|
|
36
|
-
"src/components/layout/status-bar.tsx": ["cloud"],
|
|
37
34
|
"src/components/onboarding/use-onboarding-upgrade.ts": ["chat"],
|
|
38
35
|
"src/components/onboarding/wizard-model.ts": ["portfolio-list"],
|
|
39
36
|
"src/components/onboarding/wizard-positions.ts": ["portfolio-list"],
|
|
40
|
-
"src/layout-marketplace/gallery.tsx": ["cloud"],
|
|
41
|
-
"src/layout-marketplace/linked-sync.ts": ["cloud"],
|
|
42
37
|
"src/layout/desks.ts": ["chart-composer"],
|
|
43
38
|
"src/plugins/catalog-browser.ts": ["alerts","analytics","attention","awards","backtest","bond-calculator","catalysts","cds","central-bank-rates","changelog","chart-composer","clinical-trials","cloud","comment-letters","commodities-energy","commodity-balances","company-attention","company-kpis","connections","correlation","cot","cpi","credit-boards","credit-conditions","credit-documents","crypto-board","debt-maturities","dividend-yield","docs","doe","earnings-calls","earnings-ripple","econ","econ-statistics","equity-screener","estimate-revisions","executives","exposure","fear-greed","filing-events","fixed-income","futures","futures-curve","fx-matrix","gpu","help","insider","ipo-calendar","iv-history","jobs","jodi","kelly-sizer","layout-manager","macro-day","market-halts","market-heatmap","market-valuation","members","mna","money-markets","news","openfda","options","options-calculator","options-positioning","options-scenario","pe-band","perps","portfolio-list","power","primary-dealers","rate-path","realized-vol","relative-rotation","research","research-search","revenue-breakdown","reverse-dcf","risk-factors","scanner","seasonality","sec","sectors","short-interest","short-volume","social-mentions","supply-chain","ticker-detail","time-sales","trace-bonds","treasury-auctions","treasury-daily","vol-surface","volatility","world-indices","world-venue-map","yield-curve"],
|
|
44
39
|
"src/plugins/catalog-ui.ts": ["alerts","clinical-trials","cloud","comment-letters","custom-view","fear-greed","ipo-calendar","market-halts","market-heatmap","members","news","notes","openfda","research-search"],
|
|
@@ -24,6 +24,7 @@ import { withCliServices, withMarketData } from "../context";
|
|
|
24
24
|
import { isoDate, parsePositiveInt, requireOneArg, takeFlag, takeOption } from "./command-utils";
|
|
25
25
|
import type { BuiltinCliCommandDef } from "../command-options";
|
|
26
26
|
import { CLI_COMMAND_GROUPS, TABLE_SECTION_OPTION } from "../help";
|
|
27
|
+
import { CLI_EXIT_CODES } from "../exit-codes";
|
|
27
28
|
import {
|
|
28
29
|
formatChangePercentCell,
|
|
29
30
|
formatCountCell,
|
|
@@ -44,7 +45,9 @@ import {
|
|
|
44
45
|
import { getPublishedUsEquityCalendarYears, getPublishedUsEquitySession } from "../../market-data/published-us-sessions";
|
|
45
46
|
import { isQuoteStaleForCurrentSession } from "../../market-data/quotes/freshness";
|
|
46
47
|
import { isOptionsUnavailableError, listedOptionsAlternative, optionsUnavailableTitle } from "../../market-data/options-alternatives";
|
|
47
|
-
import {
|
|
48
|
+
import {
|
|
49
|
+
cliFuturesContract, futuresContractMetrics, fundamentalsReportTables, loadForwardYieldDeclarations, renderFundamentalsReport,
|
|
50
|
+
} from "./ticker";
|
|
48
51
|
import type { FuturesContractTermsPayload } from "../../api-client/futures-curve";
|
|
49
52
|
import { futuresSettleText, isFuturesInstrument } from "../../market-data/futures-contract";
|
|
50
53
|
import {
|
|
@@ -55,18 +58,20 @@ import {
|
|
|
55
58
|
formatOptionDeltaCell,
|
|
56
59
|
formatOptionIvCell,
|
|
57
60
|
formatOptionQuoteCell,
|
|
58
|
-
missingExpiryMessage,
|
|
59
61
|
OPTION_MODEL_RATE,
|
|
60
62
|
OPTIONS_USAGE,
|
|
61
63
|
optionRows,
|
|
62
64
|
optionsBasisFields,
|
|
63
65
|
optionsBasisFootnote,
|
|
64
66
|
parseOptionExpiration,
|
|
65
|
-
requestListedOpenInterest,
|
|
66
67
|
valueChainAtModelSpot,
|
|
67
68
|
type OptionsChainBasis,
|
|
68
69
|
} from "./options-chain";
|
|
69
|
-
import {
|
|
70
|
+
import { missingExpiryMessage } from "../../utils/option-expiry";
|
|
71
|
+
import { declaredDividends } from "../../utils/declared-dividends";
|
|
72
|
+
import {
|
|
73
|
+
DEFAULT_LEAPS_CRITERIA, LEAPS_EXTRA_COLUMNS, LEAPS_USAGE, parseLeapsCriteria, runLeapsScreen, takeLeapsOptions,
|
|
74
|
+
} from "./options-leaps";
|
|
70
75
|
import type { CliResultColumn } from "../result";
|
|
71
76
|
import type { PriceHistoryResult } from "../../types/price-history";
|
|
72
77
|
import {
|
|
@@ -142,14 +147,14 @@ import { earningsCalendarFailure, earningsChoiceNote, earningsDateLabel, isListi
|
|
|
142
147
|
import { formatBasisPoints, toBasisPoints } from "../../utils/basis-points";
|
|
143
148
|
import { notATickerSymbol, providerMissReason } from "../../sources/provider-errors";
|
|
144
149
|
import { isNotATickerMessage, withListingSuggestion } from "../not-a-ticker";
|
|
145
|
-
import { describeSuggestion, suggestListing } from "../listing-suggestion";
|
|
146
|
-
import { splitSymbolArgs } from "../symbol-args";
|
|
150
|
+
import { describeSuggestion, suggestListing, suggestUsTicker, type ListingSuggestion } from "../listing-suggestion";
|
|
151
|
+
import { splitSymbolArgs, uniqueSecuritySymbols } from "../symbol-args";
|
|
147
152
|
import { cliPerpetualContract, perpetualContractStats, type PerpetualContractPayload } from "../perpetual-contract";
|
|
148
153
|
import { subMinuteDataMessage } from "../known-gaps";
|
|
149
154
|
import { secRegistrantMismatchMessage, SecRegistrantMismatchError, areDifferentCompanies } from "../../sources/sec-registrant";
|
|
150
155
|
import { isCryptoPairSymbol } from "../../utils/crypto-pair";
|
|
151
156
|
import { looksLikeCurrencyPair } from "../../utils/currency-pair";
|
|
152
|
-
import { isUsListingExchange } from "../../utils/exchanges";
|
|
157
|
+
import { canonicalExchange, isUsListingExchange } from "../../utils/exchanges";
|
|
153
158
|
import { describeTickerChange, startTickerChangeLookup, tickerChangeLine, type TickerChange } from "../../tickers/ticker-changes";
|
|
154
159
|
import { noSecReportsNotice, nonUsSecListingVenue } from "../../utils/sec";
|
|
155
160
|
import type { MarketContext } from "../types";
|
|
@@ -207,6 +212,8 @@ type QuoteCliRecord = Omit<QuoteBatchResult, "error"> & {
|
|
|
207
212
|
perpetualContract?: PerpetualContractPayload;
|
|
208
213
|
/** The symbol changed: its issuer moved to another symbol, or its holder had another before. */
|
|
209
214
|
tickerChange?: TickerChange;
|
|
215
|
+
/** A bare symbol read on a listing abroad that is one slip from a US ticker: the US ticker it was most likely typed for. */
|
|
216
|
+
usSuggestion?: ListingSuggestion;
|
|
210
217
|
};
|
|
211
218
|
type FinancialsCliData = TickerFinancials & {
|
|
212
219
|
symbol: string;
|
|
@@ -224,9 +231,13 @@ function parseNewsFeed(value: string | undefined): NewsQuery["feed"] | undefined
|
|
|
224
231
|
return value && VALID_NEWS_FEEDS.has(value as NewsFeed) ? value as NewsQuery["feed"] : undefined;
|
|
225
232
|
}
|
|
226
233
|
|
|
227
|
-
/**
|
|
234
|
+
/**
|
|
235
|
+
* The symbols of a command's arguments, one each however they were separated
|
|
236
|
+
* (spaces, commas or pasted lines), and each security once however its case or
|
|
237
|
+
* share class was written: `AAPL aapl BRK.B BRK-B` is AAPL and BRK.B.
|
|
238
|
+
*/
|
|
228
239
|
function normalizeSymbols(args: string[]): string[] {
|
|
229
|
-
return splitSymbolArgs(args).map((symbol) => symbol.toUpperCase());
|
|
240
|
+
return uniqueSecuritySymbols(splitSymbolArgs(args).map((symbol) => symbol.toUpperCase()));
|
|
230
241
|
}
|
|
231
242
|
|
|
232
243
|
/** What JSON metadata says about the listing a command resolved. */
|
|
@@ -499,6 +510,13 @@ function corporateActionRows(data: CorporateActionsData) {
|
|
|
499
510
|
date: event.exDate,
|
|
500
511
|
detail: currency ? formatDistributionAmount(event.amount, currency) : cleanDecimal(event.amount),
|
|
501
512
|
})),
|
|
513
|
+
// Declared and unpaid, at its ex-date beside the paid rows, never one of them.
|
|
514
|
+
...declaredDividends(data).map((event) => ({
|
|
515
|
+
type: "dividend",
|
|
516
|
+
date: event.exDate,
|
|
517
|
+
detail: `declared ${currency ? formatDistributionAmount(event.amount, currency) : cleanDecimal(event.amount)}`
|
|
518
|
+
+ (event.payDate ? `, payable ${event.payDate}` : ""),
|
|
519
|
+
})),
|
|
502
520
|
...data.splits.map((event) => ({
|
|
503
521
|
type: "split",
|
|
504
522
|
date: event.date,
|
|
@@ -563,7 +581,9 @@ async function runQuote(rawArgs: string[], ctx: Parameters<CliCommandDef["execut
|
|
|
563
581
|
// So is whether a symbol changed (FB is now META), for the same lists.
|
|
564
582
|
const changes = new Map(listings.length > MAX_CHOICE_LOOKUPS ? []
|
|
565
583
|
: listings.map((listing) => [listing, startTickerChangeLookup(market.dataProvider, listing.symbol, listing.exchange)] as const));
|
|
566
|
-
|
|
584
|
+
// The service's quote of the moment, not each form's local copy from whenever it was last asked for:
|
|
585
|
+
// BRK.B saved on NYSE, BRK-B and BRK.B:NYSE print one quote (GLO-735). A local copy answers only offline.
|
|
586
|
+
const results = await market.dataProvider.getQuotesBatch(targets, { forceRefresh: ctx.cliOptions.refresh, revalidate: true });
|
|
567
587
|
const listingOf = (result: QuoteBatchResult, index: number) => listings[targets.indexOf(result.target)] ?? listings[index]!;
|
|
568
588
|
const asked = results.map(listingOf);
|
|
569
589
|
const request = { command: commandName, noun: "quote" };
|
|
@@ -590,6 +610,11 @@ async function runQuote(rawArgs: string[], ctx: Parameters<CliCommandDef["execut
|
|
|
590
610
|
const perpetualContracts = await Promise.all(answers.map(({ result }) => commandName === "quote" && result.quote
|
|
591
611
|
? cliPerpetualContract(result.quote)
|
|
592
612
|
: null));
|
|
613
|
+
// A bare symbol quoted on a listing abroad (APPL, Aptus Pharma on BSE) that is one slip from a US ticker (AAPL) says so.
|
|
614
|
+
const usSuggestions = await Promise.all(answers.map(({ result, listing, notes }) => {
|
|
615
|
+
const venue = result.quote && !listing.saved ? bareListingNote(listing, result.quote) : null;
|
|
616
|
+
return venue && notes.includes(venue) ? suggestUsTicker(listing.symbol, market) : null;
|
|
617
|
+
}));
|
|
593
618
|
// Each row names its listing by key (SAN:EPA) and company, so the table needs no line above it.
|
|
594
619
|
const data = answers.map(({ result, listing, failure }, index) => ({
|
|
595
620
|
target: result.target,
|
|
@@ -599,6 +624,7 @@ async function runQuote(rawArgs: string[], ctx: Parameters<CliCommandDef["execut
|
|
|
599
624
|
quote: result.quote,
|
|
600
625
|
...contracts[index] ? { futuresContract: contracts[index] } : {},
|
|
601
626
|
...perpetualContracts[index] ? { perpetualContract: perpetualContracts[index] } : {},
|
|
627
|
+
...usSuggestions[index] ? { usSuggestion: usSuggestions[index] } : {},
|
|
602
628
|
error: failure?.oneLine ?? errorMessage(result.error),
|
|
603
629
|
...yieldIndexFields(result),
|
|
604
630
|
...tickerChanges[index] ? { tickerChange: tickerChanges[index] } : {},
|
|
@@ -625,15 +651,38 @@ async function runQuote(rawArgs: string[], ctx: Parameters<CliCommandDef["execut
|
|
|
625
651
|
freshness: quotesFreshness(data.map((row) => row.quote)),
|
|
626
652
|
}, {
|
|
627
653
|
rows: quoteRows,
|
|
628
|
-
details:
|
|
654
|
+
details: quoteDetailsText,
|
|
629
655
|
columns,
|
|
630
656
|
...(yieldsOnly ? { textColumns: columns.map((column) => column.key === "changePercent" ? { ...column, header: "Chg" } : column) } : {}),
|
|
631
657
|
});
|
|
658
|
+
// The table names each symbol it found nothing for; with none found, the exit status says so too.
|
|
659
|
+
if (data.every((row) => !row.quote)) process.exitCode = CLI_EXIT_CODES.error;
|
|
632
660
|
});
|
|
633
661
|
}
|
|
634
662
|
|
|
635
663
|
/**
|
|
636
|
-
* Under the table
|
|
664
|
+
* Under the table: each futures row's Settle line and Contract block, then the
|
|
665
|
+
* line for a symbol that is not a US ticker though it is one slip from one.
|
|
666
|
+
*/
|
|
667
|
+
function quoteDetailsText(data: QuoteCliRecord[]): string {
|
|
668
|
+
return [quoteFuturesContractText(data), ...data.flatMap((row) => notUsTickerLine(row) ?? [])].filter(Boolean).join("\n\n");
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* "APPL is not a US ticker: it is Aptus Pharma Limited on BSE (INR). Did you
|
|
673
|
+
* mean AAPL (Apple Inc.)?", for a symbol read on a listing abroad that is one
|
|
674
|
+
* slip from a US ticker, worded as the not-a-ticker answers word it.
|
|
675
|
+
*/
|
|
676
|
+
function notUsTickerLine({ target, quote, listing, usSuggestion }: QuoteCliRecord): string | null {
|
|
677
|
+
if (!quote || !usSuggestion) return null;
|
|
678
|
+
const venue = canonicalExchange(quote.listingExchangeName || quote.exchangeName);
|
|
679
|
+
const name = quote.name || listing?.name;
|
|
680
|
+
const what = `${name ? `${name} on ` : ""}${venue}${quote.currency ? ` (${quote.currency})` : ""}`;
|
|
681
|
+
return cliStyles.warning(`${target.symbol} is not a US ticker: it is ${what}. Did you mean ${describeSuggestion(usSuggestion)}?`);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Each futures row's Settle line and Contract block, worded
|
|
637
686
|
* as `ticker` words them. Several symbols name theirs in the block's title.
|
|
638
687
|
*/
|
|
639
688
|
function quoteFuturesContractText(data: QuoteCliRecord[]): string {
|
|
@@ -837,16 +886,18 @@ async function runHistory(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
|
|
|
837
886
|
const flagColumn: CliResultColumn = {
|
|
838
887
|
key: "flag", header: "Flag", format: (value) => typeof value === "string" ? cliStyles.warning(value) : "",
|
|
839
888
|
};
|
|
840
|
-
// Text also marks a bar still forming
|
|
889
|
+
// Text also marks a bar still forming, rebuilt from hourly bars or closing before its settlement; exports keep them as fields.
|
|
841
890
|
const flagTextColumn: CliResultColumn = {
|
|
842
891
|
...flagColumn,
|
|
843
892
|
format: (value, row) => [
|
|
844
893
|
typeof value === "string" ? cliStyles.warning(value) : "",
|
|
845
894
|
row.partial ? cliStyles.muted("partial") : "",
|
|
846
895
|
row.filled ? cliStyles.muted("filled") : "",
|
|
896
|
+
row.unsettled ? cliStyles.muted("unsettled") : "",
|
|
847
897
|
].filter(Boolean).join(" "),
|
|
848
898
|
};
|
|
849
899
|
const marked = data.some((row) => row.partial || row.filled);
|
|
900
|
+
const unsettled = data.some((row) => row.unsettled);
|
|
850
901
|
ctx.printResult({
|
|
851
902
|
data,
|
|
852
903
|
metadata: {
|
|
@@ -875,6 +926,7 @@ async function runHistory(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
|
|
|
875
926
|
...priceColumns,
|
|
876
927
|
flagColumn,
|
|
877
928
|
...marked ? [{ key: "partial", header: "Partial" }, { key: "filled", header: "Filled" }] : [],
|
|
929
|
+
...unsettled ? [{ key: "unsettled", header: "Unsettled" }] : [],
|
|
878
930
|
...volume ? [{ key: "volumeUnit", header: "Volume unit" }, { key: "volumeNote", header: "Volume note" }] : [],
|
|
879
931
|
],
|
|
880
932
|
// Every exported row says what it is a bar of, the currency a price is in and its bar size, so it survives head and concatenation.
|
|
@@ -932,6 +984,10 @@ async function runFinancials(rawArgs: string[], ctx: Parameters<CliCommandDef["e
|
|
|
932
984
|
// Market cap, the multiples and the yield at the regular session price, as the text gives them; the quote stays as sent.
|
|
933
985
|
const priced = atRegularSessionPrice(financials);
|
|
934
986
|
const capitalization = selectMarketCapitalization(priced.quote, priced.fundamentals);
|
|
987
|
+
// A forward yield dated ahead names the declared distribution it annualizes, in the text and tables.
|
|
988
|
+
const report = ctx.cliOptions.format === "json" ? data : {
|
|
989
|
+
...data, declaredDividends: await loadForwardYieldDeclarations(market.dataProvider, listing.request, financials.fundamentals),
|
|
990
|
+
};
|
|
935
991
|
ctx.printResult({
|
|
936
992
|
// JSON reads a multiple over a loss as null with its reason, never as a number.
|
|
937
993
|
data: {
|
|
@@ -946,8 +1002,8 @@ async function runFinancials(rawArgs: string[], ctx: Parameters<CliCommandDef["e
|
|
|
946
1002
|
freshness,
|
|
947
1003
|
...(choice.length > 0 ? { warnings: choice } : {}),
|
|
948
1004
|
}, {
|
|
949
|
-
text: () => renderFundamentalsReport(
|
|
950
|
-
...(tabular ? { tables: selectTables(fundamentalsReportTables(
|
|
1005
|
+
text: () => renderFundamentalsReport(report, view),
|
|
1006
|
+
...(tabular ? { tables: selectTables(fundamentalsReportTables(report, view, freshness)) } : {}),
|
|
951
1007
|
exportIdentity: { symbolOrSeries: listing.key },
|
|
952
1008
|
});
|
|
953
1009
|
return;
|
|
@@ -1472,10 +1528,9 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
|
|
|
1472
1528
|
const expiration = takeOption(args, "--expiration");
|
|
1473
1529
|
const exchangeOption = takeOption(args, "--exchange");
|
|
1474
1530
|
if (leapsOptions.leaps) {
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
}
|
|
1478
|
-
const criteria = parseLeapsCriteria(leapsOptions.raw);
|
|
1531
|
+
// With --leaps, --expiration is a window of one expiry.
|
|
1532
|
+
const expirationGiven = expiration != null || rawArgs.some((arg) => arg === "--expiration" || arg.startsWith("--expiration="));
|
|
1533
|
+
const criteria = parseLeapsCriteria({ ...leapsOptions.raw, ...expirationGiven ? { "--expiration": expiration ?? "" } : {} });
|
|
1479
1534
|
if ("error" in criteria) ctx.fail(criteria.error, `Usage: gloomberb ${LEAPS_USAGE}`);
|
|
1480
1535
|
const symbols = normalizeSymbols(args);
|
|
1481
1536
|
if (symbols.length === 0) ctx.fail("--leaps needs at least one symbol.", `Usage: gloomberb ${LEAPS_USAGE}`);
|
|
@@ -1505,8 +1560,6 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
|
|
|
1505
1560
|
const quotePromise = loadListingQuote(market.dataProvider, listing);
|
|
1506
1561
|
const fate = listingFateLoader(listing, market, quotePromise);
|
|
1507
1562
|
const inputsPromise = loadOptionModelInputs(market.dataProvider, listing, quotePromise, refresh);
|
|
1508
|
-
// OPX's listing dates the chain's open interest; asked for alongside the chain when the expiry is known.
|
|
1509
|
-
const listedOpenInterest = expirationDate != null ? requestListedOpenInterest(symbol, expirationDate) : null;
|
|
1510
1563
|
const { result, chain: loaded } = await loadForListing(listing, market, ctx, async () => {
|
|
1511
1564
|
const cached = await market.dataProvider.getCachedQuery?.("getOptionsChain", [symbol, exchange, expirationDate, undefined])
|
|
1512
1565
|
.load({ force: refresh });
|
|
@@ -1539,7 +1592,7 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
|
|
|
1539
1592
|
// IV and delta are valued at one spot and instant, named under the table and on every exported row.
|
|
1540
1593
|
const { chain, spot: modelSpot } = valueChainAtModelSpot(loaded, inputs, Date.now(), identity.exchange);
|
|
1541
1594
|
const basis: OptionsChainBasis = { spot: modelSpot, dividendYield: inputs.dividendYield ?? null,
|
|
1542
|
-
openInterest: await loadOptionsChainOpenInterest(symbol, chain
|
|
1595
|
+
openInterest: await loadOptionsChainOpenInterest(symbol, chain) };
|
|
1543
1596
|
const basisFields = optionsBasisFields(basis);
|
|
1544
1597
|
const currency = [...chain.calls, ...chain.puts].find((contract) => contract.currency?.trim())?.currency.trim().toUpperCase()
|
|
1545
1598
|
?? quote?.currency ?? null;
|
|
@@ -1815,10 +1868,10 @@ export const marketDataCliCommands: BuiltinCliCommandDef[] = [
|
|
|
1815
1868
|
options: [
|
|
1816
1869
|
{
|
|
1817
1870
|
flags: "--expiration <YYYY-MM-DD|unix>",
|
|
1818
|
-
description: "Expiration as a date (2028-01-21) or Unix seconds; defaults to the nearest one, and lists the others",
|
|
1871
|
+
description: "Expiration as a date (2028-01-21) or Unix seconds; defaults to the nearest one, and lists the others. With --leaps: rank that expiry alone",
|
|
1819
1872
|
},
|
|
1820
1873
|
EXCHANGE_OPTION,
|
|
1821
|
-
{ flags: "--leaps", description: "Rank contracts
|
|
1874
|
+
{ flags: "--leaps", description: "Rank long-dated contracts across the symbols given, as a stock replacement; more than a year out unless a window says otherwise" },
|
|
1822
1875
|
{ flags: "--side <calls|puts>", description: `With --leaps: the side to rank (default ${DEFAULT_LEAPS_CRITERIA.side}s)` },
|
|
1823
1876
|
{
|
|
1824
1877
|
flags: "--delta <low-high>",
|
|
@@ -1829,6 +1882,17 @@ export const marketDataCliCommands: BuiltinCliCommandDef[] = [
|
|
|
1829
1882
|
description: `With --leaps: widest bid/ask spread, in percent of the midpoint (default ${DEFAULT_LEAPS_CRITERIA.maxSpreadPercent})`,
|
|
1830
1883
|
},
|
|
1831
1884
|
{ flags: "--min-oi <contracts>", description: `With --leaps: least open interest (default ${DEFAULT_LEAPS_CRITERIA.minOpenInterest})` },
|
|
1885
|
+
{
|
|
1886
|
+
flags: "--min-days <days>",
|
|
1887
|
+
description: `With --leaps: fewest calendar days to expiry (default ${DEFAULT_LEAPS_CRITERIA.minDays}); 180 reaches six months out`,
|
|
1888
|
+
},
|
|
1889
|
+
{ flags: "--max-days <days>", description: "With --leaps: most calendar days to expiry; --min-days 365 --max-days 730 is 12 to 24 months" },
|
|
1890
|
+
{ flags: "--expiry-from <YYYY-MM-DD>", description: "With --leaps: first expiry date kept; replaces the one-year floor" },
|
|
1891
|
+
{ flags: "--expiry-to <YYYY-MM-DD>", description: "With --leaps: last expiry date kept" },
|
|
1892
|
+
{
|
|
1893
|
+
flags: "--columns <list>",
|
|
1894
|
+
description: `With --leaps: add figures, comma-separated: ${LEAPS_EXTRA_COLUMNS.join(", ")}`,
|
|
1895
|
+
},
|
|
1832
1896
|
{
|
|
1833
1897
|
flags: "--sort <order>",
|
|
1834
1898
|
description: "With --leaps: carry (extrinsic per year, lowest first; the default), spread, oi, delta, expiry or symbol",
|
|
@@ -1837,7 +1901,10 @@ export const marketDataCliCommands: BuiltinCliCommandDef[] = [
|
|
|
1837
1901
|
sections: [{
|
|
1838
1902
|
title: "LEAPS",
|
|
1839
1903
|
lines: [
|
|
1840
|
-
"--leaps reads
|
|
1904
|
+
"--leaps reads each symbol's expiries in the window and keeps the liquid contracts in the delta band, ranked by extrinsic per year: time value (midpoint less intrinsic) as a percent of spot, per year to expiry.",
|
|
1905
|
+
"--min-days, --max-days, --expiry-from and --expiry-to set the window together; without a lower bound it starts a year out. Each symbol reads at most 8 expiries, the ones nearest the window's start, and a warning names any it left.",
|
|
1906
|
+
"--columns adds iv (the contract's implied vol), ivr (the underlying's IV rank), cost (midpoint x 100 per contract), breakeven (at the midpoint, and its distance from spot), next-earnings, ex-dividend and carry-net "
|
|
1907
|
+
+ `(extrinsic per year net of the ${Number((OPTION_MODEL_RATE * 100).toFixed(2))}% rate on the strike and the dividend yield). A figure a symbol lacks is blank, with a warning.`,
|
|
1841
1908
|
"A symbol without LEAPS, a quote or a chain is named in a warning and the others still rank. docs/research-data.md defines each figure.",
|
|
1842
1909
|
],
|
|
1843
1910
|
}],
|
|
@@ -1847,6 +1914,8 @@ export const marketDataCliCommands: BuiltinCliCommandDef[] = [
|
|
|
1847
1914
|
"options AAPL:NASDAQ --json",
|
|
1848
1915
|
"options AAPL MSFT NVDA GOOGL AMZN META --leaps",
|
|
1849
1916
|
"options SPY QQQ --leaps --side puts --delta 0.20-0.40 --csv",
|
|
1917
|
+
"options MSFT --leaps --min-days 365 --max-days 730",
|
|
1918
|
+
"options AAPL MSFT NVDA --leaps --min-days 180 --columns iv,ivr,cost,breakeven,carry-net",
|
|
1850
1919
|
],
|
|
1851
1920
|
},
|
|
1852
1921
|
execute: runOptions,
|