@spfunctions/cli 1.4.1 → 1.4.2
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/dist/commands/agent.js
CHANGED
|
@@ -671,6 +671,8 @@ async function agentCommand(thesisId, opts) {
|
|
|
671
671
|
const matched = series
|
|
672
672
|
.filter((s) => keywords.every((kw) => (s.title || '').toLowerCase().includes(kw) ||
|
|
673
673
|
(s.ticker || '').toLowerCase().includes(kw)))
|
|
674
|
+
.filter((s) => parseFloat(s.volume_fp || '0') > 1000)
|
|
675
|
+
.sort((a, b) => parseFloat(b.volume_fp || '0') - parseFloat(a.volume_fp || '0'))
|
|
674
676
|
.slice(0, 15);
|
|
675
677
|
result = matched;
|
|
676
678
|
}
|
|
@@ -2187,7 +2189,7 @@ async function runPlainTextAgent(params) {
|
|
|
2187
2189
|
else if (p.query) {
|
|
2188
2190
|
const series = await (0, client_js_1.kalshiFetchAllSeries)();
|
|
2189
2191
|
const kws = p.query.toLowerCase().split(/\s+/);
|
|
2190
|
-
result = series.filter((s) => kws.every((k) => ((s.title || '') + (s.ticker || '')).toLowerCase().includes(k))).slice(0, 15);
|
|
2192
|
+
result = series.filter((s) => kws.every((k) => ((s.title || '') + (s.ticker || '')).toLowerCase().includes(k))).filter((s) => parseFloat(s.volume_fp || '0') > 1000).sort((a, b) => parseFloat(b.volume_fp || '0') - parseFloat(a.volume_fp || '0')).slice(0, 15);
|
|
2191
2193
|
}
|
|
2192
2194
|
else {
|
|
2193
2195
|
result = { error: 'Provide query, series, or market' };
|
|
@@ -8,10 +8,36 @@ const client_js_1 = require("../client.js");
|
|
|
8
8
|
const kalshi_js_1 = require("../kalshi.js");
|
|
9
9
|
const config_js_1 = require("../config.js");
|
|
10
10
|
const utils_js_1 = require("../utils.js");
|
|
11
|
-
/** Abbreviate ticker
|
|
11
|
+
/** Abbreviate ticker to something readable:
|
|
12
|
+
* KXWTIMAX-26DEC31-T135 → Oil 135
|
|
13
|
+
* KXRECSSNBER-26 → Recsn
|
|
14
|
+
* KXAAAGASM-26MAR31-4.40 → Gas 4.40
|
|
15
|
+
* KXINXY-26DEC31H1600-T4000 → S&P 4000
|
|
16
|
+
*/
|
|
12
17
|
function abbrevTicker(ticker) {
|
|
18
|
+
// Short topic names for performance table
|
|
19
|
+
const SHORT_TOPICS = {
|
|
20
|
+
KXWTIMAX: 'Oil', KXWTI: 'Oil', KXRECSSNBER: 'Recsn',
|
|
21
|
+
KXAAAGASM: 'Gas', KXCPI: 'CPI', KXINXY: 'S&P',
|
|
22
|
+
KXFEDDECISION: 'Fed', KXUNEMPLOYMENT: 'Unemp', KXCLOSEHORMUZ: 'Hormuz',
|
|
23
|
+
};
|
|
24
|
+
const sorted = Object.keys(SHORT_TOPICS).sort((a, b) => b.length - a.length);
|
|
25
|
+
let topic = '';
|
|
26
|
+
for (const prefix of sorted) {
|
|
27
|
+
if (ticker.startsWith(prefix)) {
|
|
28
|
+
topic = SHORT_TOPICS[prefix];
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Extract the meaningful suffix (strike/level)
|
|
13
33
|
const parts = ticker.split('-');
|
|
14
|
-
|
|
34
|
+
const last = parts[parts.length - 1] || '';
|
|
35
|
+
const suffix = last.startsWith('T') ? last.slice(1) : '';
|
|
36
|
+
if (topic && suffix)
|
|
37
|
+
return `${topic} ${suffix}`;
|
|
38
|
+
if (topic)
|
|
39
|
+
return topic;
|
|
40
|
+
return last || ticker.slice(0, 8);
|
|
15
41
|
}
|
|
16
42
|
/** Format date as "Mar 01" */
|
|
17
43
|
function fmtDate(d) {
|
|
@@ -155,12 +181,12 @@ async function performanceCommand(opts) {
|
|
|
155
181
|
const config = (0, config_js_1.loadConfig)();
|
|
156
182
|
const client = new client_js_1.SFClient(config.apiKey, config.apiUrl);
|
|
157
183
|
const feedData = await client.getFeed(720);
|
|
158
|
-
const feedItems = feedData?.items || feedData?.events || feedData || [];
|
|
184
|
+
const feedItems = feedData?.feed || feedData?.items || feedData?.events || feedData || [];
|
|
159
185
|
if (Array.isArray(feedItems)) {
|
|
160
186
|
for (const item of feedItems) {
|
|
161
|
-
const confDelta = item.confidenceDelta ?? item.confidence_delta ?? 0;
|
|
162
|
-
if (Math.abs(confDelta)
|
|
163
|
-
const itemDate = item.createdAt || item.created_at || item.timestamp || '';
|
|
187
|
+
const confDelta = item.delta ?? item.confidenceDelta ?? item.confidence_delta ?? 0;
|
|
188
|
+
if (Math.abs(confDelta) >= 0.02) {
|
|
189
|
+
const itemDate = item.evaluatedAt || item.createdAt || item.created_at || item.timestamp || '';
|
|
164
190
|
if (itemDate) {
|
|
165
191
|
events.push({
|
|
166
192
|
date: dateKey(new Date(itemDate)),
|
|
@@ -211,7 +237,7 @@ async function performanceCommand(opts) {
|
|
|
211
237
|
console.log();
|
|
212
238
|
// Column headers
|
|
213
239
|
const abbrevs = tickers.map(t => abbrevTicker(t.ticker));
|
|
214
|
-
const colWidth =
|
|
240
|
+
const colWidth = 11;
|
|
215
241
|
const dateCol = 'Date'.padEnd(12);
|
|
216
242
|
const headerCols = abbrevs.map(a => (0, utils_js_1.rpad)(a, colWidth)).join('');
|
|
217
243
|
const totalCol = (0, utils_js_1.rpad)('Total', colWidth);
|
|
@@ -239,6 +265,21 @@ async function performanceCommand(opts) {
|
|
|
239
265
|
const totalColor = row.total > 0 ? utils_js_1.c.green : row.total < 0 ? utils_js_1.c.red : utils_js_1.c.dim;
|
|
240
266
|
console.log(` ${dateStr}${cols}${totalColor}${(0, utils_js_1.rpad)(totalStr, colWidth)}${utils_js_1.c.reset}`);
|
|
241
267
|
}
|
|
268
|
+
// Sparkline of total P&L
|
|
269
|
+
if (dailyRows.length >= 2) {
|
|
270
|
+
const totals = dailyRows.map(r => r.total);
|
|
271
|
+
const min = Math.min(...totals);
|
|
272
|
+
const max = Math.max(...totals);
|
|
273
|
+
const range = max - min || 1;
|
|
274
|
+
const blocks = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'];
|
|
275
|
+
const spark = totals.map(v => {
|
|
276
|
+
const idx = Math.round(((v - min) / range) * (blocks.length - 1));
|
|
277
|
+
const ch = blocks[idx];
|
|
278
|
+
return v >= 0 ? `${utils_js_1.c.green}${ch}${utils_js_1.c.reset}` : `${utils_js_1.c.red}${ch}${utils_js_1.c.reset}`;
|
|
279
|
+
}).join('');
|
|
280
|
+
console.log();
|
|
281
|
+
console.log(` ${utils_js_1.c.dim}P&L trend:${utils_js_1.c.reset} ${spark}`);
|
|
282
|
+
}
|
|
242
283
|
// Events
|
|
243
284
|
if (events.length > 0) {
|
|
244
285
|
console.log();
|
package/dist/commands/scan.js
CHANGED
|
@@ -104,14 +104,16 @@ async function keywordScan(query, json) {
|
|
|
104
104
|
score += 3;
|
|
105
105
|
else if (v > 100_000)
|
|
106
106
|
score += 1;
|
|
107
|
-
if (score > 0)
|
|
108
|
-
matches.push({ series: s, score });
|
|
107
|
+
if (score > 0 && v > 1000)
|
|
108
|
+
matches.push({ series: s, score, volume: v });
|
|
109
109
|
}
|
|
110
|
-
|
|
110
|
+
// Sort by score first, then by volume as tiebreaker
|
|
111
|
+
matches.sort((a, b) => b.score - a.score || b.volume - a.volume);
|
|
111
112
|
const topSeries = matches.slice(0, 15);
|
|
112
113
|
console.log(`\n${utils_js_1.c.bold}Found ${matches.length} relevant series. Top ${topSeries.length}:${utils_js_1.c.reset}\n`);
|
|
113
|
-
for (const { series: s,
|
|
114
|
-
|
|
114
|
+
for (const { series: s, volume } of topSeries) {
|
|
115
|
+
const volStr = volume >= 1_000_000 ? `$${(volume / 1_000_000).toFixed(1)}M` : volume >= 1000 ? `$${(volume / 1000).toFixed(0)}k` : `$${volume.toFixed(0)}`;
|
|
116
|
+
console.log(` ${(0, utils_js_1.rpad)(volStr, 10)} ${(0, utils_js_1.pad)(s.ticker, 25)} ${s.title}`);
|
|
115
117
|
}
|
|
116
118
|
// Fetch live markets for top 10
|
|
117
119
|
console.log(`\n${utils_js_1.c.dim}Fetching live markets...${utils_js_1.c.reset}\n`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spfunctions/cli",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.2",
|
|
4
4
|
"description": "Prediction market intelligence CLI. Causal thesis model, 24/7 Kalshi/Polymarket scan, live orderbook, edge detection. Interactive agent mode with tool calling.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"sf": "./dist/index.js"
|