sentisense 0.63.1 → 0.65.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 +42 -7
- package/dist/cli.cjs +128 -13
- package/dist/index.cjs +31 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +212 -9
- package/dist/index.d.ts +212 -9
- package/dist/index.mjs +31 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -79,8 +79,8 @@ npx -y sentisense@latest health
|
|
|
79
79
|
| `congress [ticker]` | Congressional disclosures, market-wide or for one symbol |
|
|
80
80
|
| `news [ticker]` | Clustered news stories with impact and tone |
|
|
81
81
|
| `flows [ticker]` | Institutional 13F flows, or one ticker's holders and notable changes |
|
|
82
|
-
| `options <ticker>` | End-of-day options positioning, IV rank, walls, unusual contracts |
|
|
83
|
-
| `screen --filter ...` | Screen the universe on Score, analyst, technical, and
|
|
82
|
+
| `options <ticker>` | End-of-day options positioning, IV rank, walls, unusual contracts; `--intraday` for the session's 15-minute series (PRO) |
|
|
83
|
+
| `screen --filter ...` | Screen the universe on Score, analyst, technical, price, and end-of-day options fields |
|
|
84
84
|
| `search <name>` | Resolve a name, alias, ticker or slug to a symbol and the entity handle |
|
|
85
85
|
|
|
86
86
|
Run `sentisense help <command>` for its flags and examples.
|
|
@@ -183,9 +183,9 @@ Affected: every method whose declared return type is `PreviewResponse<T>`. A tes
|
|
|
183
183
|
| `institutional` | `getFlows` `getHolders` `getActivists` |
|
|
184
184
|
| `options` | `getOverview` |
|
|
185
185
|
| `politicians` | `getActivity` `getFilings` `getMembers` `getMember` |
|
|
186
|
-
| `stocks` | `getSentiment` `getKpis` `getOptionsSummary` `getOptionsHistory` |
|
|
186
|
+
| `stocks` | `getSentiment` `getKpis` `getOptionsSummary` `getOptionsHistory` `getOptionsIntradayHistory` |
|
|
187
187
|
|
|
188
|
-
The envelope itself is always an object, so test the payload rather than the response.
|
|
188
|
+
The envelope itself is always an object, so test the payload rather than the response. Three of these declare a `data` that can be null: `stocks.getOptionsSummary`, for a ticker outside the covered options universe, `options.getOverview`, before its first nightly build, and `stocks.getOptionsIntradayHistory`, on a FREE key's `PRO_REQUIRED` preview. Everywhere else `data` is an array or an object.
|
|
189
189
|
|
|
190
190
|
```typescript
|
|
191
191
|
const flows = await client.institutional.getFlows();
|
|
@@ -244,6 +244,7 @@ client.stocks.getFloat("GME") // Free float
|
|
|
244
244
|
client.stocks.getGraph("AAPL", { depth: 1 }) // Company knowledge graph: people, products, peers
|
|
245
245
|
client.stocks.getOptionsSummary("NVDA") // End-of-day options dossier
|
|
246
246
|
client.stocks.getOptionsHistory("NVDA", { window: "2y" }) // Daily options aggregates over time
|
|
247
|
+
client.stocks.getOptionsIntradayHistory("NVDA") // One session's intraday options series (PRO)
|
|
247
248
|
client.stocks.getRating("AAPL") // SentiSense Rating: score, letter, percentile, dimensions
|
|
248
249
|
client.stocks.getAISummary("AAPL", { depth: "deep" }) // AI report (PRO)
|
|
249
250
|
```
|
|
@@ -521,11 +522,29 @@ End-of-day options positioning: where implied volatility, put/call flow and skew
|
|
|
521
522
|
client.options.getOverview() // Market-wide radar, ranked
|
|
522
523
|
client.stocks.getOptionsSummary("NVDA") // One name's full dossier
|
|
523
524
|
client.stocks.getOptionsHistory("NVDA", { window: "2y" }) // That name's daily series
|
|
525
|
+
client.stocks.getOptionsIntradayHistory("NVDA", { session: "2026-10-14" }) // Every 15-minute cycle of one session (PRO)
|
|
524
526
|
```
|
|
525
527
|
|
|
526
528
|
The radar carries two separately-ranked boards: `data.rows` for stocks and `data.etfRows` for ETFs. Keep them apart. Every reading behind a row's `interestScore` is a percentile of that ticker's own trailing history, so a ranking built across both boards compares numbers measured against different baselines. The aggregates split the same way, with the `etf`-prefixed fields describing the ETF board alone.
|
|
527
529
|
|
|
528
|
-
During the trading session the dossier and the radar also carry a few intraday fields, the same on every tier: `intradayFlow` (a count of the ticker's unusual contracts so far, when the first one was flagged, and the board's own clock), `largePrintCount` and `largestPrintPctl` on the dossier, and `intradayActiveCount` with `intradayRanking` on the radar. They carry no contract, strike, price or premium, and are absent before the day's first board. `capabilities.intradayBoard` says where the contract-level board lives; its rows are served in the SentiSense app, not by the API.
|
|
530
|
+
During the trading session the dossier and the radar also carry a few intraday fields, the same on every tier: `intradayFlow` (a count of the ticker's unusual contracts so far, when the first one was flagged, and the board's own clock), `largePrintCount` and `largestPrintPctl` on the dossier, and `intradayActiveCount` with `intradayRanking` on the radar. They carry no contract, strike, price or premium, and are absent before the day's first board. On the radar, `intradayAsOf` (epoch seconds) and `intradayAsOfEt` date the board the ranking was read from. `capabilities.intradayBoard` says where the contract-level board lives; its rows are served in the SentiSense app, not by the API.
|
|
531
|
+
|
|
532
|
+
`getOptionsIntradayHistory` keeps every cycle of that board for one ticker, so you can test an intraday signal against what the board showed at each point in the day and then compare it with the session's end-of-day row from `getOptionsHistory`:
|
|
533
|
+
|
|
534
|
+
```typescript
|
|
535
|
+
const day = await client.stocks.getOptionsIntradayHistory("NVDA", { session: "2026-10-14" });
|
|
536
|
+
if (day.data === null) {
|
|
537
|
+
console.log(day.upgrade?.message); // PRO only: a FREE key gets a preview with no series
|
|
538
|
+
} else {
|
|
539
|
+
for (const point of day.data.series) { // oldest cycle first
|
|
540
|
+
console.log(point.asOfEt, point.callVol, point.putVol, point.pcVol, point.unusualCount, point.atmIv);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
Each point carries call and put volume so far, the put/call ratio, the unusual-contract count, the percentile of the largest qualifying contract against the ticker's own year (`maxPremiumPctl1y`) and the ATM implied volatility; readings that are unavailable are absent, never zero. Omit `session` for the session the board ran most recently, and read `data.session` for the date served. A ticker appears only on cycles where it was on the board, so gaps show in each point's `cycle`, and `missingCycles` lists cycles whose stored point could not be read. A weekend, a holiday, a ticker outside the board and an unknown symbol all return an empty `series`, not a null payload. A malformed or future date rejects with an `APIError` whose `code` is `"invalid_session"`. From the CLI: `sentisense options NVDA --intraday`, or `--session YYYY-MM-DD` for another day.
|
|
546
|
+
|
|
547
|
+
A FREE key that has spent its ten monthly dossiers receives a headline preview from `getOptionsSummary`: `asOf`, `sentiment` and six flat readings, `ivRank1y`, `atmIv`, `expectedMove1d`, `pcVol`, `pcVolPctl1y` and `maxPain`, with no `latest`, `context` or `oiWalls`. On a full dossier those six are absent and the same readings live in the nested objects, so branch on `isPreview`.
|
|
529
548
|
|
|
530
549
|
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.
|
|
531
550
|
|
|
@@ -578,7 +597,7 @@ An empty array is the normal answer for a query that matches nothing, so branch
|
|
|
578
597
|
|
|
579
598
|
### Screener
|
|
580
599
|
|
|
581
|
-
Filter the tracked universe on the SentiSense Score, attention, analyst consensus, technicals and
|
|
600
|
+
Filter the tracked universe on the SentiSense Score, attention, analyst consensus, technicals, price and end-of-day options readings 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.
|
|
582
601
|
|
|
583
602
|
```typescript
|
|
584
603
|
client.screener.fields() // Every filterable field, both universes, with units + operators
|
|
@@ -609,6 +628,18 @@ const res = await client.screener.run({
|
|
|
609
628
|
for (const row of res.results) {
|
|
610
629
|
console.log(row.ticker, row.sentiSenseScore7D, row.analystBuyRatioPct);
|
|
611
630
|
}
|
|
631
|
+
|
|
632
|
+
// Options positioning: implied volatility in the top quarter of its own year
|
|
633
|
+
const highIv = await client.screener.run({
|
|
634
|
+
plan: {
|
|
635
|
+
filters: [{ fieldName: "IV_RANK_1Y", op: "GTE", value: 75 }],
|
|
636
|
+
sort: { fieldName: "IV_RANK_1Y", dir: "DESC" },
|
|
637
|
+
},
|
|
638
|
+
limit: 25,
|
|
639
|
+
});
|
|
640
|
+
for (const row of highIv.results) {
|
|
641
|
+
console.log(row.ticker, row.ivRank1y, row.expectedMove20d, row.optionsAsOf);
|
|
642
|
+
}
|
|
612
643
|
```
|
|
613
644
|
|
|
614
645
|
`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.
|
|
@@ -623,7 +654,11 @@ The Score fields (`SENTI_SCORE_7D`, `SENTI_SCORE_1M`, `SCORE_CHANGE_7D`) are the
|
|
|
623
654
|
|
|
624
655
|
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.
|
|
625
656
|
|
|
626
|
-
|
|
657
|
+
Stock rows also carry seven end-of-day options readings, `ivRank1y`, `pcVol`, `pcVolPctl1y`, `skew25dPctl1y`, `optionsInterestScore`, `maxUnusualPremium` and `expectedMove20d`, plus `optionsAsOf`, the session date they are from. `expectedMove20d` is a fraction of price (`0.2` is 20%) and `optionsAsOf` is a `YYYY-MM-DD` date; filter on the options fields with names like `IV_RANK_1Y`.
|
|
658
|
+
|
|
659
|
+
Every stock row carries `priceAsOf`, when the market data behind `currentPrice`, `change` and `changePercent` is from, in epoch milliseconds (the same unit as the quote endpoints). It is `null` outside regular hours, on a previous-close fallback and when no quote was available, so read `null` as unknown rather than fresh, and judge a price's age from `priceAsOf`, not `lastUpdated`. Rated stocks also carry `ratingLetter`, `ratingScore` and `ratingPercentile`; all three are `null` for an unrated one.
|
|
660
|
+
|
|
661
|
+
Prices are 15-minute delayed quotes, refreshed at request time during the regular session from a cache at most 5 minutes old. Everything else on a row comes from a snapshot rebuilt about every 20 minutes during the session, so this is not a quote feed: use `client.stocks.getQuote()` for one ticker's current quote.
|
|
627
662
|
|
|
628
663
|
## Error handling
|
|
629
664
|
|
package/dist/cli.cjs
CHANGED
|
@@ -1356,7 +1356,7 @@ var flowsCommand = {
|
|
|
1356
1356
|
};
|
|
1357
1357
|
|
|
1358
1358
|
// src/version.ts
|
|
1359
|
-
var VERSION = "0.
|
|
1359
|
+
var VERSION = "0.65.0";
|
|
1360
1360
|
|
|
1361
1361
|
// src/resources/analyst.ts
|
|
1362
1362
|
var Analyst = class {
|
|
@@ -2518,7 +2518,9 @@ var Stocks = class {
|
|
|
2518
2518
|
*
|
|
2519
2519
|
* Tiering: a PRO key always receives the full dossier. A FREE key receives it for the first
|
|
2520
2520
|
* ten calls each calendar month and a headline-only preview after that, with `isPreview`
|
|
2521
|
-
* true; calls that return a null `data` never spend that allowance.
|
|
2521
|
+
* true; calls that return a null `data` never spend that allowance. The headline preview has
|
|
2522
|
+
* no nested objects: its readings arrive flat as `data.ivRank1y`, `data.atmIv`,
|
|
2523
|
+
* `data.expectedMove1d`, `data.pcVol`, `data.pcVolPctl1y` and `data.maxPain`.
|
|
2522
2524
|
*/
|
|
2523
2525
|
async getOptionsSummary(ticker) {
|
|
2524
2526
|
return this.client.get(
|
|
@@ -2548,6 +2550,33 @@ var Stocks = class {
|
|
|
2548
2550
|
options
|
|
2549
2551
|
);
|
|
2550
2552
|
}
|
|
2553
|
+
/**
|
|
2554
|
+
* Get one stock's or ETF's intraday options series for one session: its numbers at every
|
|
2555
|
+
* 15-minute cycle of the intraday board, oldest cycle first.
|
|
2556
|
+
*
|
|
2557
|
+
* Use it to test an intraday signal against what the board actually showed at each point in
|
|
2558
|
+
* the day, then compare it with the session's end-of-day row from
|
|
2559
|
+
* {@link Stocks.getOptionsHistory}. Each point carries call and put volume so far, the
|
|
2560
|
+
* put/call ratio, the unusual-contract count, the percentile of the largest qualifying
|
|
2561
|
+
* contract against the ticker's own year, and the ATM implied volatility. It never carries a
|
|
2562
|
+
* contract symbol, strike, price, premium, open interest or print size.
|
|
2563
|
+
*
|
|
2564
|
+
* **PRO only.** A FREE key receives the standard preview: `isPreview` true, `previewReason`
|
|
2565
|
+
* `"PRO_REQUIRED"`, an `upgrade` hint, and `data: null`.
|
|
2566
|
+
*
|
|
2567
|
+
* **No data is an empty `series`, not a null payload.** A weekend, a holiday, a session from
|
|
2568
|
+
* before the history was kept, a ticker outside the board and an unknown symbol all answer
|
|
2569
|
+
* with `data.series` empty. `data.missingCycles` lists cycles whose stored point could not be
|
|
2570
|
+
* read, which are unknown rather than absent. A malformed or future `session` rejects with
|
|
2571
|
+
* an `APIError` (status 400, code `invalid_session`). A 503 means the stored series could
|
|
2572
|
+
* not be read; it is retried like any other 503 and never answered with a partial series.
|
|
2573
|
+
*/
|
|
2574
|
+
async getOptionsIntradayHistory(ticker, options) {
|
|
2575
|
+
return this.client.get(
|
|
2576
|
+
`/api/v1/stocks/${encodeURIComponent(ticker.toUpperCase())}/options/intraday-history`,
|
|
2577
|
+
options
|
|
2578
|
+
);
|
|
2579
|
+
}
|
|
2551
2580
|
/**
|
|
2552
2581
|
* Get the SentiSense Rating for one stock: where it ranks against the other stocks rated
|
|
2553
2582
|
* that day, and the six dimensions the rank is blended from.
|
|
@@ -3584,6 +3613,7 @@ var newsCommand = {
|
|
|
3584
3613
|
};
|
|
3585
3614
|
|
|
3586
3615
|
// src/cli/commands/options.ts
|
|
3616
|
+
var SESSION_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
|
|
3587
3617
|
function contractTone(type) {
|
|
3588
3618
|
const side = type?.toUpperCase();
|
|
3589
3619
|
if (side === "CALL") return "up";
|
|
@@ -3594,14 +3624,79 @@ function walls(rows) {
|
|
|
3594
3624
|
if (!rows || rows.length === 0) return "n/a";
|
|
3595
3625
|
return rows.map((wall) => `${fixed(wall.strike, 0)} (${humanize(wall.oi, 1)})`).join(" ");
|
|
3596
3626
|
}
|
|
3627
|
+
async function intraday(api, ticker, session) {
|
|
3628
|
+
const envelope = await api.stocks.getOptionsIntradayHistory(ticker, { session });
|
|
3629
|
+
const data = envelope.data;
|
|
3630
|
+
if (envelope.isPreview && !data) {
|
|
3631
|
+
const lines = [
|
|
3632
|
+
{ kind: "text", text: `Intraday options history for ${ticker} needs a PRO key.` }
|
|
3633
|
+
];
|
|
3634
|
+
if (envelope.upgrade?.url) {
|
|
3635
|
+
lines.push({ kind: "text", text: envelope.upgrade.url, tone: "dim" });
|
|
3636
|
+
}
|
|
3637
|
+
return { json: envelope, doc: doc(...lines) };
|
|
3638
|
+
}
|
|
3639
|
+
const series = data?.series ?? [];
|
|
3640
|
+
const served = data?.session ?? session ?? "the latest session";
|
|
3641
|
+
if (series.length === 0) {
|
|
3642
|
+
const note = await verifyTickerOnEmpty(api, ticker);
|
|
3643
|
+
return {
|
|
3644
|
+
json: envelope,
|
|
3645
|
+
doc: doc({ kind: "text", text: `No intraday options history for ${ticker} on ${served}.` }),
|
|
3646
|
+
notes: note ? [note] : void 0
|
|
3647
|
+
};
|
|
3648
|
+
}
|
|
3649
|
+
const blocks = [
|
|
3650
|
+
{
|
|
3651
|
+
kind: "head",
|
|
3652
|
+
title: field("ticker", ticker),
|
|
3653
|
+
right: fields(
|
|
3654
|
+
field("session", served),
|
|
3655
|
+
field("board", data?.live ? "live" : "closed", data?.live ? "accent" : void 0),
|
|
3656
|
+
field("cycles", String(data?.cycles ?? series.length))
|
|
3657
|
+
)
|
|
3658
|
+
},
|
|
3659
|
+
{
|
|
3660
|
+
kind: "table",
|
|
3661
|
+
head: ["CYCLE", "TIME", "CALL VOL", "PUT VOL", "P/C", "UNUSUAL", "PCTL 1Y", "ATM IV"],
|
|
3662
|
+
align: ["right", "left", "right", "right", "right", "right", "right", "right"],
|
|
3663
|
+
rows: series.map((point) => [
|
|
3664
|
+
cell(String(point.cycle)),
|
|
3665
|
+
cell(point.asOfEt ?? ""),
|
|
3666
|
+
cell(humanize(point.callVol, 1)),
|
|
3667
|
+
cell(humanize(point.putVol, 1)),
|
|
3668
|
+
cell(fixed(point.pcVol, 2)),
|
|
3669
|
+
cell(String(point.unusualCount ?? 0)),
|
|
3670
|
+
cell(fixed(point.maxPremiumPctl1y, 1)),
|
|
3671
|
+
cell(fixed(point.atmIv, 4))
|
|
3672
|
+
])
|
|
3673
|
+
}
|
|
3674
|
+
];
|
|
3675
|
+
const missing = data?.missingCycles ?? [];
|
|
3676
|
+
if (missing.length > 0) {
|
|
3677
|
+
blocks.push({
|
|
3678
|
+
kind: "text",
|
|
3679
|
+
text: `${missing.length === 1 ? "Cycle" : "Cycles"} ${missing.join(", ")} ${missing.length === 1 ? "was" : "were"} published but could not be read, so ${ticker}'s numbers there are unknown.`,
|
|
3680
|
+
tone: "dim"
|
|
3681
|
+
});
|
|
3682
|
+
}
|
|
3683
|
+
blocks.push({
|
|
3684
|
+
kind: "text",
|
|
3685
|
+
text: `Volumes are cumulative for the session, from chains delayed ${data?.delayMinutes ?? 15} minutes.`,
|
|
3686
|
+
tone: "dim"
|
|
3687
|
+
});
|
|
3688
|
+
return { json: envelope, doc: doc(...blocks) };
|
|
3689
|
+
}
|
|
3597
3690
|
var optionsCommand = {
|
|
3598
3691
|
name: "options",
|
|
3599
3692
|
summary: "End-of-day options positioning for one stock or ETF",
|
|
3600
|
-
usage: "sentisense options <ticker>",
|
|
3693
|
+
usage: "sentisense options <ticker> [--intraday] [--session YYYY-MM-DD]",
|
|
3601
3694
|
examples: [
|
|
3602
3695
|
"sentisense options NVDA",
|
|
3603
3696
|
"sentisense options SPY --full",
|
|
3604
|
-
"sentisense options NVDA --json"
|
|
3697
|
+
"sentisense options NVDA --json",
|
|
3698
|
+
"sentisense options NVDA --intraday",
|
|
3699
|
+
"sentisense options SPY --session 2026-10-14"
|
|
3605
3700
|
],
|
|
3606
3701
|
notes: [
|
|
3607
3702
|
"End of day, not live: readings describe the latest completed session and refresh the",
|
|
@@ -3612,11 +3707,28 @@ var optionsCommand = {
|
|
|
3612
3707
|
EMPTY_VERIFY_NOTE,
|
|
3613
3708
|
EMPTY_VERIFY_NOTE_2,
|
|
3614
3709
|
"A free key gets the full dossier for the first ten calls each month, then a headline",
|
|
3615
|
-
"preview. Calls that return no dossier do not count against that."
|
|
3710
|
+
"preview. Calls that return no dossier do not count against that.",
|
|
3711
|
+
"--intraday shows one session's intraday series instead: the ticker's volumes, put/call",
|
|
3712
|
+
"ratio, unusual-contract count and ATM IV at every 15-minute cycle (PRO keys only).",
|
|
3713
|
+
"--session picks the session and implies --intraday; omitted, the latest one."
|
|
3616
3714
|
],
|
|
3617
|
-
flags: {
|
|
3715
|
+
flags: {
|
|
3716
|
+
intraday: { type: "boolean", describe: "Show the session's intraday series, every 15-minute cycle (PRO)" },
|
|
3717
|
+
session: {
|
|
3718
|
+
type: "string",
|
|
3719
|
+
placeholder: "YYYY-MM-DD",
|
|
3720
|
+
describe: "Session for the intraday series (default: the latest)"
|
|
3721
|
+
}
|
|
3722
|
+
},
|
|
3618
3723
|
async run({ args, client, full }) {
|
|
3619
3724
|
const ticker = oneTicker(args, "options");
|
|
3725
|
+
const session = typeof args.flags.session === "string" ? args.flags.session : void 0;
|
|
3726
|
+
if (session !== void 0 && !SESSION_PATTERN.test(session)) {
|
|
3727
|
+
throw new CliUsageError("--session must be a date, YYYY-MM-DD.", "for example: --session 2026-10-14");
|
|
3728
|
+
}
|
|
3729
|
+
if (args.flags.intraday === true || session !== void 0) {
|
|
3730
|
+
return intraday(client(), ticker, session);
|
|
3731
|
+
}
|
|
3620
3732
|
const api = client();
|
|
3621
3733
|
const envelope = await api.stocks.getOptionsSummary(ticker);
|
|
3622
3734
|
const data = envelope.data;
|
|
@@ -3630,21 +3742,24 @@ var optionsCommand = {
|
|
|
3630
3742
|
}
|
|
3631
3743
|
const latest = data.latest ?? {};
|
|
3632
3744
|
const context = data.context ?? {};
|
|
3745
|
+
const ivRank = context.ivRank1y ?? data.ivRank1y;
|
|
3746
|
+
const pcVol = latest.pcVol ?? data.pcVol;
|
|
3747
|
+
const maxPain = data.oiWalls?.maxPain ?? data.maxPain;
|
|
3633
3748
|
const blocks = [
|
|
3634
3749
|
{
|
|
3635
3750
|
kind: "head",
|
|
3636
3751
|
title: field("ticker", ticker),
|
|
3637
3752
|
right: fields(
|
|
3638
3753
|
field("positioning", signed(data.sentiment, 2), direction(data.sentiment)),
|
|
3639
|
-
field("iv rank 1y", fixed(
|
|
3640
|
-
field("put/call vol", fixed(
|
|
3754
|
+
field("iv rank 1y", fixed(ivRank, 1)),
|
|
3755
|
+
field("put/call vol", fixed(pcVol, 2))
|
|
3641
3756
|
)
|
|
3642
3757
|
},
|
|
3643
3758
|
{
|
|
3644
3759
|
kind: "facts",
|
|
3645
3760
|
items: fields(
|
|
3646
|
-
field("ATM IV", fixed(latest.atmIv, 4)),
|
|
3647
|
-
field("Exp move 1d", fixed(latest.expectedMove1d, 4)),
|
|
3761
|
+
field("ATM IV", fixed(latest.atmIv ?? data.atmIv, 4)),
|
|
3762
|
+
field("Exp move 1d", fixed(latest.expectedMove1d ?? data.expectedMove1d, 4)),
|
|
3648
3763
|
field("Skew 25d", signed(latest.skew25d, 4)),
|
|
3649
3764
|
field("Call vol", humanize(latest.callVol, 1)),
|
|
3650
3765
|
field("Put vol", humanize(latest.putVol, 1)),
|
|
@@ -3654,7 +3769,7 @@ var optionsCommand = {
|
|
|
3654
3769
|
{
|
|
3655
3770
|
kind: "facts",
|
|
3656
3771
|
items: fields(
|
|
3657
|
-
field("Max pain", fixed(
|
|
3772
|
+
field("Max pain", fixed(maxPain, 0)),
|
|
3658
3773
|
field("Wall expiry", data.oiWalls?.expiry ?? "n/a"),
|
|
3659
3774
|
field("Call OI", humanize(latest.callOi, 1)),
|
|
3660
3775
|
field("Put OI", humanize(latest.putOi, 1)),
|
|
@@ -3676,7 +3791,7 @@ var optionsCommand = {
|
|
|
3676
3791
|
field("term structure", `60d ${fixed(latest.atmIv60, 4)} 90d ${fixed(latest.atmIv90, 4)}`),
|
|
3677
3792
|
field("net delta", humanize(latest.netDelta, 1)),
|
|
3678
3793
|
field("put/call OI", fixed(latest.pcOi, 2)),
|
|
3679
|
-
field("pc vol percentile 1y", fixed(context.pcVolPctl1y, 1)),
|
|
3794
|
+
field("pc vol percentile 1y", fixed(context.pcVolPctl1y ?? data.pcVolPctl1y, 1)),
|
|
3680
3795
|
field("skew percentile 1y", fixed(context.skewPctl1y, 1)),
|
|
3681
3796
|
field("observations 1y", fixed(context.observations1y, 0))
|
|
3682
3797
|
)
|
|
@@ -3947,7 +4062,7 @@ function parseSort(raw) {
|
|
|
3947
4062
|
}
|
|
3948
4063
|
var screenCommand = {
|
|
3949
4064
|
name: "screen",
|
|
3950
|
-
summary: "Filter the tracked universe on Score, analyst, technical, and
|
|
4065
|
+
summary: "Filter the tracked universe on Score, analyst, technical, price, and end-of-day options fields",
|
|
3951
4066
|
usage: "sentisense screen [--filter FIELD:OP:VALUE]... [--sort FIELD:DIR] [--limit N]",
|
|
3952
4067
|
examples: [
|
|
3953
4068
|
"sentisense screen --list",
|
package/dist/index.cjs
CHANGED
|
@@ -1242,7 +1242,9 @@ var Stocks = class {
|
|
|
1242
1242
|
*
|
|
1243
1243
|
* Tiering: a PRO key always receives the full dossier. A FREE key receives it for the first
|
|
1244
1244
|
* ten calls each calendar month and a headline-only preview after that, with `isPreview`
|
|
1245
|
-
* true; calls that return a null `data` never spend that allowance.
|
|
1245
|
+
* true; calls that return a null `data` never spend that allowance. The headline preview has
|
|
1246
|
+
* no nested objects: its readings arrive flat as `data.ivRank1y`, `data.atmIv`,
|
|
1247
|
+
* `data.expectedMove1d`, `data.pcVol`, `data.pcVolPctl1y` and `data.maxPain`.
|
|
1246
1248
|
*/
|
|
1247
1249
|
async getOptionsSummary(ticker) {
|
|
1248
1250
|
return this.client.get(
|
|
@@ -1272,6 +1274,33 @@ var Stocks = class {
|
|
|
1272
1274
|
options
|
|
1273
1275
|
);
|
|
1274
1276
|
}
|
|
1277
|
+
/**
|
|
1278
|
+
* Get one stock's or ETF's intraday options series for one session: its numbers at every
|
|
1279
|
+
* 15-minute cycle of the intraday board, oldest cycle first.
|
|
1280
|
+
*
|
|
1281
|
+
* Use it to test an intraday signal against what the board actually showed at each point in
|
|
1282
|
+
* the day, then compare it with the session's end-of-day row from
|
|
1283
|
+
* {@link Stocks.getOptionsHistory}. Each point carries call and put volume so far, the
|
|
1284
|
+
* put/call ratio, the unusual-contract count, the percentile of the largest qualifying
|
|
1285
|
+
* contract against the ticker's own year, and the ATM implied volatility. It never carries a
|
|
1286
|
+
* contract symbol, strike, price, premium, open interest or print size.
|
|
1287
|
+
*
|
|
1288
|
+
* **PRO only.** A FREE key receives the standard preview: `isPreview` true, `previewReason`
|
|
1289
|
+
* `"PRO_REQUIRED"`, an `upgrade` hint, and `data: null`.
|
|
1290
|
+
*
|
|
1291
|
+
* **No data is an empty `series`, not a null payload.** A weekend, a holiday, a session from
|
|
1292
|
+
* before the history was kept, a ticker outside the board and an unknown symbol all answer
|
|
1293
|
+
* with `data.series` empty. `data.missingCycles` lists cycles whose stored point could not be
|
|
1294
|
+
* read, which are unknown rather than absent. A malformed or future `session` rejects with
|
|
1295
|
+
* an `APIError` (status 400, code `invalid_session`). A 503 means the stored series could
|
|
1296
|
+
* not be read; it is retried like any other 503 and never answered with a partial series.
|
|
1297
|
+
*/
|
|
1298
|
+
async getOptionsIntradayHistory(ticker, options) {
|
|
1299
|
+
return this.client.get(
|
|
1300
|
+
`/api/v1/stocks/${encodeURIComponent(ticker.toUpperCase())}/options/intraday-history`,
|
|
1301
|
+
options
|
|
1302
|
+
);
|
|
1303
|
+
}
|
|
1275
1304
|
/**
|
|
1276
1305
|
* Get the SentiSense Rating for one stock: where it ranks against the other stocks rated
|
|
1277
1306
|
* that day, and the six dimensions the rank is blended from.
|
|
@@ -1394,7 +1423,7 @@ var Trackers = class {
|
|
|
1394
1423
|
};
|
|
1395
1424
|
|
|
1396
1425
|
// src/version.ts
|
|
1397
|
-
var VERSION = "0.
|
|
1426
|
+
var VERSION = "0.65.0";
|
|
1398
1427
|
|
|
1399
1428
|
// src/client.ts
|
|
1400
1429
|
var DEFAULT_BASE_URL = "https://app.sentisense.ai";
|