Skip to main content
trading-kalshi Execute trades on Kalshi - full REST API access for markets, orders, positions, balance
インストールへ移動 Skills Marketplace コミュニティが作成したAIスキルを発見・探索
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
直接コマンドでは確認用 Prompt が省略されます。実行前にソースを確認してください。
npx skills add https://github.com/shreed27/DAIN --skill trading-kalshiコマンドは1行のまま表示されます。コピー前に横へスクロールして全体を確認してください。
ローカルで確認しますか?SkillsMP が現在取得できるファイルをダウンロードできます。
Zipをダウンロード ダウンロード中... name trading-kalshi description Execute trades on Kalshi - full REST API access for markets, orders, positions, balance emoji 📈 gates {"envs":["KALSHI_EMAIL","KALSHI_PASSWORD"]}
Kalshi Trading - Complete API Reference
Full access to Kalshi's CFTC-regulated prediction market via their REST API.
Docs : https://docs.kalshi.com/welcome
Discord : #dev channel for support
Required Environment Variables
KALSHI_EMAIL=your@email.com
KALSHI_PASSWORD=your_password
Installation
pip install requests
API Base URLs
BASE_URL = "https://trading-api.kalshi.com/trade-api/v2"
DEMO_URL = "https://demo-api.kalshi.co/trade-api/v2"
Authentication
Kalshi uses email/password login returning a bearer token valid for 30 minutes.
Login & Token Management
import os
time
requests
BASE_URL =
:
( ):
.email = os.getenv( )
.password = os.getenv( )
.token =
.token_expiry =
.member_id =
( ):
time.time() > .token_expiry - :
._login()
( ):
r = requests.post( , json={
: .email,
: .password
})
r.raise_for_status()
data = r.json()
.token = data[ ]
.member_id = data.get( )
.token_expiry = time.time() + *
data
( ):
._ensure_auth()
{
: ,
:
}
( ):
r = requests.post( , headers= ._headers())
.token =
.token_expiry =
r.status_code ==
client = KalshiClient()
import
import
"https://trading-api.kalshi.com/trade-api/v2"
class
KalshiClient
def
__init__
self
self
"KALSHI_EMAIL"
self
"KALSHI_PASSWORD"
self
None
self
0
self
None
def
_ensure_auth
self
"""Refresh token if expired (30 min lifetime)"""
if
self
60
self
def
_login
self
"""POST /login - Get new auth token"""
f"{BASE_URL} /login"
"email"
self
"password"
self
self
"token"
self
"member_id"
self
29
60
return
def
_headers
self
"""Get auth headers for requests"""
self
return
"Authorization"
f"Bearer {self.token} "
"Content-Type"
"application/json"
def
logout
self
"""POST /logout - Invalidate current token"""
f"{BASE_URL} /logout"
self
self
None
self
0
return
200
Market Data Endpoints
Get Markets def get_markets (
status: str = "open" ,
series_ticker: str = None ,
limit: int = 100 ,
cursor: str = None
):
"""GET /markets - List markets"""
params = {"status" : status, "limit" : limit}
if series_ticker:
params["series_ticker" ] = series_ticker
if cursor:
params["cursor" ] = cursor
r = requests.get(f"{BASE_URL} /markets" , headers=client._headers(), params=params)
r.raise_for_status()
data = r.json()
return {
"markets" : data.get("markets" , []),
"cursor" : data.get("cursor" )
}
markets = get_markets(series_ticker="INXD" )
markets = get_markets(series_ticker="FED" )
markets = get_markets(series_ticker="KXBTC" )
Get Single Market def get_market (ticker: str ):
"""GET /markets/{ticker} - Single market details"""
r = requests.get(f"{BASE_URL} /markets/{ticker} " , headers=client._headers())
r.raise_for_status()
return r.json()["market" ]
market = get_market("INXD-24JAN10-T5805" )
Get Market Orderbook def get_orderbook (ticker: str , depth: int = 10 ):
"""GET /markets/{ticker}/orderbook - Full orderbook"""
r = requests.get(f"{BASE_URL} /markets/{ticker} /orderbook" ,
headers=client._headers(),
params={"depth" : depth})
r.raise_for_status()
data = r.json()["orderbook" ]
return data
book = get_orderbook("INXD-24JAN10-T5805" )
print (f"Yes bids: {book['yes' ]} " )
print (f"No asks: {book['no' ]} " )
Get Market History/Trades def get_market_history (ticker: str , limit: int = 100 ):
"""GET /markets/{ticker}/history - Trade history"""
r = requests.get(f"{BASE_URL} /markets/{ticker} /history" ,
headers=client._headers(),
params={"limit" : limit})
r.raise_for_status()
return r.json().get("history" , [])
trades = get_market_history("INXD-24JAN10-T5805" )
for t in trades:
print (f"{t['created_time' ]} : {t['count' ]} @ {t['yes_price' ]} ¢" )
Get Series/Events def get_series ():
"""GET /series - List all series (categories)"""
r = requests.get(f"{BASE_URL} /series" , headers=client._headers())
r.raise_for_status()
return r.json().get("series" , [])
def get_events (series_ticker: str = None ):
"""GET /events - List events"""
params = {}
if series_ticker:
params["series_ticker" ] = series_ticker
r = requests.get(f"{BASE_URL} /events" , headers=client._headers(), params=params)
r.raise_for_status()
return r.json().get("events" , [])
series = get_series()
events = get_events("FED" )
Order Management
Place Order def place_order (
ticker: str ,
side: str ,
action: str ,
count: int ,
price: int = None ,
order_type: str = "limit" ,
expiration_ts: int = None ,
client_order_id: str = None
):
"""POST /portfolio/orders - Place an order"""
payload = {
"ticker" : ticker,
"side" : side.lower(),
"action" : action.lower(),
"count" : count,
"type" : order_type
}
if order_type == "limit" and price:
payload["yes_price" ] = price if side.lower() == "yes" else (100 - price)
if expiration_ts:
payload["expiration_ts" ] = expiration_ts
if client_order_id:
payload["client_order_id" ] = client_order_id
r = requests.post(f"{BASE_URL} /portfolio/orders" ,
headers=client._headers(),
json=payload)
r.raise_for_status()
return r.json()
result = place_order("INXD-24JAN10-T5805" , "yes" , "buy" , 10 , 45 )
result = place_order("INXD-24JAN10-T5805" , "no" , "sell" , 5 , 30 )
result = place_order("INXD-24JAN10-T5805" , "yes" , "buy" , 10 , order_type="market" )
Batch Create Orders def batch_create_orders (orders: list ):
"""POST /portfolio/orders/batched - Create multiple orders"""
payload = {"orders" : orders}
r = requests.post(f"{BASE_URL} /portfolio/orders/batched" ,
headers=client._headers(),
json=payload)
r.raise_for_status()
return r.json()
orders = [
{"ticker" : "INXD-24JAN10-T5805" , "side" : "yes" , "action" : "buy" , "count" : 5 , "type" : "limit" , "yes_price" : 40 },
{"ticker" : "INXD-24JAN10-T5805" , "side" : "yes" , "action" : "buy" , "count" : 5 , "type" : "limit" , "yes_price" : 42 },
]
results = batch_create_orders(orders)
Amend Order def amend_order (order_id: str , count: int = None , price: int = None ):
"""POST /portfolio/orders/{order_id}/amend - Modify order"""
payload = {}
if count:
payload["count" ] = count
if price:
payload["yes_price" ] = price
r = requests.post(f"{BASE_URL} /portfolio/orders/{order_id} /amend" ,
headers=client._headers(),
json=payload)
r.raise_for_status()
return r.json()
Decrease Order Size def decrease_order (order_id: str , reduce_by: int ):
"""POST /portfolio/orders/{order_id}/decrease - Reduce order size"""
r = requests.post(f"{BASE_URL} /portfolio/orders/{order_id} /decrease" ,
headers=client._headers(),
json={"reduce_by" : reduce_by})
r.raise_for_status()
return r.json()
Cancel Order def cancel_order (order_id: str ):
"""DELETE /portfolio/orders/{order_id} - Cancel single order"""
r = requests.delete(f"{BASE_URL} /portfolio/orders/{order_id} " ,
headers=client._headers())
return r.status_code in [200 , 204 ]
def batch_cancel_orders (order_ids: list ):
"""DELETE /portfolio/orders/batched - Cancel multiple orders"""
r = requests.delete(f"{BASE_URL} /portfolio/orders/batched" ,
headers=client._headers(),
json={"order_ids" : order_ids})
r.raise_for_status()
return r.json()
cancel_order("abc123-order-id" )
batch_cancel_orders(["order-1" , "order-2" , "order-3" ])
Get Orders def get_orders (
ticker: str = None ,
status: str = None ,
limit: int = 100
):
"""GET /portfolio/orders - List orders"""
params = {"limit" : limit}
if ticker:
params["ticker" ] = ticker
if status:
params["status" ] = status
r = requests.get(f"{BASE_URL} /portfolio/orders" ,
headers=client._headers(),
params=params)
r.raise_for_status()
return r.json().get("orders" , [])
def get_order (order_id: str ):
"""GET /portfolio/orders/{order_id} - Single order"""
r = requests.get(f"{BASE_URL} /portfolio/orders/{order_id} " ,
headers=client._headers())
r.raise_for_status()
return r.json()["order" ]
orders = get_orders(status="resting" )
for o in orders:
print (f"{o['order_id' ]} : {o['action' ]} {o['side' ]} {o['remaining_count' ]} @ {o['yes_price' ]} ¢" )
Portfolio Management
Get Balance def get_balance ():
"""GET /portfolio/balance - Account balance"""
r = requests.get(f"{BASE_URL} /portfolio/balance" , headers=client._headers())
r.raise_for_status()
data = r.json()
return {
"balance" : data.get("balance" , 0 ) / 100 ,
"portfolio_value" : data.get("portfolio_value" , 0 ) / 100
}
bal = get_balance()
print (f"Available: ${bal['balance' ]:.2 f} " )
print (f"Portfolio: ${bal['portfolio_value' ]:.2 f} " )
Get Positions def get_positions (limit: int = 100 ):
"""GET /portfolio/positions - Current positions"""
r = requests.get(f"{BASE_URL} /portfolio/positions" ,
headers=client._headers(),
params={"limit" : limit})
r.raise_for_status()
return r.json().get("market_positions" , [])
positions = get_positions()
for p in positions:
if p.get("position" , 0 ) != 0 :
print (f"{p['ticker' ]} : {p['position' ]} contracts @ avg {p['average_price' ]} ¢" )
print (f" Realized P&L: ${p.get('realized_pnl' , 0 ) / 100 :.2 f} " )
Get Fills (Trade History) def get_fills (
ticker: str = None ,
limit: int = 100 ,
cursor: str = None
):
"""GET /portfolio/fills - Executed trades"""
params = {"limit" : limit}
if ticker:
params["ticker" ] = ticker
if cursor:
params["cursor" ] = cursor
r = requests.get(f"{BASE_URL} /portfolio/fills" ,
headers=client._headers(),
params=params)
r.raise_for_status()
data = r.json()
return {
"fills" : data.get("fills" , []),
"cursor" : data.get("cursor" )
}
fills = get_fills()
for f in fills["fills" ]:
print (f"{f['created_time' ]} : {f['action' ]} {f['side' ]} {f['count' ]} @ {f['price' ]} ¢" )
Get Settlements def get_settlements (limit: int = 100 ):
"""GET /portfolio/settlements - Settlement history"""
r = requests.get(f"{BASE_URL} /portfolio/settlements" ,
headers=client._headers(),
params={"limit" : limit})
r.raise_for_status()
return r.json().get("settlements" , [])
settlements = get_settlements()
for s in settlements:
print (f"{s['ticker' ]} : Settled at {s['settlement_value' ]} ¢, P&L: ${s['revenue' ] / 100 :.2 f} " )
Exchange Status def get_exchange_status ():
"""GET /exchange/status - Exchange operational status"""
r = requests.get(f"{BASE_URL} /exchange/status" , headers=client._headers())
r.raise_for_status()
return r.json()
status = get_exchange_status()
print (f"Trading: {status.get('trading_active' )} " )
print (f"Exchange open: {status.get('exchange_active' )} " )
WebSocket (Real-time Data) For real-time updates, use WebSocket after REST authentication:
import websocket
import json
def on_message (ws, message ):
data = json.loads(message)
print (f"Update: {data} " )
def on_open (ws ):
ws.send(json.dumps({
"type" : "subscribe" ,
"channel" : "orderbook" ,
"ticker" : "INXD-24JAN10-T5805"
}))
ws = websocket.WebSocketApp(
f"wss://trading-api.kalshi.com/trade-api/ws/v2?token={client.token} " ,
on_message=on_message,
on_open=on_open
)
ws.run_forever()
Complete Trading Bot
"""
Production Kalshi trading bot
"""
import os
import time
import requests
BASE_URL = "https://trading-api.kalshi.com/trade-api/v2"
class KalshiBot :
def __init__ (self ):
self .email = os.getenv("KALSHI_EMAIL" )
self .password = os.getenv("KALSHI_PASSWORD" )
self .token = None
self .token_expiry = 0
def _auth (self ):
if time.time() > self .token_expiry - 60 :
r = requests.post(f"{BASE_URL} /login" , json={
"email" : self .email, "password" : self .password
})
r.raise_for_status()
self .token = r.json()["token" ]
self .token_expiry = time.time() + 29 * 60
def _h (self ):
self ._auth()
return {"Authorization" : f"Bearer {self.token} " , "Content-Type" : "application/json" }
def get_market (self, ticker ):
r = requests.get(f"{BASE_URL} /markets/{ticker} " , headers=self ._h())
r.raise_for_status()
return r.json()["market" ]
def get_positions (self ):
r = requests.get(f"{BASE_URL} /portfolio/positions" , headers=self ._h())
r.raise_for_status()
return {p["ticker" ]: p for p in r.json().get("market_positions" , [])}
def get_balance (self ):
r = requests.get(f"{BASE_URL} /portfolio/balance" , headers=self ._h())
r.raise_for_status()
return r.json().get("balance" , 0 ) / 100
def buy (self, ticker, side, count, price ):
payload = {
"ticker" : ticker, "side" : side, "action" : "buy" ,
"count" : count, "type" : "limit" ,
"yes_price" : price if side == "yes" else (100 - price)
}
r = requests.post(f"{BASE_URL} /portfolio/orders" , headers=self ._h(), json=payload)
return r.json() if r.status_code == 200 else {"error" : r.text}
def sell (self, ticker, side, count, price ):
payload = {
"ticker" : ticker, "side" : side, "action" : "sell" ,
"count" : count, "type" : "limit" ,
"yes_price" : price if side == "yes" else (100 - price)
}
r = requests.post(f"{BASE_URL} /portfolio/orders" , headers=self ._h(), json=payload)
return r.json() if r.status_code == 200 else {"error" : r.text}
bot = KalshiBot()
TICKER = "INXD-24JAN10-T5805"
while True :
try :
market = bot.get_market(TICKER)
positions = bot.get_positions()
balance = bot.get_balance()
yes_bid = market["yes_bid" ]
yes_ask = market["yes_ask" ]
pos = positions.get(TICKER, {}).get("position" , 0 )
print (f"Balance: ${balance:.2 f} , Position: {pos} , Price: {yes_bid} /{yes_ask} " )
if yes_ask < 40 and pos < 10 and balance > 5 :
print (f"BUYING at {yes_ask} " )
bot.buy(TICKER, "yes" , 5 , yes_ask)
elif yes_bid > 60 and pos > 0 :
print (f"SELLING at {yes_bid} " )
bot.sell(TICKER, "yes" , pos, yes_bid)
time.sleep(10 )
except Exception as e:
print (f"Error: {e} " )
time.sleep(30 )
Popular Market Series Series Description Example Ticker FED Fed rate decisions FED-24MAR-T525 INXD S&P 500 daily close INXD-24JAN10-T5805 KXBTC Bitcoin price brackets KXBTC-24JAN-T45000 KXETH Ethereum price KXETH-24JAN-T2500 CPI Inflation data CPI-24JAN-T3.5 GDP GDP growth GDP-24Q1-T2.0 NFP Non-farm payrolls NFP-24JAN-T200K
Key Notes
Prices in CENTS - 45 means $0.45 per contract
Contracts pay $1 if correct - Cost is the price, profit is $1 - price
No trading fees - Only spread matters
Token expires in 30 min - Auto-refresh before expiry
US residents only - KYC verification required
Rate limits exist - Implement exponential backoff on 429 errors
Max position limits - Varies by market, check market details
CLI Wrapper python trading/kalshi.py search "fed rate"
python trading/kalshi.py market <ticker>
python trading/kalshi.py buy <ticker> <side> <count> <price>
python trading/kalshi.py sell <ticker> <side> <count> <price>
python trading/kalshi.py positions
python trading/kalshi.py balance
python trading/kalshi.py orders
python trading/kalshi.py cancel <order_id>