@spfunctions/cli 1.4.4 → 1.5.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.
Files changed (86) hide show
  1. package/README.md +205 -48
  2. package/dist/cache.d.ts +6 -0
  3. package/dist/cache.js +31 -0
  4. package/dist/cache.test.d.ts +1 -0
  5. package/dist/cache.test.js +73 -0
  6. package/dist/client.test.d.ts +1 -0
  7. package/dist/client.test.js +89 -0
  8. package/dist/commands/agent.js +594 -106
  9. package/dist/commands/book.d.ts +17 -0
  10. package/dist/commands/book.js +220 -0
  11. package/dist/commands/dashboard.d.ts +6 -3
  12. package/dist/commands/dashboard.js +53 -22
  13. package/dist/commands/liquidity.d.ts +2 -0
  14. package/dist/commands/liquidity.js +128 -43
  15. package/dist/commands/performance.js +9 -2
  16. package/dist/commands/positions.js +50 -0
  17. package/dist/commands/scan.d.ts +1 -0
  18. package/dist/commands/scan.js +66 -15
  19. package/dist/commands/setup.d.ts +1 -0
  20. package/dist/commands/setup.js +71 -6
  21. package/dist/commands/telegram.d.ts +15 -0
  22. package/dist/commands/telegram.js +125 -0
  23. package/dist/config.d.ts +3 -0
  24. package/dist/config.js +9 -0
  25. package/dist/config.test.d.ts +1 -0
  26. package/dist/config.test.js +138 -0
  27. package/dist/index.js +107 -9
  28. package/dist/polymarket.d.ts +237 -0
  29. package/dist/polymarket.js +353 -0
  30. package/dist/polymarket.test.d.ts +1 -0
  31. package/dist/polymarket.test.js +424 -0
  32. package/dist/telegram/agent-bridge.d.ts +15 -0
  33. package/dist/telegram/agent-bridge.js +368 -0
  34. package/dist/telegram/bot.d.ts +10 -0
  35. package/dist/telegram/bot.js +297 -0
  36. package/dist/telegram/commands.d.ts +11 -0
  37. package/dist/telegram/commands.js +120 -0
  38. package/dist/telegram/format.d.ts +11 -0
  39. package/dist/telegram/format.js +51 -0
  40. package/dist/telegram/format.test.d.ts +1 -0
  41. package/dist/telegram/format.test.js +73 -0
  42. package/dist/telegram/poller.d.ts +6 -0
  43. package/dist/telegram/poller.js +32 -0
  44. package/dist/topics.d.ts +3 -0
  45. package/dist/topics.js +65 -7
  46. package/dist/topics.test.d.ts +1 -0
  47. package/dist/topics.test.js +131 -0
  48. package/dist/tui/border.d.ts +33 -0
  49. package/dist/tui/border.js +87 -0
  50. package/dist/tui/chart.d.ts +19 -0
  51. package/dist/tui/chart.js +117 -0
  52. package/dist/tui/dashboard.d.ts +9 -0
  53. package/dist/tui/dashboard.js +814 -0
  54. package/dist/tui/layout.d.ts +16 -0
  55. package/dist/tui/layout.js +41 -0
  56. package/dist/tui/screen.d.ts +33 -0
  57. package/dist/tui/screen.js +102 -0
  58. package/dist/tui/state.d.ts +40 -0
  59. package/dist/tui/state.js +36 -0
  60. package/dist/tui/widgets/commandbar.d.ts +8 -0
  61. package/dist/tui/widgets/commandbar.js +82 -0
  62. package/dist/tui/widgets/detail.d.ts +9 -0
  63. package/dist/tui/widgets/detail.js +151 -0
  64. package/dist/tui/widgets/edges.d.ts +4 -0
  65. package/dist/tui/widgets/edges.js +34 -0
  66. package/dist/tui/widgets/liquidity.d.ts +9 -0
  67. package/dist/tui/widgets/liquidity.js +142 -0
  68. package/dist/tui/widgets/orders.d.ts +4 -0
  69. package/dist/tui/widgets/orders.js +37 -0
  70. package/dist/tui/widgets/portfolio.d.ts +4 -0
  71. package/dist/tui/widgets/portfolio.js +59 -0
  72. package/dist/tui/widgets/signals.d.ts +4 -0
  73. package/dist/tui/widgets/signals.js +31 -0
  74. package/dist/tui/widgets/statusbar.d.ts +8 -0
  75. package/dist/tui/widgets/statusbar.js +72 -0
  76. package/dist/tui/widgets/thesis.d.ts +4 -0
  77. package/dist/tui/widgets/thesis.js +66 -0
  78. package/dist/tui/widgets/trade.d.ts +9 -0
  79. package/dist/tui/widgets/trade.js +117 -0
  80. package/dist/tui/widgets/upcoming.d.ts +4 -0
  81. package/dist/tui/widgets/upcoming.js +41 -0
  82. package/dist/tui/widgets/whatif.d.ts +7 -0
  83. package/dist/tui/widgets/whatif.js +113 -0
  84. package/dist/utils.test.d.ts +1 -0
  85. package/dist/utils.test.js +111 -0
  86. package/package.json +6 -2
