Overview
Kalshi is a CFTC-regulated prediction market based in the United States. It uses RSA certificate-based authentication for API access.
| Feature | Status |
|---|
| REST API | Full Support |
| WebSocket | Not Supported |
| Authentication | RSA Certificate |
| Environment | Production & Demo |
Configuration
Demo Environment (No Auth Required)
use pc_exchange_kalshi::{Kalshi, KalshiConfig};
// Use demo environment for testing
let config = KalshiConfig::demo();
let exchange = Kalshi::new(config)?;
// Fetch demo markets
let markets = exchange.fetch_markets(None).await?;
Production with Authentication
use pc_exchange_kalshi::{Kalshi, KalshiConfig};
let config = KalshiConfig::new()
.with_api_key_id("your-api-key-id")
.with_private_key_path("/path/to/private-key.pem");
let exchange = Kalshi::new(config)?;
Full Configuration Options
use pc_exchange_kalshi::{Kalshi, KalshiConfig};
let config = KalshiConfig::new()
// Authentication
.with_api_key_id("your-api-key-id")
.with_private_key_path("/path/to/private-key.pem")
// Or provide PEM content directly
// .with_private_key_pem("-----BEGIN RSA PRIVATE KEY-----\n...")
// API endpoint (optional)
.with_api_url("https://api.elections.kalshi.com/trade-api/v2")
// Logging
.with_verbose(true);
let exchange = Kalshi::new(config)?;
Configuration Reference
| Option | Type | Default | Description |
|---|
api_key_id | Option<String> | None | API key identifier |
private_key_path | Option<String> | None | Path to RSA private key PEM |
private_key_pem | Option<String> | None | RSA private key PEM content |
api_url | String | Production URL | API endpoint |
demo | bool | false | Use demo environment |
verbose | bool | false | Enable debug logging |
Environment Variables
export KALSHI_API_KEY_ID="your-api-key-id"
export KALSHI_PRIVATE_KEY_PATH="/path/to/private-key.pem"
Load from environment:
use std::env;
let config = KalshiConfig::new()
.with_api_key_id(env::var("KALSHI_API_KEY_ID")?)
.with_private_key_path(env::var("KALSHI_PRIVATE_KEY_PATH")?);
API Key Setup
To get API access to Kalshi:
- Create an account at kalshi.com
- Navigate to API settings in your account
- Generate an RSA key pair
- Upload your public key to Kalshi
- Store your private key securely
Never commit your private key to version control. Use environment variables or a secrets manager.
Examples
Fetch Markets
use pc_core::{Exchange, FetchMarketsParams};
use pc_exchange_kalshi::{Kalshi, KalshiConfig};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Use demo for testing
let exchange = Kalshi::new(KalshiConfig::demo())?;
let markets = exchange
.fetch_markets(Some(FetchMarketsParams {
limit: Some(10),
active_only: true,
}))
.await?;
for market in markets {
println!("─────────────────────────────────");
println!("ID: {}", market.id);
println!("Question: {}", market.question);
println!("Outcomes: {:?}", market.outcomes);
if !market.prices.is_empty() {
for (outcome, price) in &market.prices {
println!(" {}: {:.1}%", outcome, price * 100.0);
}
}
}
Ok(())
}
Place an Order
use pc_core::{Exchange, OrderSide};
use pc_exchange_kalshi::{Kalshi, KalshiConfig};
use std::collections::HashMap;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let config = KalshiConfig::new()
.with_api_key_id("your-api-key-id")
.with_private_key_path("/path/to/private-key.pem");
let exchange = Kalshi::new(config)?;
let order = exchange
.create_order(
"INXD-24DEC31-T5250", // ticker
"Yes", // outcome
OrderSide::Buy,
0.55, // price
10.0, // quantity
HashMap::new(),
)
.await?;
println!("Order placed: {}", order.id);
println!("Status: {:?}", order.status);
Ok(())
}
Fetch Positions
let positions = exchange.fetch_positions(None).await?;
for pos in positions {
println!(
"{}: {} contracts @ ${:.2}",
pos.market_id, pos.size, pos.average_price
);
}
Fetch Balance
let balance = exchange.fetch_balance().await?;
if let Some(usd) = balance.get("USD") {
println!("Available balance: ${:.2}", usd);
}
Market Tickers
Kalshi uses ticker-based market identification. Tickers follow a pattern like:
INXD-24DEC31-T5250 - S&P 500 above 5250 by Dec 31, 2024
FED-24DEC18-T450 - Fed rate at 4.50% by Dec 18, 2024
// Fetch a specific market by ticker
let market = exchange.fetch_market("INXD-24DEC31-T5250").await?;
println!("Question: {}", market.question);
Demo vs Production
| Aspect | Demo | Production |
|---|
| URL | demo-api.kalshi.co | api.elections.kalshi.com |
| Auth Required | No | Yes |
| Real Money | No | Yes |
| Market Data | Sample | Live |
// Demo - for testing
let demo = Kalshi::new(KalshiConfig::demo())?;
// Production - requires authentication
let production = Kalshi::new(
KalshiConfig::new()
.with_api_key_id("...")
.with_private_key_path("...")
)?;
Rate Limits
Kalshi has API rate limits. The exchange automatically handles rate limiting, but be aware:
- Default rate limit: 10 requests/second
- Configurable through base
ExchangeConfig
use std::time::Duration;
let config = KalshiConfig::new()
// ... auth config ...
.with_rate_limit(5); // More conservative rate
Error Handling
use pc_core::{ParsecError, ExchangeError};
match exchange.fetch_markets(None).await {
Ok(markets) => println!("Found {} markets", markets.len()),
Err(ParsecError::Exchange(ExchangeError::Authentication(msg))) => {
println!("Authentication failed: {}", msg);
println!("Check your API key and private key configuration");
}
Err(ParsecError::RateLimitExceeded) => {
println!("Rate limit exceeded, please wait");
}
Err(e) => println!("Error: {}", e),
}
Next Steps