sentisense 0.49.0 → 0.51.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 +37 -2
- package/dist/cli.cjs +44 -1
- package/dist/index.cjs +44 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +254 -3
- package/dist/index.d.ts +254 -3
- package/dist/index.mjs +44 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/sentisense)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
Official JavaScript/TypeScript SDK and CLI for the [SentiSense](https://sentisense.ai) market intelligence API: stock prices, news and social sentiment, the SentiSense Score, insider and congressional trading, institutional 13F flows, options positioning, analyst ratings, earnings analysis, and a cross-signal screener.
|
|
6
|
+
Official JavaScript/TypeScript SDK and CLI for the [SentiSense](https://sentisense.ai) market intelligence API: stock prices, news and social sentiment, the SentiSense Score, the SentiSense Rating, insider and congressional trading, institutional 13F flows, options positioning, analyst ratings, earnings analysis, and a cross-signal screener.
|
|
7
7
|
|
|
8
8
|
- Full TypeScript support with detailed type definitions
|
|
9
9
|
- Works in Node.js 18+, Deno, Bun, and browsers
|
|
@@ -212,6 +212,7 @@ client.stocks.getFundamentals("AAPL") // Financial data
|
|
|
212
212
|
client.stocks.getShortInterest("GME") // Short interest
|
|
213
213
|
client.stocks.getOptionsSummary("NVDA") // End-of-day options dossier
|
|
214
214
|
client.stocks.getOptionsHistory("NVDA", { window: "2y" }) // Daily options aggregates over time
|
|
215
|
+
client.stocks.getRating("AAPL") // SentiSense Rating: score, letter, percentile, dimensions
|
|
215
216
|
client.stocks.getAISummary("AAPL", { depth: "deep" }) // AI report (PRO)
|
|
216
217
|
```
|
|
217
218
|
|
|
@@ -332,6 +333,11 @@ const { data: book } = await client.analyst.coverage("NVDA");
|
|
|
332
333
|
console.log(`${book.firmCount} firms, ${book.namedAnalystCount} named analysts`);
|
|
333
334
|
console.log(`${book.attributedNoteCount} of ${book.noteCount} notes name someone`);
|
|
334
335
|
|
|
336
|
+
const buckets = book.ratingBuckets;
|
|
337
|
+
if (buckets) {
|
|
338
|
+
console.log(`${buckets.buy} buy, ${buckets.hold} hold, ${buckets.sell} sell, ${buckets.unrated} unrated of ${buckets.total}`);
|
|
339
|
+
}
|
|
340
|
+
|
|
335
341
|
for (const row of book.coverage.slice(0, 5)) {
|
|
336
342
|
if (row.noteCount === 0) {
|
|
337
343
|
// A desk can cover a stock on rating actions alone, with no price target.
|
|
@@ -351,6 +357,8 @@ for (const row of book.coverage.slice(0, 5)) {
|
|
|
351
357
|
|
|
352
358
|
Two shapes to read rather than assume. A firm can appear with `noteCount: 0`, a `null` `latestNote` and a populated `firmRating`, because coverage means a price target **or** a rating action in the window. And a large, publisher-dependent share of notes name no individual, so an empty `analysts` array alongside a non-zero `noteCount` is normal: read `attributedNoteCount` and `unattributedNoteCount` off the response rather than hardcoding a rate. The response-level counts survive the free truncation, so they describe the whole window even when only 5 rows come back. An unknown slug throws `NotFoundError`, which keeps "published nothing we hold" distinguishable from "does not exist".
|
|
353
359
|
|
|
360
|
+
`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.
|
|
361
|
+
|
|
354
362
|
### Earnings
|
|
355
363
|
|
|
356
364
|
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. Both return the preview envelope.
|
|
@@ -418,7 +426,7 @@ client.entityMetrics.getDistribution("AAPL", "sentiment")
|
|
|
418
426
|
client.entityMetrics.getDistribution("AAPL", "mentions", { dimension: "source" })
|
|
419
427
|
```
|
|
420
428
|
|
|
421
|
-
Available metric types: `mentions`, `sentiment`, `
|
|
429
|
+
Available metric types: `mentions`, `sentiment`, `sentisense_score`, `sentisense_rating`, `social_dominance`, `creators`. `sentisense_rating` is the SentiSense Rating score and is a time series only: it has no source breakdown, so `getDistribution` answers with an empty distribution for it.
|
|
422
430
|
|
|
423
431
|
### Options
|
|
424
432
|
|
|
@@ -434,6 +442,33 @@ The radar carries two separately-ranked boards: `data.rows` for stocks and `data
|
|
|
434
442
|
|
|
435
443
|
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; `getOptionsHistory` reports it as an empty `series` instead, so check the array rather than null-checking there.
|
|
436
444
|
|
|
445
|
+
### SentiSense Rating
|
|
446
|
+
|
|
447
|
+
Where a stock ranks against the other stocks rated that day, as a score, a letter and a percentile, plus the six 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).
|
|
448
|
+
|
|
449
|
+
```typescript
|
|
450
|
+
const rating = await client.stocks.getRating("AAPL");
|
|
451
|
+
if (rating.rated) {
|
|
452
|
+
console.log(rating.letter, rating.score, "percentile", rating.percentile, "of", rating.ratedCount);
|
|
453
|
+
for (const adj of rating.riskAdjustments ?? []) console.log(" ", adj.condition, -adj.points);
|
|
454
|
+
for (const dim of rating.dimensions.filter((d) => d.present)) {
|
|
455
|
+
console.log(" ", dim.label, dim.percentile);
|
|
456
|
+
}
|
|
457
|
+
} else {
|
|
458
|
+
console.log("no grade today:", rating.reason);
|
|
459
|
+
}
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
`getRating` returns `StockRatingResponse`, a discriminated union on `rated` of `StockRating` (graded) and `StockNotRated`. The `if` narrows to `score`, `letter`, `percentile`, `composite`, `ratedCount` and `methodologyVersion`, the `else` to `reason`, `dimensionsPresent` and `presentDimensions`. Branch on that flag rather than testing a field for `undefined`.
|
|
463
|
+
|
|
464
|
+
Having no grade is a normal 200, not a 404: ETFs and tickers outside the swept universe answer that way, and `reason` is one of `stale`, `not_rated_today`, `insufficient_dimensions` or `insufficient_coverage_weight`. Only a ticker that resolves to nothing we track rejects with `NotFoundError`.
|
|
465
|
+
|
|
466
|
+
`dimensions` always holds all six rows in a fixed order, including the ones with no data, which arrive with `present` false and a `null` percentile. Read `present` first and never substitute zero for a missing percentile: zero is the bottom of the cross-section, absence is not a position on it. Only the smart-money dimension carries `subLegs`.
|
|
467
|
+
|
|
468
|
+
**`score` is not `percentile`.** `percentile` is the rank of the blended signals against the day's rated set. `score = percentile - sum(riskAdjustments.map((a) => a.points))`, floored at 10 when fewer than five dimensions are available, and it is the number `letter` bands (A 90, B 70, C 30, D 10). `bucketLetter` is the band the percentile alone would give, so the two letters differ by exactly what the conditions cost. `riskAdjustments` itemises that cost, `penaltyPoints` totals it, and `riskConditions` names the active ones from the `RiskCondition` union: `thin_coverage`, `weak_dimension`, `unprofitable`, `no_fundamentals`, `high_leverage`, `unseasoned_listing`, `small_market_cap`, `thin_liquidity`, `extended_price`, `insider_selling` and `institutional_outflow`.
|
|
469
|
+
|
|
470
|
+
All five are optional: a response served before they shipped omits them. For the daily history of a stock's score, ask `entityMetrics.getMetrics` for the `sentisense_rating` metric.
|
|
471
|
+
|
|
437
472
|
### Market mood & knowledge base
|
|
438
473
|
|
|
439
474
|
```typescript
|
package/dist/cli.cjs
CHANGED
|
@@ -1037,7 +1037,7 @@ var flowsCommand = {
|
|
|
1037
1037
|
};
|
|
1038
1038
|
|
|
1039
1039
|
// src/version.ts
|
|
1040
|
-
var VERSION = "0.
|
|
1040
|
+
var VERSION = "0.51.0";
|
|
1041
1041
|
|
|
1042
1042
|
// src/resources/analyst.ts
|
|
1043
1043
|
var Analyst = class {
|
|
@@ -2069,6 +2069,49 @@ var Stocks = class {
|
|
|
2069
2069
|
options
|
|
2070
2070
|
);
|
|
2071
2071
|
}
|
|
2072
|
+
/**
|
|
2073
|
+
* Get the SentiSense Rating for one stock: where it ranks against the other stocks rated
|
|
2074
|
+
* that day, and the six dimensions the rank is blended from.
|
|
2075
|
+
*
|
|
2076
|
+
* The Rating is a *relative*, automatically generated research signal, for informational
|
|
2077
|
+
* and educational purposes only. It ranks a stock against its cross-section; it is not
|
|
2078
|
+
* financial, investment or trading advice and it is not a recommendation about any
|
|
2079
|
+
* security. `disclaimer` carries the wording to display alongside a grade. Methodology:
|
|
2080
|
+
* https://sentisense.ai/methodology/#sentisense-rating
|
|
2081
|
+
*
|
|
2082
|
+
* **A discriminated union on `rated`.** `if (rating.rated)` narrows to `score`,
|
|
2083
|
+
* `letter`, `percentile`, `composite`, `ratedCount` and `methodologyVersion`; the
|
|
2084
|
+
* `else` branch narrows to `reason`, `dimensionsPresent` and `presentDimensions`.
|
|
2085
|
+
* Branch on the flag rather than testing a field for `undefined`.
|
|
2086
|
+
*
|
|
2087
|
+
* **Having no grade is a normal 200, not a 404.** ETFs and tickers outside the swept
|
|
2088
|
+
* universe answer with `rated` false, and the composition still arrives so a card can
|
|
2089
|
+
* render. Only a ticker that resolves to nothing we track rejects with
|
|
2090
|
+
* {@link NotFoundError}; a request with no usable key rejects with
|
|
2091
|
+
* {@link AuthenticationError}.
|
|
2092
|
+
*
|
|
2093
|
+
* `dimensions` always holds all six rows in a fixed order, including the ones with no
|
|
2094
|
+
* data, which arrive with `present` false and a `null` percentile. Read `present` first
|
|
2095
|
+
* and never read a missing percentile as zero.
|
|
2096
|
+
*
|
|
2097
|
+
* **`score` and `percentile` are different numbers.** `percentile` is the rank of the
|
|
2098
|
+
* blended signals against the day's rated set, and
|
|
2099
|
+
* `score = percentile - sum(riskAdjustments.map((a) => a.points))`, floored at 10 when
|
|
2100
|
+
* fewer than five dimensions are available and at 0 otherwise. `letter` is the band
|
|
2101
|
+
* `score` falls in, at edges 90, 70, 30 and 10, while `bucketLetter` is the band the
|
|
2102
|
+
* percentile alone would fall in, so a difference between the two letters is exactly
|
|
2103
|
+
* what the conditions cost. `riskConditions` names the active ones, `riskAdjustments`
|
|
2104
|
+
* gives the points each cost (graded, up to 12 apiece), and `penaltyPoints` is their
|
|
2105
|
+
* sum. `letter` is served as stored, so read it instead of computing your own bucket
|
|
2106
|
+
* edges. The five fields arrive from the next API deploy onward and are optional, so a
|
|
2107
|
+
* response served before then still parses.
|
|
2108
|
+
*
|
|
2109
|
+
* For the daily history of a stock's score, ask `client.entityMetrics.getMetrics` for
|
|
2110
|
+
* the `sentisense_rating` metric.
|
|
2111
|
+
*/
|
|
2112
|
+
async getRating(ticker) {
|
|
2113
|
+
return this.client.get(`/api/v1/rating/${encodeURIComponent(ticker.toUpperCase())}`);
|
|
2114
|
+
}
|
|
2072
2115
|
};
|
|
2073
2116
|
|
|
2074
2117
|
// src/resources/indexes.ts
|
package/dist/index.cjs
CHANGED
|
@@ -1104,6 +1104,49 @@ var Stocks = class {
|
|
|
1104
1104
|
options
|
|
1105
1105
|
);
|
|
1106
1106
|
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Get the SentiSense Rating for one stock: where it ranks against the other stocks rated
|
|
1109
|
+
* that day, and the six dimensions the rank is blended from.
|
|
1110
|
+
*
|
|
1111
|
+
* The Rating is a *relative*, automatically generated research signal, for informational
|
|
1112
|
+
* and educational purposes only. It ranks a stock against its cross-section; it is not
|
|
1113
|
+
* financial, investment or trading advice and it is not a recommendation about any
|
|
1114
|
+
* security. `disclaimer` carries the wording to display alongside a grade. Methodology:
|
|
1115
|
+
* https://sentisense.ai/methodology/#sentisense-rating
|
|
1116
|
+
*
|
|
1117
|
+
* **A discriminated union on `rated`.** `if (rating.rated)` narrows to `score`,
|
|
1118
|
+
* `letter`, `percentile`, `composite`, `ratedCount` and `methodologyVersion`; the
|
|
1119
|
+
* `else` branch narrows to `reason`, `dimensionsPresent` and `presentDimensions`.
|
|
1120
|
+
* Branch on the flag rather than testing a field for `undefined`.
|
|
1121
|
+
*
|
|
1122
|
+
* **Having no grade is a normal 200, not a 404.** ETFs and tickers outside the swept
|
|
1123
|
+
* universe answer with `rated` false, and the composition still arrives so a card can
|
|
1124
|
+
* render. Only a ticker that resolves to nothing we track rejects with
|
|
1125
|
+
* {@link NotFoundError}; a request with no usable key rejects with
|
|
1126
|
+
* {@link AuthenticationError}.
|
|
1127
|
+
*
|
|
1128
|
+
* `dimensions` always holds all six rows in a fixed order, including the ones with no
|
|
1129
|
+
* data, which arrive with `present` false and a `null` percentile. Read `present` first
|
|
1130
|
+
* and never read a missing percentile as zero.
|
|
1131
|
+
*
|
|
1132
|
+
* **`score` and `percentile` are different numbers.** `percentile` is the rank of the
|
|
1133
|
+
* blended signals against the day's rated set, and
|
|
1134
|
+
* `score = percentile - sum(riskAdjustments.map((a) => a.points))`, floored at 10 when
|
|
1135
|
+
* fewer than five dimensions are available and at 0 otherwise. `letter` is the band
|
|
1136
|
+
* `score` falls in, at edges 90, 70, 30 and 10, while `bucketLetter` is the band the
|
|
1137
|
+
* percentile alone would fall in, so a difference between the two letters is exactly
|
|
1138
|
+
* what the conditions cost. `riskConditions` names the active ones, `riskAdjustments`
|
|
1139
|
+
* gives the points each cost (graded, up to 12 apiece), and `penaltyPoints` is their
|
|
1140
|
+
* sum. `letter` is served as stored, so read it instead of computing your own bucket
|
|
1141
|
+
* edges. The five fields arrive from the next API deploy onward and are optional, so a
|
|
1142
|
+
* response served before then still parses.
|
|
1143
|
+
*
|
|
1144
|
+
* For the daily history of a stock's score, ask `client.entityMetrics.getMetrics` for
|
|
1145
|
+
* the `sentisense_rating` metric.
|
|
1146
|
+
*/
|
|
1147
|
+
async getRating(ticker) {
|
|
1148
|
+
return this.client.get(`/api/v1/rating/${encodeURIComponent(ticker.toUpperCase())}`);
|
|
1149
|
+
}
|
|
1107
1150
|
};
|
|
1108
1151
|
|
|
1109
1152
|
// src/resources/indexes.ts
|
|
@@ -1183,7 +1226,7 @@ var Trackers = class {
|
|
|
1183
1226
|
};
|
|
1184
1227
|
|
|
1185
1228
|
// src/version.ts
|
|
1186
|
-
var VERSION = "0.
|
|
1229
|
+
var VERSION = "0.51.0";
|
|
1187
1230
|
|
|
1188
1231
|
// src/client.ts
|
|
1189
1232
|
var DEFAULT_BASE_URL = "https://app.sentisense.ai";
|