kalshi-trading-bot-cli 2.1.3 → 2.1.5

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 CHANGED
@@ -28,6 +28,8 @@ That's it — no clone, no install. The setup wizard runs automatically on first
28
28
 
29
29
  Prefer a global install? `bun add -g kalshi-trading-bot-cli` then run `kalshi`.
30
30
 
31
+ > **Scripting and agent use** — for parallel invocations, `--json` consumers, or anything that pipes our output: **install globally and use the `kalshi` binary**, not `bunx`. See [Scripting & Parallel Use](#scripting--parallel-use) below for the gory details.
32
+
31
33
  Or work from a clone:
32
34
 
33
35
  ```bash
@@ -114,8 +116,31 @@ Type help for commands, or just ask a question.
114
116
 
115
117
  | Command | Description |
116
118
  |---------|-------------|
117
- | `search [theme\|ticker\|query]` | Find markets by keyword or theme |
118
- | `search edge [--min-edge N]` | Scan all markets by model edge |
119
+ | `search [theme\|ticker\|query]` | Find markets by keyword or theme (Octagon-backed when key set) |
120
+ | `search edge [--min-edge N]` | Scan all markets by model edge (Octagon `markets-with-edge`) |
121
+ | `similar <ticker\|"query">` | Semantic neighbors via Octagon embeddings |
122
+ | `clusters [--label X]` | Browse thematic clusters of the Kalshi universe |
123
+ | `clusters <id>` | List markets inside a cluster |
124
+ | `clusters --behavioral` | Behavioral clusters by 30-day return vectors |
125
+ | `clusters --ranked` | Rank clusters by historical basket return |
126
+ | `peers <ticker>` | Markets in the same cluster as a ticker |
127
+ | `correlate <t1> <t2> [...]` | Pairwise Pearson correlation matrix |
128
+ | `basket build` | Diversified basket with cluster + correlation caps |
129
+ | `basket backtest` | NAV summary: total return, Sharpe, max drawdown, win rate |
130
+ | `basket size` | Fractional Kelly sizing for picked legs |
131
+ | `basket candles` | OHLC bars for a weighted basket NAV |
132
+ | `basket validate` | One-call portfolio diagnostics (clusters, correlations, calendar clashes, warnings) |
133
+ | `basket size --auto-probs` | Auto-fetch model probabilities via `markets/edge` and Kelly-size |
134
+ | `basket backtest --theme <name>` | Resolve an editorial theme to a NAV basket and backtest it |
135
+ | `series events <ticker>` | List events inside a series |
136
+ | `events` / `events <ticker>` | Octagon events list + outcome ladder per event |
137
+ | `series` / `series <ticker>` | Kalshi series rollup (24h vol, market count) |
138
+ | `series candles <ticker>` | Series-level NAV (basket of top sub-markets) |
139
+ | `catalysts upcoming --days N` | Markets closing in the next N days, grouped by week |
140
+ | `themes` (registry) | Editorial narrative buckets — list/show/import/create/delete/add-series |
141
+ | `themes report` | 25-theme dashboard with SEO + liquidity |
142
+ | `themes audit` | Flag dead themes (high SEO + zero volume) |
143
+ | `themes overlap` | Cross-theme dedupe report |
119
144
  | `analyze <ticker>` | Deep analysis: edge, drivers, Kelly sizing |
120
145
  | `watch <ticker>` | Live price and orderbook feed |
121
146
  | `watch --theme <theme>` | Continuous theme scan |
@@ -151,6 +176,143 @@ Type help for commands, or just ask a question.
151
176
  | `--min-price <n>` | Min contract price, 0-100 scale (backtest, default 5) |
152
177
  | `--max-price <n>` | Max contract price, 0-100 scale (backtest, default 95) |
153
178
  | `--export <path>` | Export per-market CSV (backtest) |
179
+ | `--top-k <n>` | Number of neighbors (similar); legs per cluster (clusters --ranked) |
180
+ | `--behavioral` | Use behavioral clustering (clusters, peers) |
181
+ | `--ranked` | Rank clusters by historical basket return (clusters) |
182
+ | `--label <substr,...>` | Filter by cluster label substring (clusters, basket build) |
183
+ | `--close-before <iso>` | Only markets closing before this timestamp |
184
+ | `--window-days <n>` | Correlation lookback (correlate; basket build) |
185
+ | `--correlation-interval <1h\|1d>` | Override candle bin size for correlate |
186
+ | `--timeframe <1w\|1m\|3m\|6m\|1y>` | Window/bin size for basket commands |
187
+ | `--weights <csv>` | Comma-separated weights for basket backtest/candles |
188
+ | `--bankroll <usd>` | Bankroll for Kelly sizing (basket size/build) |
189
+ | `--kelly <0-1>` | Kelly multiplier (default 0.25) |
190
+ | `-n <n>` | Basket size requested (basket build) |
191
+ | `--max-per-cluster <n>` | Cap legs per thematic cluster (basket build) |
192
+ | `--max-corr <-1..1>` | Pairwise correlation cap (basket build) |
193
+ | `--min-return <n>` | Minimum total_return for clusters --ranked |
194
+ | `--series <ticker>` | Filter to a Kalshi series (search, similar, basket) |
195
+ | `--sort-by <key>` | Sort key for search edge: edge_pp \| expected_return \| total_volume \| model_probability |
196
+ | `--probs <csv>` | Per-leg probabilities, e.g. `KX-A:0.62,KX-B:0.55` |
197
+ | `--tickers <csv>` | Comma-separated tickers (correlate, basket backtest/candles) |
198
+ | `-q "text"` | Free-text anchor for similar / basket build |
199
+ | `--show-cluster` | Print cluster membership only (peers) |
200
+ | `--theme <name>` | Resolve an editorial theme to a ticker list (basket backtest/candles/validate/size) |
201
+ | `--aggregate-by series` | Roll up search results to the series level |
202
+ | `--active-only` | Drop non-active markets (defensive flag — open universe by default) |
203
+ | `--series-prefix <prefix>` | Server-side series prefix match (e.g. `KXBTC` matches KXBTCD, KXBTCY, ...) |
204
+ | `--sides yes,no,yes` | Per-ticker side for `correlate` (sign-flipped) |
205
+ | `--cells` | Include per-cell detail (overlap, reason) in `correlate` |
206
+ | `--auto-probs` | `basket size`: auto-fetch model probabilities via `markets/edge` |
207
+
208
+ ### Discovery & Portfolio (Octagon-powered)
209
+
210
+ The `search`, `similar`, `clusters`, `peers`, `correlate`, and `basket` commands turn the whole Kalshi universe into a queryable database. When `OCTAGON_API_KEY` is set the bot routes searches through Octagon's typed endpoints — semantic embedding lookups, nightly k-means clusters (thematic + behavioral), Pearson correlation matrices, and one-call diversified basket construction with cluster caps and pairwise-correlation gates. Without a key, `search` and `search edge` fall back to the local SQLite cache.
211
+
212
+ ```bash
213
+ # Free-text + structured search (semantic full-text + filters)
214
+ kalshi search "bitcoin price" --category crypto --min-volume 10000 --limit 20
215
+
216
+ # Edge ranking from Octagon's latest run (server-side, no local pre-fetch)
217
+ kalshi search edge --min-edge 5 --limit 10 --sort-by total_volume
218
+
219
+ # Semantic neighbors — catches matches keyword search misses
220
+ kalshi similar KXBTCD-26DEC31-T100000 --top-k 25
221
+ kalshi similar -q "Will Bitcoin pierce six figures" --category crypto
222
+
223
+ # Browse the universe by theme
224
+ kalshi clusters --label fed # find Fed-decision clusters
225
+ kalshi clusters 42 # markets in cluster 42
226
+ kalshi clusters --behavioral # behavioral clusters (mean ret + vol)
227
+ kalshi clusters --ranked --timeframe 1y --min-return 0.20 --top-k 5
228
+
229
+ # Same-theme dedup
230
+ kalshi peers KXBTCD-26DEC31-T100000 --kind thematic --limit 50
231
+ kalshi peers KXBTCD-26DEC31-T100000 --show-cluster # which cluster does this belong to?
232
+
233
+ # Pairwise correlation matrix — most-uncorrelated pairs first
234
+ kalshi correlate KXBTCD-... KXETHU-... KXSOL-... --window-days 90
235
+
236
+ # Build a diversified basket (one HTTP call — universe → cluster cap → corr cap → sizing)
237
+ kalshi basket build --category crypto --min-volume 10000 \
238
+ -n 8 --max-per-cluster 2 --max-corr 0.6 \
239
+ --bankroll 1000 --kelly 0.25 \
240
+ --probs KXBTCD-...:0.62,KXETHU-...:0.58
241
+
242
+ # "Find me 5 uncorrelated bets on macro themes" — one HTTP call
243
+ kalshi basket build --label fed,cpi,fomc,gdp,jobs \
244
+ -n 5 --max-per-cluster 1 --max-corr 0.4
245
+
246
+ # Backtest a basket and read total_return / Sharpe / max DD directly
247
+ kalshi basket backtest --tickers KX-A,KX-B,KX-C --weights 0.4,0.4,0.2 --timeframe 1y
248
+
249
+ # Kelly-size legs you've already picked
250
+ kalshi basket size --bankroll 1000 --kelly 0.25 --probs KX-A:0.62,KX-B:0.55
251
+
252
+ # Or let Octagon's model fill in the probabilities for you
253
+ kalshi basket size --auto-probs --tickers KX-A,KX-B,KX-C --bankroll 1000 --kelly 0.25
254
+ kalshi basket size --auto-probs --theme "AI Race Milestones" --bankroll 1000 --kelly 0.25
255
+
256
+ # Diversified basket builder over an explicit candidate pool
257
+ kalshi basket build --tickers KX-A,KX-B,KX-C,KX-D -n 3 --max-per-cluster 1 --max-corr 0.5
258
+ kalshi basket build --theme "Iran Escalation" -n 4 --max-per-cluster 1 --max-corr 0.5 --auto-probs --bankroll 1000
259
+
260
+ # Sanity-check a proposed basket before placing orders (one call, server-side)
261
+ kalshi basket validate --tickers KX-A,KX-B --bankroll 1000 --max-corr 0.5
262
+ kalshi basket validate --theme "Iran Escalation" --bankroll 1000
263
+ # → cluster breakdown, pairwise correlations (top by |corr|), calendar
264
+ # clashes (weeks where many legs resolve), duplicate underliers, warnings.
265
+ ```
266
+
267
+ ### Editorial Theme Dashboard
268
+
269
+ `themes` is a local registry of editorial narrative buckets (e.g. "AI Race Milestones", "Iran Escalation") that maps to lists of Kalshi series with optional monthly search-volume annotations. The bot ships with a 25-theme seed dataset in `data/themes_seo.json`. Distinct from Octagon's ML clusters — these are *narratives* you curate.
270
+
271
+ ```bash
272
+ # Seed from the included starter dataset (25 themes, 173 series mappings)
273
+ kalshi themes import
274
+
275
+ # Browse the registry
276
+ kalshi themes list
277
+ kalshi themes show "Iran Escalation"
278
+
279
+ # THE dashboard view: 25-theme grid with SEO + liquidity
280
+ kalshi themes report
281
+
282
+ # Flag dead themes (high SEO + zero active Kalshi inventory)
283
+ kalshi themes audit
284
+ # → Epstein / Celebrity Trials STALE 4.3M searches, 0 active markets
285
+ # → RFK Jr Changes Health NO_INVENTORY 422k searches, 0 active markets
286
+ # → AI Race Milestones TRADEABLE 138M searches, 28 active mkts
287
+ # → Bitcoin Breakout TRADEABLE 29k searches, 270 active mkts
288
+
289
+ # Cross-theme dedupe (when a series belongs to multiple themes)
290
+ kalshi themes overlap
291
+ # → KXUSAIRANAGREEMENT Iran Escalation · Nuclear Renaissance
292
+ # → KXMORTGAGERATE Fed Cuts Aggressively · Housing / Mortgage Crisis
293
+
294
+ # Build/manage your own themes
295
+ kalshi themes create "My Macro Hedge" --label "..." --tickers KXRECSSNBER,KXCPIYOY
296
+ kalshi themes add-series "My Macro Hedge" KXFEDDECISION,KXU3
297
+ kalshi themes set-search-volume "My Macro Hedge" 50000
298
+
299
+ # Backtest an entire theme as a NAV basket (one top market per series)
300
+ kalshi basket backtest --theme "Iran Escalation" --timeframe 3m
301
+ kalshi basket candles --theme "Fed Cuts Aggressively" --timeframe 1y --json
302
+
303
+ # Series-level rollup and NAV
304
+ kalshi series list --min-volume 10000 # liquid series, ranked
305
+ kalshi series KXBTCD --limit 10 # drill in
306
+ kalshi series candles KXBTCD --timeframe 3m # series NAV momentum
307
+ kalshi series search bitcoin --limit 10 # keyword → rollup
308
+
309
+ # Event ↔ outcome ladder
310
+ kalshi events --category Politics --limit 10 # top political events by volume
311
+ kalshi events KXFEDCHAIRNOM-29 # outcome probabilities + per-contract edge
312
+
313
+ # Catalyst calendar
314
+ kalshi catalysts upcoming --days 14 --min-volume 5000 --category Politics
315
+ ```
154
316
 
155
317
  ### Backtesting
156
318
 
@@ -180,8 +342,6 @@ kalshi backtest --export results.csv # per-market detail
180
342
  Octagon Backtest — 15-day lookback (04/02 – 04/17)
181
343
  ══════════════════════════════════════════════════════════
182
344
 
183
- VERDICT: Model has edge (Skill +12.5% [CI: +4.1%, +20.8%]; ROI +7.8%)
184
-
185
345
  Events 83
186
346
  Markets 247 (142 resolved, 105 unresolved)
187
347
  Brier (Octagon) 0.168
@@ -205,12 +365,47 @@ UNRESOLVED (105 markets)
205
365
 
206
366
  Set `KALSHI_USE_DEMO=true` in your `.env` to use Kalshi's demo environment. All trades are simulated — no real money at risk.
207
367
 
368
+ ## Scripting & Parallel Use
369
+
370
+ The `bunx kalshi-trading-bot-cli@latest …` form is great for one-off interactive use, but it has two gotchas when you script against it:
371
+
372
+ **1. Install chatter leaks into `--json` output.** Bun prints lines like `Resolving dependencies` and `Saved lockfile` to stdout *before* our CLI runs, which corrupts JSON pipelines.
373
+
374
+ **2. Parallel invocations race on the install cache.** Running multiple `bunx kalshi-trading-bot-cli@latest …` calls in parallel can fail with `Failed to link …: EEXIST` and `could not determine executable`. See [oven-sh/bun#12917](https://github.com/oven-sh/bun/issues/12917) for current upstream status — `bunx`'s ephemeral install path isn't covered by the `bun install` global-store fix, so the workarounds below are still the recommended path.
375
+
376
+ **Recommended pattern for scripts and agents:**
377
+
378
+ ```bash
379
+ # Install once globally — this is parallel-safe and emits no install chatter on subsequent runs
380
+ bun add -g kalshi-trading-bot-cli
381
+
382
+ # Then use the `kalshi` binary directly — fan out as much as you want
383
+ parallel -j 30 'kalshi analyze {} --json > {}.json' ::: KXBTC-26APR-B95000 KXETH-… …
384
+ ```
385
+
386
+ **If you must use `bunx`:**
387
+
388
+ ```bash
389
+ # --silent suppresses Bun's install chatter (keeps your CLI's stdout clean)
390
+ bunx --silent kalshi-trading-bot-cli@latest analyze KXBTC-26APR-B95000 --json
391
+
392
+ # For parallel bunx, pre-warm the cache serially first to dodge the link race
393
+ bunx --silent kalshi-trading-bot-cli@latest --version # one-shot, populates cache
394
+ parallel -j 30 'bunx --silent kalshi-trading-bot-cli@latest analyze {} --json' ::: KXBTC-… …
395
+ ```
396
+
397
+ Keep `@latest` if you want auto-update on every invocation; drop it after the first run if you've pinned a version and want speed.
398
+
208
399
  ## Agent Usage
209
400
 
210
401
  Every command supports `--json` for structured output, making the bot easy to orchestrate from scripts or AI agents.
211
402
 
212
403
  ```bash
213
404
  kalshi search crypto --json
405
+ kalshi similar KXBTC-26APR-B95000 --top-k 10 --json
406
+ kalshi clusters --ranked --timeframe 1y --min-return 0.2 --json
407
+ kalshi correlate KX-A KX-B KX-C --window-days 90 --json
408
+ kalshi basket build --category crypto -n 8 --max-per-cluster 2 --max-corr 0.6 --json
214
409
  kalshi analyze KXBTC-26APR-B95000 --json
215
410
  kalshi buy KXBTC-26APR-B95000 3 58 --json
216
411
  kalshi portfolio --json
@@ -263,6 +458,20 @@ fi
263
458
  kalshi portfolio --json
264
459
  ```
265
460
 
461
+ ### Server-side basket construction
462
+
463
+ For agents that want to skip the per-ticker analysis loop, the `basket build` command pushes universe selection, cluster diversification, correlation gating, and Kelly sizing server-side into a single HTTP call:
464
+
465
+ ```bash
466
+ # Pull Octagon's edge ranking, build a diversified 8-leg crypto basket sized for $1000
467
+ EDGE=$(kalshi search edge --category crypto --min-edge 5 --json | jq '.data.data')
468
+ PROBS=$(echo "$EDGE" | jq -r 'map("\(.market_ticker):\(.model_probability/100)") | join(",")')
469
+
470
+ kalshi basket build --category crypto --min-volume 10000 \
471
+ -n 8 --max-per-cluster 2 --max-corr 0.6 \
472
+ --bankroll 1000 --kelly 0.25 --probs "$PROBS" --json
473
+ ```
474
+
266
475
  The `watch --theme` command outputs NDJSON (one JSON object per scan cycle), suitable for streaming pipelines.
267
476
 
268
477
  ## Configuration
@@ -282,7 +491,7 @@ cp env.example ~/.kalshi-bot/.env
282
491
  | `KALSHI_API_KEY` | Kalshi API key ID |
283
492
  | `KALSHI_PRIVATE_KEY_FILE` | Path to your Kalshi RSA private key PEM file |
284
493
  | `OPENAI_API_KEY` | OpenAI API key (default model is GPT-5.4) |
285
- | `OCTAGON_API_KEY` | Octagon API key for deep research. Get one at [app.octagonai.co](https://app.octagonai.co) |
494
+ | `OCTAGON_API_KEY` | Octagon API key. Powers deep research (`analyze`), edge scanning (`search edge`), and the Octagon-backed discovery + basket commands (`search`, `similar`, `clusters`, `peers`, `correlate`, `basket`). Get one at [app.octagonai.co](https://app.octagonai.co) |
286
495
 
287
496
  **Optional:**
288
497
 
@@ -0,0 +1,159 @@
1
+ {
2
+ "_meta": {
3
+ "description": "Curated editorial themes for Kalshi prediction markets, ranked by Google search demand. Each theme maps to a list of Kalshi series tickers and carries a monthly search-volume estimate. Use `kalshi themes import data/themes_seo.json` to load. Volumes are point-in-time estimates; refresh quarterly.",
4
+ "version": "1.0",
5
+ "as_of": "2026-05-25"
6
+ },
7
+ "themes": [
8
+ {
9
+ "name": "AI Race Milestones",
10
+ "description": "Frontier model releases, AI infrastructure, training-compute and AGI predictions",
11
+ "search_volume": 138300000,
12
+ "series": ["KXLLM1", "KXIPOOPENAI", "KXAIREVIEW", "KXOAIANTH", "KXTECHRANKLISTAICODE", "KXH200CHINA", "KXGPT", "KXCLAUDE", "KXCODINGMODEL", "KXOAIHARDWARE", "KXCHAICUTS", "KXTOPAI", "KXBESTLLMCHINA"]
13
+ },
14
+ {
15
+ "name": "Elon Musk / Tesla / SpaceX",
16
+ "description": "Musk-empire markets: SpaceX IPO, Starship cadence, Tesla KPIs, Neuralink, wealth",
17
+ "search_volume": 8400000,
18
+ "series": ["KXIPOSPACEX", "KXSPACEXCOUNT", "KXSPACEXSTARSHIP", "KXMUSKWEALTH", "KXMUSKTRILLION", "KXTSLA", "KXIPOSTARLINK", "KXNEURALINKCOUNT", "KXTESLACAR", "KXSTARSHIPMARS", "KXSTARSHIPDOCK", "KXBLUESPACEX"]
19
+ },
20
+ {
21
+ "name": "Epstein / Celebrity Trials",
22
+ "description": "Massive SEO demand but thin Kalshi inventory — flag as STALE",
23
+ "search_volume": 4280000,
24
+ "series": ["KXEPSTEINLIST", "KXRELEASEMAXWELL", "KXEPSTEIN"]
25
+ },
26
+ {
27
+ "name": "Government Dysfunction",
28
+ "description": "House Speaker fights, filibuster reform, government shutdowns",
29
+ "search_volume": 3730000,
30
+ "series": ["KXNEXTSPEAKER", "KXFBUSTER", "KXNUMSHUTDOWNS"]
31
+ },
32
+ {
33
+ "name": "FDA / Pharma Approvals",
34
+ "description": "Drug approvals, psychedelic milestones, FDA commissioner pick",
35
+ "search_volume": 3070000,
36
+ "series": ["KXFDAAPPROVALPSYCHEDELIC", "KXFDANOM", "KXFDAAPPROVE", "KXFDARETATRUTIDE", "KXFDAANNOUNCE", "KXFDAAPPROVALDATECMPS", "KXFDAAPPROVALDATENTLA"]
37
+ },
38
+ {
39
+ "name": "Iran Escalation",
40
+ "description": "Hormuz traffic, US-Iran nuclear deal, oil & gas price ladders",
41
+ "search_volume": 1140000,
42
+ "series": ["KXHORMUZNORM", "KXUSAIRANAGREEMENT", "KXAAAGASM", "KXWTIW", "KXAAAGASW", "KXWTI", "KXAAAGASD", "KXBRENTW", "KXHORMUZWEEKLY", "KXBRENTMON", "KXWTIMINM", "KXAAAGASMAX"]
43
+ },
44
+ {
45
+ "name": "Gaza War Wraps",
46
+ "description": "Israel rate decisions, Netanyahu / next PM, post-war politics",
47
+ "search_volume": 1090000,
48
+ "series": ["KXCBDISRAEL", "KXNETANYAHUPARDON", "KXNEXTISRAELPM", "KXISRAELPM", "KXISLGAME", "KXKANYEISRAEL"]
49
+ },
50
+ {
51
+ "name": "Trump Survives Politically",
52
+ "description": "Approval ratings, midterm dynamics, 25th Amendment / impeachment",
53
+ "search_volume": 505000,
54
+ "series": ["KXVOTEHUBTRUMPUPDOWN", "KXMIDTERMMOV", "KXMIDTERMVOTETURN", "KXRUNBYMIDTERM", "KXTRUMPREMOVE", "KXMOCTRUMP25", "KXAMEND25", "KXLEAVEDUNN", "KXLEAVEMILLS"]
55
+ },
56
+ {
57
+ "name": "RFK Jr Changes Health",
58
+ "description": "Huge SEO but zero active Kalshi inventory — AVOID",
59
+ "search_volume": 422000,
60
+ "series": []
61
+ },
62
+ {
63
+ "name": "Nuclear Renaissance",
64
+ "description": "Reactor licenses, criticality milestones, data-center nuclear, fusion",
65
+ "search_volume": 382000,
66
+ "series": ["KXUSAIRANAGREEMENT", "KXCRITICALITY", "KXREACTOR", "KXDATACENTER", "KXFUSION"]
67
+ },
68
+ {
69
+ "name": "Fed Cuts Aggressively",
70
+ "description": "Fed meeting decisions, CPI prints, rate-cut paths, mortgage rates",
71
+ "search_volume": 340000,
72
+ "series": ["KXFEDDECISION", "KXFEDHIKE", "KXFED", "KXCPIYOY", "KXMORTGAGERATE", "KXCPI", "KXECONSTATCPIYOY", "KXLCPIMAXYOY", "KXCBDISRAEL", "KXRATECUT", "KXFOMCDISSENTCOUNT", "KXUKCPIYOY"]
73
+ },
74
+ {
75
+ "name": "SCOTUS Rulings",
76
+ "description": "Birthright citizenship, trans sports ban, tariff cases, justice changes",
77
+ "search_volume": 334000,
78
+ "series": ["KX14AMENDCASE", "KXWATSONRNC", "KXSCOTUSRESIGN", "KXTRANSGENDERSPORTSBAN", "KXTRUMPTARIFFHEAR", "KXSCOTUSN", "KXTRUMPSLAUGHTERVOTE", "KXTRUMPVSLAUGHTER", "KXSCOTUSCERT3RD", "KXSCOTUSMARIJUANAGUN"]
79
+ },
80
+ {
81
+ "name": "Housing / Mortgage Crisis",
82
+ "description": "Mortgage rates, new home sales, hedge-fund housing tax, starts",
83
+ "search_volume": 291000,
84
+ "series": ["KXMORTGAGERATE", "KXHFHOUSING", "KXNHSALES", "KXHOUSINGSTART", "KXEHSALES"]
85
+ },
86
+ {
87
+ "name": "US-China Decoupling",
88
+ "description": "Tariffs, chip export controls, Taiwan posture, PRC PMI",
89
+ "search_volume": 211000,
90
+ "series": ["KXTARIFFCHECKS", "KXNEWTARIFFS", "KXH200CHINA", "KXTAIWANLVL4", "KXTARIFFRATEPRC", "KXBEEFTARIFF", "KXTARIFFRATEINDIA", "KXF1CHINA", "KXBESTLLMCHINA", "KXCHNBSPMI", "KXTRUMPTARIFFHEAR", "KXRECOGROC"]
91
+ },
92
+ {
93
+ "name": "TikTok Ban",
94
+ "description": "Story died — high SEO with zero active inventory. AVOID",
95
+ "search_volume": 173000,
96
+ "series": []
97
+ },
98
+ {
99
+ "name": "Immigration Crackdown",
100
+ "description": "ICE funding, deportations, border encounters",
101
+ "search_volume": 163000,
102
+ "series": ["KXICEERO", "KXSWENCOUNTERS", "KXICERENAME", "KXDEPORTATIONS"]
103
+ },
104
+ {
105
+ "name": "Stock Market Crash / S&P",
106
+ "description": "S&P 500 / NASDAQ ranges, unemployment, NBER recession",
107
+ "search_volume": 132000,
108
+ "series": ["KXINXY", "KXINXMAXY", "KXNASDAQ100Y", "KXU3", "KXRECSSNBER", "KXINX", "KXNASDAQ100MAXY", "KXINXVSNDQ100", "KXSP500ADDQ", "KXU3MAX", "KXNASDAQ100POS", "KXUE"]
109
+ },
110
+ {
111
+ "name": "Crypto Regulation",
112
+ "description": "Single market, low volume — likely STALE",
113
+ "search_volume": 79000,
114
+ "series": ["KXCRYPTOCAPGAIN"]
115
+ },
116
+ {
117
+ "name": "Climate / EV Policy Reversal",
118
+ "description": "Truflation EV, IFO sentiment, climate-goal markets",
119
+ "search_volume": 60000,
120
+ "series": ["KXTRUEV", "KXDEIFO", "KXINDIACLIMATE", "KXUSCLIMATE", "KXEVSHARE", "KXEUCLIMATE"]
121
+ },
122
+ {
123
+ "name": "No 2026 Recession",
124
+ "description": "Unemployment + recession ladders — overlaps Stock Market Crash",
125
+ "search_volume": 48000,
126
+ "series": ["KXU3", "KXRECSSNBER", "KXU3MAX", "KXUE", "KXECONSTATU3", "KXNBERRECESSQ", "KXIMFRECESS", "KXBRAZILU"]
127
+ },
128
+ {
129
+ "name": "Russia-Ukraine Ends",
130
+ "description": "Zelensky/Putin summit, Russia rate decisions, post-war politics",
131
+ "search_volume": 44000,
132
+ "series": ["KXZELENSKYPUTIN", "KXCBDECISIONRUSSIA", "KXZELENSKYYOUT", "KXUKRAINEEU", "KXPUTINZELENSKYYLOCATION"]
133
+ },
134
+ {
135
+ "name": "Bitcoin Breakout",
136
+ "description": "Deepest crypto inventory: BTC/ETH price ladders, one-touch markets",
137
+ "search_volume": 29000,
138
+ "series": ["KXBTCD", "KXETHMAXY", "KXBTCY", "KXBTCMAX100", "KXETHD", "KXBTCMAX150", "KXBTCMAXMON", "KXBTCMINMON", "KXBTC", "KXBTCMINY", "KXETH", "KXCRYPTOSTRUCTURE"]
139
+ },
140
+ {
141
+ "name": "Trump Cabinet Shake-up",
142
+ "description": "Hegseth, McConnell, Trump firings, cabinet exits",
143
+ "search_volume": 22000,
144
+ "series": ["KXHEGSETHOUT", "KXCABOUT", "KXRETIREMM", "KXTRUMPRESIGN", "KXSCOTUSRESIGN", "KXTRYFIREPOWELL", "KXTRUMPFIRE", "KXVANCEPAKISTAN", "KXJIMMYKIMMELFIRED", "KXHEGSETHANNOUNCEOUT", "KXIMPEACHCABINET", "KXLEAVECONGRESS"]
145
+ },
146
+ {
147
+ "name": "Putin Out",
148
+ "description": "Thin inventory — overlaps Russia-Ukraine Ends",
149
+ "search_volume": 4700,
150
+ "series": ["KXZELENSKYPUTIN", "KXPUTINZELENSKYYLOCATION"]
151
+ },
152
+ {
153
+ "name": "Weed Rescheduled",
154
+ "description": "Thin overlap with FDA/SCOTUS themes",
155
+ "search_volume": 1600,
156
+ "series": ["KXFDAAPPROVALPSYCHEDELIC", "KXSCOTUSMARIJUANAGUN"]
157
+ }
158
+ ]
159
+ }
package/env.example CHANGED
@@ -24,8 +24,11 @@ GOOGLE_API_KEY=your-google-api-key
24
24
  XAI_API_KEY=your-xai-api-key
25
25
  OPENROUTER_API_KEY=your-openrouter-api-key
26
26
 
27
- # Octagon AI — required for /scan, /watch, and deep research
28
- # Get a key at https://app.octagonai.co
27
+ # Octagon AI — required for deep research (/analyze, /watch, /scan) AND for
28
+ # the Octagon-backed discovery + basket commands: /search, /search edge,
29
+ # /similar, /clusters, /peers, /correlate, /basket. Without a key, /search
30
+ # and /search edge fall back to the local SQLite cache; the others require
31
+ # the key. Get one at https://app.octagonai.co
29
32
  OCTAGON_API_KEY=your-octagon-api-key
30
33
 
31
34
  # ── Optional ─────────────────────────────────────────────────────────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kalshi-trading-bot-cli",
3
- "version": "2.1.3",
3
+ "version": "2.1.5",
4
4
  "description": "Kalshi Trading Bot CLI - AI-powered prediction market terminal.",
5
5
  "license": "MIT",
6
6
  "author": "Octagon AI, Inc.",
@@ -37,8 +37,6 @@ export function formatBacktestHuman(result: BacktestResult, opts?: FormatOpts):
37
37
  }
38
38
 
39
39
  // Unified scorecard
40
- lines.push(`VERDICT: ${result.verdict.summary}`);
41
- lines.push('');
42
40
  lines.push(` Events ${result.events_scored}`);
43
41
  lines.push(` Markets ${result.markets_resolved + result.markets_unresolved} (${result.markets_resolved} resolved, ${result.markets_unresolved} unresolved)`);
44
42
  lines.push('');
package/src/cli.ts CHANGED
@@ -354,6 +354,15 @@ export async function runCli(options?: { forceSetup?: boolean }) {
354
354
  const helpTopicCompletions = (typed: string): AutocompleteItem[] | null => {
355
355
  const topics = [
356
356
  { value: 'search', label: 'search', description: 'Discovery commands' },
357
+ { value: 'similar', label: 'similar', description: 'Semantic market search (Octagon)' },
358
+ { value: 'clusters', label: 'clusters', description: 'Browse thematic & behavioral clusters' },
359
+ { value: 'peers', label: 'peers', description: 'Cluster peers for a ticker' },
360
+ { value: 'correlate', label: 'correlate', description: 'Pairwise correlation matrix' },
361
+ { value: 'basket', label: 'basket', description: 'Build / backtest / size baskets' },
362
+ { value: 'events', label: 'events', description: 'Octagon events (event ↔ outcome ladder)' },
363
+ { value: 'series', label: 'series', description: 'Series rollup / NAV' },
364
+ { value: 'catalysts', label: 'catalysts', description: 'Upcoming market closes by week' },
365
+ { value: 'themes', label: 'themes', description: 'Editorial narrative registry + dashboard' },
357
366
  { value: 'portfolio', label: 'portfolio', description: 'Account state' },
358
367
  { value: 'analyze', label: 'analyze', description: 'Market analysis' },
359
368
  { value: 'watch', label: 'watch', description: 'Live monitoring' },
@@ -362,6 +371,7 @@ export async function runCli(options?: { forceSetup?: boolean }) {
362
371
  { value: 'cancel', label: 'cancel', description: 'Cancel an order' },
363
372
  { value: 'backtest', label: 'backtest', description: 'Model accuracy & edge scanner' },
364
373
  { value: 'help', label: 'help', description: 'Show help' },
374
+ { value: 'scripting', label: 'scripting', description: 'Tips for agents, pipelines, parallel use' },
365
375
  { value: 'setup', label: 'setup', description: 'Re-run setup wizard' },
366
376
  ];
367
377
  if (!typed) return topics;
@@ -394,6 +404,85 @@ export async function runCli(options?: { forceSetup?: boolean }) {
394
404
  const lower = typed.toLowerCase();
395
405
  return opts.filter(o => o.value.toLowerCase().includes(lower));
396
406
  }},
407
+ // Octagon Kalshi search/clusters/basket
408
+ { name: 'similar', description: 'Semantic market search by ticker or query', getArgumentCompletions: (typed: string): AutocompleteItem[] | null => {
409
+ const opts = [
410
+ { value: '<ticker>', label: '<ticker>', description: 'Anchor by ticker (no embedding call)' },
411
+ { value: '-q "query text"', label: '-q "query text"', description: 'Anchor by free-text (server-side embed)' },
412
+ { value: '--top-k 25', label: '--top-k 25', description: 'Number of neighbors (default 25)' },
413
+ { value: '--category crypto', label: '--category crypto', description: 'Filter by category' },
414
+ { value: '--min-volume 10000', label: '--min-volume 10000', description: '24h volume floor' },
415
+ ];
416
+ if (!typed) return opts;
417
+ return opts.filter(o => o.value.toLowerCase().includes(typed.toLowerCase()));
418
+ }},
419
+ { name: 'clusters', description: 'Browse thematic & behavioral clusters', getArgumentCompletions: (typed: string): AutocompleteItem[] | null => {
420
+ const opts = [
421
+ { value: '--label fed', label: '--label fed', description: 'Filter by label substring' },
422
+ { value: '--behavioral', label: '--behavioral', description: 'Behavioral clusters (30-day return vectors)' },
423
+ { value: '--ranked', label: '--ranked', description: 'Rank clusters by historical basket return' },
424
+ { value: '--ranked --timeframe 1y --min-return 0.20', label: '--ranked --timeframe 1y --min-return 0.20', description: 'Top-return baskets, 1y window' },
425
+ { value: '<cluster_id>', label: '<cluster_id>', description: 'List markets in a specific cluster' },
426
+ ];
427
+ if (!typed) return opts;
428
+ return opts.filter(o => o.value.toLowerCase().includes(typed.toLowerCase()));
429
+ }},
430
+ { name: 'peers', description: 'Find markets in the same cluster as a ticker', getArgumentCompletions: usageHint('<ticker> [--behavioral] [--limit N] [--show-cluster]', 'e.g. KXBTCD-26DEC31-T100000 --limit 20') },
431
+ { name: 'correlate', description: 'Pairwise correlation matrix (2-100 tickers)', getArgumentCompletions: usageHint('<ticker1> <ticker2> [...] [--window-days N]', 'e.g. KXA KXB KXC --window-days 90') },
432
+ { name: 'events', description: 'Octagon events — outcome ladder per event', getArgumentCompletions: usageHint('<event_ticker> | --category Politics | --min-volume 10000', 'e.g. KXFEDCHAIRNOM-29 to drill in') },
433
+ { name: 'series', description: 'Kalshi series rollup (24h vol, market count)', getArgumentCompletions: (typed: string): AutocompleteItem[] | null => {
434
+ const opts = [
435
+ { value: '<series_ticker>', label: '<series_ticker>', description: 'Drill into one series (e.g. KXBTCD)' },
436
+ { value: 'search <query>', label: 'search <query>', description: 'Keyword search rolled up by series' },
437
+ { value: 'candles <series_ticker> --timeframe 3m', label: 'candles <SERIES>', description: 'Series NAV basket' },
438
+ { value: '--min-volume 10000', label: '--min-volume 10000', description: 'Liquidity floor' },
439
+ { value: '--category Crypto', label: '--category Crypto', description: 'Filter by category' },
440
+ ];
441
+ if (!typed) return opts;
442
+ return opts.filter(o => o.value.toLowerCase().includes(typed.toLowerCase()));
443
+ }},
444
+ { name: 'catalysts', description: 'Upcoming market closes grouped by week', getArgumentCompletions: (typed: string): AutocompleteItem[] | null => {
445
+ const opts = [
446
+ { value: 'upcoming', label: 'upcoming', description: 'Next 30 days (default)' },
447
+ { value: 'upcoming --days 7', label: '--days 7', description: 'Next week' },
448
+ { value: 'upcoming --days 14 --min-volume 5000', label: '--days 14 --min-volume 5000', description: 'Two weeks, liquid only' },
449
+ { value: 'upcoming --category Politics', label: '--category Politics', description: 'By category' },
450
+ ];
451
+ if (!typed) return opts;
452
+ return opts.filter(o => o.value.toLowerCase().includes(typed.toLowerCase()));
453
+ }},
454
+ { name: 'themes', description: 'Editorial themes registry: import, report, audit, overlap', getArgumentCompletions: (typed: string): AutocompleteItem[] | null => {
455
+ const opts = [
456
+ { value: 'list', label: 'list', description: 'List registered themes' },
457
+ { value: 'import', label: 'import', description: 'Seed from data/themes_seo.json' },
458
+ { value: 'report', label: 'report', description: '25-theme dashboard with SEO + liquidity' },
459
+ { value: 'audit', label: 'audit', description: 'Flag STALE/NO_INVENTORY/THIN themes' },
460
+ { value: 'overlap', label: 'overlap', description: 'Cross-theme dedupe' },
461
+ { value: 'show <name>', label: 'show <name>', description: 'Drill into one theme' },
462
+ { value: 'create <name> --tickers KX-A,KX-B', label: 'create', description: 'Add a new theme' },
463
+ { value: 'add-series <name> KX-A,KX-B', label: 'add-series', description: 'Map series to a theme' },
464
+ { value: 'export themes.json', label: 'export', description: 'Save registry to JSON' },
465
+ ];
466
+ if (!typed) return opts;
467
+ return opts.filter(o => o.value.toLowerCase().includes(typed.toLowerCase()));
468
+ }},
469
+ { name: 'basket', description: 'Build, backtest, or size diversified baskets', getArgumentCompletions: (typed: string): AutocompleteItem[] | null => {
470
+ const opts = [
471
+ { value: 'build', label: 'build', description: 'Diversified basket builder (cluster + correlation caps)' },
472
+ { value: 'backtest', label: 'backtest', description: 'NAV + Sharpe/MaxDD/WinRate over basket history' },
473
+ { value: 'size', label: 'size', description: 'Fractional Kelly sizing for picked legs' },
474
+ { value: 'candles', label: 'candles', description: 'OHLC bars for a weighted basket NAV' },
475
+ { value: 'validate', label: 'validate', description: 'Sanity-check a proposed basket (corr, clusters, calendar)' },
476
+ { value: 'build --category crypto --min-volume 10000 -n 8 --max-per-cluster 2 --max-corr 0.6', label: 'build crypto basket', description: 'Build 8-leg crypto basket' },
477
+ { value: 'backtest --tickers KX-A,KX-B --timeframe 1y', label: 'backtest 1y', description: 'Backtest a basket over 1y' },
478
+ { value: 'backtest --theme "Iran Escalation" --timeframe 3m', label: 'backtest --theme', description: 'Backtest an editorial theme NAV' },
479
+ { value: 'candles --theme "Fed Cuts Aggressively" --timeframe 1y', label: 'candles --theme', description: 'NAV candles for a theme' },
480
+ { value: 'validate --theme "Iran Escalation" --bankroll 1000', label: 'validate --theme', description: 'Sanity-check theme basket' },
481
+ { value: 'size --auto-probs --theme "AI Race Milestones" --bankroll 1000 --kelly 0.25', label: 'size --auto-probs', description: 'Auto-fetch model edges + Kelly-size' },
482
+ ];
483
+ if (!typed) return opts;
484
+ return opts.filter(o => o.value.toLowerCase().includes(typed.toLowerCase()));
485
+ }},
397
486
  // Utility
398
487
  { name: 'help', description: 'Show help (/help <command> for details)', getArgumentCompletions: helpTopicCompletions },
399
488
  { name: 'model', description: 'Change LLM model/provider', getArgumentCompletions: usageHint('<provider:model>', 'e.g. anthropic:sonnet') },