You don't need a computer science degree to build a Kalshi trading bot. You need Python, an API key, and about an hour. This tutorial takes you from zero to a working bot that monitors markets and places trades automatically — with real code you can run today.
By the end of this guide, you'll have a Python bot that authenticates with Kalshi, fetches market data, evaluates a simple strategy, and places orders. We'll build it step by step, explaining every line.
Prerequisites
- Python 3.9+ installed on your machine
- A Kalshi account with API access enabled
- Your Kalshi API key (key ID + secret) from your account settings
- Basic Python knowledge (variables, functions, loops)
If you've never used Python, this tutorial will still work — but consider running through a quick Python basics course first. If you'd rather skip coding entirely, our no-code bot builder lets you create bots visually.
Project Setup
Create a new project directory and install the required packages:
mkdir kalshi-bot && cd kalshi-bot
python3 -m venv venv
source venv/bin/activate
pip install requests python-dotenv
Create a .env file for your credentials (never hardcode API keys):
KALSHI_API_KEY_ID=your-key-id-here
KALSHI_API_KEY_SECRET=your-key-secret-here
KALSHI_BASE_URL=https://api.elections.kalshi.com/trade-api/v2
Step 1: Authentication
Kalshi uses API key authentication. Here's a clean client class that handles auth and request signing:
import os
import time
import requests
from dotenv import load_dotenv
load_dotenv()
class KalshiClient:
def __init__(self):
self.base_url = os.getenv("KALSHI_BASE_URL")
self.key_id = os.getenv("KALSHI_API_KEY_ID")
self.key_secret = os.getenv("KALSHI_API_KEY_SECRET")
self.session = requests.Session()
def _headers(self):
# Kalshi uses key-based auth headers
return {
"Content-Type": "application/json",
"Authorization": f"Bearer {self.key_id}:{self.key_secret}",
}
def get(self, path, params=None):
url = f"{self.base_url}{path}"
resp = self.session.get(url, headers=self._headers(), params=params)
resp.raise_for_status()
return resp.json()
def post(self, path, data=None):
url = f"{self.base_url}{path}"
resp = self.session.post(url, headers=self._headers(), json=data)
resp.raise_for_status()
return resp.json()
Test your connection:
client = KalshiClient()
balance = client.get("/portfolio/balance")
print(f"Account balance: ${balance['balance'] / 100:.2f}")
If you see your balance printed, you're connected. If you get an auth error, double-check your API credentials in the .env file.
Step 2: Fetching Market Data
Let's fetch available markets and find one to trade:
def get_markets(client, status="open", limit=20):
"""Fetch open markets from Kalshi."""
params = {"status": status, "limit": limit}
data = client.get("/markets", params=params)
return data.get("markets", [])
def find_market(client, ticker):
"""Fetch a specific market by ticker."""
data = client.get(f"/markets/{ticker}")
return data.get("market", {})
# Example: list some markets
markets = get_markets(client)
for m in markets[:5]:
print(f"{m['ticker']}: {m['title']} — YES: {m.get('yes_ask', 'N/A')}¢")
Each market object contains the ticker, title, current prices (yes_bid, yes_ask, no_bid, no_ask), volume, and settlement details. The prices are in cents (1-99).
Step 3: Building a Simple Strategy
Let's build a simple mean-reversion strategy: when a market's YES price drops sharply (more than 10 cents below its recent average), we buy — betting that the drop is an overreaction.
class SimpleStrategy:
def __init__(self, ticker, lookback=10, threshold=10, max_position=5):
self.ticker = ticker
self.threshold = threshold # cents below average to trigger buy
self.max_position = max_position # max contracts to hold
self.price_history = []
self.lookback = lookback
def update(self, yes_price):
"""Add a new price observation."""
self.price_history.append(yes_price)
if len(self.price_history) > self.lookback:
self.price_history = self.price_history[-self.lookback:]
def should_buy(self, current_price, current_position):
"""Return True if we should buy."""
if len(self.price_history) < self.lookback:
return False # not enough data yet
if current_position >= self.max_position:
return False # position limit reached
avg = sum(self.price_history) / len(self.price_history)
return current_price < (avg - self.threshold)
def should_sell(self, current_price, entry_price):
"""Return True if we should take profit."""
return current_price >= entry_price + 15 # take 15¢ profit
This is intentionally simple. The point isn't to run this strategy in production — it's to show the pattern. Your real strategy should be based on your own research and edge.
Step 4: Placing Orders
def place_order(client, ticker, side, quantity, price_cents, order_type="limit"):
"""Place an order on Kalshi.
side: 'yes' or 'no'
price_cents: price in cents (1-99)
"""
order = {
"ticker": ticker,
"action": "buy",
"side": side,
"type": order_type,
"count": quantity,
"yes_price": price_cents if side == "yes" else None,
"no_price": price_cents if side == "no" else None,
}
result = client.post("/portfolio/orders", data=order)
print(f"Order placed: {side.upper()} x{quantity} @ {price_cents}¢")
return result
Step 5: The Bot Loop
Now let's tie it all together into a bot that runs continuously:
import time
def run_bot(ticker, check_interval=30):
"""Main bot loop."""
client = KalshiClient()
strategy = SimpleStrategy(ticker, lookback=10, threshold=10, max_position=5)
current_position = 0
entry_price = None
print(f"Bot started — watching {ticker}")
print(f"Checking every {check_interval} seconds")
while True:
try:
market = find_market(client, ticker)
yes_price = market.get("yes_ask", 0)
if yes_price == 0:
print("Market closed or no price available")
time.sleep(check_interval)
continue
strategy.update(yes_price)
print(f"[{ticker}] YES: {yes_price}¢ | Position: {current_position}")
# Check buy signal
if strategy.should_buy(yes_price, current_position):
print(f"BUY SIGNAL at {yes_price}¢")
place_order(client, ticker, "yes", 1, yes_price)
current_position += 1
entry_price = yes_price
# Check sell signal
elif entry_price and strategy.should_sell(yes_price, entry_price):
print(f"SELL SIGNAL at {yes_price}¢ (entry: {entry_price}¢)")
place_order(client, ticker, "no", 1, 100 - yes_price)
current_position -= 1
if current_position == 0:
entry_price = None
except Exception as e:
print(f"Error: {e}")
time.sleep(check_interval)
# Run the bot
if __name__ == "__main__":
run_bot("YOUR-MARKET-TICKER-HERE")
Step 6: Adding Risk Controls
Never run a bot without risk controls. Here's a simple risk manager:
class RiskManager:
def __init__(self, max_daily_loss=500, max_position_size=10):
self.max_daily_loss = max_daily_loss # cents
self.max_position_size = max_position_size
self.daily_pnl = 0
def can_trade(self, position_size):
if self.daily_pnl <= -self.max_daily_loss:
print("RISK: Daily loss limit reached. Stopping.")
return False
if position_size >= self.max_position_size:
print("RISK: Position limit reached.")
return False
return True
def record_trade(self, pnl):
self.daily_pnl += pnl
Integrate this into your bot loop by checking risk_manager.can_trade() before every order.
Running Your Bot
# Activate your virtual environment
source venv/bin/activate
# Run the bot
python bot.py
For production deployment tips (running 24/7), see our complete bot guide.
Next Steps
You now have a working Kalshi bot. Here's where to go from here:
- Deep dive into the Kalshi API →
- Deep dive into the Kalshi API →
- Explore proven trading strategies →
- Optimal position sizing with Kelly →
Or skip the coding entirely:
Build Bots Without Code
Our visual bot builder lets you create the same multi-step strategies — without writing Python.