sentisense 0.61.0 → 0.63.0
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 +28 -2
- package/dist/cli.cjs +123 -39
- package/dist/index.cjs +51 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +373 -13
- package/dist/index.d.ts +373 -13
- package/dist/index.mjs +51 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -68,7 +68,7 @@ npx -y sentisense@latest health
|
|
|
68
68
|
|---------|--------------|
|
|
69
69
|
| `auth [key]` | Store a key, show what is configured, or `--remove` it |
|
|
70
70
|
| `health` | Reachability, key validity, latency, and the resolved base URL |
|
|
71
|
-
| `quote <ticker>...` | Price, day range, 52-week range, market cap, P/E. One request per ticker |
|
|
71
|
+
| `quote <ticker>...` | Price, day range, 52-week range, market cap, P/E. One request per ticker; ETFs show AUM, expense ratio and NAV |
|
|
72
72
|
| `sentiment <ticker>` | SentiSense Score, tone, attention, per-source breakdown, `--days N` history |
|
|
73
73
|
| `mood` | Composite market sentiment, the signals behind it, and the sector map |
|
|
74
74
|
| `analysts <ticker>` | Consensus, price target band, recent upgrades and downgrades. `--coverage` for who covers it, by firm |
|
|
@@ -238,7 +238,10 @@ client.stocks.getProfile("AAPL") // Company profile
|
|
|
238
238
|
client.stocks.getChart("AAPL", { timeframe: "6M" }) // OHLCV chart data
|
|
239
239
|
client.stocks.getMarketStatus() // Market open/closed
|
|
240
240
|
client.stocks.getFundamentals("AAPL") // Financial data
|
|
241
|
-
client.stocks.getShortInterest("GME")
|
|
241
|
+
client.stocks.getShortInterest("GME", { limit: 12 }) // Short interest by settlement date
|
|
242
|
+
client.stocks.getShortVolume("GME") // Daily short volume
|
|
243
|
+
client.stocks.getFloat("GME") // Free float
|
|
244
|
+
client.stocks.getGraph("AAPL", { depth: 1 }) // Company knowledge graph: people, products, peers
|
|
242
245
|
client.stocks.getOptionsSummary("NVDA") // End-of-day options dossier
|
|
243
246
|
client.stocks.getOptionsHistory("NVDA", { window: "2y" }) // Daily options aggregates over time
|
|
244
247
|
client.stocks.getRating("AAPL") // SentiSense Rating: score, letter, percentile, dimensions
|
|
@@ -247,6 +250,10 @@ client.stocks.getAISummary("AAPL", { depth: "deep" }) // AI report (PRO)
|
|
|
247
250
|
|
|
248
251
|
Price fields carry `priceAsOf` (Unix milliseconds) for the age of the market data; read that for freshness rather than `timestamp`, which is when the response was served.
|
|
249
252
|
|
|
253
|
+
Short interest and short volume come back newest first, and an unknown ticker returns an empty `dataPoints` array rather than an error. Every identifier in `getGraph` is a slug, the same handle the metric and document endpoints take. An ETF symbol is refused by `getQuote` with an `APIError` whose `code` is `"ticker_is_etf"`; use `etfs.quote()` for funds.
|
|
254
|
+
|
|
255
|
+
Product nodes (`type === "PRODUCT_OR_SERVICE"`) in `stocks.getGraph` now carry optional `category` when known. Other nodes and products without a category omit it.
|
|
256
|
+
|
|
250
257
|
### Documents & news
|
|
251
258
|
|
|
252
259
|
```typescript
|
|
@@ -287,6 +294,18 @@ client.institutional.getHolders("AAPL", "2025-02-14")
|
|
|
287
294
|
client.institutional.getActivists("2025-02-14")
|
|
288
295
|
```
|
|
289
296
|
|
|
297
|
+
`positionsHeld` on an institution detail counts the full portfolio's held positions:
|
|
298
|
+
`max(0, holdingsCount - soldOutPositions)`, even when the holdings list is truncated.
|
|
299
|
+
`getInstitutionDetail` keeps its `Promise<unknown>` signature. The exported all-optional
|
|
300
|
+
`InstitutionDetail` type is available for callers who want to opt in:
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
import type { InstitutionDetail, PreviewResponse } from "sentisense";
|
|
304
|
+
|
|
305
|
+
const detail = await client.institutional.getInstitutionDetail("1067983") as PreviewResponse<InstitutionDetail>;
|
|
306
|
+
console.log(detail.data.positionsHeld); // undefined when an older response omits it
|
|
307
|
+
```
|
|
308
|
+
|
|
290
309
|
**Paging the holder list.** A widely held ticker returns thousands of rows: a megacap quarter is roughly 6,000 holders and 1.5 MB on the wire. Pass `limit` unless you really want the whole list; omitting the options object sends the original unbounded request, so existing code keeps working.
|
|
291
310
|
|
|
292
311
|
| Option | Values |
|
|
@@ -412,6 +431,8 @@ Two shapes to read rather than assume. A firm can appear with `noteCount: 0`, a
|
|
|
412
431
|
|
|
413
432
|
`ratingBuckets` sizes the same book by rating tier: `buy`, `hold`, `sell`, `unrated` and `total`, counted over every covering firm before the free truncation, so `buy + hold + sell + unrated === total` and a free key reads the same numbers as a PRO one. `unrated` is a desk with no current rating on record, such as a price-target-only firm. These count the firms in this coverage book, a different population from the `strongBuy` through `strongSell` figures on `client.analyst.consensus`, which come from the provider's analyst survey. Read one or the other, do not reconcile them.
|
|
414
433
|
|
|
434
|
+
Surprise rows now carry optional `surprisePct`, the signed true percent rounded half-up to two decimals: `(actualEps - estimateEps) * 100 / abs(estimateEps)`. It is `null` when either EPS is missing or the estimate is zero, and `undefined` on older responses. The existing `surprisePercent` fraction is unchanged (`0.03` means about 3%).
|
|
435
|
+
|
|
415
436
|
### Earnings
|
|
416
437
|
|
|
417
438
|
The earnings analysis report is the assembled version of a quarter: one object per fiscal period carrying the editorial headline, the KPI cards with year-over-year deltas, the guidance language as management phrased it, and a summary of the earnings call. Pair it with the recent-reporters feed to drive a post-earnings sweep. Summaries, recent reports, statistics, and rankings return the preview envelope; per-ticker reactions return a direct payload.
|
|
@@ -446,6 +467,8 @@ if (quarter) {
|
|
|
446
467
|
|
|
447
468
|
The forward-looking half of the family is `client.calendar.getEarnings()`, which covers scheduled dates and consensus EPS rather than results.
|
|
448
469
|
|
|
470
|
+
`earnings.getSummaries` exposes optional `totalCount` on the envelope on both PRO and FREE. It counts indexed quarters; returned rows can be fewer because of `limit` or an unavailable body. Older responses without the count still read as `undefined`.
|
|
471
|
+
|
|
449
472
|
### Company KPIs (PRO)
|
|
450
473
|
|
|
451
474
|
```typescript
|
|
@@ -459,6 +482,7 @@ Composition data is public; the holdings-weighted aggregate views follow the sam
|
|
|
459
482
|
|
|
460
483
|
```typescript
|
|
461
484
|
client.etfs.list() // Every ETF tracked
|
|
485
|
+
client.etfs.quote("SPY") // Price, ranges, AUM, expense ratio, NAV
|
|
462
486
|
client.etfs.holdings("QQQ") // Full composition + freshness metadata
|
|
463
487
|
client.etfs.analystAggregate("QQQ") // Holdings-weighted analyst consensus
|
|
464
488
|
client.etfs.insiderAggregate("ARKK", { lookbackDays: 90 }) // Holdings-weighted Form 4 net flow
|
|
@@ -505,6 +529,8 @@ During the trading session the dossier and the radar also carry a few intraday f
|
|
|
505
529
|
|
|
506
530
|
A row whose baseline is still building carries its raw readings with the percentiles and `interestScore` omitted, which means "not enough history yet" rather than "nothing interesting". `getOptionsSummary` reports an uncovered ticker as a null payload inside the usual envelope, so the check is `result.data === null`: the response object itself is always truthy, and a bare `if (summary === null)` never fires. `getOptionsHistory` reports it as an empty `series` instead, so check the array's length rather than null-checking there.
|
|
507
531
|
|
|
532
|
+
On a delisted symbol, the options summary carries `listingStatus === "DELISTED"` and, when known, `delistedDate` (YYYY-MM-DD). This marks a frozen last dossier, so read `asOf` before treating it as current. Listed and pending symbols omit both fields.
|
|
533
|
+
|
|
508
534
|
### SentiSense Rating
|
|
509
535
|
|
|
510
536
|
Where a stock ranks against the other stocks rated that day, as a score, a letter and a percentile, plus the seven dimensions the rank is blended from. It is a relative research signal for informational and educational purposes, not financial, investment or trading advice, and not a recommendation about any security. Every response carries the wording to display alongside a grade in `disclaimer`. [Methodology](https://sentisense.ai/methodology/#sentisense-rating).
|
package/dist/cli.cjs
CHANGED
|
@@ -502,10 +502,22 @@ async function verifyTickerOnEmpty(api, ticker) {
|
|
|
502
502
|
await api.stocks.getQuote(ticker);
|
|
503
503
|
return void 0;
|
|
504
504
|
} catch (error) {
|
|
505
|
+
if (isEtfRedirect(error)) return void 0;
|
|
505
506
|
if (error instanceof NotFoundError) throw new UnknownTickerError(ticker);
|
|
506
507
|
return `could not verify ${ticker}, so the empty result is unconfirmed`;
|
|
507
508
|
}
|
|
508
509
|
}
|
|
510
|
+
function isEtfRedirect(error) {
|
|
511
|
+
return error instanceof APIError && error.code === "ticker_is_etf";
|
|
512
|
+
}
|
|
513
|
+
async function quoteAnyTicker(api, ticker) {
|
|
514
|
+
try {
|
|
515
|
+
return { kind: "stock", quote: await api.stocks.getQuote(ticker) };
|
|
516
|
+
} catch (error) {
|
|
517
|
+
if (!isEtfRedirect(error)) throw error;
|
|
518
|
+
return { kind: "etf", quote: await api.etfs.quote(ticker) };
|
|
519
|
+
}
|
|
520
|
+
}
|
|
509
521
|
var EMPTY_VERIFY_NOTE = "An empty result verifies the ticker before reporting no data, so a typo exits 4 rather";
|
|
510
522
|
var EMPTY_VERIFY_NOTE_2 = "than looking like a company with nothing to report.";
|
|
511
523
|
|
|
@@ -518,11 +530,13 @@ function actionTone(actionType) {
|
|
|
518
530
|
return void 0;
|
|
519
531
|
}
|
|
520
532
|
function primaryAnalyst(row) {
|
|
521
|
-
const named = row.latestNote?.analyst;
|
|
522
|
-
const match = (named ? row.analysts.find(
|
|
523
|
-
|
|
533
|
+
const named = row.latestNote?.analyst ?? null;
|
|
534
|
+
const match = (named ? row.analysts.find(
|
|
535
|
+
(analyst) => named.slug !== null && analyst.slug === named.slug || analyst.name === named.name
|
|
536
|
+
) : void 0) ?? row.analysts[0];
|
|
537
|
+
const name = match?.name ?? named?.name ?? "";
|
|
524
538
|
const extra = row.analysts.length > 1 ? ` +${row.analysts.length - 1}` : "";
|
|
525
|
-
return { name: name ? `${name}${extra}` : "", slug: match?.slug ?? "" };
|
|
539
|
+
return { name: name ? `${name}${extra}` : "", slug: match?.slug ?? named?.slug ?? "" };
|
|
526
540
|
}
|
|
527
541
|
var analystsCommand = {
|
|
528
542
|
name: "analysts",
|
|
@@ -1331,7 +1345,7 @@ var flowsCommand = {
|
|
|
1331
1345
|
};
|
|
1332
1346
|
|
|
1333
1347
|
// src/version.ts
|
|
1334
|
-
var VERSION = "0.
|
|
1348
|
+
var VERSION = "0.63.0";
|
|
1335
1349
|
|
|
1336
1350
|
// src/resources/analyst.ts
|
|
1337
1351
|
var Analyst = class {
|
|
@@ -1590,9 +1604,11 @@ var Earnings = class {
|
|
|
1590
1604
|
* management phrased it, and a summary of the earnings call.
|
|
1591
1605
|
*
|
|
1592
1606
|
* Branch on `isPreview`: a PRO key receives every hydrated quarter in full, a
|
|
1593
|
-
* FREE key receives the latest quarter shaped rather than truncated
|
|
1594
|
-
* `totalCount
|
|
1595
|
-
*
|
|
1607
|
+
* FREE key receives the latest quarter shaped rather than truncated.
|
|
1608
|
+
* `totalCount` on the envelope counts indexed quarters on both tiers. The
|
|
1609
|
+
* returned array can be shorter when a body is unavailable or limit cuts it.
|
|
1610
|
+
* Older responses may omit the count. {@link EarningsQuarter} documents
|
|
1611
|
+
* which fields each tier carries.
|
|
1596
1612
|
*
|
|
1597
1613
|
* A quarter typically appears within 48 hours of the company reporting, and
|
|
1598
1614
|
* the call summary can arrive after the press-release content for the same
|
|
@@ -1726,6 +1742,19 @@ var Etfs = class {
|
|
|
1726
1742
|
async list() {
|
|
1727
1743
|
return this.client.get("/api/v1/etfs");
|
|
1728
1744
|
}
|
|
1745
|
+
/**
|
|
1746
|
+
* Get the quote snapshot for an ETF: price, day and 52-week range, volume, dividend
|
|
1747
|
+
* yield, AUM, expense ratio, NAV and inception date.
|
|
1748
|
+
*
|
|
1749
|
+
* Fails with a 400 `APIError` whose `code` is `"ticker_is_not_etf"` when the symbol is a
|
|
1750
|
+
* stock (use `stocks.getQuote()` for those), and a `NotFoundError` when there is no
|
|
1751
|
+
* price data for the fund.
|
|
1752
|
+
*/
|
|
1753
|
+
async quote(ticker) {
|
|
1754
|
+
return this.client.get(
|
|
1755
|
+
`/api/v1/etfs/${encodeURIComponent(ticker.toUpperCase())}/quote`
|
|
1756
|
+
);
|
|
1757
|
+
}
|
|
1729
1758
|
/**
|
|
1730
1759
|
* Get the full holdings composition for an ETF, including per-holding weights
|
|
1731
1760
|
* and freshness metadata. Returns 404 for unknown ETFs or commodity-only funds.
|
|
@@ -2054,6 +2083,10 @@ var Institutional = class {
|
|
|
2054
2083
|
* Resolved by URL slug (e.g. `Berkshire-Hathaway`) or numeric SEC CIK.
|
|
2055
2084
|
* Free users receive the profile and top 10 holdings; PRO users receive the
|
|
2056
2085
|
* full holdings array. Returns 404 if the slug or CIK is unknown.
|
|
2086
|
+
*
|
|
2087
|
+
* The signature remains unknown for compatibility. Opt in to the exported
|
|
2088
|
+
* PreviewResponse<InstitutionDetail> type to read data.positionsHeld, the full
|
|
2089
|
+
* portfolio count excluding SOLD_OUT rows, even on a truncated holdings list.
|
|
2057
2090
|
*/
|
|
2058
2091
|
async getInstitutionDetail(slugOrCik) {
|
|
2059
2092
|
return this.client.get(
|
|
@@ -2320,6 +2353,22 @@ var Stocks = class {
|
|
|
2320
2353
|
async getEntities(ticker) {
|
|
2321
2354
|
return this.client.get(`/api/v1/stocks/${encodeURIComponent(ticker)}/entities`);
|
|
2322
2355
|
}
|
|
2356
|
+
/**
|
|
2357
|
+
* Get the company knowledge graph around a stock: the people, products, peers and other
|
|
2358
|
+
* entities linked to the company, and the typed relationships between them.
|
|
2359
|
+
*
|
|
2360
|
+
* Every identifier in the response is a slug, the same handle the metric and document
|
|
2361
|
+
* endpoints take, so a node can be passed straight to them. `depth` is 1 (default) or 2,
|
|
2362
|
+
* `cap` limits the number of non-root nodes (1 to 200, default 75); the root is always
|
|
2363
|
+
* included in addition. Out-of-range values are rejected with a 400. A ticker with no
|
|
2364
|
+
* graph returns a `NotFoundError`.
|
|
2365
|
+
*/
|
|
2366
|
+
async getGraph(ticker, options) {
|
|
2367
|
+
return this.client.get(
|
|
2368
|
+
`/api/v1/stocks/${encodeURIComponent(ticker.toUpperCase())}/graph`,
|
|
2369
|
+
options
|
|
2370
|
+
);
|
|
2371
|
+
}
|
|
2323
2372
|
/**
|
|
2324
2373
|
* Get AI-generated stock analysis report. Requires PRO tier.
|
|
2325
2374
|
*
|
|
@@ -2382,17 +2431,23 @@ var Stocks = class {
|
|
|
2382
2431
|
async getHistoricalRevenue(ticker) {
|
|
2383
2432
|
return this.client.get("/api/v1/stocks/fundamentals/historical/revenue", { ticker });
|
|
2384
2433
|
}
|
|
2385
|
-
/**
|
|
2386
|
-
|
|
2387
|
-
|
|
2434
|
+
/**
|
|
2435
|
+
* Get short interest history (FINRA), newest first: shares short, days to cover and
|
|
2436
|
+
* average daily volume per settlement date. `limit` defaults to 24 settlement dates.
|
|
2437
|
+
*/
|
|
2438
|
+
async getShortInterest(ticker, options) {
|
|
2439
|
+
return this.client.get("/api/v1/stocks/short-interest", { ticker, ...options });
|
|
2388
2440
|
}
|
|
2389
2441
|
/** Get float information. */
|
|
2390
2442
|
async getFloat(ticker) {
|
|
2391
2443
|
return this.client.get("/api/v1/stocks/float", { ticker });
|
|
2392
2444
|
}
|
|
2393
|
-
/**
|
|
2394
|
-
|
|
2395
|
-
|
|
2445
|
+
/**
|
|
2446
|
+
* Get daily short volume, newest first: shares sold short against total volume on the
|
|
2447
|
+
* reporting venues. `limit` defaults to 90 trading days.
|
|
2448
|
+
*/
|
|
2449
|
+
async getShortVolume(ticker, options) {
|
|
2450
|
+
return this.client.get("/api/v1/stocks/short-volume", { ticker, ...options });
|
|
2396
2451
|
}
|
|
2397
2452
|
/**
|
|
2398
2453
|
* Get company-specific KPI time-series for a ticker. Returns curated GAAP and
|
|
@@ -3641,6 +3696,37 @@ var optionsCommand = {
|
|
|
3641
3696
|
};
|
|
3642
3697
|
|
|
3643
3698
|
// src/cli/commands/quote.ts
|
|
3699
|
+
function valuation(row) {
|
|
3700
|
+
if (row.kind === "etf") {
|
|
3701
|
+
const etf = row.quote;
|
|
3702
|
+
return {
|
|
3703
|
+
kind: "facts",
|
|
3704
|
+
items: fields(
|
|
3705
|
+
field("AUM", humanize(etf.aum)),
|
|
3706
|
+
// Both ratios, like `dividendYield` on the stock quote.
|
|
3707
|
+
field("Expense ratio", ratioPercent(etf.expenseRatio)),
|
|
3708
|
+
field("NAV", fixed(etf.nav)),
|
|
3709
|
+
field("Div yield", ratioPercent(etf.dividendYield)),
|
|
3710
|
+
field("52w", `${fixed(etf.week52Low)} to ${fixed(etf.week52High)}`)
|
|
3711
|
+
)
|
|
3712
|
+
};
|
|
3713
|
+
}
|
|
3714
|
+
const quote = row.quote;
|
|
3715
|
+
return {
|
|
3716
|
+
kind: "facts",
|
|
3717
|
+
items: fields(
|
|
3718
|
+
field("Mkt cap", humanize(quote.marketCap)),
|
|
3719
|
+
field("P/E", fixed(quote.peRatio)),
|
|
3720
|
+
field("EPS TTM", fixed(quote.epsTTM)),
|
|
3721
|
+
// A ratio, unlike `changePercent` and the other percentages in the same payload.
|
|
3722
|
+
field("Div yield", ratioPercent(quote.dividendYield)),
|
|
3723
|
+
field(
|
|
3724
|
+
"52w",
|
|
3725
|
+
`${fixed(quote.week52Low)} to ${fixed(quote.week52High)}`
|
|
3726
|
+
)
|
|
3727
|
+
)
|
|
3728
|
+
};
|
|
3729
|
+
}
|
|
3644
3730
|
function single(row, full) {
|
|
3645
3731
|
const { quote, profile } = row;
|
|
3646
3732
|
const tone = direction(quote.changePercent);
|
|
@@ -3668,20 +3754,7 @@ function single(row, full) {
|
|
|
3668
3754
|
field("Prev close", fixed(quote.previousClose))
|
|
3669
3755
|
)
|
|
3670
3756
|
},
|
|
3671
|
-
|
|
3672
|
-
kind: "facts",
|
|
3673
|
-
items: fields(
|
|
3674
|
-
field("Mkt cap", humanize(quote.marketCap)),
|
|
3675
|
-
field("P/E", fixed(quote.peRatio)),
|
|
3676
|
-
field("EPS TTM", fixed(quote.epsTTM)),
|
|
3677
|
-
// A ratio, unlike `changePercent` and the other percentages in the same payload.
|
|
3678
|
-
field("Div yield", ratioPercent(quote.dividendYield)),
|
|
3679
|
-
field(
|
|
3680
|
-
"52w",
|
|
3681
|
-
`${fixed(quote.week52Low)} to ${fixed(quote.week52High)}`
|
|
3682
|
-
)
|
|
3683
|
-
)
|
|
3684
|
-
}
|
|
3757
|
+
valuation(row)
|
|
3685
3758
|
];
|
|
3686
3759
|
if (quote.extendedHours) {
|
|
3687
3760
|
const ext = quote.extendedHours;
|
|
@@ -3700,25 +3773,33 @@ function single(row, full) {
|
|
|
3700
3773
|
)
|
|
3701
3774
|
});
|
|
3702
3775
|
}
|
|
3703
|
-
if (full) {
|
|
3776
|
+
if (full && row.kind === "etf") {
|
|
3777
|
+
blocks.push({
|
|
3778
|
+
kind: "kv",
|
|
3779
|
+
items: fields(
|
|
3780
|
+
row.quote.inceptionDate ? field("inception", row.quote.inceptionDate) : void 0
|
|
3781
|
+
)
|
|
3782
|
+
});
|
|
3783
|
+
} else if (full && row.kind === "stock") {
|
|
3704
3784
|
blocks.push({
|
|
3705
3785
|
kind: "kv",
|
|
3706
3786
|
items: fields(
|
|
3707
|
-
field("200d average", fixed(quote.movingAverage200Day)),
|
|
3708
|
-
quote.reportedCurrency ? field("reported currency", quote.reportedCurrency) : void 0,
|
|
3787
|
+
field("200d average", fixed(row.quote.movingAverage200Day)),
|
|
3788
|
+
row.quote.reportedCurrency ? field("reported currency", row.quote.reportedCurrency) : void 0,
|
|
3709
3789
|
profile?.sector ? field("sector", String(profile.sector)) : void 0,
|
|
3710
3790
|
profile?.industry ? field("industry", String(profile.industry)) : void 0,
|
|
3711
3791
|
profile?.ceo ? field("ceo", String(profile.ceo)) : void 0
|
|
3712
3792
|
)
|
|
3713
3793
|
});
|
|
3714
3794
|
}
|
|
3715
|
-
|
|
3795
|
+
const listingStatus = row.kind === "stock" ? row.quote.listingStatus : void 0;
|
|
3796
|
+
if (row.kind === "stock" && listingStatus === "DELISTED") {
|
|
3716
3797
|
blocks.push({
|
|
3717
3798
|
kind: "text",
|
|
3718
|
-
text: `Delisted on ${quote.delistedDate ?? "an unrecorded date"}. Every figure above is frozen at the last trade, not a live market move.`,
|
|
3799
|
+
text: `Delisted on ${row.quote.delistedDate ?? "an unrecorded date"}. Every figure above is frozen at the last trade, not a live market move.`,
|
|
3719
3800
|
tone: "down"
|
|
3720
3801
|
});
|
|
3721
|
-
} else if (
|
|
3802
|
+
} else if (listingStatus === "PENDING_DELISTING") {
|
|
3722
3803
|
blocks.push({
|
|
3723
3804
|
kind: "text",
|
|
3724
3805
|
text: "A merger or take-private is scheduled. The stock still trades, so these figures are current.",
|
|
@@ -3745,7 +3826,8 @@ function table(rows, full) {
|
|
|
3745
3826
|
cell(signed(row.quote.change), tone),
|
|
3746
3827
|
cell(signedPercent(row.quote.changePercent), tone),
|
|
3747
3828
|
cell(humanize(row.quote.volume, 1)),
|
|
3748
|
-
|
|
3829
|
+
// An ETF has no market cap; its AUM is a different number and stays out of this column.
|
|
3830
|
+
cell(humanize(row.kind === "stock" ? row.quote.marketCap : void 0))
|
|
3749
3831
|
];
|
|
3750
3832
|
return full ? [cell(row.ticker), cell(row.profile?.name ?? ""), ...tail] : [cell(row.ticker), ...tail];
|
|
3751
3833
|
})
|
|
@@ -3767,7 +3849,9 @@ var quoteCommand = {
|
|
|
3767
3849
|
"Use canonical symbols, for example GOOGL rather than GOOG and BRK.B rather than BRK-B.",
|
|
3768
3850
|
"One request per ticker. The company name costs a second request, so it is fetched only",
|
|
3769
3851
|
"for the terminal layout: piped and --json output carry the quote alone.",
|
|
3770
|
-
"JSON is the exact quote response for one ticker, and an object keyed by ticker for more."
|
|
3852
|
+
"JSON is the exact quote response for one ticker, and an object keyed by ticker for more.",
|
|
3853
|
+
"An ETF symbol answers with the ETF quote: AUM, expense ratio and NAV in place of market",
|
|
3854
|
+
"cap, P/E and EPS. That costs one extra request per ETF symbol."
|
|
3771
3855
|
],
|
|
3772
3856
|
flags: {},
|
|
3773
3857
|
async run({ args, client, full, mode }) {
|
|
@@ -3779,12 +3863,12 @@ var quoteCommand = {
|
|
|
3779
3863
|
const wantName = mode === "pretty";
|
|
3780
3864
|
const rows = await Promise.all(
|
|
3781
3865
|
tickers.map(async (ticker) => {
|
|
3782
|
-
const [
|
|
3783
|
-
api
|
|
3866
|
+
const [answer, profile] = await Promise.all([
|
|
3867
|
+
quoteAnyTicker(api, ticker),
|
|
3784
3868
|
// A name is a nicety, not the answer. A ticker with no profile still gets a quote.
|
|
3785
3869
|
wantName ? api.stocks.getProfile(ticker).catch(() => null) : Promise.resolve(null)
|
|
3786
3870
|
]);
|
|
3787
|
-
return {
|
|
3871
|
+
return { ...answer, ticker, profile };
|
|
3788
3872
|
})
|
|
3789
3873
|
);
|
|
3790
3874
|
if (rows.length === 1) {
|
package/dist/index.cjs
CHANGED
|
@@ -339,9 +339,11 @@ var Earnings = class {
|
|
|
339
339
|
* management phrased it, and a summary of the earnings call.
|
|
340
340
|
*
|
|
341
341
|
* Branch on `isPreview`: a PRO key receives every hydrated quarter in full, a
|
|
342
|
-
* FREE key receives the latest quarter shaped rather than truncated
|
|
343
|
-
* `totalCount
|
|
344
|
-
*
|
|
342
|
+
* FREE key receives the latest quarter shaped rather than truncated.
|
|
343
|
+
* `totalCount` on the envelope counts indexed quarters on both tiers. The
|
|
344
|
+
* returned array can be shorter when a body is unavailable or limit cuts it.
|
|
345
|
+
* Older responses may omit the count. {@link EarningsQuarter} documents
|
|
346
|
+
* which fields each tier carries.
|
|
345
347
|
*
|
|
346
348
|
* A quarter typically appears within 48 hours of the company reporting, and
|
|
347
349
|
* the call summary can arrive after the press-release content for the same
|
|
@@ -475,6 +477,19 @@ var Etfs = class {
|
|
|
475
477
|
async list() {
|
|
476
478
|
return this.client.get("/api/v1/etfs");
|
|
477
479
|
}
|
|
480
|
+
/**
|
|
481
|
+
* Get the quote snapshot for an ETF: price, day and 52-week range, volume, dividend
|
|
482
|
+
* yield, AUM, expense ratio, NAV and inception date.
|
|
483
|
+
*
|
|
484
|
+
* Fails with a 400 `APIError` whose `code` is `"ticker_is_not_etf"` when the symbol is a
|
|
485
|
+
* stock (use `stocks.getQuote()` for those), and a `NotFoundError` when there is no
|
|
486
|
+
* price data for the fund.
|
|
487
|
+
*/
|
|
488
|
+
async quote(ticker) {
|
|
489
|
+
return this.client.get(
|
|
490
|
+
`/api/v1/etfs/${encodeURIComponent(ticker.toUpperCase())}/quote`
|
|
491
|
+
);
|
|
492
|
+
}
|
|
478
493
|
/**
|
|
479
494
|
* Get the full holdings composition for an ETF, including per-holding weights
|
|
480
495
|
* and freshness metadata. Returns 404 for unknown ETFs or commodity-only funds.
|
|
@@ -803,6 +818,10 @@ var Institutional = class {
|
|
|
803
818
|
* Resolved by URL slug (e.g. `Berkshire-Hathaway`) or numeric SEC CIK.
|
|
804
819
|
* Free users receive the profile and top 10 holdings; PRO users receive the
|
|
805
820
|
* full holdings array. Returns 404 if the slug or CIK is unknown.
|
|
821
|
+
*
|
|
822
|
+
* The signature remains unknown for compatibility. Opt in to the exported
|
|
823
|
+
* PreviewResponse<InstitutionDetail> type to read data.positionsHeld, the full
|
|
824
|
+
* portfolio count excluding SOLD_OUT rows, even on a truncated holdings list.
|
|
806
825
|
*/
|
|
807
826
|
async getInstitutionDetail(slugOrCik) {
|
|
808
827
|
return this.client.get(
|
|
@@ -1069,6 +1088,22 @@ var Stocks = class {
|
|
|
1069
1088
|
async getEntities(ticker) {
|
|
1070
1089
|
return this.client.get(`/api/v1/stocks/${encodeURIComponent(ticker)}/entities`);
|
|
1071
1090
|
}
|
|
1091
|
+
/**
|
|
1092
|
+
* Get the company knowledge graph around a stock: the people, products, peers and other
|
|
1093
|
+
* entities linked to the company, and the typed relationships between them.
|
|
1094
|
+
*
|
|
1095
|
+
* Every identifier in the response is a slug, the same handle the metric and document
|
|
1096
|
+
* endpoints take, so a node can be passed straight to them. `depth` is 1 (default) or 2,
|
|
1097
|
+
* `cap` limits the number of non-root nodes (1 to 200, default 75); the root is always
|
|
1098
|
+
* included in addition. Out-of-range values are rejected with a 400. A ticker with no
|
|
1099
|
+
* graph returns a `NotFoundError`.
|
|
1100
|
+
*/
|
|
1101
|
+
async getGraph(ticker, options) {
|
|
1102
|
+
return this.client.get(
|
|
1103
|
+
`/api/v1/stocks/${encodeURIComponent(ticker.toUpperCase())}/graph`,
|
|
1104
|
+
options
|
|
1105
|
+
);
|
|
1106
|
+
}
|
|
1072
1107
|
/**
|
|
1073
1108
|
* Get AI-generated stock analysis report. Requires PRO tier.
|
|
1074
1109
|
*
|
|
@@ -1131,17 +1166,23 @@ var Stocks = class {
|
|
|
1131
1166
|
async getHistoricalRevenue(ticker) {
|
|
1132
1167
|
return this.client.get("/api/v1/stocks/fundamentals/historical/revenue", { ticker });
|
|
1133
1168
|
}
|
|
1134
|
-
/**
|
|
1135
|
-
|
|
1136
|
-
|
|
1169
|
+
/**
|
|
1170
|
+
* Get short interest history (FINRA), newest first: shares short, days to cover and
|
|
1171
|
+
* average daily volume per settlement date. `limit` defaults to 24 settlement dates.
|
|
1172
|
+
*/
|
|
1173
|
+
async getShortInterest(ticker, options) {
|
|
1174
|
+
return this.client.get("/api/v1/stocks/short-interest", { ticker, ...options });
|
|
1137
1175
|
}
|
|
1138
1176
|
/** Get float information. */
|
|
1139
1177
|
async getFloat(ticker) {
|
|
1140
1178
|
return this.client.get("/api/v1/stocks/float", { ticker });
|
|
1141
1179
|
}
|
|
1142
|
-
/**
|
|
1143
|
-
|
|
1144
|
-
|
|
1180
|
+
/**
|
|
1181
|
+
* Get daily short volume, newest first: shares sold short against total volume on the
|
|
1182
|
+
* reporting venues. `limit` defaults to 90 trading days.
|
|
1183
|
+
*/
|
|
1184
|
+
async getShortVolume(ticker, options) {
|
|
1185
|
+
return this.client.get("/api/v1/stocks/short-volume", { ticker, ...options });
|
|
1145
1186
|
}
|
|
1146
1187
|
/**
|
|
1147
1188
|
* Get company-specific KPI time-series for a ticker. Returns curated GAAP and
|
|
@@ -1353,7 +1394,7 @@ var Trackers = class {
|
|
|
1353
1394
|
};
|
|
1354
1395
|
|
|
1355
1396
|
// src/version.ts
|
|
1356
|
-
var VERSION = "0.
|
|
1397
|
+
var VERSION = "0.63.0";
|
|
1357
1398
|
|
|
1358
1399
|
// src/client.ts
|
|
1359
1400
|
var DEFAULT_BASE_URL = "https://app.sentisense.ai";
|