High-profit-focused Bitcoin 15-minute arbitrage bot for Kalshi + Polymarket. It watches both venues, detects cross-market mispricing, and executes paired entries when the edge is inside your configured band.
- Built for frequent BTC 15m opportunities, not random discretionary entries.
- Focuses on edge quality first (
ARB_SUM_THRESHOLD) and then scales with size. - Keeps execution disciplined with one-leg-per-market guards.
- Writes clear logs for fast parameter optimization.
The arb engine continuously computes:
sumUp = Kalshi UP ask + Polymarket DOWN asksumDown = Kalshi DOWN ask + Polymarket UP ask
A signal is tradable when:
sum >= ARB_SUM_LOWsum < ARB_SUM_THRESHOLD
When valid, the bot places one order per venue for that leg. This is a spread-capture approach designed to accumulate small edges repeatedly.
Kalshi UP ask 0.43
Polymarket DOWN ask 0.45
sumUp 0.88
If ARB_SUM_THRESHOLD=0.92,
0.88 is an executable signal.
- Start dual monitor loop.
- Pull Kalshi + Polymarket BTC 15m prices.
- Compute
sumUpandsumDown. - Check range
[ARB_SUM_LOW, ARB_SUM_THRESHOLD). - Add
ARB_PRICE_BUFFERfor fill reliability. - Execute Kalshi + Polymarket leg.
- Mark leg done for this market to avoid duplicate firing.
- Continue monitoring the next dislocation.
- Dual venue monitor for Kalshi + Polymarket in one process.
- High-profit signal gating via threshold and lower-bound filters.
- Paired order placement (Kalshi + Polymarket) per valid leg.
- Dry-run safety for no-risk testing.
- Quarter-hour aligned logs for easier analytics.
- Single-process lock to prevent parallel monitor conflicts.
- Standalone order scripts for isolated testing of each venue.
npm install
cp .env.sample .envKalshi:
KALSHI_API_KEYKALSHI_PRIVATE_KEY_PATHorKALSHI_PRIVATE_KEY_PEM
Polymarket (required for full paired arbitrage):
POLYMARKET_PRIVATE_KEYPOLYMARKET_PROXY
ARB_DRY_RUN=true npm startARB_DRY_RUN=false npm start| Command | Description |
|---|---|
npm start |
Run dual monitor + cross-venue arb loop |
npm run balance |
Check Kalshi portfolio balance |
npm run kalshi-single-order |
Place one Kalshi BTC 15m limit order |
npm run poly-single-order |
Place one Polymarket BTC 15m order |
npm run build |
Compile TypeScript |
Use .env for all runtime controls.
| Variable | Purpose | Typical |
|---|---|---|
KALSHI_API_KEY |
API key | required |
KALSHI_PRIVATE_KEY_PATH |
RSA PEM file path | recommended |
KALSHI_PRIVATE_KEY_PEM |
Inline PEM | optional |
KALSHI_DEMO |
Demo/prod switch | false |
KALSHI_BASE_PATH |
Manual endpoint override | optional |
| Variable | Purpose | Typical |
|---|---|---|
KALSHI_BOT_SIDE |
yes or no |
yes |
KALSHI_BOT_PRICE_CENTS |
Limit in cents | 50 |
KALSHI_BOT_CONTRACTS |
Contracts | 1 |
KALSHI_BOT_MAX_MARKETS |
Market scan count | 1 |
KALSHI_BOT_DRY_RUN |
Dry-run mode | true |
| Variable | Purpose | Typical |
|---|---|---|
KALSHI_MONITOR_INTERVAL_MS |
Poll interval | 200 |
KALSHI_MONITOR_TICKER |
Force ticker | empty |
KALSHI_MONITOR_NO_RESTART |
Disable quarter-hour restart | false |
| Variable | Purpose | Typical |
|---|---|---|
ARB_SUM_THRESHOLD |
Max combined price for entry | 0.92 |
ARB_SUM_LOW |
Min combined price sanity bound | 0.75 |
ARB_PRICE_BUFFER |
Price padding for fill chance | 0.01 |
ARB_SIZE |
Size per leg | 1 |
ARB_DRY_RUN |
Execute or only log | true |
| Variable | Purpose | Typical |
|---|---|---|
POLYMARKET_PRIVATE_KEY |
Wallet private key | required for live |
POLYMARKET_PROXY |
Proxy/funder address | required for live |
POLYMARKET_CLOB_URL |
CLOB endpoint | default set |
POLYMARKET_CHAIN_ID |
Chain id | 137 |
POLYMARKET_TICK_SIZE |
Tick precision | 0.01 |
POLYMARKET_NEG_RISK |
Neg-risk toggle | optional |
POLYMARKET_CREDENTIAL_PATH |
API credential json path | optional |
POLYMARKET_MIN_USD |
Min notional check | 1 |
POLYMARKET_SIGNATURE_TYPE |
Signature mode | auto |
- Run dry mode across multiple sessions.
- Count opportunities per quarter-hour.
- Measure how often signals appear under your threshold.
- Start with
ARB_SUM_THRESHOLD=0.92. - Tighten to improve edge quality if fills are expensive.
- Keep
ARB_SUM_LOWas a sanity filter against bad ticks.
- Tune
ARB_PRICE_BUFFERcarefully:- too low: missed entries,
- too high: edge erosion.
- Keep poll interval responsive but stable.
- Increase
ARB_SIZEgradually. - Track reject/fail rates while scaling.
- Roll back if execution quality drops.
The monitor writes:
- live console logs,
logs/monitor_YYYY-MM-DD_HH-{00|15|30|45}.log.
Important patterns to review:
[Arb] Opportunityfrequency,- order error rates by venue,
- signal quality by market slot,
- fill consistency after buffer adjustments.
- Dry-run support before live deployment.
- One monitor instance lock file.
- One trade leg per market guard.
- Bounded entry band with upper/lower limits.
- Polymarket minimum notional validation.
.
├── src/
│ ├── monitor-run.ts
│ ├── monitor.ts
│ ├── arb.ts
│ ├── bot.ts
│ ├── polymarket-order.ts
│ ├── polymarket-monitor.ts
│ └── config.ts
├── image/
│ ├── banner.jpg
│ └── result.png
├── .env.sample
└── README.md
No. This is an execution framework, not a guarantee. Slippage, latency, liquidity, and outages can reduce or erase expected edge.
They provide frequent recurring cycles that are suitable for repeated cross-venue monitoring and signal capture.
You can, but the full arbitrage model requires both Kalshi and Polymarket legs.
Use at your own risk. Trading prediction markets can result in financial loss. You are responsible for key management, configuration, and all live-trading decisions.

