@spfunctions/cli 1.2.1 → 1.4.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/dist/commands/agent.js +365 -0
- package/dist/commands/dashboard.js +3 -14
- package/dist/commands/liquidity.d.ts +12 -0
- package/dist/commands/liquidity.js +293 -0
- package/dist/commands/performance.d.ts +8 -0
- package/dist/commands/performance.js +261 -0
- package/dist/commands/setup.js +123 -123
- package/dist/index.js +26 -3
- package/dist/kalshi.d.ts +18 -0
- package/dist/kalshi.js +43 -0
- package/dist/topics.d.ts +14 -0
- package/dist/topics.js +44 -0
- package/package.json +2 -2
package/dist/commands/agent.js
CHANGED
|
@@ -1007,6 +1007,73 @@ async function agentCommand(thesisId, opts) {
|
|
|
1007
1007
|
}
|
|
1008
1008
|
},
|
|
1009
1009
|
},
|
|
1010
|
+
{
|
|
1011
|
+
name: 'create_thesis',
|
|
1012
|
+
label: 'Create Thesis',
|
|
1013
|
+
description: 'Create a new thesis from a raw thesis statement. Returns the thesis ID, confidence, node count, and edge count.',
|
|
1014
|
+
parameters: Type.Object({
|
|
1015
|
+
rawThesis: Type.String({ description: 'The raw thesis statement to create' }),
|
|
1016
|
+
webhookUrl: Type.Optional(Type.String({ description: 'Optional webhook URL for notifications' })),
|
|
1017
|
+
}),
|
|
1018
|
+
execute: async (_toolCallId, params) => {
|
|
1019
|
+
const result = await sfClient.createThesis(params.rawThesis, true);
|
|
1020
|
+
const thesis = result.thesis || result;
|
|
1021
|
+
const nodeCount = thesis.causalTree?.nodes?.length || 0;
|
|
1022
|
+
const edgeCount = (thesis.edges || []).length;
|
|
1023
|
+
const confidence = typeof thesis.confidence === 'number' ? Math.round(thesis.confidence * 100) : 0;
|
|
1024
|
+
return {
|
|
1025
|
+
content: [{ type: 'text', text: `Thesis created.\nID: ${thesis.id}\nConfidence: ${confidence}%\nNodes: ${nodeCount}\nEdges: ${edgeCount}` }],
|
|
1026
|
+
details: {},
|
|
1027
|
+
};
|
|
1028
|
+
},
|
|
1029
|
+
},
|
|
1030
|
+
{
|
|
1031
|
+
name: 'get_edges',
|
|
1032
|
+
label: 'Get Edges',
|
|
1033
|
+
description: 'Get top edges across all active theses. Returns the top 10 edges sorted by absolute edge size with ticker, market name, edge size, direction, and venue.',
|
|
1034
|
+
parameters: emptyParams,
|
|
1035
|
+
execute: async () => {
|
|
1036
|
+
const { theses } = await sfClient.listTheses();
|
|
1037
|
+
const activeTheses = (theses || []).filter((t) => t.status === 'active' || t.status === 'monitoring');
|
|
1038
|
+
const allEdges = [];
|
|
1039
|
+
for (const t of activeTheses) {
|
|
1040
|
+
try {
|
|
1041
|
+
const ctx = await sfClient.getContext(t.id);
|
|
1042
|
+
for (const edge of (ctx.edges || [])) {
|
|
1043
|
+
allEdges.push({ ...edge, thesisId: t.id });
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
catch { /* skip inaccessible theses */ }
|
|
1047
|
+
}
|
|
1048
|
+
allEdges.sort((a, b) => Math.abs(b.edge || b.edgeSize || 0) - Math.abs(a.edge || a.edgeSize || 0));
|
|
1049
|
+
const top10 = allEdges.slice(0, 10).map((e) => ({
|
|
1050
|
+
ticker: e.marketId || e.ticker || '-',
|
|
1051
|
+
market: e.market || e.marketTitle || '-',
|
|
1052
|
+
edge: e.edge || e.edgeSize || 0,
|
|
1053
|
+
direction: e.direction || 'yes',
|
|
1054
|
+
venue: e.venue || 'kalshi',
|
|
1055
|
+
}));
|
|
1056
|
+
return {
|
|
1057
|
+
content: [{ type: 'text', text: JSON.stringify(top10, null, 2) }],
|
|
1058
|
+
details: {},
|
|
1059
|
+
};
|
|
1060
|
+
},
|
|
1061
|
+
},
|
|
1062
|
+
{
|
|
1063
|
+
name: 'get_feed',
|
|
1064
|
+
label: 'Get Feed',
|
|
1065
|
+
description: 'Get evaluation history / activity feed. Shows recent evaluations, signals, and changes across theses.',
|
|
1066
|
+
parameters: Type.Object({
|
|
1067
|
+
hours: Type.Optional(Type.Number({ description: 'Hours of history to fetch (default 24)' })),
|
|
1068
|
+
}),
|
|
1069
|
+
execute: async (_toolCallId, params) => {
|
|
1070
|
+
const result = await sfClient.getFeed(params.hours || 24);
|
|
1071
|
+
return {
|
|
1072
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
1073
|
+
details: {},
|
|
1074
|
+
};
|
|
1075
|
+
},
|
|
1076
|
+
},
|
|
1010
1077
|
];
|
|
1011
1078
|
// ── What-if tool (always available) ────────────────────────────────────────
|
|
1012
1079
|
tools.push({
|
|
@@ -2303,7 +2370,305 @@ async function runPlainTextAgent(params) {
|
|
|
2303
2370
|
}
|
|
2304
2371
|
},
|
|
2305
2372
|
},
|
|
2373
|
+
{
|
|
2374
|
+
name: 'create_thesis',
|
|
2375
|
+
label: 'Create Thesis',
|
|
2376
|
+
description: 'Create a new thesis from a raw thesis statement. Returns the thesis ID, confidence, node count, and edge count.',
|
|
2377
|
+
parameters: Type.Object({
|
|
2378
|
+
rawThesis: Type.String({ description: 'The raw thesis statement to create' }),
|
|
2379
|
+
webhookUrl: Type.Optional(Type.String({ description: 'Optional webhook URL for notifications' })),
|
|
2380
|
+
}),
|
|
2381
|
+
execute: async (_id, p) => {
|
|
2382
|
+
const result = await sfClient.createThesis(p.rawThesis, true);
|
|
2383
|
+
const thesis = result.thesis || result;
|
|
2384
|
+
const nodeCount = thesis.causalTree?.nodes?.length || 0;
|
|
2385
|
+
const edgeCount = (thesis.edges || []).length;
|
|
2386
|
+
const confidence = typeof thesis.confidence === 'number' ? Math.round(thesis.confidence * 100) : 0;
|
|
2387
|
+
return {
|
|
2388
|
+
content: [{ type: 'text', text: `Thesis created.\nID: ${thesis.id}\nConfidence: ${confidence}%\nNodes: ${nodeCount}\nEdges: ${edgeCount}` }],
|
|
2389
|
+
details: {},
|
|
2390
|
+
};
|
|
2391
|
+
},
|
|
2392
|
+
},
|
|
2393
|
+
{
|
|
2394
|
+
name: 'get_edges',
|
|
2395
|
+
label: 'Get Edges',
|
|
2396
|
+
description: 'Get top edges across all active theses. Returns the top 10 edges sorted by absolute edge size with ticker, market name, edge size, direction, and venue.',
|
|
2397
|
+
parameters: emptyParams,
|
|
2398
|
+
execute: async () => {
|
|
2399
|
+
const { theses } = await sfClient.listTheses();
|
|
2400
|
+
const activeTheses = (theses || []).filter((t) => t.status === 'active' || t.status === 'monitoring');
|
|
2401
|
+
const allEdges = [];
|
|
2402
|
+
for (const t of activeTheses) {
|
|
2403
|
+
try {
|
|
2404
|
+
const ctx = await sfClient.getContext(t.id);
|
|
2405
|
+
for (const edge of (ctx.edges || [])) {
|
|
2406
|
+
allEdges.push({ ...edge, thesisId: t.id });
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2409
|
+
catch { /* skip inaccessible theses */ }
|
|
2410
|
+
}
|
|
2411
|
+
allEdges.sort((a, b) => Math.abs(b.edge || b.edgeSize || 0) - Math.abs(a.edge || a.edgeSize || 0));
|
|
2412
|
+
const top10 = allEdges.slice(0, 10).map((e) => ({
|
|
2413
|
+
ticker: e.marketId || e.ticker || '-',
|
|
2414
|
+
market: e.market || e.marketTitle || '-',
|
|
2415
|
+
edge: e.edge || e.edgeSize || 0,
|
|
2416
|
+
direction: e.direction || 'yes',
|
|
2417
|
+
venue: e.venue || 'kalshi',
|
|
2418
|
+
}));
|
|
2419
|
+
return {
|
|
2420
|
+
content: [{ type: 'text', text: JSON.stringify(top10, null, 2) }],
|
|
2421
|
+
details: {},
|
|
2422
|
+
};
|
|
2423
|
+
},
|
|
2424
|
+
},
|
|
2425
|
+
{
|
|
2426
|
+
name: 'get_feed',
|
|
2427
|
+
label: 'Get Feed',
|
|
2428
|
+
description: 'Get evaluation history / activity feed. Shows recent evaluations, signals, and changes across theses.',
|
|
2429
|
+
parameters: Type.Object({
|
|
2430
|
+
hours: Type.Optional(Type.Number({ description: 'Hours of history to fetch (default 24)' })),
|
|
2431
|
+
}),
|
|
2432
|
+
execute: async (_id, p) => {
|
|
2433
|
+
const result = await sfClient.getFeed(p.hours || 24);
|
|
2434
|
+
return {
|
|
2435
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
2436
|
+
details: {},
|
|
2437
|
+
};
|
|
2438
|
+
},
|
|
2439
|
+
},
|
|
2440
|
+
{
|
|
2441
|
+
name: 'explore_public',
|
|
2442
|
+
label: 'Explore Public Theses',
|
|
2443
|
+
description: 'Browse public theses from other users. No auth required. Pass a slug to get details, or omit to list all.',
|
|
2444
|
+
parameters: Type.Object({
|
|
2445
|
+
slug: Type.Optional(Type.String({ description: 'Specific thesis slug, or empty to list all' })),
|
|
2446
|
+
}),
|
|
2447
|
+
execute: async (_id, p) => {
|
|
2448
|
+
const base = 'https://simplefunctions.dev';
|
|
2449
|
+
if (p.slug) {
|
|
2450
|
+
const res = await fetch(`${base}/api/public/thesis/${p.slug}`);
|
|
2451
|
+
if (!res.ok)
|
|
2452
|
+
return { content: [{ type: 'text', text: `Not found: ${p.slug}` }], details: {} };
|
|
2453
|
+
const data = await res.json();
|
|
2454
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }], details: {} };
|
|
2455
|
+
}
|
|
2456
|
+
const res = await fetch(`${base}/api/public/theses`);
|
|
2457
|
+
if (!res.ok)
|
|
2458
|
+
return { content: [{ type: 'text', text: 'Failed to fetch public theses' }], details: {} };
|
|
2459
|
+
const data = await res.json();
|
|
2460
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }], details: {} };
|
|
2461
|
+
},
|
|
2462
|
+
},
|
|
2463
|
+
{
|
|
2464
|
+
name: 'create_strategy',
|
|
2465
|
+
label: 'Create Strategy',
|
|
2466
|
+
description: 'Create a trading strategy for a thesis. Extract hard conditions (entryBelow/stopLoss/takeProfit as cents) and soft conditions from conversation. Called when user mentions specific trade ideas.',
|
|
2467
|
+
parameters: Type.Object({
|
|
2468
|
+
thesisId: Type.String({ description: 'Thesis ID' }),
|
|
2469
|
+
marketId: Type.String({ description: 'Market ticker e.g. KXWTIMAX-26DEC31-T150' }),
|
|
2470
|
+
market: Type.String({ description: 'Human-readable market name' }),
|
|
2471
|
+
direction: Type.String({ description: 'yes or no' }),
|
|
2472
|
+
horizon: Type.Optional(Type.String({ description: 'short, medium, or long. Default: medium' })),
|
|
2473
|
+
entryBelow: Type.Optional(Type.Number({ description: 'Entry trigger: ask <= this value (cents)' })),
|
|
2474
|
+
entryAbove: Type.Optional(Type.Number({ description: 'Entry trigger: ask >= this value (cents, for NO direction)' })),
|
|
2475
|
+
stopLoss: Type.Optional(Type.Number({ description: 'Stop loss: bid <= this value (cents)' })),
|
|
2476
|
+
takeProfit: Type.Optional(Type.Number({ description: 'Take profit: bid >= this value (cents)' })),
|
|
2477
|
+
maxQuantity: Type.Optional(Type.Number({ description: 'Max total contracts. Default: 500' })),
|
|
2478
|
+
perOrderQuantity: Type.Optional(Type.Number({ description: 'Contracts per order. Default: 50' })),
|
|
2479
|
+
softConditions: Type.Optional(Type.String({ description: 'LLM-evaluated conditions e.g. "only enter when n3 > 60%"' })),
|
|
2480
|
+
rationale: Type.Optional(Type.String({ description: 'Full logic description' })),
|
|
2481
|
+
}),
|
|
2482
|
+
execute: async (_id, p) => {
|
|
2483
|
+
const result = await sfClient.createStrategyAPI(p.thesisId, {
|
|
2484
|
+
marketId: p.marketId,
|
|
2485
|
+
market: p.market,
|
|
2486
|
+
direction: p.direction,
|
|
2487
|
+
horizon: p.horizon,
|
|
2488
|
+
entryBelow: p.entryBelow,
|
|
2489
|
+
entryAbove: p.entryAbove,
|
|
2490
|
+
stopLoss: p.stopLoss,
|
|
2491
|
+
takeProfit: p.takeProfit,
|
|
2492
|
+
maxQuantity: p.maxQuantity,
|
|
2493
|
+
perOrderQuantity: p.perOrderQuantity,
|
|
2494
|
+
softConditions: p.softConditions,
|
|
2495
|
+
rationale: p.rationale,
|
|
2496
|
+
createdBy: 'agent',
|
|
2497
|
+
});
|
|
2498
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }], details: {} };
|
|
2499
|
+
},
|
|
2500
|
+
},
|
|
2501
|
+
{
|
|
2502
|
+
name: 'list_strategies',
|
|
2503
|
+
label: 'List Strategies',
|
|
2504
|
+
description: 'List strategies for a thesis. Filter by status (active/watching/executed/cancelled/review) or omit for all.',
|
|
2505
|
+
parameters: Type.Object({
|
|
2506
|
+
thesisId: Type.String({ description: 'Thesis ID' }),
|
|
2507
|
+
status: Type.Optional(Type.String({ description: 'Filter by status. Omit for all.' })),
|
|
2508
|
+
}),
|
|
2509
|
+
execute: async (_id, p) => {
|
|
2510
|
+
const result = await sfClient.getStrategies(p.thesisId, p.status);
|
|
2511
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], details: {} };
|
|
2512
|
+
},
|
|
2513
|
+
},
|
|
2514
|
+
{
|
|
2515
|
+
name: 'update_strategy',
|
|
2516
|
+
label: 'Update Strategy',
|
|
2517
|
+
description: 'Update a strategy (change stop loss, take profit, status, priority, etc.)',
|
|
2518
|
+
parameters: Type.Object({
|
|
2519
|
+
thesisId: Type.String({ description: 'Thesis ID' }),
|
|
2520
|
+
strategyId: Type.String({ description: 'Strategy ID (UUID)' }),
|
|
2521
|
+
stopLoss: Type.Optional(Type.Number({ description: 'New stop loss (cents)' })),
|
|
2522
|
+
takeProfit: Type.Optional(Type.Number({ description: 'New take profit (cents)' })),
|
|
2523
|
+
entryBelow: Type.Optional(Type.Number({ description: 'New entry below trigger (cents)' })),
|
|
2524
|
+
entryAbove: Type.Optional(Type.Number({ description: 'New entry above trigger (cents)' })),
|
|
2525
|
+
status: Type.Optional(Type.String({ description: 'New status: active|watching|executed|cancelled|review' })),
|
|
2526
|
+
priority: Type.Optional(Type.Number({ description: 'New priority' })),
|
|
2527
|
+
softConditions: Type.Optional(Type.String({ description: 'Updated soft conditions' })),
|
|
2528
|
+
rationale: Type.Optional(Type.String({ description: 'Updated rationale' })),
|
|
2529
|
+
}),
|
|
2530
|
+
execute: async (_id, p) => {
|
|
2531
|
+
const { thesisId, strategyId, ...updates } = p;
|
|
2532
|
+
const result = await sfClient.updateStrategyAPI(thesisId, strategyId, updates);
|
|
2533
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }], details: {} };
|
|
2534
|
+
},
|
|
2535
|
+
},
|
|
2536
|
+
{
|
|
2537
|
+
name: 'what_if',
|
|
2538
|
+
label: 'What-If',
|
|
2539
|
+
description: 'Run a what-if scenario: override causal tree node probabilities and see how edges and confidence change. Zero LLM cost — pure computation.',
|
|
2540
|
+
parameters: Type.Object({
|
|
2541
|
+
overrides: Type.Array(Type.Object({
|
|
2542
|
+
nodeId: Type.String({ description: 'Causal tree node ID (e.g. n1, n3.1)' }),
|
|
2543
|
+
newProbability: Type.Number({ description: 'New probability 0-1' }),
|
|
2544
|
+
}), { description: 'Node probability overrides' }),
|
|
2545
|
+
}),
|
|
2546
|
+
execute: async (_id, p) => {
|
|
2547
|
+
const ctx = latestContext;
|
|
2548
|
+
const allNodes = [];
|
|
2549
|
+
function flatten(nodes) {
|
|
2550
|
+
for (const n of nodes) {
|
|
2551
|
+
allNodes.push(n);
|
|
2552
|
+
if (n.children?.length)
|
|
2553
|
+
flatten(n.children);
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
const rawNodes = ctx.causalTree?.nodes || [];
|
|
2557
|
+
flatten(rawNodes);
|
|
2558
|
+
const treeNodes = rawNodes.filter((n) => n.depth === 0 || (n.depth === undefined && !n.id.includes('.')));
|
|
2559
|
+
const overrideMap = new Map(p.overrides.map((o) => [o.nodeId, o.newProbability]));
|
|
2560
|
+
const oldConf = treeNodes.reduce((s, n) => s + (n.probability || 0) * (n.importance || 0), 0);
|
|
2561
|
+
const newConf = treeNodes.reduce((s, n) => {
|
|
2562
|
+
const prob = overrideMap.get(n.id) ?? n.probability ?? 0;
|
|
2563
|
+
return s + prob * (n.importance || 0);
|
|
2564
|
+
}, 0);
|
|
2565
|
+
const nodeScales = new Map();
|
|
2566
|
+
for (const [nid, np] of overrideMap.entries()) {
|
|
2567
|
+
const nd = allNodes.find((n) => n.id === nid);
|
|
2568
|
+
if (nd && nd.probability > 0)
|
|
2569
|
+
nodeScales.set(nid, Math.max(0, Math.min(2, np / nd.probability)));
|
|
2570
|
+
}
|
|
2571
|
+
const edges = (ctx.edges || []).map((edge) => {
|
|
2572
|
+
const relNode = edge.relatedNodeId;
|
|
2573
|
+
let scaleFactor = 1;
|
|
2574
|
+
if (relNode) {
|
|
2575
|
+
const candidates = [relNode, relNode.split('.').slice(0, -1).join('.'), relNode.split('.')[0]].filter(Boolean);
|
|
2576
|
+
for (const cid of candidates) {
|
|
2577
|
+
if (nodeScales.has(cid)) {
|
|
2578
|
+
scaleFactor = nodeScales.get(cid);
|
|
2579
|
+
break;
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2583
|
+
const mkt = edge.marketPrice || 0;
|
|
2584
|
+
const oldTP = edge.thesisPrice || edge.thesisImpliedPrice || mkt;
|
|
2585
|
+
const oldEdge = edge.edge || edge.edgeSize || 0;
|
|
2586
|
+
const newTP = Math.round((mkt + (oldTP - mkt) * scaleFactor) * 100) / 100;
|
|
2587
|
+
const dir = edge.direction || 'yes';
|
|
2588
|
+
const newEdge = Math.round((dir === 'yes' ? newTP - mkt : mkt - newTP) * 100) / 100;
|
|
2589
|
+
return {
|
|
2590
|
+
market: edge.market || edge.marketTitle || edge.marketId,
|
|
2591
|
+
marketPrice: mkt,
|
|
2592
|
+
oldEdge,
|
|
2593
|
+
newEdge,
|
|
2594
|
+
delta: newEdge - oldEdge,
|
|
2595
|
+
signal: Math.abs(newEdge - oldEdge) < 1 ? 'unchanged' : (oldEdge > 0 && newEdge < 0) || (oldEdge < 0 && newEdge > 0) ? 'REVERSED' : Math.abs(newEdge) < 2 ? 'GONE' : 'reduced',
|
|
2596
|
+
};
|
|
2597
|
+
}).filter((e) => e.signal !== 'unchanged');
|
|
2598
|
+
const result = {
|
|
2599
|
+
overrides: p.overrides.map((o) => {
|
|
2600
|
+
const node = allNodes.find((n) => n.id === o.nodeId);
|
|
2601
|
+
return { nodeId: o.nodeId, label: node?.label || o.nodeId, oldProb: node?.probability, newProb: o.newProbability };
|
|
2602
|
+
}),
|
|
2603
|
+
confidence: { old: Math.round(oldConf * 100), new: Math.round(newConf * 100), delta: Math.round((newConf - oldConf) * 100) },
|
|
2604
|
+
affectedEdges: edges,
|
|
2605
|
+
};
|
|
2606
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], details: {} };
|
|
2607
|
+
},
|
|
2608
|
+
},
|
|
2306
2609
|
];
|
|
2610
|
+
// ── Trading tools (conditional on tradingEnabled) for plain mode ──────────
|
|
2611
|
+
const config = (0, config_js_1.loadConfig)();
|
|
2612
|
+
if (config.tradingEnabled) {
|
|
2613
|
+
tools.push({
|
|
2614
|
+
name: 'place_order',
|
|
2615
|
+
label: 'Place Order',
|
|
2616
|
+
description: 'Place a buy or sell order on Kalshi. Executes directly (no confirmation prompt in plain mode).',
|
|
2617
|
+
parameters: Type.Object({
|
|
2618
|
+
ticker: Type.String({ description: 'Market ticker e.g. KXWTIMAX-26DEC31-T135' }),
|
|
2619
|
+
side: Type.String({ description: 'yes or no' }),
|
|
2620
|
+
action: Type.String({ description: 'buy or sell' }),
|
|
2621
|
+
type: Type.String({ description: 'limit or market' }),
|
|
2622
|
+
count: Type.Number({ description: 'Number of contracts' }),
|
|
2623
|
+
price_cents: Type.Optional(Type.Number({ description: 'Limit price in cents (1-99). Required for limit orders.' })),
|
|
2624
|
+
}),
|
|
2625
|
+
execute: async (_id, p) => {
|
|
2626
|
+
const { createOrder } = await import('../kalshi.js');
|
|
2627
|
+
const priceCents = p.price_cents ? Math.round(Number(p.price_cents)) : undefined;
|
|
2628
|
+
const maxCost = ((priceCents || 99) * p.count / 100).toFixed(2);
|
|
2629
|
+
process.stderr.write(` Order: ${p.action.toUpperCase()} ${p.count}x ${p.ticker} ${p.side.toUpperCase()} @ ${priceCents ? priceCents + '\u00A2' : 'market'} (max $${maxCost})\n`);
|
|
2630
|
+
try {
|
|
2631
|
+
const result = await createOrder({
|
|
2632
|
+
ticker: p.ticker,
|
|
2633
|
+
side: p.side,
|
|
2634
|
+
action: p.action,
|
|
2635
|
+
type: p.type,
|
|
2636
|
+
count: p.count,
|
|
2637
|
+
...(priceCents ? { yes_price: priceCents } : {}),
|
|
2638
|
+
});
|
|
2639
|
+
const order = result.order || result;
|
|
2640
|
+
return {
|
|
2641
|
+
content: [{ type: 'text', text: `Order placed: ${order.order_id || 'OK'}\nStatus: ${order.status || '-'}\nFilled: ${order.fill_count_fp || 0}/${order.initial_count_fp || p.count}` }],
|
|
2642
|
+
details: {},
|
|
2643
|
+
};
|
|
2644
|
+
}
|
|
2645
|
+
catch (err) {
|
|
2646
|
+
const msg = err.message || String(err);
|
|
2647
|
+
if (msg.includes('403')) {
|
|
2648
|
+
return { content: [{ type: 'text', text: '403 Forbidden \u2014 your Kalshi key lacks write permission. Get a read+write key at kalshi.com/account/api-keys' }], details: {} };
|
|
2649
|
+
}
|
|
2650
|
+
return { content: [{ type: 'text', text: `Order failed: ${msg}` }], details: {} };
|
|
2651
|
+
}
|
|
2652
|
+
},
|
|
2653
|
+
}, {
|
|
2654
|
+
name: 'cancel_order',
|
|
2655
|
+
label: 'Cancel Order',
|
|
2656
|
+
description: 'Cancel a resting order by order ID. Executes directly (no confirmation prompt in plain mode).',
|
|
2657
|
+
parameters: Type.Object({
|
|
2658
|
+
order_id: Type.String({ description: 'Order ID to cancel' }),
|
|
2659
|
+
}),
|
|
2660
|
+
execute: async (_id, p) => {
|
|
2661
|
+
const { cancelOrder } = await import('../kalshi.js');
|
|
2662
|
+
try {
|
|
2663
|
+
await cancelOrder(p.order_id);
|
|
2664
|
+
return { content: [{ type: 'text', text: `Order ${p.order_id} cancelled.` }], details: {} };
|
|
2665
|
+
}
|
|
2666
|
+
catch (err) {
|
|
2667
|
+
return { content: [{ type: 'text', text: `Cancel failed: ${err.message}` }], details: {} };
|
|
2668
|
+
}
|
|
2669
|
+
},
|
|
2670
|
+
});
|
|
2671
|
+
}
|
|
2307
2672
|
// ── System prompt ─────────────────────────────────────────────────────────
|
|
2308
2673
|
const ctx = latestContext;
|
|
2309
2674
|
const edgesSummary = ctx.edges
|
|
@@ -9,24 +9,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
9
9
|
exports.dashboardCommand = dashboardCommand;
|
|
10
10
|
const client_js_1 = require("../client.js");
|
|
11
11
|
const kalshi_js_1 = require("../kalshi.js");
|
|
12
|
-
|
|
13
|
-
const RISK_CATEGORIES = {
|
|
14
|
-
KXWTIMAX: 'Oil',
|
|
15
|
-
KXWTI: 'Oil',
|
|
16
|
-
KXRECSSNBER: 'Recession',
|
|
17
|
-
KXAAAGASM: 'Gas',
|
|
18
|
-
KXCPI: 'Inflation',
|
|
19
|
-
KXINXY: 'S&P 500',
|
|
20
|
-
KXFEDDECISION: 'Fed Rate',
|
|
21
|
-
KXUNEMPLOYMENT: 'Unemployment',
|
|
22
|
-
KXCLOSEHORMUZ: 'Hormuz',
|
|
23
|
-
};
|
|
12
|
+
const topics_js_1 = require("../topics.js");
|
|
24
13
|
function categorize(ticker) {
|
|
25
14
|
// Match longest prefix first
|
|
26
|
-
const sorted = Object.keys(RISK_CATEGORIES).sort((a, b) => b.length - a.length);
|
|
15
|
+
const sorted = Object.keys(topics_js_1.RISK_CATEGORIES).sort((a, b) => b.length - a.length);
|
|
27
16
|
for (const prefix of sorted) {
|
|
28
17
|
if (ticker.startsWith(prefix))
|
|
29
|
-
return RISK_CATEGORIES[prefix];
|
|
18
|
+
return topics_js_1.RISK_CATEGORIES[prefix];
|
|
30
19
|
}
|
|
31
20
|
return 'Other';
|
|
32
21
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sf liquidity — Market liquidity scanner by topic and horizon
|
|
3
|
+
*
|
|
4
|
+
* Scans known series, fetches public orderbooks, and displays
|
|
5
|
+
* spread/depth/slippage data grouped by topic and horizon.
|
|
6
|
+
*/
|
|
7
|
+
export declare function liquidityCommand(opts: {
|
|
8
|
+
topic?: string;
|
|
9
|
+
horizon?: string;
|
|
10
|
+
minDepth?: number;
|
|
11
|
+
json?: boolean;
|
|
12
|
+
}): Promise<void>;
|