@@ -0,0 +1,17 @@
1
+ /**
2
+ * sf book — Orderbook depth, price history, and liquidity for individual markets
3
+ *
4
+ * Usage:
5
+ * sf book KXWTIMAX-26DEC31-T135 Single Kalshi market
6
+ * sf book KXWTI-T135 KXCPI-26MAY Multiple markets
7
+ * sf book --poly "oil price" Polymarket search
8
+ * sf book KXWTIMAX-26DEC31-T135 --history With 7d price history
9
+ * sf book KXWTIMAX-26DEC31-T135 --json JSON output
10
+ */
11
+ interface BookOpts {
12
+ poly?: string;
13
+ history?: boolean;
14
+ json?: boolean;
15
+ }
16
+ export declare function bookCommand(tickers: string[], opts: BookOpts): Promise<void>;
17
+ export {};
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ /**
3
+ * sf book — Orderbook depth, price history, and liquidity for individual markets
4
+ *
5
+ * Usage:
6
+ * sf book KXWTIMAX-26DEC31-T135 Single Kalshi market
7
+ * sf book KXWTI-T135 KXCPI-26MAY Multiple markets
8
+ * sf book --poly "oil price" Polymarket search
9
+ * sf book KXWTIMAX-26DEC31-T135 --history With 7d price history
10
+ * sf book KXWTIMAX-26DEC31-T135 --json JSON output
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.bookCommand = bookCommand;
14
+ const client_js_1 = require("../client.js");
15
+ const kalshi_js_1 = require("../kalshi.js");
16
+ const polymarket_js_1 = require("../polymarket.js");
17
+ const utils_js_1 = require("../utils.js");
18
+ async function bookCommand(tickers, opts) {
19
+ const results = [];
20
+ // ── Polymarket search mode ──
21
+ if (opts.poly) {
22
+ console.log(`${utils_js_1.c.dim}Searching Polymarket for "${opts.poly}"...${utils_js_1.c.reset}`);
23
+ const events = await (0, polymarket_js_1.polymarketSearch)(opts.poly, 10);
24
+ for (const event of events) {
25
+ for (const m of (event.markets || []).slice(0, 5)) {
26
+ if (!m.active || m.closed || !m.clobTokenIds)
27
+ continue;
28
+ const ids = (0, polymarket_js_1.parseClobTokenIds)(m.clobTokenIds);
29
+ if (!ids)
30
+ continue;
31
+ const depth = await (0, polymarket_js_1.polymarketGetOrderbookWithDepth)(ids[0]);
32
+ if (!depth)
33
+ continue;
34
+ const prices = (0, polymarket_js_1.parseOutcomePrices)(m.outcomePrices);
35
+ const book = {
36
+ venue: 'polymarket',
37
+ ticker: m.conditionId?.slice(0, 16) || m.id,
38
+ title: m.groupItemTitle
39
+ ? `${event.title}: ${m.groupItemTitle}`
40
+ : m.question || event.title,
41
+ bestBid: depth.bestBid,
42
+ bestAsk: depth.bestAsk,
43
+ spread: depth.spread,
44
+ bidDepth: depth.totalBidDepth,
45
+ askDepth: depth.totalAskDepth,
46
+ liquidityScore: depth.liquidityScore,
47
+ volume24h: m.volume24hr || 0,
48
+ openInterest: m.liquidityNum || 0,
49
+ lastPrice: prices[0] ? (0, polymarket_js_1.toCents)(prices[0]) : 0,
50
+ expiry: m.endDateIso || null,
51
+ bidLevels: depth.levels.bids.slice(0, 5).map(l => ({ price: Math.round(parseFloat(l.price) * 100), size: Math.round(parseFloat(l.size)) })),
52
+ askLevels: depth.levels.asks.slice(0, 5).map(l => ({ price: Math.round(parseFloat(l.price) * 100), size: Math.round(parseFloat(l.size)) })),
53
+ };
54
+ // Price history sparkline
55
+ if (opts.history) {
56
+ try {
57
+ const hist = await (0, polymarket_js_1.polymarketGetPriceHistory)({ tokenId: ids[0], interval: '1w', fidelity: 360 });
58
+ if (hist.length > 0) {
59
+ book.sparkline = makeSparkline(hist.map(h => h.p * 100));
60
+ }
61
+ }
62
+ catch { /* skip */ }
63
+ }
64
+ results.push(book);
65
+ }
66
+ }
67
+ }
68
+ // ── Kalshi tickers ──
69
+ for (const ticker of tickers) {
70
+ console.log(`${utils_js_1.c.dim}Fetching ${ticker}...${utils_js_1.c.reset}`);
71
+ try {
72
+ const market = await (0, client_js_1.kalshiFetchMarket)(ticker);
73
+ const ob = await (0, kalshi_js_1.getPublicOrderbook)(ticker);
74
+ const yesBids = (ob?.yes_dollars || [])
75
+ .map(([p, q]) => ({ price: Math.round(parseFloat(p) * 100), size: Math.round(parseFloat(q)) }))
76
+ .filter((l) => l.price > 0)
77
+ .sort((a, b) => b.price - a.price);
78
+ const noAsks = (ob?.no_dollars || [])
79
+ .map(([p, q]) => ({ price: Math.round(parseFloat(p) * 100), size: Math.round(parseFloat(q)) }))
80
+ .filter((l) => l.price > 0)
81
+ .sort((a, b) => b.price - a.price);
82
+ const bestBid = yesBids[0]?.price || 0;
83
+ const bestAsk = noAsks.length > 0 ? (100 - noAsks[0].price) : 100;
84
+ const spread = bestAsk - bestBid;
85
+ const bidDepth = yesBids.reduce((s, l) => s + l.size, 0);
86
+ const askDepth = noAsks.reduce((s, l) => s + l.size, 0);
87
+ const totalDepth = yesBids.slice(0, 3).reduce((s, l) => s + l.size, 0) +
88
+ noAsks.slice(0, 3).reduce((s, l) => s + l.size, 0);
89
+ const liq = spread <= 2 && totalDepth >= 500 ? 'high' : spread <= 5 && totalDepth >= 100 ? 'medium' : 'low';
90
+ const lastPrice = parseFloat(market.last_price_dollars || '0') * 100;
91
+ const book = {
92
+ venue: 'kalshi',
93
+ ticker: market.ticker || ticker,
94
+ title: market.title || market.subtitle || ticker,
95
+ bestBid,
96
+ bestAsk,
97
+ spread,
98
+ bidDepth,
99
+ askDepth,
100
+ liquidityScore: liq,
101
+ volume24h: parseFloat(market.volume_24h_fp || '0'),
102
+ openInterest: parseFloat(market.open_interest_fp || '0'),
103
+ lastPrice: Math.round(lastPrice),
104
+ expiry: market.close_time || market.expiration_time || null,
105
+ bidLevels: yesBids.slice(0, 5),
106
+ askLevels: noAsks.slice(0, 5).map((l) => ({ price: 100 - l.price, size: l.size })),
107
+ };
108
+ // Kalshi price history
109
+ if (opts.history) {
110
+ // Try authenticated candlestick API first (requires Kalshi keys)
111
+ if ((0, kalshi_js_1.isKalshiConfigured)()) {
112
+ try {
113
+ const now = Math.floor(Date.now() / 1000);
114
+ const weekAgo = now - 7 * 86400;
115
+ const candleResults = await (0, kalshi_js_1.getBatchCandlesticks)({
116
+ tickers: [ticker],
117
+ startTs: weekAgo,
118
+ endTs: now,
119
+ periodInterval: 1440,
120
+ });
121
+ const mktEntry = candleResults.find((e) => e.market_ticker === ticker) || candleResults[0];
122
+ const mktCandles = mktEntry?.candlesticks || [];
123
+ if (Array.isArray(mktCandles) && mktCandles.length > 0) {
124
+ const prices = mktCandles.map((cd) => {
125
+ // Kalshi nests prices: cd.price.close_dollars or cd.yes_ask.close_dollars
126
+ const p = cd.price?.close_dollars ?? cd.yes_ask?.close_dollars ?? cd.yes_bid?.close_dollars ?? cd.close ?? cd.price;
127
+ const v = typeof p === 'string' ? parseFloat(p) * 100 : (typeof p === 'number' ? p : 0);
128
+ return Math.round(v);
129
+ }).filter((p) => p > 0);
130
+ if (prices.length >= 2) {
131
+ book.sparkline = makeSparkline(prices);
132
+ }
133
+ }
134
+ }
135
+ catch { /* skip */ }
136
+ }
137
+ // Fallback: show previous vs current from market data
138
+ if (!book.sparkline) {
139
+ const prev = parseFloat(market.previous_price_dollars || '0') * 100;
140
+ if (prev > 0 && Math.abs(prev - book.lastPrice) > 0) {
141
+ const delta = book.lastPrice - Math.round(prev);
142
+ const deltaColor = delta >= 0 ? utils_js_1.c.green : utils_js_1.c.red;
143
+ const deltaStr = delta >= 0 ? `+${delta}` : `${delta}`;
144
+ book.sparkline = `prev ${Math.round(prev)}¢ → now ${book.lastPrice}¢ ${deltaColor}${deltaStr}${utils_js_1.c.reset}`;
145
+ }
146
+ }
147
+ }
148
+ results.push(book);
149
+ }
150
+ catch (err) {
151
+ console.error(`${utils_js_1.c.red}Failed to fetch ${ticker}: ${err.message}${utils_js_1.c.reset}`);
152
+ }
153
+ }
154
+ if (results.length === 0) {
155
+ console.log(`${utils_js_1.c.dim}No markets found.${utils_js_1.c.reset}`);
156
+ return;
157
+ }
158
+ // ── JSON output ──
159
+ if (opts.json) {
160
+ console.log(JSON.stringify(results, null, 2));
161
+ return;
162
+ }
163
+ // ── Formatted output ──
164
+ for (const book of results) {
165
+ const venueTag = book.venue === 'polymarket' ? `${utils_js_1.c.blue}POLY${utils_js_1.c.reset}` : `${utils_js_1.c.cyan}KLSH${utils_js_1.c.reset}`;
166
+ console.log();
167
+ console.log(`${utils_js_1.c.bold}${venueTag} ${book.title}${utils_js_1.c.reset}`);
168
+ console.log(`${utils_js_1.c.dim}${book.ticker}${utils_js_1.c.reset}`);
169
+ console.log();
170
+ // Summary line
171
+ const liqColor = book.liquidityScore === 'high' ? utils_js_1.c.green : book.liquidityScore === 'medium' ? utils_js_1.c.yellow : utils_js_1.c.red;
172
+ console.log(` Last ${utils_js_1.c.bold}${book.lastPrice}¢${utils_js_1.c.reset} ` +
173
+ `Bid ${utils_js_1.c.green}${book.bestBid}¢${utils_js_1.c.reset} ` +
174
+ `Ask ${utils_js_1.c.red}${book.bestAsk}¢${utils_js_1.c.reset} ` +
175
+ `Spread ${liqColor}${book.spread}¢${utils_js_1.c.reset} ` +
176
+ `Liq ${liqColor}${book.liquidityScore}${utils_js_1.c.reset}`);
177
+ console.log(` Vol24h ${(0, utils_js_1.vol)(book.volume24h)} ` +
178
+ `OI ${(0, utils_js_1.vol)(book.openInterest)}` +
179
+ (book.expiry ? ` Expires ${book.expiry.slice(0, 10)}` : ''));
180
+ // Sparkline
181
+ if (book.sparkline) {
182
+ console.log(` 7d ${book.sparkline}`);
183
+ }
184
+ // Orderbook depth
185
+ if (book.bidLevels && book.askLevels) {
186
+ console.log();
187
+ console.log(` ${utils_js_1.c.dim}${(0, utils_js_1.pad)('BID', 18)} ${(0, utils_js_1.pad)('ASK', 18)}${utils_js_1.c.reset}`);
188
+ console.log(` ${utils_js_1.c.dim}${'─'.repeat(38)}${utils_js_1.c.reset}`);
189
+ const maxLevels = Math.max(book.bidLevels.length, book.askLevels.length);
190
+ for (let i = 0; i < Math.min(maxLevels, 5); i++) {
191
+ const bid = book.bidLevels[i];
192
+ const ask = book.askLevels[i];
193
+ const bidStr = bid ? `${utils_js_1.c.green}${(0, utils_js_1.rpad)(`${bid.price}¢`, 5)}${utils_js_1.c.reset} ${(0, utils_js_1.rpad)(String(bid.size), 8)}` : (0, utils_js_1.pad)('', 18);
194
+ const askStr = ask ? `${utils_js_1.c.red}${(0, utils_js_1.rpad)(`${ask.price}¢`, 5)}${utils_js_1.c.reset} ${(0, utils_js_1.rpad)(String(ask.size), 8)}` : '';
195
+ console.log(` ${bidStr} ${askStr}`);
196
+ }
197
+ console.log(` ${utils_js_1.c.dim}depth: ${book.bidDepth} bid / ${book.askDepth} ask${utils_js_1.c.reset}`);
198
+ }
199
+ console.log();
200
+ }
201
+ }
202
+ // ── Sparkline helper ──
203
+ function makeSparkline(values) {
204
+ if (values.length < 2)
205
+ return '';
206
+ const min = Math.min(...values);
207
+ const max = Math.max(...values);
208
+ const range = max - min || 1;
209
+ const blocks = '▁▂▃▄▅▆▇█';
210
+ const line = values.map(v => {
211
+ const idx = Math.round(((v - min) / range) * 7);
212
+ return blocks[idx];
213
+ }).join('');
214
+ const startPrice = Math.round(values[0]);
215
+ const endPrice = Math.round(values[values.length - 1]);
216
+ const delta = endPrice - startPrice;
217
+ const deltaColor = delta >= 0 ? utils_js_1.c.green : utils_js_1.c.red;
218
+ const deltaStr = delta >= 0 ? `+${delta}` : `${delta}`;
219
+ return `${line} ${startPrice}¢→${endPrice}¢ ${deltaColor}${deltaStr}${utils_js_1.c.reset}`;
220
+ }
@@ -1,11 +1,14 @@
1
1
  /**
2
- * sf dashboard — Portfolio overview
2
+ * sf dashboard — Commander entry point
3
3
  *
4
- * One-screen summary: theses, positions, risk exposure, top unpositioned edges.
5
- * Uses existing APIs + local Kalshi positions.
4
+ * Three modes:
5
+ * --json → dump current state as JSON
6
+ * --once → one-time formatted print (no interactive TUI)
7
+ * default → launch interactive TUI dashboard
6
8
  */
