@spfunctions/cli 1.4.5 → 1.5.1
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 +2 -0
- package/dist/client.js +11 -2
- package/dist/client.test.js +1 -1
- package/dist/commands/agent.js +370 -48
- package/dist/commands/book.d.ts +17 -0
- package/dist/commands/book.js +220 -0
- package/dist/commands/create.d.ts +2 -0
- package/dist/commands/create.js +18 -7
- package/dist/commands/dashboard.js +30 -1
- package/dist/commands/liquidity.d.ts +2 -0
- package/dist/commands/liquidity.js +128 -43
- package/dist/commands/list.d.ts +1 -0
- package/dist/commands/list.js +4 -0
- package/dist/commands/positions.js +50 -0
- package/dist/commands/scan.d.ts +1 -0
- package/dist/commands/scan.js +66 -15
- package/dist/commands/setup.d.ts +1 -0
- package/dist/commands/setup.js +71 -6
- package/dist/config.d.ts +2 -0
- package/dist/config.js +8 -0
- package/dist/index.js +97 -11
- package/dist/polymarket.d.ts +237 -0
- package/dist/polymarket.js +353 -0
- package/dist/polymarket.test.d.ts +1 -0
- package/dist/polymarket.test.js +424 -0
- package/dist/telegram/agent-bridge.js +81 -8
- package/dist/topics.d.ts +3 -0
- package/dist/topics.js +65 -7
- package/dist/topics.test.js +83 -6
- package/dist/tui/dashboard.js +65 -30
- package/dist/tui/widgets/edges.js +5 -4
- package/dist/tui/widgets/portfolio.js +3 -2
- package/package.json +1 -1
|
@@ -14,6 +14,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
14
14
|
exports.positionsCommand = positionsCommand;
|
|
15
15
|
const client_js_1 = require("../client.js");
|
|
16
16
|
const kalshi_js_1 = require("../kalshi.js");
|
|
17
|
+
const polymarket_js_1 = require("../polymarket.js");
|
|
18
|
+
const config_js_1 = require("../config.js");
|
|
17
19
|
const utils_js_1 = require("../utils.js");
|
|
18
20
|
async function positionsCommand(opts) {
|
|
19
21
|
const client = new client_js_1.SFClient(opts.apiKey, opts.apiUrl);
|
|
@@ -23,6 +25,18 @@ async function positionsCommand(opts) {
|
|
|
23
25
|
console.log(`${utils_js_1.c.dim}Fetching Kalshi positions...${utils_js_1.c.reset}`);
|
|
24
26
|
positions = await (0, kalshi_js_1.getPositions)();
|
|
25
27
|
}
|
|
28
|
+
// ── Step 1b: Fetch Polymarket positions (if wallet configured) ──
|
|
29
|
+
const config = (0, config_js_1.loadConfig)();
|
|
30
|
+
let polyPositions = [];
|
|
31
|
+
if (config.polymarketWalletAddress) {
|
|
32
|
+
console.log(`${utils_js_1.c.dim}Fetching Polymarket positions...${utils_js_1.c.reset}`);
|
|
33
|
+
try {
|
|
34
|
+
polyPositions = await (0, polymarket_js_1.polymarketGetPositions)(config.polymarketWalletAddress);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// skip
|
|
38
|
+
}
|
|
39
|
+
}
|
|
26
40
|
// ── Step 2: Fetch all theses and their edges (via SF API) ──
|
|
27
41
|
console.log(`${utils_js_1.c.dim}Fetching thesis edges...${utils_js_1.c.reset}`);
|
|
28
42
|
let theses = [];
|
|
@@ -100,7 +114,9 @@ async function positionsCommand(opts) {
|
|
|
100
114
|
if (opts.json) {
|
|
101
115
|
console.log(JSON.stringify({
|
|
102
116
|
kalshiConfigured: (0, kalshi_js_1.isKalshiConfigured)(),
|
|
117
|
+
polymarketConfigured: !!config.polymarketWalletAddress,
|
|
103
118
|
positions: positions || [],
|
|
119
|
+
polymarketPositions: polyPositions,
|
|
104
120
|
edges: allEdges.map(e => ({ ...e.edge, thesisId: e.thesisId })),
|
|
105
121
|
}, null, 2));
|
|
106
122
|
return;
|
|
@@ -169,6 +185,40 @@ async function positionsCommand(opts) {
|
|
|
169
185
|
else {
|
|
170
186
|
console.log(`\n${utils_js_1.c.yellow}Kalshi not configured.${utils_js_1.c.reset} Set KALSHI_API_KEY_ID and KALSHI_PRIVATE_KEY_PATH to see positions.\n`);
|
|
171
187
|
}
|
|
188
|
+
// C) Polymarket positions
|
|
189
|
+
if (polyPositions.length > 0) {
|
|
190
|
+
(0, utils_js_1.header)('Polymarket Positions');
|
|
191
|
+
console.log(' ' + utils_js_1.c.bold +
|
|
192
|
+
(0, utils_js_1.pad)('Market', 35) +
|
|
193
|
+
(0, utils_js_1.rpad)('Side', 5) +
|
|
194
|
+
(0, utils_js_1.rpad)('Size', 8) +
|
|
195
|
+
(0, utils_js_1.rpad)('Avg', 6) +
|
|
196
|
+
(0, utils_js_1.rpad)('Now', 6) +
|
|
197
|
+
(0, utils_js_1.rpad)('P&L', 9) +
|
|
198
|
+
utils_js_1.c.reset);
|
|
199
|
+
console.log(' ' + utils_js_1.c.dim + '─'.repeat(75) + utils_js_1.c.reset);
|
|
200
|
+
for (const pos of polyPositions) {
|
|
201
|
+
const title = (pos.title || pos.slug || pos.asset || '').slice(0, 34);
|
|
202
|
+
const side = pos.outcome || 'YES';
|
|
203
|
+
const size = pos.size || 0;
|
|
204
|
+
const avgPrice = Math.round((pos.avgPrice || 0) * 100);
|
|
205
|
+
const curPrice = Math.round((pos.curPrice || pos.currentPrice || 0) * 100);
|
|
206
|
+
const pnl = pos.cashPnl || ((curPrice - avgPrice) * size / 100);
|
|
207
|
+
const pnlColor = pnl >= 0 ? utils_js_1.c.green : utils_js_1.c.red;
|
|
208
|
+
const pnlStr = pnl >= 0 ? `+$${pnl.toFixed(2)}` : `-$${Math.abs(pnl).toFixed(2)}`;
|
|
209
|
+
console.log(' ' +
|
|
210
|
+
(0, utils_js_1.pad)(title, 35) +
|
|
211
|
+
(0, utils_js_1.rpad)(side.toUpperCase(), 5) +
|
|
212
|
+
(0, utils_js_1.rpad)(String(Math.round(size)), 8) +
|
|
213
|
+
(0, utils_js_1.rpad)(`${avgPrice}¢`, 6) +
|
|
214
|
+
(0, utils_js_1.rpad)(`${curPrice}¢`, 6) +
|
|
215
|
+
`${pnlColor}${(0, utils_js_1.rpad)(pnlStr, 9)}${utils_js_1.c.reset}`);
|
|
216
|
+
}
|
|
217
|
+
console.log('');
|
|
218
|
+
}
|
|
219
|
+
else if (config.polymarketWalletAddress) {
|
|
220
|
+
console.log(`${utils_js_1.c.dim}No open positions on Polymarket.${utils_js_1.c.reset}\n`);
|
|
221
|
+
}
|
|
172
222
|
// B) Unpositioned edges (edges without matching positions)
|
|
173
223
|
const positionedTickers = new Set((positions || []).map(p => p.ticker));
|
|
174
224
|
const unpositionedEdges = allEdges.filter(e => !positionedTickers.has(e.edge.marketId));
|
package/dist/commands/scan.d.ts
CHANGED
package/dist/commands/scan.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.scanCommand = scanCommand;
|
|
4
4
|
const client_js_1 = require("../client.js");
|
|
5
|
+
const polymarket_js_1 = require("../polymarket.js");
|
|
5
6
|
const utils_js_1 = require("../utils.js");
|
|
6
7
|
async function scanCommand(query, opts) {
|
|
7
8
|
// Mode 1: --market TICKER — single market detail
|
|
@@ -14,8 +15,8 @@ async function scanCommand(query, opts) {
|
|
|
14
15
|
await showSeries(opts.series.toUpperCase(), opts.json);
|
|
15
16
|
return;
|
|
16
17
|
}
|
|
17
|
-
// Mode 3: keyword scan across all series
|
|
18
|
-
await keywordScan(query, opts.json);
|
|
18
|
+
// Mode 3: keyword scan across all series + Polymarket
|
|
19
|
+
await keywordScan(query, opts.json, opts.venue || 'all');
|
|
19
20
|
}
|
|
20
21
|
async function showMarket(ticker, json) {
|
|
21
22
|
console.log(`${utils_js_1.c.dim}Fetching market ${ticker}...${utils_js_1.c.reset}`);
|
|
@@ -77,10 +78,19 @@ async function showSeries(seriesTicker, json) {
|
|
|
77
78
|
printMarketsTable(markets);
|
|
78
79
|
}
|
|
79
80
|
}
|
|
80
|
-
async function keywordScan(query, json) {
|
|
81
|
+
async function keywordScan(query, json, venue = 'all') {
|
|
81
82
|
const terms = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
82
|
-
|
|
83
|
-
const
|
|
83
|
+
// ── Polymarket search (runs in parallel with Kalshi) ───────────────────────
|
|
84
|
+
const polyPromise = (venue === 'kalshi')
|
|
85
|
+
? Promise.resolve([])
|
|
86
|
+
: (0, polymarket_js_1.polymarketSearch)(query, 10).catch(() => []);
|
|
87
|
+
if (venue !== 'polymarket') {
|
|
88
|
+
console.log(`${utils_js_1.c.dim}Scanning Kalshi for: "${query}"...${utils_js_1.c.reset}`);
|
|
89
|
+
}
|
|
90
|
+
if (venue !== 'kalshi') {
|
|
91
|
+
console.log(`${utils_js_1.c.dim}Scanning Polymarket for: "${query}"...${utils_js_1.c.reset}`);
|
|
92
|
+
}
|
|
93
|
+
const allSeries = venue === 'polymarket' ? [] : await (0, client_js_1.kalshiFetchAllSeries)();
|
|
84
94
|
// Score each series
|
|
85
95
|
const thesisKeywords = [
|
|
86
96
|
'oil', 'wti', 'gas', 'recession', 'gdp', 'fed', 'inflation',
|
|
@@ -126,13 +136,14 @@ async function keywordScan(query, json) {
|
|
|
126
136
|
for (const m of markets) {
|
|
127
137
|
if (m.status === 'open' || m.status === 'active') {
|
|
128
138
|
allMarkets.push({
|
|
139
|
+
venue: 'kalshi',
|
|
129
140
|
seriesTicker: s.ticker,
|
|
130
141
|
ticker: m.ticker,
|
|
131
142
|
title: m.title || m.subtitle || '',
|
|
132
143
|
yesAsk: parseFloat(m.yes_ask_dollars || '0'),
|
|
133
144
|
lastPrice: parseFloat(m.last_price_dollars || '0'),
|
|
134
145
|
volume24h: parseFloat(m.volume_24h_fp || '0'),
|
|
135
|
-
liquidity: parseFloat(m.liquidity_dollars || '0'),
|
|
146
|
+
liquidity: parseFloat(m.open_interest_fp || m.liquidity_dollars || '0'),
|
|
136
147
|
});
|
|
137
148
|
}
|
|
138
149
|
}
|
|
@@ -144,27 +155,67 @@ async function keywordScan(query, json) {
|
|
|
144
155
|
}
|
|
145
156
|
}
|
|
146
157
|
allMarkets.sort((a, b) => b.liquidity - a.liquidity);
|
|
158
|
+
// ── Polymarket results ──────────────────────────────────────────────────────
|
|
159
|
+
const polyEvents = await polyPromise;
|
|
160
|
+
const polyMarkets = [];
|
|
161
|
+
for (const event of polyEvents) {
|
|
162
|
+
for (const m of (event.markets || [])) {
|
|
163
|
+
if (!m.active || m.closed)
|
|
164
|
+
continue;
|
|
165
|
+
const prices = (0, polymarket_js_1.parseOutcomePrices)(m.outcomePrices);
|
|
166
|
+
const yesPrice = prices[0] || 0;
|
|
167
|
+
polyMarkets.push({
|
|
168
|
+
venue: 'polymarket',
|
|
169
|
+
ticker: m.conditionId?.slice(0, 16) || m.id,
|
|
170
|
+
title: m.groupItemTitle
|
|
171
|
+
? `${event.title}: ${m.groupItemTitle}`
|
|
172
|
+
: m.question || event.title,
|
|
173
|
+
yesAsk: yesPrice,
|
|
174
|
+
lastPrice: m.lastTradePrice || yesPrice,
|
|
175
|
+
volume24h: m.volume24hr || 0,
|
|
176
|
+
liquidity: m.liquidityNum || 0,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// ── Merge & output ─────────────────────────────────────────────────────────
|
|
181
|
+
// Tag Kalshi markets with venue
|
|
182
|
+
for (const m of allMarkets) {
|
|
183
|
+
if (!m.venue)
|
|
184
|
+
m.venue = 'kalshi';
|
|
185
|
+
}
|
|
186
|
+
const combined = [...allMarkets, ...polyMarkets];
|
|
187
|
+
combined.sort((a, b) => b.liquidity - a.liquidity);
|
|
147
188
|
if (json) {
|
|
148
|
-
console.log(JSON.stringify(
|
|
189
|
+
console.log(JSON.stringify(combined, null, 2));
|
|
149
190
|
return;
|
|
150
191
|
}
|
|
151
|
-
(0, utils_js_1.header)(`${
|
|
192
|
+
(0, utils_js_1.header)(`${combined.length} Live Markets (${allMarkets.length} Kalshi + ${polyMarkets.length} Polymarket)`);
|
|
152
193
|
console.log(utils_js_1.c.bold +
|
|
153
|
-
(0, utils_js_1.pad)('
|
|
194
|
+
(0, utils_js_1.pad)('', 5) +
|
|
195
|
+
(0, utils_js_1.pad)('Ticker', 30) +
|
|
154
196
|
(0, utils_js_1.rpad)('Yes', 6) +
|
|
155
197
|
(0, utils_js_1.rpad)('Last', 6) +
|
|
156
198
|
(0, utils_js_1.rpad)('Vol24h', 10) +
|
|
157
199
|
(0, utils_js_1.rpad)('Liq', 10) +
|
|
158
200
|
' Title' +
|
|
159
201
|
utils_js_1.c.reset);
|
|
160
|
-
(0, utils_js_1.hr)(
|
|
161
|
-
for (const m of
|
|
162
|
-
|
|
202
|
+
(0, utils_js_1.hr)(120);
|
|
203
|
+
for (const m of combined.slice(0, 60)) {
|
|
204
|
+
// Venue tag: fixed 5-char column, color applied AFTER padding
|
|
205
|
+
const venuePad = m.venue === 'polymarket' ? 'POLY ' : 'KLSH ';
|
|
206
|
+
const venueColored = m.venue === 'polymarket'
|
|
207
|
+
? utils_js_1.c.blue + venuePad + utils_js_1.c.reset
|
|
208
|
+
: utils_js_1.c.cyan + venuePad + utils_js_1.c.reset;
|
|
209
|
+
const tickerStr = m.venue === 'polymarket'
|
|
210
|
+
? (m.ticker || '').slice(0, 28)
|
|
211
|
+
: (m.ticker || '').slice(0, 28);
|
|
212
|
+
console.log(venueColored +
|
|
213
|
+
(0, utils_js_1.pad)(tickerStr, 30) +
|
|
163
214
|
(0, utils_js_1.rpad)(`${Math.round(m.yesAsk * 100)}¢`, 6) +
|
|
164
215
|
(0, utils_js_1.rpad)(`${Math.round(m.lastPrice * 100)}¢`, 6) +
|
|
165
|
-
(0, utils_js_1.rpad)((0, utils_js_1.vol)(m.volume24h), 10) +
|
|
166
|
-
(0, utils_js_1.rpad)((0, utils_js_1.vol)(m.liquidity), 10) +
|
|
167
|
-
` ${m.title.slice(0, 55)}`);
|
|
216
|
+
(0, utils_js_1.rpad)((0, utils_js_1.vol)(Math.round(m.volume24h)), 10) +
|
|
217
|
+
(0, utils_js_1.rpad)((0, utils_js_1.vol)(Math.round(m.liquidity)), 10) +
|
|
218
|
+
` ${(m.title || '').slice(0, 55)}`);
|
|
168
219
|
}
|
|
169
220
|
console.log('');
|
|
170
221
|
}
|
package/dist/commands/setup.d.ts
CHANGED
package/dist/commands/setup.js
CHANGED
|
@@ -165,6 +165,17 @@ async function setupCommand(opts) {
|
|
|
165
165
|
blank();
|
|
166
166
|
return;
|
|
167
167
|
}
|
|
168
|
+
// ── sf setup --polymarket (reconfigure Polymarket credentials) ──────────
|
|
169
|
+
if (opts.polymarket) {
|
|
170
|
+
const existing = (0, config_js_1.loadFileConfig)();
|
|
171
|
+
blank();
|
|
172
|
+
console.log(` ${bold('Reconfigure Polymarket Credentials')}`);
|
|
173
|
+
blank();
|
|
174
|
+
await promptForPolymarket(existing);
|
|
175
|
+
(0, config_js_1.saveConfig)(existing);
|
|
176
|
+
blank();
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
168
179
|
// ── sf setup --enable-trading / --disable-trading ────────────────────────
|
|
169
180
|
if (opts.enableTrading) {
|
|
170
181
|
const existing = (0, config_js_1.loadFileConfig)();
|
|
@@ -211,6 +222,13 @@ async function showCheck() {
|
|
|
211
222
|
else {
|
|
212
223
|
info(`${dim('○')} KALSHI ${dim('skipped')}`);
|
|
213
224
|
}
|
|
225
|
+
// Polymarket
|
|
226
|
+
if (config.polymarketWalletAddress) {
|
|
227
|
+
ok(`POLYMARKET ${dim(mask(config.polymarketWalletAddress))}`);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
info(`${dim('○')} POLYMARKET ${dim('skipped')}`);
|
|
231
|
+
}
|
|
214
232
|
// Tavily
|
|
215
233
|
if (config.tavilyKey) {
|
|
216
234
|
ok(`TAVILY ${dim(mask(config.tavilyKey))}`);
|
|
@@ -318,9 +336,27 @@ async function runWizard() {
|
|
|
318
336
|
}
|
|
319
337
|
(0, config_js_1.saveConfig)(config);
|
|
320
338
|
// ════════════════════════════════════════════════════════════════════════════
|
|
321
|
-
// Step 4:
|
|
339
|
+
// Step 4: Polymarket
|
|
340
|
+
// ════════════════════════════════════════════════════════════════════════════
|
|
341
|
+
console.log(` ${bold('Step 4: Polymarket (optional)')}`);
|
|
342
|
+
blank();
|
|
343
|
+
const existingPolyWallet = process.env.POLYMARKET_WALLET_ADDRESS || config.polymarketWalletAddress;
|
|
344
|
+
if (existingPolyWallet) {
|
|
345
|
+
ok(`Detected wallet — ${dim(mask(existingPolyWallet))}`);
|
|
346
|
+
info(dim('Skipping.'));
|
|
347
|
+
config.polymarketWalletAddress = existingPolyWallet;
|
|
348
|
+
blank();
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
await promptForPolymarket(config);
|
|
352
|
+
}
|
|
353
|
+
(0, config_js_1.saveConfig)(config);
|
|
354
|
+
if (config.polymarketWalletAddress)
|
|
355
|
+
process.env.POLYMARKET_WALLET_ADDRESS = config.polymarketWalletAddress;
|
|
356
|
+
// ════════════════════════════════════════════════════════════════════════════
|
|
357
|
+
// Step 5: Tavily
|
|
322
358
|
// ════════════════════════════════════════════════════════════════════════════
|
|
323
|
-
console.log(` ${bold('Step
|
|
359
|
+
console.log(` ${bold('Step 5: News Search (optional)')}`);
|
|
324
360
|
blank();
|
|
325
361
|
const existingTavily = process.env.TAVILY_API_KEY || config.tavilyKey;
|
|
326
362
|
if (existingTavily) {
|
|
@@ -346,7 +382,7 @@ async function runWizard() {
|
|
|
346
382
|
// Step 5: Trading
|
|
347
383
|
// ════════════════════════════════════════════════════════════════════════════
|
|
348
384
|
if (config.kalshiKeyId) {
|
|
349
|
-
console.log(` ${bold('Step
|
|
385
|
+
console.log(` ${bold('Step 6: Trading (optional)')}`);
|
|
350
386
|
blank();
|
|
351
387
|
info('Warning: enabling this unlocks sf buy / sf sell / sf cancel.');
|
|
352
388
|
info('Your Kalshi API key must have read+write permissions.');
|
|
@@ -493,7 +529,36 @@ async function promptForTavily() {
|
|
|
493
529
|
blank();
|
|
494
530
|
return answer;
|
|
495
531
|
}
|
|
496
|
-
|
|
532
|
+
async function promptForPolymarket(config) {
|
|
533
|
+
info('Connect Polymarket to view positions and scan orderbooks.');
|
|
534
|
+
info('Your Polygon wallet address is needed (starts with 0x...).');
|
|
535
|
+
info(`Find it at ${cyan('https://polymarket.com')} → Settings → Profile.`);
|
|
536
|
+
info('Press Enter to skip:');
|
|
537
|
+
blank();
|
|
538
|
+
const walletAddress = await prompt(' Wallet address > ');
|
|
539
|
+
if (!walletAddress) {
|
|
540
|
+
info(dim('Skipped.'));
|
|
541
|
+
blank();
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
if (!walletAddress.startsWith('0x') || walletAddress.length < 40) {
|
|
545
|
+
fail('Invalid wallet address (must start with 0x and be 42 characters)');
|
|
546
|
+
info(dim('Saved anyway. You can fix it later with sf setup.'));
|
|
547
|
+
}
|
|
548
|
+
else {
|
|
549
|
+
ok(`Wallet: ${mask(walletAddress)}`);
|
|
550
|
+
}
|
|
551
|
+
config.polymarketWalletAddress = walletAddress;
|
|
552
|
+
// Optionally configure private key for future trading
|
|
553
|
+
info(dim('Private key (for future trading) — press Enter to skip:'));
|
|
554
|
+
const keyPath = await prompt(' Key path > ');
|
|
555
|
+
if (keyPath) {
|
|
556
|
+
config.polymarketPrivateKeyPath = keyPath;
|
|
557
|
+
ok(`Private key path: ${dim(keyPath)}`);
|
|
558
|
+
}
|
|
559
|
+
blank();
|
|
560
|
+
}
|
|
561
|
+
// ─── Step 7: Thesis ──────────────────────────────────────────────────────────
|
|
497
562
|
async function handleThesisStep(config) {
|
|
498
563
|
try {
|
|
499
564
|
const client = new client_js_1.SFClient(config.apiKey, config.apiUrl);
|
|
@@ -501,7 +566,7 @@ async function handleThesisStep(config) {
|
|
|
501
566
|
const theses = data.theses || [];
|
|
502
567
|
const activeTheses = theses.filter((t) => t.status === 'active');
|
|
503
568
|
if (activeTheses.length > 0) {
|
|
504
|
-
console.log(` ${bold('Step
|
|
569
|
+
console.log(` ${bold('Step 7: Theses')}`);
|
|
505
570
|
blank();
|
|
506
571
|
ok(`Found ${activeTheses.length} active thesis(es):`);
|
|
507
572
|
for (const t of activeTheses.slice(0, 5)) {
|
|
@@ -542,7 +607,7 @@ async function handleThesisStep(config) {
|
|
|
542
607
|
return;
|
|
543
608
|
}
|
|
544
609
|
// No theses — offer to create one
|
|
545
|
-
console.log(` ${bold('Step
|
|
610
|
+
console.log(` ${bold('Step 7: Create Your First Thesis')}`);
|
|
546
611
|
blank();
|
|
547
612
|
info('A thesis is your core market conviction. The system builds a causal model');
|
|
548
613
|
info('from it, then continuously scans prediction markets for mispriced contracts.');
|
package/dist/config.d.ts
CHANGED
package/dist/config.js
CHANGED
|
@@ -50,6 +50,8 @@ function loadConfig() {
|
|
|
50
50
|
openrouterKey: process.env.OPENROUTER_API_KEY || file.openrouterKey,
|
|
51
51
|
kalshiKeyId: process.env.KALSHI_API_KEY_ID || file.kalshiKeyId,
|
|
52
52
|
kalshiPrivateKeyPath: process.env.KALSHI_PRIVATE_KEY_PATH || file.kalshiPrivateKeyPath,
|
|
53
|
+
polymarketWalletAddress: process.env.POLYMARKET_WALLET_ADDRESS || file.polymarketWalletAddress,
|
|
54
|
+
polymarketPrivateKeyPath: process.env.POLYMARKET_PRIVATE_KEY_PATH || file.polymarketPrivateKeyPath,
|
|
53
55
|
tavilyKey: process.env.TAVILY_API_KEY || file.tavilyKey,
|
|
54
56
|
model: process.env.SF_MODEL || file.model || DEFAULT_MODEL,
|
|
55
57
|
tradingEnabled: file.tradingEnabled || false,
|
|
@@ -101,6 +103,12 @@ function applyConfig() {
|
|
|
101
103
|
if (!process.env.KALSHI_PRIVATE_KEY_PATH && file.kalshiPrivateKeyPath) {
|
|
102
104
|
process.env.KALSHI_PRIVATE_KEY_PATH = file.kalshiPrivateKeyPath;
|
|
103
105
|
}
|
|
106
|
+
if (!process.env.POLYMARKET_WALLET_ADDRESS && file.polymarketWalletAddress) {
|
|
107
|
+
process.env.POLYMARKET_WALLET_ADDRESS = file.polymarketWalletAddress;
|
|
108
|
+
}
|
|
109
|
+
if (!process.env.POLYMARKET_PRIVATE_KEY_PATH && file.polymarketPrivateKeyPath) {
|
|
110
|
+
process.env.POLYMARKET_PRIVATE_KEY_PATH = file.polymarketPrivateKeyPath;
|
|
111
|
+
}
|
|
104
112
|
if (!process.env.TAVILY_API_KEY && file.tavilyKey) {
|
|
105
113
|
process.env.TAVILY_API_KEY = file.tavilyKey;
|
|
106
114
|
}
|
package/dist/index.js
CHANGED
|
@@ -52,18 +52,84 @@ const announcements_js_1 = require("./commands/announcements.js");
|
|
|
52
52
|
const history_js_1 = require("./commands/history.js");
|
|
53
53
|
const performance_js_1 = require("./commands/performance.js");
|
|
54
54
|
const liquidity_js_1 = require("./commands/liquidity.js");
|
|
55
|
+
const book_js_1 = require("./commands/book.js");
|
|
55
56
|
const telegram_js_1 = require("./commands/telegram.js");
|
|
56
57
|
const utils_js_1 = require("./utils.js");
|
|
57
58
|
// ── Apply ~/.sf/config.json to process.env BEFORE any command ────────────────
|
|
58
59
|
// This means client.ts, kalshi.ts, agent.ts keep reading process.env and just work.
|
|
59
60
|
(0, config_js_1.applyConfig)();
|
|
60
61
|
const program = new commander_1.Command();
|
|
62
|
+
const GROUPED_HELP = `
|
|
63
|
+
\x1b[1mSimpleFunctions CLI\x1b[22m — prediction market thesis agent
|
|
64
|
+
|
|
65
|
+
\x1b[1mUsage:\x1b[22m sf <command> [options]
|
|
66
|
+
sf <command> --help for detailed options
|
|
67
|
+
|
|
68
|
+
\x1b[1mSetup\x1b[22m
|
|
69
|
+
\x1b[36msetup\x1b[39m Interactive config wizard
|
|
70
|
+
\x1b[36msetup --check\x1b[39m Show config status
|
|
71
|
+
\x1b[36msetup --polymarket\x1b[39m Configure Polymarket wallet
|
|
72
|
+
|
|
73
|
+
\x1b[1mThesis\x1b[22m
|
|
74
|
+
\x1b[36mlist\x1b[39m List all theses
|
|
75
|
+
\x1b[36mget\x1b[39m <id> Full thesis details
|
|
76
|
+
\x1b[36mcontext\x1b[39m <id> [--json] Thesis snapshot \x1b[2m(primary for agents)\x1b[22m
|
|
77
|
+
\x1b[36mcreate\x1b[39m "thesis" Create a new thesis
|
|
78
|
+
\x1b[36msignal\x1b[39m <id> "content" Inject a signal
|
|
79
|
+
\x1b[36mevaluate\x1b[39m <id> Trigger deep evaluation
|
|
80
|
+
\x1b[36mpublish\x1b[39m / \x1b[36munpublish\x1b[39m <id> Manage public visibility
|
|
81
|
+
|
|
82
|
+
\x1b[1mMarkets\x1b[22m
|
|
83
|
+
\x1b[36mscan\x1b[39m "keywords" Search Kalshi + Polymarket
|
|
84
|
+
\x1b[36mscan\x1b[39m --series TICKER Browse a Kalshi series
|
|
85
|
+
\x1b[36medges\x1b[39m [--json] Top edges across all theses
|
|
86
|
+
\x1b[36mwhatif\x1b[39m <id> What-if scenario analysis
|
|
87
|
+
\x1b[36mliquidity\x1b[39m [topic] Orderbook liquidity scanner
|
|
88
|
+
\x1b[36mbook\x1b[39m <ticker> [ticker2...] Orderbook depth for specific markets
|
|
89
|
+
\x1b[36mexplore\x1b[39m [slug] Browse public theses
|
|
90
|
+
\x1b[36mforecast\x1b[39m <event> Market distribution (P50/P75/P90)
|
|
91
|
+
|
|
92
|
+
\x1b[1mPortfolio\x1b[22m
|
|
93
|
+
\x1b[36mpositions\x1b[39m Kalshi + Polymarket positions
|
|
94
|
+
\x1b[36mbalance\x1b[39m Account balance
|
|
95
|
+
\x1b[36morders\x1b[39m Resting orders
|
|
96
|
+
\x1b[36mfills\x1b[39m Recent trade fills
|
|
97
|
+
\x1b[36msettlements\x1b[39m Settled contracts with P&L
|
|
98
|
+
\x1b[36mperformance\x1b[39m P&L over time
|
|
99
|
+
\x1b[36mdashboard\x1b[39m Interactive TUI overview
|
|
100
|
+
|
|
101
|
+
\x1b[1mTrading\x1b[22m \x1b[2m(requires sf setup --enable-trading)\x1b[22m
|
|
102
|
+
\x1b[36mbuy\x1b[39m <ticker> <qty> Buy contracts
|
|
103
|
+
\x1b[36msell\x1b[39m <ticker> <qty> Sell contracts
|
|
104
|
+
\x1b[36mcancel\x1b[39m [orderId] Cancel order(s)
|
|
105
|
+
\x1b[36mrfq\x1b[39m <ticker> <qty> Request for quote
|
|
106
|
+
|
|
107
|
+
\x1b[1mInteractive\x1b[22m
|
|
108
|
+
\x1b[36magent\x1b[39m [id] Agent with natural language + tools
|
|
109
|
+
\x1b[36mtelegram\x1b[39m Telegram bot for monitoring
|
|
110
|
+
|
|
111
|
+
\x1b[1mInfo\x1b[22m
|
|
112
|
+
\x1b[36mfeed\x1b[39m Evaluation history stream
|
|
113
|
+
\x1b[36mmilestones\x1b[39m Upcoming Kalshi events
|
|
114
|
+
\x1b[36mschedule\x1b[39m Exchange status
|
|
115
|
+
\x1b[36mannouncements\x1b[39m Exchange announcements
|
|
116
|
+
\x1b[36mhistory\x1b[39m <ticker> Historical market data
|
|
117
|
+
`;
|
|
61
118
|
program
|
|
62
119
|
.name('sf')
|
|
63
120
|
.description('SimpleFunctions CLI — prediction market thesis agent')
|
|
64
121
|
.version('0.1.0')
|
|
65
122
|
.option('--api-key <key>', 'API key (or set SF_API_KEY env var)')
|
|
66
|
-
.option('--api-url <url>', 'API base URL (or set SF_API_URL env var)')
|
|
123
|
+
.option('--api-url <url>', 'API base URL (or set SF_API_URL env var)')
|
|
124
|
+
.configureHelp({
|
|
125
|
+
formatHelp: (cmd, helper) => {
|
|
126
|
+
// For subcommands, use default help
|
|
127
|
+
if (cmd.parent)
|
|
128
|
+
return helper.formatHelp(cmd, helper);
|
|
129
|
+
// For main program, show grouped help
|
|
130
|
+
return GROUPED_HELP;
|
|
131
|
+
},
|
|
132
|
+
});
|
|
67
133
|
// ── Pre-action guard: check configuration ────────────────────────────────────
|
|
68
134
|
const NO_CONFIG_COMMANDS = new Set(['setup', 'help', 'scan', 'explore', 'milestones', 'forecast', 'settlements', 'balance', 'orders', 'fills', 'schedule', 'announcements', 'history', 'liquidity']);
|
|
69
135
|
program.hook('preAction', (thisCommand, actionCommand) => {
|
|
@@ -91,16 +157,18 @@ program
|
|
|
91
157
|
.option('--enable-trading', 'Enable trading (sf buy/sell/cancel)')
|
|
92
158
|
.option('--disable-trading', 'Disable trading')
|
|
93
159
|
.option('--kalshi', 'Reconfigure Kalshi API credentials')
|
|
160
|
+
.option('--polymarket', 'Reconfigure Polymarket wallet address')
|
|
94
161
|
.action(async (opts) => {
|
|
95
|
-
await run(() => (0, setup_js_1.setupCommand)({ check: opts.check, reset: opts.reset, key: opts.key, enableTrading: opts.enableTrading, disableTrading: opts.disableTrading, kalshi: opts.kalshi }));
|
|
162
|
+
await run(() => (0, setup_js_1.setupCommand)({ check: opts.check, reset: opts.reset, key: opts.key, enableTrading: opts.enableTrading, disableTrading: opts.disableTrading, kalshi: opts.kalshi, polymarket: opts.polymarket }));
|
|
96
163
|
});
|
|
97
164
|
// ── sf list ──────────────────────────────────────────────────────────────────
|
|
98
165
|
program
|
|
99
166
|
.command('list')
|
|
100
167
|
.description('List all theses')
|
|
101
|
-
.
|
|
168
|
+
.option('--json', 'JSON output')
|
|
169
|
+
.action(async (opts, cmd) => {
|
|
102
170
|
const g = cmd.optsWithGlobals();
|
|
103
|
-
await run(() => (0, list_js_1.listCommand)({ apiKey: g.apiKey, apiUrl: g.apiUrl }));
|
|
171
|
+
await run(() => (0, list_js_1.listCommand)({ json: opts.json, apiKey: g.apiKey, apiUrl: g.apiUrl }));
|
|
104
172
|
});
|
|
105
173
|
// ── sf get <id> ───────────────────────────────────────────────────────────────
|
|
106
174
|
program
|
|
@@ -125,9 +193,10 @@ program
|
|
|
125
193
|
.command('create <thesis>')
|
|
126
194
|
.description('Create a new thesis (sync by default — waits for formation)')
|
|
127
195
|
.option('--async', 'Async mode — return immediately without waiting')
|
|
196
|
+
.option('--json', 'JSON output')
|
|
128
197
|
.action(async (thesis, opts, cmd) => {
|
|
129
198
|
const g = cmd.optsWithGlobals();
|
|
130
|
-
await run(() => (0, create_js_1.createCommand)(thesis, { async: opts.async, apiKey: g.apiKey, apiUrl: g.apiUrl }));
|
|
199
|
+
await run(() => (0, create_js_1.createCommand)(thesis, { async: opts.async, json: opts.json, apiKey: g.apiKey, apiUrl: g.apiUrl }));
|
|
131
200
|
});
|
|
132
201
|
// ── sf signal <id> <content> ──────────────────────────────────────────────────
|
|
133
202
|
program
|
|
@@ -149,9 +218,10 @@ program
|
|
|
149
218
|
// ── sf scan [query] ───────────────────────────────────────────────────────────
|
|
150
219
|
program
|
|
151
220
|
.command('scan [query]')
|
|
152
|
-
.description('Explore Kalshi
|
|
221
|
+
.description('Explore Kalshi + Polymarket markets')
|
|
153
222
|
.option('--series <ticker>', 'List events + markets for a series (e.g. KXWTIMAX)')
|
|
154
223
|
.option('--market <ticker>', 'Get single market detail (e.g. KXWTIMAX-26DEC31-T140)')
|
|
224
|
+
.option('--venue <venue>', 'Filter by venue: kalshi, polymarket, or all (default: all)')
|
|
155
225
|
.option('--json', 'Output raw JSON')
|
|
156
226
|
.action(async (query, opts, cmd) => {
|
|
157
227
|
const g = cmd.optsWithGlobals();
|
|
@@ -163,6 +233,7 @@ program
|
|
|
163
233
|
await run(() => (0, scan_js_1.scanCommand)(q, {
|
|
164
234
|
series: opts.series,
|
|
165
235
|
market: opts.market,
|
|
236
|
+
venue: opts.venue,
|
|
166
237
|
json: opts.json,
|
|
167
238
|
apiKey: g.apiKey,
|
|
168
239
|
apiUrl: g.apiUrl,
|
|
@@ -402,14 +473,29 @@ program
|
|
|
402
473
|
});
|
|
403
474
|
// ── sf liquidity ─────────────────────────────────────────────────────────────
|
|
404
475
|
program
|
|
405
|
-
.command('liquidity')
|
|
406
|
-
.description('Market liquidity scanner
|
|
407
|
-
.option('--
|
|
476
|
+
.command('liquidity [topic]')
|
|
477
|
+
.description('Market liquidity scanner — run without args to see topics')
|
|
478
|
+
.option('--all', 'Scan all topics')
|
|
479
|
+
.option('--venue <venue>', 'Filter venue: kalshi, polymarket, all (default: all)')
|
|
408
480
|
.option('--horizon <horizon>', 'Filter horizon (weekly, monthly, long-term)')
|
|
409
481
|
.option('--min-depth <depth>', 'Minimum bid+ask depth', parseInt)
|
|
410
482
|
.option('--json', 'JSON output')
|
|
411
|
-
.action(async (opts) => {
|
|
412
|
-
await run(() => (0, liquidity_js_1.liquidityCommand)(opts));
|
|
483
|
+
.action(async (topic, opts) => {
|
|
484
|
+
await run(() => (0, liquidity_js_1.liquidityCommand)({ ...opts, topic }));
|
|
485
|
+
});
|
|
486
|
+
// ── sf book ──────────────────────────────────────────────────────────────────
|
|
487
|
+
program
|
|
488
|
+
.command('book [tickers...]')
|
|
489
|
+
.description('Orderbook depth, spread, and liquidity for specific markets')
|
|
490
|
+
.option('--poly <query>', 'Search Polymarket markets by keyword')
|
|
491
|
+
.option('--history', 'Include 7-day price history sparkline')
|
|
492
|
+
.option('--json', 'JSON output')
|
|
493
|
+
.action(async (tickers, opts) => {
|
|
494
|
+
if (tickers.length === 0 && !opts.poly) {
|
|
495
|
+
console.error('Usage: sf book <ticker> [ticker2...] OR sf book --poly "oil price"');
|
|
496
|
+
process.exit(1);
|
|
497
|
+
}
|
|
498
|
+
await run(() => (0, book_js_1.bookCommand)(tickers, opts));
|
|
413
499
|
});
|
|
414
500
|
// ── sf telegram ──────────────────────────────────────────────────────────────
|
|
415
501
|
program
|