pam ▸ docs/archive/2026-05-02-pam-hardening/diagnostics/overnight-diagnostic/MATCHER-REFACTOR-FINDINGS.md
updated 2026-04-18

Matcher refactor — findings and honest path forward

Date: 2026-04-18 Commits today: 0ebb6c1 (Kalshi v2 endpoint), 01d7c09 (candidate pool widening), 5a2e904 (config key typo).

What I found while trying to refactor the matcher

The matcher’s market_family equality gate at pairing.py:949 is technically blocking pairs, but fixing that alone won’t surface arbitrage. Going one layer deeper revealed three compounded problems that make Kalshi ↔ Polymarket strict arbitrage structurally hard today.

Problem 1: Products differ by design

Kalshi commodities are dense binary threshold ladders:

family=threshold  asset=None  comparator=above  threshold=74.25  "silver close > 74.25 on Apr 20"
family=threshold  asset=None  comparator=above  threshold=74.50  "silver close > 74.50 on Apr 20"
family=threshold  asset=None  comparator=above  threshold=74.75  "silver close > 74.75 on Apr 20"
... 40 contracts, 25-cent steps

Polymarket commodities are categorical bucket markets:

family=occurrence  asset=None  comparator=None  threshold=None  "What will Silver (SI) settle at in June?"

These are not equivalent pairs. The only way to arbitrage between them is to reconstruct a CDF from Kalshi’s threshold ladder and compare to Polymarket’s bucket distribution. That’s a new matching mode, not a tweak.

Problem 2: Normalizer quality

Scanning normalized contracts revealed two separate normalization bugs:

Both need dedicated fixes. Without asset on Kalshi, the matcher can’t build a cross-venue asset bridge even with relaxed family rules.

Problem 3: Overlap actually is thin

After the endpoint fix, 90-day in-horizon pools are 2,077 Kalshi × 2,380 Polymarket. Category breakdown:

Category Kalshi Polymarket
sports 13 975
politics 17 511
crypto 8 11
commodities 222 104
econ 15 37
entertainment 16 16
other 1786 726

The only category where both venues are non-trivially present is commodities — which hits Problem 1.

Honest conclusion

Strict Kalshi ↔ Polymarket arbitrage is a narrow-to-empty opportunity today without larger investment in (a) a CDF matching mode and (b) normalizer fixes. My earlier work and Codex’s endpoint fix were both correct — they just don’t unlock the downstream edge because the downstream is structurally limited.

Three viable paths forward, ranked

Kalshi has 40-contract silver ladders, 35-contract oil ladders, etc. On dense ladders, prices occasionally go out of monotonic order (e.g., “silver > 74.50” trades higher than “silver > 74.25”), which is a risk-free arb. The arbitrage/intra_venue/ code exists but intraarb.py is only wired to sample data — wire it to the catalog inventory and scan.

2. Fix normalizer, then CDF matcher (medium-term — biggest TAM if it works)

Two subprojects:

3. Reframe as thematic-divergence signal, not arbitrage (product pivot)

Accept that the venues don’t share propositions. Instead: identify same-asset same-window markets where Kalshi’s implied distribution diverges from Polymarket’s implied distribution by more than X. Surface those as signals for human discretion, not auto-arb.

My recommendation

Path 1 this week (intra-Kalshi) for near-term €-capital deployment under your overnight caps. Path 2 behind that if Path 1 produces any revenue at all — it proves the edge exists, worth the invest. Path 3 as a hedge if Path 2 takes too long.

What NOT to do

Do not keep tuning the cross-venue matcher thresholds. I tried. The remaining 0-result isn’t about thresholds; it’s about the underlying pools not sharing arbitrageable propositions.

Changes committed today

Net: the scanner now evaluates the right universe with the right tolerances. No pairs surface because the underlying products differ. That’s a product-reality answer, not a config answer.