Skip to content

feat: add Kalshi support with grammar-based ticker parser (#19)#41

Merged
e35ventura merged 2 commits intoentrius:mainfrom
MkDev11:feat/issue-19-kalshi-support
Mar 13, 2026
Merged

feat: add Kalshi support with grammar-based ticker parser (#19)#41
e35ventura merged 2 commits intoentrius:mainfrom
MkDev11:feat/issue-19-kalshi-support

Conversation

@MkDev11
Copy link
Contributor

@MkDev11 MkDev11 commented Mar 13, 2026

Summary

Add Kalshi support to the Synth Overlay Chrome extension. Traders browsing Kalshi markets now see the same edge analysis, confidence scoring, and signal data they get on Polymarket — the side panel activates automatically on kalshi.com, matches the market to a Synth forecast, and displays the edge between Synth's probability and Kalshi's price.

Key architectural decisions

  1. Grammar-based Kalshi ticker parser — Instead of maintaining a 25+ entry series→asset lookup map and 3 separate series→type frozensets, Kalshi tickers are structurally decomposed using their grammar: KX{asset_code}{market_suffix}-{date}-{strike}. Asset and market type are derived from the ticker structure, not looked up. Adding a new Kalshi asset requires 1 entry in _KX_CODES — no series sets to update.

  2. Rule-chain market type inference — Polymarket market type detection uses ordered (matcher, type) tuples instead of if/else chains. Rules are declarative data, not control flow.

  3. Config-driven platform definitions — Each platform is a data dict with domain, URL patterns, detection heuristics, and resolution strategy. A generic engine processes any config. Adding a third platform = adding a config entry + a resolver function — zero changes to existing platform code.

  4. Structured ResolveResult — The resolve() pipeline returns typed error codes (invalid_input, unknown_platform, unsupported_market, normalize_failed) so the server produces actionable 400/404 responses instead of generic error strings. New /api/platforms endpoint provides runtime introspection of registered platforms, supported assets, and market types.

  5. Centralized JS platform config (platforms.js) — Single source of truth for platform origins, labels, URL templates, and tab search patterns. All extension scripts reference this instead of hard-coding platform strings.

Files changed

File Change
matcher.py Complete rewrite: grammar-based Kalshi parser, rule-chain Polymarket inference, config-driven platform dicts, ResolveResult dataclass, PlatformRegistry
server.py Structured error responses with error codes, /api/platforms introspection endpoint, registry.resolve() integration
extension/content.js Kalshi platform detection, slugFromKalshi() (last-segment extraction), 3-pass Kalshi price scraper (trading panel → fallback DOM → order book pattern), scanKalshiMarketLinks() for browse pages, context invalidation guards
extension/background.js Platform-aware isSupportedUrl() via SynthPlatforms, watchlist polling passes &platform= param, notification click opens correct platform URL from stored platform field
extension/sidepanel.js Dynamic "Poly"/"Kalshi" column labels, fetchEdge() sends platform param, suggested market buttons on Kalshi browse pages
extension/sidepanel.html Dynamic market label span, platforms.js script import
extension/alerts.js Watchlist schema stores platform field, addToWatchlist() accepts platform, formatMarketLabel() is platform-aware
extension/manifest.json kalshi.com and *.kalshi.com in host_permissions and content_scripts.matches, version bump to 1.4.0
extension/platforms.js New file — centralized platform configuration for JS extension code
tests/test_matcher.py 74 tests: Polymarket + Kalshi matching, grammar parser, ResolveResult structured errors, registry introspection, custom platform registration
tests/test_server.py 22 new tests: Kalshi daily/ETH/SOL/15min/range/live-price/auto-detect/multi-segment-URL, /api/platforms endpoint, structured error codes, unknown platform handling
README.md Updated: Kalshi support docs, platform architecture, Kalshi market matching explanation, verification URLs

Kalshi price scraping strategy

The content script uses a multi-strategy approach to scrape live Yes/No prices from Kalshi's DOM:

  • Pass 1 (trading panel priority) — Scans elements inside the trading panel only (detected by walking ancestors for Buy/Sell/Amount container). Ensures the selected contract's price is used on multi-strike pages.
  • Pass 2 (fallback) — General DOM scan with standalone price leaf-walk (parent context).
  • Pass 3 (order book) — Matches "Best Yes: $0.52" / "Best Yes: 52¢" patterns.
  • Inference — If only one side found, the other is inferred as 1 - found.

Grammar parser example

KXBTCD-26MAR1317-T70499.99
│ │  ││                │
│ │  │└─ suffix "d" → daily
│ │  └── asset code "btc" → BTC
│ └───── prefix "kx" → Kalshi
└─────── date + strike (stripped during normalization)

Result: asset=BTC, market_type=daily, platform=kalshi

Adding a new asset (e.g. LINK) → _KX_CODES["link"] = "LINK"kxlinkd, kxlink, kxlink15m all auto-work.

Related Issues

Fixes #19

Type of Change

  • Bug fix
  • Improvement to existing tool
  • Documentation
  • Other (describe below)

Testing

  • Tested against Synth API
  • Manually tested
  • Tests added/updated

213 tests passing (74 matcher + 139 server):

source .venv/bin/activate
PYTHONPATH="/path/to/venth:$PYTHONPATH" python -m pytest tools/synth-overlay/tests/ -v

Test coverage includes:

  • Polymarket slug normalization, asset extraction, market type inference (all existing tests preserved)
  • Kalshi ticker grammar parsing (daily, range, 15min, contract with -T/-B suffixes)
  • Kalshi URL normalization (single-segment, multi-segment, www subdomain)
  • Platform detection and disambiguation (Polymarket slugs with "btc-" prefix not misrouted to Kalshi)
  • Legacy ticker handling (btcd, btcd-b, eth, ethd) with collision avoidance
  • Extended asset coverage (XRP, DOGE, kxspy, btcd-b)
  • ResolveResult structured diagnostics (success, invalid input, unknown platform, unsupported market)
  • PlatformRegistry introspection and custom platform registration
  • Server: Kalshi daily/ETH/SOL/15min/range/auto-detect/live-price/multi-segment endpoints
  • Server: /api/platforms endpoint, structured error codes in 400/404 responses

Checklist

  • Code follows project style guidelines
  • Self-review completed
  • Changes are documented (if applicable)

Demo Video

screen-capture_a5RZ2H7W.mp4

Implements issue entrius#19 — Synth Overlay now works on Kalshi pages.

Architecture:
- Grammar-based Kalshi ticker parser: derives asset and market type
  from ticker structure (KX + asset_code + suffix), not lookup tables.
  Adding a new Kalshi asset = 1 entry in _KX_CODES.
- Rule-chain Polymarket inference: ordered (matcher, type) tuples
  replace if/else chains.
- Config-driven platform definitions: data dicts, not classes.
- Structured ResolveResult with typed error codes for actionable
  API error responses.
- /api/platforms introspection endpoint.
- platforms.js: centralized JS platform config.

Extension changes:
- content.js: Kalshi price scraper (3-pass: trading panel, fallback
  DOM, order book pattern), slug extraction, context invalidation.
- background.js: platform-aware notifications and watchlist polling.
- sidepanel.js/html: dynamic Kalshi/Poly labels, suggested markets.
- alerts.js: watchlist stores platform field.
- manifest.json: Kalshi permissions.

Tests: 213 passing (74 matcher + 139 server).
@MkDev11 MkDev11 force-pushed the feat/issue-19-kalshi-support branch from 7f4a5f4 to 8cbd185 Compare March 13, 2026 06:15
@MkDev11 MkDev11 changed the title feat(synth-overlay): add Kalshi support (closes #19) feat: add Kalshi support with grammar-based ticker parser (#19) Mar 13, 2026
@e35ventura e35ventura merged commit 4cf35d4 into entrius:main Mar 13, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Synth Overlay: Kalshi Support

2 participants