kalshi_rust/
lib.rs

1//! An HTTPS and Websocket wrapper that allows users to write trading bots for the [Kalshi events trading platform](https://kalshi.com).
2//!
3//! kalshi-rust is asynchronous, performant, and succint. Dash past verbose and annoying HTTPS requests
4//! and use this wrapper to quickly write blazingly fast trading bots in Rust!
5//!
6//! As of version 0.9.0, HTTPS features are fully complete but websocket support and advanced API access features are not complete.
7//! If you'd like to keep up on kalshi-rust's development, report bugs, or view a sample trading script,
8//! feel free to visit the [github](https://github.com/dpeachpeach/kalshi-rust)!
9//! A star would also be greatly appreciated, I'm a student developer writing this for free and any recognition is incredibly helpful!
10//!
11//! ## The Kalshi Struct
12//!
13//! The [`Kalshi`] struct is the central component of this crate.
14//! All authentication, order routing, market requests, and position snapshots are handled through the struct and its methods.
15//!
16//! For more details, see [`Kalshi`].
17//!
18//! For a quick tutorial / beginners guide, jump [here](#quick-start-guide).
19//!
20//! ### Initializing the Kalshi struct in demo mode.
21//! ```
22//! use kalshi::Kalshi;
23//! use kalshi::TradingEnvironment;
24//!
25//! let kalshi_instance = Kalshi::new(TradingEnvironment::DemoMode, "your-key-id", "path/to/private.pem").await?;
26//! ```
27//!
28//! ## Quick Start Guide
29//!
30//! First, list the Kalshi struct as a dependency in your crate.
31//!
32//! ```toml
33//! kalshi = { version = "0.9"}
34//! ```
35//!
36//! Initialize the Kalshi Struct with key-based authentication:
37//! - **IMPORTANT**:  The authentication is handled automatically when creating a new instance.
38//! - Store your key ID and private key file securely, an implementation of extracting these from local environmental variables
39//!   is available [here](https://github.com/dpeachpeach/kalshi-rust/blob/main/sample_bot/src/main.rs#L12)
40//! ```
41//! use kalshi::Kalshi;
42//! use kalshi::TradingEnvironment;
43//!
44//! let key_id = "your-key-id";
45//! let pem_path = "path/to/private.pem";
46//!
47//! let kalshi_instance = Kalshi::new(TradingEnvironment::DemoMode, key_id, pem_path).await?;
48//! ```
49//!
50//! After logging in, you can call any method present in the crate without issue.
51//! Here is a script that buys a 'yes' contract on November 13th's New York temperature
52//! market.
53//!
54//! ```
55//! let new_york_ticker = "HIGHNY-23NOV13-T51".to_string();
56//!
57//! let bought_order = kalshi_instance
58//!     .create_order(
59//!     kalshi::Action::Buy,
60//!     None,
61//!     1,
62//!     kalshi::Side::Yes,
63//!     new_york_ticker,
64//!     kalshi::OrderType::Limit,
65//!     None,
66//!     None,
67//!     None,
68//!     None,
69//!     Some(5)).await.unwrap();
70//! ```
71//!
72//! Refer to the rest of the documentation for details on all other methods!
73//!
74//! ## Returned Values
75//!
76//! Whenever a user makes a method call using the kalshi struct, data is typically returned
77//! in structs that encapsulate the json fields returned by the server. All data
78//! in the structs is owned so a user can access the attributes without issue.
79//!
80//! ### Examples:
81//!
82//! #### Obtaining the Exchange's current status
83//! Returns a struct that represents whether trading or the exchange are currently active.
84//! ```
85//! use kalshi::Kalshi;
86//! use kalshi::TradingEnvironment;
87//! let kalshi_instance = Kalshi::new(TradingEnvironment::DemoMode, "your-key-id", "path/to/private.pem").await?;
88//!
89//! kalshi_instance.get_exchange_status().await.unwrap();
90//! ```
91//!
92//! #### Obtaining 5 miscellaneous market events
93//! Returns a vector of 'event' structs and a cursor.
94//! ```
95//! use kalshi::Kalshi;
96//! use kalshi::TradingEnvironment;
97//! let kalshi_instance = Kalshi::new(TradingEnvironment::DemoMode, "your-key-id", "path/to/private.pem").await?;
98//!
99//! kalshi_instance.get_multiple_events(Some(5), None, None, None, None).await.unwrap();
100//! ```
101//! #### Checking the User's balance
102//! Returns an i64 representing the user's balance in cents.
103//! ```
104//! use kalshi::Kalshi;
105//! use kalshi::TradingEnvironment;
106//! let kalshi_instance = Kalshi::new(TradingEnvironment::DemoMode, "your-key-id", "path/to/private.pem").await?;
107//!
108//! kalshi_instance.get_balance();
109//! ```
110//!
111
112#[macro_use]
113mod utils;
114mod api_keys;
115mod auth;
116mod collection;
117mod communications;
118mod events;
119mod exchange;
120mod fcm;
121mod incentive_programs;
122mod kalshi_error;
123mod live_data;
124mod market;
125mod milestone;
126mod portfolio;
127mod search;
128mod structured_targets;
129mod websocket;
130
131// pub use auth::*;  // Unused import
132pub use api_keys::*;
133pub use collection::*;
134pub use communications::*;
135pub use events::*;
136pub use exchange::*;
137pub use fcm::FcmPosition; // Only export the specific type, not all
138pub use incentive_programs::*;
139pub use kalshi_error::*;
140pub use live_data::*;
141pub use market::*;
142pub use milestone::*;
143pub use portfolio::*;
144pub use search::*;
145pub use structured_targets::*;
146pub use websocket::*;
147
148// imports
149use openssl::pkey::{PKey, Private};
150use std::fs;
151use std::path::Path;
152
153/// The Kalshi struct is the core of the kalshi-crate. It acts as the interface
154/// between the user and the market, abstracting away the meat of requests
155/// by encapsulating authentication information and the client itself.
156///
157/// ## Creating a new `Kalshi` instance for demo mode:
158///
159/// ```
160/// use kalshi::Kalshi;
161/// use kalshi::TradingEnvironment;
162///
163/// let kalshi_instance = Kalshi::new(TradingEnvironment::DemoMode, "your-key-id", "path/to/private.pem").await?;
164/// ```
165///
166///
167#[derive(Debug, Clone)]
168
169pub struct Kalshi {
170    /// - `base_url`: The base URL for the API, determined by the trading environment.
171    base_url: String,
172    /// - `key_id`: Key ID for key-based authentication
173    key_id: String,
174    /// - `private_key`: Private key for key-based authentication
175    private_key: PKey<Private>,
176    /// - `client`: The HTTP client used for making requests to the marketplace.
177    client: reqwest::Client,
178}
179
180impl Kalshi {
181    /// Creates a new instance of Kalshi with the specified trading environment and authenticates immediately.
182    /// This environment determines the base URL used for API requests.
183    ///
184    /// # Arguments
185    ///
186    /// * `trading_env` - The trading environment to be used (ProdMode: Trading with real money. DemoMode: Paper Trading).
187    /// * `key_id` - The UUID shown next to the key in your Kalshi UI
188    /// * `pem_path` - Path to the private key file you downloaded
189    ///
190    /// # Example
191    ///
192    /// ## Creating a Demo instance with authentication.
193    /// ```
194    /// use kalshi::{Kalshi, TradingEnvironment};
195    /// let kalshi = Kalshi::new(TradingEnvironment::DemoMode, "your-key-id", "path/to/private.pem").await?;
196    /// ```
197    ///
198    /// ## Creating a Live Trading instance with authentication (Warning, you're using real money!)
199    /// ```
200    /// use kalshi::{Kalshi, TradingEnvironment};
201    /// let kalshi = Kalshi::new(TradingEnvironment::ProdMode, "your-key-id", "path/to/private.pem").await?;
202    /// ```
203    ///
204    pub async fn new(
205        trading_env: TradingEnvironment,
206        key_id: &str,
207        pem_path: &str,
208    ) -> Result<Self, crate::kalshi_error::KalshiError> {
209        println!("Loading private key from: {}", pem_path);
210
211        // Load the private key first
212        let pem = match fs::read(Path::new(pem_path)) {
213            Ok(pem) => {
214                println!("Successfully read private key file");
215                pem
216            }
217            Err(e) => {
218                eprintln!("Failed to read private key file: {:?}", e);
219                return Err(e.into());
220            }
221        };
222
223        let private_key = match PKey::private_key_from_pem(&pem) {
224            Ok(key) => {
225                println!("Successfully parsed private key");
226                key
227            }
228            Err(e) => {
229                eprintln!("Failed to parse private key: {:?}", e);
230                return Err(e.into());
231            }
232        };
233
234        let base_url = utils::build_base_url(trading_env).to_string();
235        let kalshi = Self {
236            base_url,
237            key_id: key_id.to_string(),
238            private_key,
239            client: reqwest::Client::new(),
240        };
241
242        // Verify authentication by hitting an authenticated endpoint (balance)
243        println!("Verifying authentication with balance endpoint...");
244        match kalshi.get_balance().await {
245            Ok(balance) => {
246                println!(
247                    "Authentication successful! Account balance: {} cents",
248                    balance
249                );
250                Ok(kalshi)
251            }
252            Err(e) => {
253                eprintln!("Authentication failed: {:?}", e);
254                eprintln!("Please check your API key and private key file");
255                Err(e)
256            }
257        }
258    }
259
260    /// Creates a new WebSocket client using the same credentials.
261    pub fn websocket(&self) -> websocket::KalshiWebSocket {
262        websocket::KalshiWebSocket::new(self.trading_env(), &self.key_id, self.private_key.clone())
263    }
264
265    /// Returns the current trading environment.
266    pub fn trading_env(&self) -> TradingEnvironment {
267        if self.base_url.contains("demo") {
268            TradingEnvironment::DemoMode
269        } else {
270            TradingEnvironment::ProdMode
271        }
272    }
273}
274
275// GENERAL ENUMS
276// -----------------------------------------------
277
278/// Defines the trading environment for the Kalshi exchange.
279///
280/// This enum is used to specify whether the interaction with the Kalshi API should be in a demo (simulated) environment
281/// or in the live market with real financial transactions.
282///
283#[derive(Debug, Clone, Copy, PartialEq)]
284pub enum TradingEnvironment {
285    /// The demo mode represents a simulated environment where trades do not involve real money.
286    /// This mode is typically used for testing and practice purposes.
287    DemoMode,
288
289    /// The live market mode is the real trading environment where all transactions involve actual financial stakes.
290    /// Use this mode for actual trading activities with real money.
291    ProdMode,
292}