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:

  1. 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.
  2. 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.
  3. 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.
  4. Risk controller. Enforces position limits, cancels all quotes if volatility spikes or the bot detects adverse selection, and implements a kill switch for emergencies.
  5. 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 CategoryTypical RangeNotes
Bot purchase (source code)$1,000-5,000Includes quoting engine and risk controls
VPS hosting (low-latency)$20-50/monthUS East Coast recommended
Kalshi trading fees$0.01-0.07/contractBoth sides of each trade
Minimum recommended capital$5,000 (single market)$15,000+ for multi-market
Expected monthly infrastructure$20-50Hosting 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.