How to Build a Kalshi Trading Bot with Python (2026 Guide)
Kalshi is the first regulated prediction market in the United States — a CFTC-registered exchange where you can trade event contracts on everything from elections to weather to economic indicators. This guide shows you how to build a fully working Python trading bot that connects to Kalshi, fetches market data, places orders, and runs unattended 24/7.
What you'll build
1. Prerequisites & account setup
Before writing any code, you'll need three things:
- A Kalshi account. Sign up at kalshi.com. US residents only; KYC required.
- Python 3.10+ installed locally. We'll use
requestsfor HTTP and the built-incryptographylibrary for signing. - API credentials. Go to Profile → API Keys in your Kalshi dashboard and generate a key. You'll get an
access-keystring and download a private key file (private_key.pem). Guard this file like a password — it signs every order.
One-time tip: Kalshi's API uses RSA-PSS signed requests, not bearer tokens. This is more secure but adds a small wrinkle compared to most REST APIs. Don't worry — the code below handles it for you.
2. Authenticating with the Kalshi API
Every authenticated Kalshi request needs four headers:
KALSHI-ACCESS-KEY— your access key stringKALSHI-ACCESS-TIMESTAMP— Unix millisecondsKALSHI-ACCESS-SIGNATURE— base64 RSA-PSS signature oftimestamp + method + pathContent-Type: application/json
Here's a minimal, copy-paste auth helper:
# kalshi_client.py
import time, base64
from pathlib import Path
import requests
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
BASE_URL = "https://api.elections.kalshi.com/trade-api/v2"
class KalshiClient:
def __init__(self, access_key, private_key_path):
self.access_key = access_key
self.private_key = serialization.load_pem_private_key(
Path(private_key_path).read_bytes(), password=None
)
def _sign(self, method, path):
ts = str(int(time.time() * 1000))
msg = (ts + method + path).encode()
sig = self.private_key.sign(
msg,
padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.DIGEST_LENGTH),
hashes.SHA256(),
)
return ts, base64.b64encode(sig).decode()
def _headers(self, method, path):
ts, sig = self._sign(method, path)
return {
"KALSHI-ACCESS-KEY": self.access_key,
"KALSHI-ACCESS-TIMESTAMP": ts,
"KALSHI-ACCESS-SIGNATURE": sig,
"Content-Type": "application/json",
}
def get(self, path, params=None):
r = requests.get(BASE_URL + path, headers=self._headers("GET", path), params=params, timeout=10)
r.raise_for_status()
return r.json()
def post(self, path, body):
r = requests.post(BASE_URL + path, headers=self._headers("POST", path), json=body, timeout=10)
r.raise_for_status()
return r.json()
Save that as kalshi_client.py. Test it with a quick balance check:
from kalshi_client import KalshiClient
client = KalshiClient(
access_key="YOUR_ACCESS_KEY",
private_key_path="./private_key.pem"
)
print(client.get("/portfolio/balance"))
# {'balance': 100000, 'payout': 0} # cents
3. Fetching market data
Markets on Kalshi are organized as events (a question) containing one or more markets (the YES/NO contracts you actually trade). Each market has a unique ticker.
# List open markets in the weather series
markets = client.get("/markets", params={"series_ticker": "KXHIGHNY", "status": "open"})
for m in markets["markets"][:5]:
print(f"{m['ticker']:30} YES bid {m['yes_bid']:>3} YES ask {m['yes_ask']:>3}")
# Get a specific market's full orderbook
ob = client.get("/markets/KXHIGHNY-26MAY20-T75/orderbook")
print(ob)
Prices on Kalshi are in cents (1–99), representing the implied probability of YES. A market at 73¢ implies the market thinks YES has a 73% chance.
4. Your first trading bot — full working code
Here's a complete, runnable bot that monitors a weather market and buys YES when the price drops below your threshold. It's intentionally simple — the goal is to see the full loop end to end.
# my_first_bot.py
import time
from kalshi_client import KalshiClient
ACCESS_KEY = "YOUR_ACCESS_KEY"
PRIVATE_KEY_PATH = "./private_key.pem"
MARKET_TICKER = "KXHIGHNY-26MAY20-T75"
BUY_BELOW = 40 # buy YES if price drops below 40 cents
MAX_CONTRACTS = 10
POLL_SECONDS = 30
def run():
client = KalshiClient(ACCESS_KEY, PRIVATE_KEY_PATH)
bought = 0
while bought < MAX_CONTRACTS:
try:
market = client.get(f"/markets/{MARKET_TICKER}")["market"]
ask = market["yes_ask"]
print(f"[{time.strftime('%H:%M:%S')}] YES ask = {ask} target < {BUY_BELOW}")
if ask > 0 and ask < BUY_BELOW:
order = client.post("/portfolio/orders", {
"ticker": MARKET_TICKER,
"action": "buy",
"side": "yes",
"count": 1,
"type": "limit",
"yes_price": ask,
"client_order_id": f"bot-{int(time.time())}",
})
print(f" BOUGHT 1 YES at {ask} order id: {order['order']['order_id']}")
bought += 1
except Exception as e:
print(f" ! error: {e}")
time.sleep(POLL_SECONDS)
print(f"Done — bought {bought} contracts")
if __name__ == "__main__":
run()
That's a complete, working trading bot in ~40 lines. Run it locally with python my_first_bot.py and watch it tick.
Important: Test with tiny sizes first (MAX_CONTRACTS = 1) until you're confident in the logic. Real money moves on every order.
5. Placing and managing orders
The order API supports limit and market orders, plus the full portfolio lifecycle:
# Place a limit order
client.post("/portfolio/orders", {
"ticker": "KXHIGHNY-26MAY20-T75",
"action": "buy", # or "sell"
"side": "yes", # or "no"
"count": 5,
"type": "limit", # or "market"
"yes_price": 42, # cents
"client_order_id": "my-order-1",
})
# List your open orders
open_orders = client.get("/portfolio/orders", params={"status": "resting"})
# Cancel an order via DELETE on /portfolio/orders/{order_id}
# Check positions
positions = client.get("/portfolio/positions")
6. Deploying with WatchDog Bot (the easy way)
Running python my_first_bot.py on your laptop works fine — until you close the lid, your laptop sleeps, or the bot crashes at 3 AM because cryptography wasn't installed in the right environment. This is where most beginner traders give up.
WatchDog Bot solves this. Paste your bot code into WatchDog Bot and:
- It auto-installs every dependency the moment it sees a
ModuleNotFoundError. Nopip install, no virtualenvs, no requirements.txt to maintain. - It runs your bot in an isolated environment so different bots don't fight over package versions.
- It monitors the bot 24/7 with real-time log streaming. When something breaks, you see it.
- If your code throws an error, you get a one-click Fix with AI button that points Claude at your code + the traceback and suggests a fix.
- Your API credentials live in the platform's encrypted connection store — never hardcoded in source.
The bot above, ported to WatchDog Bot's built-in SDK, becomes this:
import time
import wd # built-in WatchDog SDK — no install needed
# Pull credentials from the encrypted connection store
conn = wd.connection("Kalshi")
ACCESS_KEY = conn.api_key
PRIVATE_KEY = conn.api_secret # PEM string
# ...rest of your bot code, using wd.log.info(...) for structured logging
wd.log.info("Bot started, watching %s", MARKET_TICKER)
That's it — no credentials in code, structured logs that show up in the dashboard, and the bot reconnects automatically if Kalshi's API hiccups.
7. Handling errors, dependencies & uptime
Three things kill more trading bots than bad strategy combined: missing dependencies, crashed processes, and silent errors. Here's how to handle each.
Missing dependencies
The single most common bot failure mode: ModuleNotFoundError: No module named 'cryptography'. WatchDog Bot v1.1.13+ catches this, runs uv pip install cryptography in your bot's isolated venv, and retries up to 3 times. You never see the error.
Crashed processes
Wrap the main loop in a top-level try/except and restart on any non-fatal exception:
while True:
try:
run_one_iteration()
except Exception as e:
wd.log.error("iteration failed: %s — retrying in 60s", e)
time.sleep(60)
Silent errors
Always log key actions with structured fields. WatchDog's log dashboard lets you filter on level, message, and time — silent bugs are visible bugs.
8. Where to go from here
You now have a working Kalshi bot. The hard part is over. From here, the interesting questions are strategic, not technical:
- Market making — quote both sides of the spread, capture the bid/ask difference. Works best on illiquid markets where the spread is wide.
- News-driven strategies — pull headlines from an LLM and adjust positions before slower traders react.
- Weather and quantitative signals — Kalshi's temperature markets are highly correlated with NOAA forecasts. Edge exists for anyone modeling well.
- Arbitrage — when the same underlying outcome trades on Kalshi and another venue (Polymarket, sports books), price gaps can be captured.
The bot is the easy part. The strategy is everything.
Ready to ship your Kalshi bot?
WatchDog Bot is the trading bot platform built for Python developers. Free trial, no credit card. Your bot up and running in under 5 minutes.
Start Free Trial →
WatchDog Bot