kalshi_trading/lib.rs
1//! # kalshi-rs
2//!
3//! A high-performance Rust client for the [Kalshi](https://kalshi.com) prediction market API.
4//!
5//! ## Features
6//!
7//! - **REST API Client** - Full coverage of trading and market data endpoints
8//! - **WebSocket Client** - Real-time orderbook, trades, fills, and lifecycle events
9//! - **HFT-Grade Orderbook** - Cache-optimized with O(log n) updates
10//! - **Async/Await** - Built on Tokio for maximum concurrency
11//!
12//! ## Quick Start
13//!
14//! ```rust,no_run
15//! use kalshi_trading::{Config, KalshiClient};
16//! use kalshi_trading::types::{CreateOrderRequest, Side, Action};
17//!
18//! #[tokio::main]
19//! async fn main() -> Result<(), kalshi_trading::Error> {
20//! // Create client with API credentials
21//! let private_key = std::fs::read_to_string("private_key.pem")?;
22//! let config = Config::new("api-key-id", &private_key);
23//! let client = KalshiClient::new(config)?;
24//!
25//! // Get markets
26//! let markets = client.rest().get_markets(Some("open"), None, None).await?;
27//!
28//! // Place an order (buy 10 Yes contracts at $0.50)
29//! let order = CreateOrderRequest::limit(
30//! &markets.markets[0].ticker,
31//! Side::Yes,
32//! Action::Buy,
33//! 10,
34//! 5000, // Price in centi-cents ($0.50 = 5000 centi-cents)
35//! );
36//! let response = client.rest().create_order(&order).await?;
37//!
38//! Ok(())
39//! }
40//! ```
41//!
42//! ## Price Representation
43//!
44//! Kalshi uses **centi-cents** for subpenny precision:
45//! - 100 centi-cents = 1 cent = $0.01
46//! - 5000 centi-cents = 50 cents = $0.50
47//! - 9900 centi-cents = 99 cents = $0.99
48//!
49//! ## Architecture
50//!
51//! This crate is organized into several modules:
52//!
53//! - [`client`] - REST and WebSocket clients for API communication
54//! - [`types`] - Request/response types matching the Kalshi API
55//! - [`orderbook`] - High-performance orderbook data structure
56//! - [`config`] - Configuration and credentials management
57//! - [`error`] - Error types for the crate
58//!
59//! ## Performance
60//!
61//! This crate is designed for low-latency trading workloads:
62//!
63//! - Integer prices (centi-cents) instead of floating point
64//! - `FxHashMap` for faster hashing of small keys
65//! - `parking_lot` mutexes (faster than std)
66//! - Minimal allocations in hot paths
67//! - `BTreeMap` for sorted price levels
68
69#![warn(missing_docs)]
70#![warn(rustdoc::missing_crate_level_docs)]
71#![deny(unsafe_code)]
72
73pub mod client;
74pub mod config;
75pub mod error;
76pub mod orderbook;
77pub mod types;
78
79// Re-export main types at crate root for convenience
80pub use config::Config;
81pub use error::Error;
82
83/// Result type alias using the crate's Error type
84pub type Result<T> = std::result::Result<T, Error>;
85
86/// The main Kalshi API client
87///
88/// This struct provides access to both REST and WebSocket APIs.
89///
90/// # Example
91///
92/// ```rust,no_run
93/// use kalshi_trading::{Config, KalshiClient};
94/// use kalshi_trading::types::{CreateOrderRequest, Side, Action};
95///
96/// # async fn example() -> kalshi_trading::Result<()> {
97/// let config = Config::new("api-key", "private-key-pem");
98/// let client = KalshiClient::new(config)?;
99///
100/// // Get markets
101/// let markets = client.rest().get_markets(Some("open"), None, None).await?;
102///
103/// // Get your balance
104/// let balance = client.rest().get_balance().await?;
105/// println!("Balance: ${:.2}", balance.balance as f64 / 10000.0);
106///
107/// // Place an order
108/// let order = CreateOrderRequest::limit("TICKER", Side::Yes, Action::Buy, 10, 5000);
109/// let response = client.rest().create_order(&order).await?;
110/// # Ok(())
111/// # }
112/// ```
113#[derive(Debug)]
114pub struct KalshiClient {
115 config: Config,
116 rest_client: client::rest::RestClient,
117}
118
119impl KalshiClient {
120 /// Create a new Kalshi client with the given configuration
121 ///
122 /// # Errors
123 ///
124 /// Returns an error if the private key cannot be parsed or the HTTP client
125 /// cannot be initialized.
126 pub fn new(config: Config) -> Result<Self> {
127 let rest_client = client::rest::RestClient::new(&config)?;
128 Ok(Self {
129 config,
130 rest_client,
131 })
132 }
133
134 /// Get a reference to the REST client
135 pub fn rest(&self) -> &client::rest::RestClient {
136 &self.rest_client
137 }
138
139 /// Get a reference to the configuration
140 pub fn config(&self) -> &Config {
141 &self.config
142 }
143
144 // TODO: Add WebSocket connection method
145 // pub async fn websocket(&self) -> Result<client::websocket::WebSocketClient> { ... }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151
152 #[test]
153 fn test_config_creation() {
154 let config = Config::new("test-key", "test-private-key");
155 assert_eq!(config.api_key_id(), "test-key");
156 }
157}