pam ▸ docs/archive/2026-05-02-pam-hardening/diagnostics/overnight-diagnostic/KALSHI-FIX-RESULTS.md
updated 2026-04-17

Kalshi endpoint fix — results

Date: 2026-04-17 Commit: 0ebb6c1 Continues from: Codex handoff (uncommitted work on execution/kalshi_api.py, watchers/catalog_inventory.py, tests/test_kalshi_api.py).

What changed

  1. Kalshi API path: /v1/events/trade-api/v2/markets with cursor pagination.
  2. Catalog inventory: sync_kalshi_once pulls from /markets directly instead of flattening events.
  3. Tests: 3 new kalshi_api tests, all pass.
  4. Matcher config (pairing block): added to config.yaml with loosened defaults — require_exact_threshold: false, min_question_similarity: 0.70, expiry_tolerance_sec: 86400 (was 90 seconds), near_pair_expiry_tolerance_sec: 604800.

What the resync revealed

Scanner funnel (current state)

Kalshi raw inventory:  216,702
→ normalized:            2,573
→ in 90d horizon:        2,077  ← passed to scanner

Polymarket normalized:   7,285
→ in 90d horizon:        2,380
→ candidate pool:          216  ← scanner narrows here (load_candidate_contracts)

Matcher output:              0 exact, 0 near-pair

Where the remaining leak is

The scanner calls load_candidate_contracts which narrows Polymarket from 2,380 → 216 by requiring (market_family, token) intersection with Kalshi source contracts. This kills the commodities crossover I measured:

Candidate examples from Kalshi: KXGOLDD / KXSILVERD / KXBRENTD — daily close-price markets (family=”daily_settle” or similar). Polymarket likely has “Gold above $X by Y” style (family=”threshold”). Same asset, different market_family, so the intersection yields empty.

The fix after this one

Either:

  1. Widen the candidate pool — intersect on token only, not (family, token) — let the matcher decide.
  2. Add an asset-based path — if both sides share an asset tag (gold, silver, oil, btc) plus an in-horizon window, include them regardless of family. Matcher then filters on price-axis compatibility (comparator + threshold).
  3. Build a “thematic divergence” workflow — the real edge on Kalshi/Polymarket isn’t strict arbitrage (markets don’t line up exactly); it’s identifying same-asset same-window bets where pricing diverges meaningfully, with a human-in-the-loop validation.

My recommendation: start with #1 (one-line change in load_candidate_contracts) and re-run the scan. If that produces usable near-pair candidates, we ship. If still nothing, #2 is next, and #3 is the reframe.

Ready-to-trade state

Zero tradeable opportunities produced today. €50/venue caps you authorized remain unused. Placing blind trades without validated edge is -EV; holding.

Suggested next step

Attempt the one-line candidate-pool widening in load_candidate_contracts (drop family constraint, keep token). ~10-minute fix, one re-scan, definitive answer on whether this is a pre-filter problem or a deeper matcher problem.