Market-making is the most technically sophisticated prediction market strategy. Instead of betting on outcomes, you provide liquidity by posting buy and sell orders on both sides of the order book. Your profit comes from the spread between your bid and ask prices, collected over hundreds or thousands of trades.
On Kalshi, market-making is particularly attractive because many event contracts have wide spreads and thin order books — meaning there is room for a well-run bot to earn consistent returns by tightening spreads and capturing the difference.
This guide covers everything you need to evaluate and purchase a market-making bot for Kalshi, configure it properly, and avoid the pitfalls that blow up market makers.
What You Will Learn
- How market-making works on Kalshi’s order book
- What components a quality market-making bot must have
- How to evaluate a bot purchase and what to test before buying
- How to configure spreads, inventory limits, and volatility adjustments
- How to manage the unique risks of market-making
Prerequisites
- A funded Kalshi account with significant capital. Market-making requires more capital than other strategies. Minimum $5,000 for a single market, $15,000+ for multi-market operation. Complete KYC and API access setup via the Kalshi agents guide.
- Kalshi API access with WebSocket support. Market-making requires real-time order book data, not just REST polling. Your Kalshi account must support WebSocket connections.
- A VPS with low latency. Market-making is latency-sensitive. A VPS in the US East Coast (close to Kalshi’s servers) reduces round-trip time. Budget $20-50/month for a suitable instance.
- Understanding of order book mechanics. Know what bid, ask, spread, and fill mean. Read the Kalshi API guide and the prediction market API reference first.
Step-by-Step Instructions
Step 1: Understand What a Market-Making Bot Must Do
A production market-making bot has five core components. When evaluating a purchase, verify that the bot implements all five:
- Fair value estimator. The bot must estimate the true probability of each event to center its quotes correctly. This could be as simple as the mid-price of the order book or as complex as a proprietary model.
- Quoting engine. Posts bid and ask orders at calculated spreads around the fair value. Must handle order amendments (changing price/size) without canceling and re-placing, which is slower.
- Inventory manager. Tracks net position across all markets and adjusts quotes to reduce inventory risk. If the bot is long 100 contracts, it should widen the bid and tighten the ask to discourage further accumulation.
- Risk controller. Enforces position limits, cancels all quotes if volatility spikes or the bot detects adverse selection, and implements a kill switch for emergencies.
- Market data handler. Processes real-time order book updates via WebSocket. Must handle reconnections, stale data detection, and order book synchronization.
Step 2: Evaluate the Bot Before Purchase
Request these specifics from the seller:
- Source code access. For market-making bots, this is non-negotiable. You need to inspect the quoting logic, inventory management, and risk controls. A binary-only market-making bot is too risky.
- Live P&L history. At least 90 days of daily P&L on Kalshi markets, broken down by market category. Look for consistent small daily gains rather than large swings.
- Average spread captured after fees. Post-fee spread of $0.02-0.05 per contract is typical on Kalshi for prediction markets.
- Inventory distribution. How often does the bot end the day with significant directional positions? A well-managed bot should be near-flat by end of day most of the time.
- Adverse selection metrics. What percentage of fills come from informed traders moving the market against the bot? Lower is better.
- Recovery behavior. What happens when the bot crashes? Does it cancel all resting orders on restart? How does it reconcile positions?
Use the bot verification guide for additional evaluation criteria.
Step 3: Set Up Kalshi API with WebSocket
Market-making requires the WebSocket feed for real-time order book updates. Set up the connection:
import asyncio
import websockets
import json
import requests
KALSHI_API_BASE = "https://api.elections.kalshi.com/trade-api/v2"
KALSHI_WS_URL = "wss://api.elections.kalshi.com/trade-api/ws/v2"
class KalshiMarketMaker:
def __init__(self, api_key_id, api_secret):
self.api_key_id = api_key_id
self.api_secret = api_secret
self.token = None
self.orderbook = {}
self.positions = {}
def authenticate(self):
resp = requests.post(
f"{KALSHI_API_BASE}/login",
json={"email": self.api_key_id, "password": self.api_secret}
)
self.token = resp.json()["token"]
return self.token
async def connect_websocket(self, market_ticker):
"""Connect to Kalshi WebSocket for real-time orderbook updates."""
self.authenticate()
async with websockets.connect(
KALSHI_WS_URL,
extra_headers={"Authorization": f"Bearer {self.token}"}
) as ws:
# Subscribe to orderbook channel
subscribe_msg = {
"id": 1,
"cmd": "subscribe",
"params": {
"channels": ["orderbook_delta"],
"market_ticker": market_ticker
}
}
await ws.send(json.dumps(subscribe_msg))
async for message in ws:
data = json.loads(message)
await self.handle_orderbook_update(data)
async def handle_orderbook_update(self, data):
"""Process orderbook update and adjust quotes."""
# Update local orderbook state
if data.get("type") == "orderbook_snapshot":
self.orderbook = data["msg"]
elif data.get("type") == "orderbook_delta":
self.apply_delta(data["msg"])
# Recalculate fair value and requote
fair_value = self.estimate_fair_value()
await self.update_quotes(fair_value)
Step 4: Configure Spread and Inventory Parameters
The two most important configuration decisions for a market-making bot:
# mm_config.yaml
quoting:
base_spread_cents: 4 # $0.04 base spread (bid to ask)
min_spread_cents: 2 # never tighten below $0.02
max_spread_cents: 15 # widen to $0.15 in volatile conditions
quote_size_contracts: 50 # contracts per side
levels: 3 # number of price levels to quote
inventory:
max_position_contracts: 500 # hard limit per market
target_position: 0 # aim for flat
skew_per_100_contracts: 1 # skew quotes $0.01 per 100 contracts of inventory
# If long 200 contracts, bid shifts down $0.02, ask shifts down $0.02
# This encourages sells and discourages buys
volatility:
lookback_minutes: 30 # window for volatility calculation
volatility_spread_multiplier: 2.0 # widen spread by 2x vol
max_volatility_pause: 0.10 # pause quoting if 30min vol > 10%
markets:
tickers:
- "PRESIDENT-2028-DEM"
- "FED-RATE-MAR26"
- "GDP-Q1-2026"
min_daily_volume: 10000
min_open_interest: 5000
Key tuning guidance:
- Base spread should exceed your total fees per round-trip. On Kalshi, with fees up to $0.07 per contract side, your minimum profitable spread is roughly $0.03-0.04.
- Inventory skew is critical. Without it, the bot accumulates large directional positions during trending markets. The skew biases quotes to reduce inventory back toward zero.
- Volatility adjustment widens spreads during fast-moving markets to protect against adverse selection. Without this, informed traders will pick off your stale quotes.
Step 5: Implement and Test Risk Controls
Before going live, verify these risk controls function correctly:
class RiskManager:
def __init__(self, config):
self.max_position = config["max_position_contracts"]
self.max_daily_loss = config["max_daily_loss_usd"]
self.daily_pnl = 0.0
self.kill_switch_active = False
def check_new_order(self, side, size, price, current_position):
"""Validate order against risk limits before submission."""
if self.kill_switch_active:
return False, "Kill switch active — all trading halted"
projected_position = current_position + (size if side == "buy" else -size)
if abs(projected_position) > self.max_position:
return False, f"Position limit: {abs(projected_position)} > {self.max_position}"
if self.daily_pnl < -self.max_daily_loss:
self.kill_switch_active = True
return False, f"Daily loss limit breached: ${self.daily_pnl:.2f}"
return True, "OK"
def activate_kill_switch(self):
"""Emergency: cancel all orders and halt trading."""
self.kill_switch_active = True
# Cancel all resting orders immediately
self.cancel_all_orders()
print("KILL SWITCH ACTIVATED — all orders canceled, trading halted")
Test the kill switch in paper-trading mode before risking real capital. Simulate scenarios: what happens if the bot loses connectivity? What if a market moves 20% in one minute? What if the API returns errors?
Step 6: Paper-Trade for Two to Four Weeks
Market-making requires a longer paper-trading period than other strategies because you need to observe behavior across different market conditions:
- Low volatility days. Does the bot generate consistent small profits from spread capture?
- High volatility events. Does the bot widen spreads and manage inventory correctly when news breaks?
- Thin market conditions. Does the bot handle situations where it is the only liquidity provider?
Track daily: spread captured, inventory at end of day, number of adverse selection events, and simulated P&L.
Step 7: Go Live with Conservative Parameters
Start with wider spreads and smaller position limits than your paper-trade configuration. Scale in over 4-6 weeks:
- Week 1-2: 50% of target position size, 150% of target spread width
- Week 3-4: 75% of target position size, 125% of spread width
- Week 5-6: Full position size, target spreads
Monitor daily during the scale-in period. If the bot experiences unexpected losses or inventory blowups at any stage, pause and investigate before continuing to scale.
Common Mistakes and How to Avoid Them
No inventory management. The single most common failure mode. Without inventory skew, the bot accumulates massive directional positions during trending markets and gives back all spread profits (and more) when the market moves against it.
Quoting through events. Some Kalshi markets have binary resolution events (election results, economic data releases). Quoting through these events is extremely dangerous because informed traders will pick off your quotes. Pause quoting 1-2 hours before known resolution events.
Ignoring latency. If your bot takes 500ms to update quotes but the market moves in 100ms, you are consistently giving away edge to faster participants. Measure and optimize your quote update latency.
Not testing the kill switch. Every market maker blows up eventually. The question is whether your kill switch works when it happens. Test it in paper mode, and test it when the bot is live on small size.
Under-capitalizing. Market-making with $1,000 means your position limits are so small that individual fills move your inventory to the limit immediately. You need 3-5x your expected daily volume in available capital.
Cost Breakdown
| Cost Category | Typical Range | Notes |
|---|---|---|
| Bot purchase (source code) | $1,000-5,000 | Includes quoting engine and risk controls |
| VPS hosting (low-latency) | $20-50/month | US East Coast recommended |
| Kalshi trading fees | $0.01-0.07/contract | Both sides of each trade |
| Minimum recommended capital | $5,000 (single market) | $15,000+ for multi-market |
| Expected monthly infrastructure | $20-50 | Hosting only after purchase |
Market-making bot purchases are the most expensive category because the code is more complex and the quoting/risk logic is proprietary. Expect to pay 2-5x what an arbitrage bot costs. The trade-off is that market-making scales better with capital and can produce more consistent returns if managed well.
Next Steps and Related Guides
- How to Set Up a Trading Bot on Kalshi — General Kalshi bot setup if you need API and account fundamentals first.
- Kalshi API Guide — Complete API documentation for Kalshi including WebSocket reference.
- Prediction Market Bot Pricing — Compare market-making bot costs against other strategy types.
- Prediction Market Bot Verification — Full evaluation checklist for any bot purchase.
- Agent Betting Stack — How market-making bots fit into the four-layer agent architecture.
- Best Prediction Market Bots — Rankings including market-making tools.