sentisense 0.35.0 → 0.38.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 +84 -0
- package/dist/index.cjs +133 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +564 -5
- package/dist/index.d.ts +564 -5
- package/dist/index.mjs +133 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -263,6 +263,41 @@ client.stocks.getKpis("AAPL") // Product metrics and segment revenue time-
|
|
|
263
263
|
client.stocks.listKpiCoverage() // All tickers with curated KPI data (free, no quota cost)
|
|
264
264
|
```
|
|
265
265
|
|
|
266
|
+
### Earnings
|
|
267
|
+
|
|
268
|
+
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.
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
client.earnings.getSummaries("AAPL", { limit: 4 }) // Per-quarter analysis report, newest first. FREE: latest quarter, shaped. PRO: every hydrated quarter in full.
|
|
272
|
+
client.earnings.getRecent({ days: 7, limit: 25 }) // Who reported in the last N days. Full window on every key.
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
import SentiSense from "sentisense";
|
|
277
|
+
|
|
278
|
+
const client = new SentiSense({ apiKey: process.env.SENTISENSE_API_KEY });
|
|
279
|
+
|
|
280
|
+
const res = await client.earnings.getSummaries("AAPL", { limit: 1 });
|
|
281
|
+
const quarter = res.data[0];
|
|
282
|
+
|
|
283
|
+
if (quarter) {
|
|
284
|
+
console.log(quarter.fiscalPeriod, quarter.reportDate);
|
|
285
|
+
console.log(quarter.headline);
|
|
286
|
+
for (const kpi of quarter.kpiHighlights ?? []) {
|
|
287
|
+
console.log(` ${kpi.label}: ${kpi.value} (${kpi.yoy ?? "no YoY"})`);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (res.isPreview) {
|
|
291
|
+
// Free key: section titles stand in for the bodies.
|
|
292
|
+
console.log("Summary covers:", quarter.summaryTopics?.join(", "));
|
|
293
|
+
} else {
|
|
294
|
+
console.log(quarter.summaryMd);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
The forward-looking half of the family is `client.calendar.getEarnings()`, which covers scheduled dates and consensus EPS rather than results.
|
|
300
|
+
|
|
266
301
|
### ETFs (beta)
|
|
267
302
|
|
|
268
303
|
Composition data is public; the holdings-weighted aggregate views follow the same PRO-with-preview pattern as Analyst/Insider. Aggregates synthesize fund-level views from each constituent's per-stock data, weighted by allocation, with a `coverage` block on every response.
|
|
@@ -281,6 +316,55 @@ client.etfs.sentimentAggregate("QQQ") // SentiSense re
|
|
|
281
316
|
client.marketMood.get()
|
|
282
317
|
```
|
|
283
318
|
|
|
319
|
+
### Screener
|
|
320
|
+
|
|
321
|
+
Filter the tracked universe on the SentiSense Score, attention, analyst consensus, technicals and price in one query. Screening on analyst ratings alone is something a dozen free tools do; screening on analyst ratings *where the Score disagrees* is not.
|
|
322
|
+
|
|
323
|
+
```typescript
|
|
324
|
+
client.screener.fields() // Every filterable field, both universes, with units + operators
|
|
325
|
+
client.screener.screens() // The curated screens shipped in the product, each with a runnable plan
|
|
326
|
+
client.screener.run({ plan, tickers, limit }) // Run a screen against the stock universe
|
|
327
|
+
client.screener.runEtfs({ plan, limit }) // Run a screen against the ETF universe
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
// Run a curated screen as-is
|
|
332
|
+
const { screens } = await client.screener.screens();
|
|
333
|
+
const crowdVsStreet = screens.find((s) => s.id === "crowd-vs-street")!;
|
|
334
|
+
const curated = await client.screener.run({ plan: crowdVsStreet.plan, limit: 25 });
|
|
335
|
+
console.log(`${curated.matched} matched, showing ${curated.results.length}`);
|
|
336
|
+
|
|
337
|
+
// Or build your own: bullish Score, thin analyst enthusiasm
|
|
338
|
+
const res = await client.screener.run({
|
|
339
|
+
plan: {
|
|
340
|
+
filters: [
|
|
341
|
+
{ fieldName: "SENTI_SCORE_7D", op: "GTE", value: 13 },
|
|
342
|
+
{ fieldName: "ANALYST_BUY_RATIO_PCT", op: "LTE", value: 30 },
|
|
343
|
+
{ fieldName: "ANALYST_COUNT", op: "GTE", value: 5 },
|
|
344
|
+
],
|
|
345
|
+
sort: { fieldName: "SENTI_SCORE_7D", dir: "DESC" },
|
|
346
|
+
},
|
|
347
|
+
limit: 25,
|
|
348
|
+
});
|
|
349
|
+
for (const row of res.results) {
|
|
350
|
+
console.log(row.ticker, row.sentiSenseScore7D, row.analystBuyRatioPct);
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
`limit` rides next to the plan rather than inside it, because a plan is a stored object and paging is a transport concern. It defaults to 100 and caps at 500. `matched` is the count before `limit` was applied, so truncation is visible. `tickers` is optional: omit it to screen the whole tracked universe, pass a list to screen a watchlist.
|
|
355
|
+
|
|
356
|
+
Three field semantics are worth stating outright, because guessing them wrong produces a screen that looks fine and means nothing:
|
|
357
|
+
|
|
358
|
+
- **`ANALYST_RATING_MEAN` is inverted.** It is the vendor's 1-to-5 scale where **1.0 is strong buy**, so bullish is `LTE 2.5`. Prefer `ANALYST_BUY_RATIO_PCT`, which runs the intuitive direction.
|
|
359
|
+
- **`MA_CROSS_STATE` is ordinal**, not a percentage: `1` golden cross, `-1` death cross, `0` neither. Use `EQ`.
|
|
360
|
+
- **`SENTIMENT_DIRECTION` is the sign of the 7-day SentiSense Score** (`1` / `0` / `-1`) with a neutral band of plus-or-minus 5. Despite the name it is not sentiment polarity, and `0` matches only an exact zero.
|
|
361
|
+
|
|
362
|
+
The Score fields (`SENTI_SCORE_7D`, `SENTI_SCORE_1M`, `SCORE_CHANGE_7D`) are the SentiSense Score, not polarity: unbounded, banded at 5 / 13 / 23 either side of zero. Filter on those band edges, not on values like `0.5`, which behave as "any positive score". Nulls never match in either direction, so `RETURN_1Y >= 0` and `RETURN_1Y < 0` do not partition the universe: a stock listed four months ago is in neither result. If a screen returns fewer rows than you expect, check coverage before you check your thresholds.
|
|
363
|
+
|
|
364
|
+
On the ETF side, `CONSTITUENTS_WEIGHTED_SENTISENSE` is the holdings-weighted Score across what the fund owns and is usually the one you want; `DIRECT_SENTISENSE` is the Score from chatter about the fund ticker itself. `WEIGHT_COVERED_PCT` tells you how much of the fund's weight had constituent data behind the weighted number.
|
|
365
|
+
|
|
366
|
+
Screens read a snapshot that refreshes every 20 minutes, so this is not a quote feed. Use `client.stocks.getQuote()` for live prices.
|
|
367
|
+
|
|
284
368
|
## Error Handling
|
|
285
369
|
|
|
286
370
|
```typescript
|
package/dist/index.cjs
CHANGED
|
@@ -185,6 +185,53 @@ var Documents = class {
|
|
|
185
185
|
}
|
|
186
186
|
};
|
|
187
187
|
|
|
188
|
+
// src/resources/earnings.ts
|
|
189
|
+
var Earnings = class {
|
|
190
|
+
constructor(client) {
|
|
191
|
+
this.client = client;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Per-quarter earnings analysis report for one ticker, newest first.
|
|
195
|
+
*
|
|
196
|
+
* Each quarter carries the editorial headline, the KPI cards that matter for
|
|
197
|
+
* that company with year-over-year deltas, the guidance language as
|
|
198
|
+
* management phrased it, and a summary of the earnings call.
|
|
199
|
+
*
|
|
200
|
+
* Branch on `isPreview`: a PRO key receives every hydrated quarter in full, a
|
|
201
|
+
* FREE key receives the latest quarter shaped rather than truncated, plus
|
|
202
|
+
* `totalCount`. {@link EarningsQuarter} documents which fields each tier
|
|
203
|
+
* carries.
|
|
204
|
+
*
|
|
205
|
+
* A quarter typically appears within 48 hours of the company reporting, and
|
|
206
|
+
* the call summary can arrive after the press-release content for the same
|
|
207
|
+
* quarter, so read `generatedAt` and `transcriptGeneratedAt` rather than
|
|
208
|
+
* assuming a fixed lag. A ticker with no stored quarter answers with an empty
|
|
209
|
+
* `data` array, not a 404.
|
|
210
|
+
*
|
|
211
|
+
* Use canonical ticker symbols: `GOOGL` (not `GOOG`), `BRK.B` (not `BRK-B`).
|
|
212
|
+
*/
|
|
213
|
+
async getSummaries(ticker, options) {
|
|
214
|
+
return this.client.get(
|
|
215
|
+
`/api/v1/stocks/${encodeURIComponent(ticker.toUpperCase())}/earnings-summaries`,
|
|
216
|
+
options
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Which covered companies reported on or after `today - days`, newest first.
|
|
221
|
+
*
|
|
222
|
+
* Every API key receives the full window it asks for, so `isPreview` is
|
|
223
|
+
* always `false` here. The window is bounded by `reportDate`, so a quarter
|
|
224
|
+
* reported inside it appears even when its call summary lands later, and an
|
|
225
|
+
* empty `data` array means nobody in the covered set reported in that window.
|
|
226
|
+
*
|
|
227
|
+
* This is the backward-looking feed; `client.calendar.getEarnings()` is the
|
|
228
|
+
* forward-looking one.
|
|
229
|
+
*/
|
|
230
|
+
async getRecent(options) {
|
|
231
|
+
return this.client.get("/api/v1/earnings/recent", options);
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
|
|
188
235
|
// src/resources/entityMetrics.ts
|
|
189
236
|
var EntityMetrics = class {
|
|
190
237
|
constructor(client) {
|
|
@@ -285,7 +332,7 @@ var Insider = class {
|
|
|
285
332
|
/**
|
|
286
333
|
* Get market-wide insider activity: top buys and sells aggregated by ticker.
|
|
287
334
|
*
|
|
288
|
-
* PRO-gated. Free
|
|
335
|
+
* PRO-gated. Free-tier users receive a preview (top 5 per direction)
|
|
289
336
|
* with `isPreview: true` in the response.
|
|
290
337
|
*/
|
|
291
338
|
async getActivity(options) {
|
|
@@ -320,7 +367,7 @@ var Politicians = class {
|
|
|
320
367
|
/**
|
|
321
368
|
* Get recent congressional STOCK Act trading activity across all politicians.
|
|
322
369
|
*
|
|
323
|
-
* PRO-gated. Free
|
|
370
|
+
* PRO-gated. Free-tier users receive a preview (top 5 trades)
|
|
324
371
|
* with `isPreview: true` in the response.
|
|
325
372
|
*
|
|
326
373
|
* The feed is longer than one response: a default 90-day window is routinely well over a
|
|
@@ -432,7 +479,7 @@ var Insights = class {
|
|
|
432
479
|
}
|
|
433
480
|
/**
|
|
434
481
|
* Get available insight types for a specific stock.
|
|
435
|
-
*
|
|
482
|
+
* API key required.
|
|
436
483
|
*
|
|
437
484
|
* Returns an array of insight type strings (e.g., `["sentiment_shift", "options_activity"]`).
|
|
438
485
|
*/
|
|
@@ -571,6 +618,86 @@ var MarketSummaryResource = class {
|
|
|
571
618
|
}
|
|
572
619
|
};
|
|
573
620
|
|
|
621
|
+
// src/resources/screener.ts
|
|
622
|
+
var Screener = class {
|
|
623
|
+
constructor(client) {
|
|
624
|
+
this.client = client;
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Every filterable field, with its unit, operators and description, for both
|
|
628
|
+
* universes.
|
|
629
|
+
*
|
|
630
|
+
* Build a filter UI from this rather than hardcoding the list and you inherit
|
|
631
|
+
* new fields as they ship. The ETF `STRING` fields (`ISSUER`, `ASSET_CLASS`,
|
|
632
|
+
* `TRACKED_INDEX`) come back with their `values` populated from the live
|
|
633
|
+
* universe, so pickers stay current without a redeploy.
|
|
634
|
+
*/
|
|
635
|
+
async fields() {
|
|
636
|
+
return this.client.get("/api/v1/screener/fields");
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* The curated screens shipped in the product, each with a runnable plan.
|
|
640
|
+
*
|
|
641
|
+
* Each `plan` round-trips straight into {@link run} (or {@link runEtfs} when
|
|
642
|
+
* `plan.universe === "ETF"`) with nothing to rebuild.
|
|
643
|
+
*
|
|
644
|
+
* Their filters identify the field with `field` rather than `fieldName`.
|
|
645
|
+
* Both keys are accepted on the way in, so read either when inspecting a plan
|
|
646
|
+
* you did not build yourself.
|
|
647
|
+
*/
|
|
648
|
+
async screens() {
|
|
649
|
+
return this.client.get("/api/v1/screener/screens");
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Run a screen against the stock universe.
|
|
653
|
+
*
|
|
654
|
+
* `tickers` is optional: omit it to screen the whole tracked universe, pass a
|
|
655
|
+
* list to screen a watchlist. `limit` sits next to the plan rather than
|
|
656
|
+
* inside it, because a plan is a stored object and paging is a transport
|
|
657
|
+
* concern; it defaults to 100 and caps at 500.
|
|
658
|
+
*
|
|
659
|
+
* Read `matched` before you read `results`: it is the count before `limit`
|
|
660
|
+
* was applied, so a `matched` above your `limit` means you are holding the
|
|
661
|
+
* top slice under the plan's sort, not the whole answer.
|
|
662
|
+
*
|
|
663
|
+
* @example
|
|
664
|
+
* ```ts
|
|
665
|
+
* const res = await client.screener.run({
|
|
666
|
+
* plan: {
|
|
667
|
+
* filters: [
|
|
668
|
+
* { fieldName: "SENTI_SCORE_7D", op: "GTE", value: 13 },
|
|
669
|
+
* { fieldName: "ANALYST_BUY_RATIO_PCT", op: "LTE", value: 30 },
|
|
670
|
+
* { fieldName: "ANALYST_COUNT", op: "GTE", value: 5 },
|
|
671
|
+
* ],
|
|
672
|
+
* sort: { fieldName: "SENTI_SCORE_7D", dir: "DESC" },
|
|
673
|
+
* },
|
|
674
|
+
* limit: 25,
|
|
675
|
+
* });
|
|
676
|
+
* ```
|
|
677
|
+
*/
|
|
678
|
+
async run(options) {
|
|
679
|
+
return this.client.post("/api/v1/screener/execute", options);
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Run a screen against the ETF universe.
|
|
683
|
+
*
|
|
684
|
+
* Same request shape as {@link run}, against a different field vocabulary:
|
|
685
|
+
* take the ETF names from `fields().etf`. `IN` / `NOT_IN` take a `values`
|
|
686
|
+
* array instead of `value` and are the operators for the string fields
|
|
687
|
+
* (`ISSUER`, `ASSET_CLASS`, `TRACKED_INDEX`).
|
|
688
|
+
*
|
|
689
|
+
* `CONSTITUENTS_WEIGHTED_SENTISENSE` is the holdings-weighted SentiSense
|
|
690
|
+
* Score across what the fund owns and is usually the one you want;
|
|
691
|
+
* `DIRECT_SENTISENSE` is the Score from chatter about the fund ticker itself,
|
|
692
|
+
* which on a broad index fund is mostly macro noise. `WEIGHT_COVERED_PCT`
|
|
693
|
+
* tells you how much of the fund's weight had constituent data behind the
|
|
694
|
+
* weighted number.
|
|
695
|
+
*/
|
|
696
|
+
async runEtfs(options) {
|
|
697
|
+
return this.client.post("/api/v1/screener/etfs/execute", options);
|
|
698
|
+
}
|
|
699
|
+
};
|
|
700
|
+
|
|
574
701
|
// src/resources/stocks.ts
|
|
575
702
|
var Stocks = class {
|
|
576
703
|
constructor(client) {
|
|
@@ -844,7 +971,7 @@ var Trackers = class {
|
|
|
844
971
|
};
|
|
845
972
|
|
|
846
973
|
// src/version.ts
|
|
847
|
-
var VERSION = "0.
|
|
974
|
+
var VERSION = "0.38.0";
|
|
848
975
|
|
|
849
976
|
// src/client.ts
|
|
850
977
|
var DEFAULT_BASE_URL = "https://app.sentisense.ai";
|
|
@@ -889,6 +1016,8 @@ var SentiSense = class {
|
|
|
889
1016
|
this.indexes = new Indexes(this);
|
|
890
1017
|
this.trackers = new Trackers(this);
|
|
891
1018
|
this.calendar = new Calendar(this);
|
|
1019
|
+
this.earnings = new Earnings(this);
|
|
1020
|
+
this.screener = new Screener(this);
|
|
892
1021
|
}
|
|
893
1022
|
/** @internal */
|
|
894
1023
|
async get(path, params) {
|