predtools-arb — Cross-platform arbitrage framework
Scaffold for cross-platform arbitrage between Polymarket and Kalshi. Boilerplate only, CLOB v2 client, lock file, logging, stats, 60s main loop. No trading logic implemented yet, you bring the signal.
| Strategy type | Pair arbitrage |
|---|---|
| Asset | Multi-market |
| Timeframe | Event-driven |
| Market type | Cross-platform |
| Minimum capital | $100 |
| Dependencies | @polymarket/clob-client, ethers |
What it does
predtools-arb is a starter kit, not a finished bot. It bundles everything you need to start running a cross-platform arbitrage strategy between Polymarket and Kalshi: argument parsing, secrets loading, CLOB v2 client wiring, lock-file singleton, structured logging, stats persistence, a 60-second main loop, and a heartbeat. The strategy file itself is empty. You write the edge.
The edge
Cross-platform arb between Polymarket and Kalshi is one of the few documented edges that does not decay quickly. The two venues quote the same political and macro events with materially different prices because their user bases barely overlap (US-only KYC on Kalshi vs anyone-with-a-wallet on Polymarket). What kills most attempts is plumbing: connecting both APIs, handling order rejection, persisting state across restarts. predtools-arb gives you all of that so you can focus on the signal.
How it works
The scaffold is organized into seven concerns, each isolated so you can replace or extend them independently:
- Args (
getArg(name, def)): minimal CLI parser, no library - Secrets: reads
secrets.jsonfor Polymarket wallet + CLOB credentials (Kalshi credentials TBD by you) - CLOB v2 client: dynamic import of
@polymarket/clob-client-v2, wired with your wallet + API key triplet - Lock file in
data/arb.lock: prevents two instances on the same wallet - Logging in
data/arb.log: Paris-timezone timestamps, identical format to every other bot in the suite - Stats persistence: writes
data/arb-stats.jsonper cycle so PnL survives restarts - Main loop: 60s
SCAN_INTERVAL_MS, heartbeat every cycle, your trading code lives in the marked block
Sample output
[25/05/2026, 15:57:00] Arb Scaffold (SIM $100) [25/05/2026, 15:57:00] SCAFFOLD — no trading logic implemented [25/05/2026, 15:57:00] [25/05/2026, 15:58:00] Heartbeat | Bal: $100.00 | PnL: $0.00 [25/05/2026, 15:58:00] SCAFFOLD — no trading logic | Bal: $100.00
Design targets
The scaffold has no trading logic and therefore no win rate, no PnL, no fee math to break even on. What it does guarantee:
- One process per wallet (lock file)
- Persistent state across restarts (
data/arb-stats.json) - Graceful shutdown on SIGINT (releases lock, flushes stats)
- 60-second cycle with try/catch on the whole loop so a single bad fetch can't crash the bot
FAQ
Why is this priced at $19 if it does no trading?
Because the boilerplate is the part most people get wrong. The CLOB v2 client, the ethers v6 signTypedData shim, the lock-file pattern, the relay-friendly stats file, the heartbeat watchdog: all production-tested. You save the 2-3 days it takes to assemble those from scratch.
Can I bolt my own Kalshi client into it?
Yes. The main loop has a marked block where Kalshi calls slot in alongside the existing Polymarket client. Add your Kalshi credentials to secrets.json, npm install kalshi-trading-api, and your code is the only thing missing.
What's included
others/arb.js(the scaffold)polymarket-limits.js(fee + tick constants)- README with a worked example of dropping in a single-leg trigger
Configuration
| Flag | Default | Description |
|---|---|---|
| --live | — | Intended for live mode (no trading logic yet). |
| --sim-balance 100 | 100 | Starting balance in dry-run mode (USD). |