7
9
  export declare function dashboardCommand(opts?: {
8
10
  json?: boolean;
11
+ once?: boolean;
9
12
  apiKey?: string;
10
13
  apiUrl?: string;
11
14
  }): Promise<void>;
@@ -1,17 +1,21 @@
1
1
  "use strict";
2
2
  /**
3
- * sf dashboard — Portfolio overview
3
+ * sf dashboard — Commander entry point
4
4
  *
5
- * One-screen summary: theses, positions, risk exposure, top unpositioned edges.
6
- * Uses existing APIs + local Kalshi positions.
5
+ * Three modes:
6
+ * --json → dump current state as JSON
7
+ * --once → one-time formatted print (no interactive TUI)
8
+ * default → launch interactive TUI dashboard
7
9
  */
8
10
  Object.defineProperty(exports, "__esModule", { value: true });
9
11
  exports.dashboardCommand = dashboardCommand;
10
12
  const client_js_1 = require("../client.js");
11
13
  const kalshi_js_1 = require("../kalshi.js");
14
+ const polymarket_js_1 = require("../polymarket.js");
15
+ const config_js_1 = require("../config.js");
12
16
  const topics_js_1 = require("../topics.js");
17
+ const dashboard_js_1 = require("../tui/dashboard.js");
13
18
  function categorize(ticker) {
14
- // Match longest prefix first
15
19
  const sorted = Object.keys(topics_js_1.RISK_CATEGORIES).sort((a, b) => b.length - a.length);
16
20
  for (const prefix of sorted) {
17
21
  if (ticker.startsWith(prefix))
@@ -31,8 +35,13 @@ function timeAgo(dateStr) {
31
35
  return `${days}d ago`;
32
36
  }
33
37
  async function dashboardCommand(opts) {
38
+ // ── Default: interactive TUI ──
39
+ if (!opts?.json && !opts?.once) {
40
+ await (0, dashboard_js_1.startDashboard)();
41
+ return;
42
+ }
43
+ // ── JSON or one-time print modes (legacy behavior) ──
34
44
  const client = new client_js_1.SFClient(opts?.apiKey, opts?.apiUrl);
35
- // ── Fetch data in parallel ─────────────────────────────────────────────────
36
45
  const [thesesResult, positions] = await Promise.all([
37
46
  client.listTheses(),
38
47
  (0, kalshi_js_1.getPositions)().catch(() => null),
@@ -59,7 +68,7 @@ async function dashboardCommand(opts) {
59
68
  }
60
69
  }
61
70
  }
62
- // ── Collect all edges across all theses ────────────────────────────────────
71
+ // Collect all edges across all theses
63
72
  const allEdges = [];
64
73
  for (const ctx of contexts) {
65
74
  if (!ctx?.edges)
@@ -78,26 +87,49 @@ async function dashboardCommand(opts) {
78
87
  }
79
88
  // Find positioned tickers
80
89
  const positionedTickers = new Set(positions?.map((p) => p.ticker) || []);
81
- // Unpositioned edges = edges where no position exists on that marketId
90
+ // Unpositioned edges
82
91
  const unpositionedEdges = [...edgeMap.values()]
83
92
  .filter(e => !positionedTickers.has(e.marketId))
84
93
  .sort((a, b) => Math.abs(b.edge) - Math.abs(a.edge))
85
94
  .slice(0, 10);
86
- // ── JSON output ────────────────────────────────────────────────────────────
95
+ // Fetch additional data for JSON mode
96
+ const [orders, balance, polyPositions] = await Promise.all([
97
+ opts?.json ? (0, kalshi_js_1.getOrders)({ status: 'resting' }).catch(() => []) : Promise.resolve([]),
98
+ opts?.json ? (0, kalshi_js_1.getBalance)().catch(() => null) : Promise.resolve(null),
99
+ opts?.json && (0, config_js_1.loadConfig)().polymarketWalletAddress
100
+ ? (0, polymarket_js_1.polymarketGetPositions)((0, config_js_1.loadConfig)().polymarketWalletAddress).catch(() => [])
101
+ : Promise.resolve([]),
102
+ ]);
103
+ // Fetch feed for recent evaluations
104
+ let feed = [];
105
+ if (opts?.json) {
106
+ try {
107
+ feed = (await client.getFeed(24, 20)).evaluations || [];
108
+ }
109
+ catch { /* skip */ }
110
+ }
111
+ // ── JSON output ──
87
112
  if (opts?.json) {
88
113
  console.log(JSON.stringify({
89
114
  theses,
90
- positions,
115
+ positions: positions || [],
116
+ polymarketPositions: polyPositions,
117
+ orders,
118
+ balance,
91
119
  unpositionedEdges,
120
+ feed,
121
+ kalshiConfigured: (0, kalshi_js_1.isKalshiConfigured)(),
122
+ polymarketConfigured: !!(0, config_js_1.loadConfig)().polymarketWalletAddress,
123
+ timestamp: new Date().toISOString(),
92
124
  }, null, 2));
93
125
  return;
94
126
  }
95
- // ── Formatted output ───────────────────────────────────────────────────────
127
+ // ── One-time formatted output ──
96
128
  console.log();
97
129
  console.log(' SimpleFunctions Dashboard');
98
- console.log(' ' + ''.repeat(50));
130
+ console.log(' ' + '\u2500'.repeat(50));
99
131
  console.log();
100
- // ── Theses ─────────────────────────────────────────────────────────────────
132
+ // Theses
101
133
  console.log(' Theses');
102
134
  if (theses.length === 0) {
103
135
  console.log(' (none)');
@@ -115,7 +147,7 @@ async function dashboardCommand(opts) {
115
147
  }
116
148
  }
117
149
  console.log();
118
- // ── Positions ──────────────────────────────────────────────────────────────
150
+ // Positions
119
151
  console.log(' Positions');
120
152
  if (!positions || positions.length === 0) {
121
153
  console.log(' (no Kalshi positions or Kalshi not configured)');
@@ -126,8 +158,8 @@ async function dashboardCommand(opts) {
126
158
  for (const p of positions) {
127
159
  const ticker = (p.ticker || '').padEnd(22);
128
160
  const qty = String(p.quantity || 0).padStart(5);
129
- const avg = `${p.average_price_paid || 0}¢`;
130
- const now = typeof p.current_value === 'number' ? `${p.current_value}¢` : '';
161
+ const avg = `${p.average_price_paid || 0}\u00A2`;
162
+ const now = typeof p.current_value === 'number' ? `${p.current_value}\u00A2` : '?\u00A2';
131
163
  const pnlCents = p.unrealized_pnl || 0;
132
164
  const pnlDollars = (pnlCents / 100).toFixed(2);
133
165
  const pnlStr = pnlCents >= 0 ? `+$${pnlDollars}` : `-$${Math.abs(parseFloat(pnlDollars)).toFixed(2)}`;
@@ -136,14 +168,14 @@ async function dashboardCommand(opts) {
136
168
  totalPnl += pnlCents;
137
169
  console.log(` ${ticker} ${qty} @ ${avg.padEnd(5)} now ${now.padEnd(5)} ${pnlStr}`);
138
170
  }
139
- console.log(' ' + ''.repeat(45));
171
+ console.log(' ' + '\u2500'.repeat(45));
140
172
  const totalCostDollars = (totalCost / 100).toFixed(0);
141
173
  const totalPnlDollars = (totalPnl / 100).toFixed(2);
142
174
  const pnlDisplay = totalPnl >= 0 ? `+$${totalPnlDollars}` : `-$${Math.abs(parseFloat(totalPnlDollars)).toFixed(2)}`;
143
175
  console.log(` Total cost: $${totalCostDollars} | P&L: ${pnlDisplay}`);
144
176
  }
145
177
  console.log();
146
- // ── Risk Exposure ──────────────────────────────────────────────────────────
178
+ // Risk Exposure
147
179
  if (positions && positions.length > 0) {
148
180
  console.log(' Risk Exposure');
149
181
  const riskGroups = new Map();
@@ -157,7 +189,6 @@ async function dashboardCommand(opts) {
157
189
  existing.tickers.push(p.ticker);
158
190
  riskGroups.set(cat, existing);
159
191
  }
160
- // Sort by cost descending
161
192
  const sorted = [...riskGroups.entries()].sort((a, b) => b[1].cost - a[1].cost);
162
193
  for (const [category, data] of sorted) {
163
194
  const costDollars = `$${(data.cost / 100).toFixed(0)}`;
@@ -168,16 +199,16 @@ async function dashboardCommand(opts) {
168
199
  }
169
200
  console.log();
170
201
  }
171
- // ── Top Unpositioned Edges ─────────────────────────────────────────────────
202
+ // Top Unpositioned Edges
172
203
  if (unpositionedEdges.length > 0) {
173
204
  console.log(' Top Unpositioned Edges');
174
205
  for (const e of unpositionedEdges) {
175
206
  const name = (e.market || e.marketId || '').slice(0, 25).padEnd(25);
176
- const mkt = `${e.marketPrice}¢`;
177
- const thesis = `${e.thesisPrice}¢`;
207
+ const mkt = `${e.marketPrice}\u00A2`;
208
+ const thesis = `${e.thesisPrice}\u00A2`;
178
209
  const edge = e.edge > 0 ? `+${e.edge}` : `${e.edge}`;
179
210
  const liq = e.orderbook?.liquidityScore || '?';
180
- console.log(` ${name} ${mkt.padStart(5)} ${thesis.padStart(5)} edge ${edge.padStart(4)} ${liq}`);
211
+ console.log(` ${name} ${mkt.padStart(5)} \u2192 ${thesis.padStart(5)} edge ${edge.padStart(4)} ${liq}`);
181
212
  }
182
213
  console.log();
183
214
  }
@@ -9,4 +9,6 @@ export declare function liquidityCommand(opts: {
9
9
  horizon?: string;
10
10
  minDepth?: number;
11
11
  json?: boolean;
12
+ all?: boolean;
13
+ venue?: string;
12
14
  }): Promise<void>;