kalshi_fast/lib.rs
1//! # kalshi-fast-rs
2//!
3//! High-performance async Rust client for the [Kalshi](https://kalshi.com) prediction markets API.
4//!
5#![allow(
6 clippy::large_enum_variant,
7 clippy::result_large_err,
8 clippy::too_many_arguments,
9 clippy::type_complexity
10)]
11
12//! ## Features
13//!
14//! - **OpenAPI parity** — full REST operation coverage for the current docs snapshot
15//! - **AsyncAPI parity** — WebSocket commands, responses, and `user_orders`
16//! - **Pagination helpers** — page-level ([`CursorPager`]) and item-level (`stream_*`) iteration
17//! - **REST reliability controls** — retry/backoff/jitter with `429 Retry-After` support
18//! - **Transport builder** — timeout/connect-timeout/headers/user-agent/proxy/custom client
19//! - **RSA-PSS authentication** — secure signing for private endpoints
20//!
21//! ## Quick Start: REST (Builder + Retry)
22//!
23//! ```no_run
24//! use std::time::Duration;
25//! use kalshi_fast::{
26//! KalshiEnvironment, KalshiRestClient, RateLimitConfig, RetryConfig,
27//! };
28//!
29//! # async fn run() -> Result<(), kalshi_fast::KalshiError> {
30//! let client = KalshiRestClient::builder(KalshiEnvironment::demo())
31//! .with_rate_limit_config(RateLimitConfig { read_rps: 30, write_rps: 15 })
32//! .with_retry_config(RetryConfig {
33//! max_retries: 4,
34//! base_delay: Duration::from_millis(200),
35//! max_delay: Duration::from_secs(2),
36//! jitter: 0.2,
37//! retry_non_idempotent: false,
38//! })
39//! .build()?;
40//!
41//! let status = client.get_exchange_status().await?;
42//! println!("exchange_active={}", status.exchange_active);
43//! # Ok(())
44//! # }
45//! ```
46//!
47//! ## Quick Start: WebSocket
48//!
49//! ```no_run
50//! use kalshi_fast::{
51//! KalshiAuth, KalshiEnvironment, KalshiWsClient, WsChannel,
52//! WsDataMessage, WsEvent, WsMessage, WsReconnectConfig, WsSubscriptionParams,
53//! };
54//!
55//! # async fn run() -> Result<(), kalshi_fast::KalshiError> {
56//! let auth = KalshiAuth::from_pem_file(
57//! std::env::var("KALSHI_KEY_ID").unwrap(),
58//! std::env::var("KALSHI_PRIVATE_KEY_PATH").unwrap(),
59//! )?;
60//!
61//! let mut ws = KalshiWsClient::connect_authenticated(
62//! KalshiEnvironment::demo(),
63//! auth,
64//! WsReconnectConfig::default(),
65//! ).await?;
66//!
67//! ws.subscribe(WsSubscriptionParams {
68//! channels: vec![WsChannel::UserOrders],
69//! ..Default::default()
70//! }).await?;
71//!
72//! loop {
73//! match ws.next_event().await? {
74//! WsEvent::Message(WsMessage::Data(WsDataMessage::UserOrder { msg, .. })) => {
75//! println!("order={} status={:?}", msg.order_id, msg.status);
76//! }
77//! WsEvent::Reconnected { attempt } => println!("Reconnected (attempt {})", attempt),
78//! WsEvent::Disconnected { .. } => break,
79//! _ => {}
80//! }
81//! }
82//! # Ok(())
83//! # }
84//! ```
85//!
86//! ## Authentication
87//!
88//! Private endpoints (portfolio, orders, WebSocket fills) require RSA-PSS signing.
89//! Load your key with [`KalshiAuth::from_pem_file`] or [`KalshiAuth::from_pem_str`]:
90//!
91//! ```no_run
92//! # use kalshi_fast::{KalshiAuth, KalshiError};
93//! # fn run() -> Result<(), KalshiError> {
94//! // From a .key file on disk
95//! let auth = KalshiAuth::from_pem_file("your-key-id", "/path/to/private.key")?;
96//!
97//! // Or from PEM content directly (supports PKCS#8 and PKCS#1)
98//! let pem = std::fs::read_to_string("/path/to/private.key").unwrap();
99//! let auth = KalshiAuth::from_pem_str("your-key-id", &pem)?;
100//! # Ok(())
101//! # }
102//! ```
103//!
104//! Environment variables used by the examples:
105//! - `KALSHI_KEY_ID` — your API key ID
106//! - `KALSHI_PRIVATE_KEY_PATH` — path to your RSA private key (PEM format)
107//!
108//! ## Pagination
109//!
110//! **Page-level** with [`CursorPager`]:
111//!
112//! ```no_run
113//! # use kalshi_fast::{GetMarketsParams, KalshiEnvironment, KalshiRestClient};
114//! # async fn run() -> Result<(), kalshi_fast::KalshiError> {
115//! # let client = KalshiRestClient::new(KalshiEnvironment::demo());
116//! let mut pager = client.markets_pager(GetMarketsParams::default());
117//! while let Some(page) = pager.next_page().await? {
118//! for market in page {
119//! println!("{}", market.ticker);
120//! }
121//! }
122//! # Ok(())
123//! # }
124//! ```
125//!
126//! **Item-level** with streams:
127//!
128//! ```no_run
129//! use futures::stream::TryStreamExt;
130//! # use kalshi_fast::{GetMarketsParams, KalshiEnvironment, KalshiRestClient, Market};
131//!
132//! # async fn run() -> Result<(), kalshi_fast::KalshiError> {
133//! # let client = KalshiRestClient::new(KalshiEnvironment::demo());
134//! let markets: Vec<Market> = client
135//! .stream_markets(GetMarketsParams::default(), Some(250))
136//! .try_collect()
137//! .await?;
138//! # Ok(())
139//! # }
140//! ```
141//!
142//! ## WebSocket Reconnection
143//!
144//! [`KalshiWsClient`] handles reconnection automatically with exponential backoff
145//! and resubscribes to active channels. Configure via [`WsReconnectConfig`]:
146//!
147//! | Field | Default | Description |
148//! |---|---|---|
149//! | `max_retries` | `None` (unlimited) | Maximum reconnection attempts |
150//! | `base_delay` | 250 ms | First backoff delay |
151//! | `max_delay` | 30 s | Upper bound on backoff |
152//! | `jitter` | 0.2 | Random jitter factor |
153//! | `resubscribe` | `true` | Resubscribe to active channels on reconnect |
154//!
155//! Connection lifecycle events are exposed through [`WsEvent`]:
156//!
157//! - [`WsEvent::Message`] — incoming data
158//! - [`WsEvent::Reconnected`] — connection restored after a drop
159//! - [`WsEvent::Disconnected`] — connection lost after max retries
160//!
161//! **Note:** Sequence resync is not automatic; callers must handle any gaps.
162//!
163//! ## Performance
164//!
165//! Optimized for low-latency algorithmic trading:
166//!
167//! - **Deferred JSON parsing** — uses `serde_json::RawValue` to skip parsing unused fields
168//! - **Zero-copy message parsing** — binary WebSocket frames parsed with `from_slice`
169//! - **Split read/write streams** — no lock contention on WebSocket operations
170
171pub mod auth;
172pub mod env;
173pub mod error;
174pub mod rest;
175pub mod types;
176pub mod ws;
177
178// Primary clients
179pub use auth::{KalshiAuth, KalshiAuthHeaders};
180pub use env::{KalshiEnvironment, REST_PREFIX, WS_PATH};
181pub use error::KalshiError;
182pub use rest::{
183 CursorPager, KalshiRestClient, KalshiRestClientBuilder, RateLimitConfig, RateLimitTier,
184 RetryConfig,
185};
186pub use ws::{
187 KalshiWsClient, KalshiWsLowLevelClient, WsEvent, WsEventReceiver, WsReaderConfig, WsReaderMode,
188 WsReconnectConfig,
189};
190
191// Backwards-compatible type re-exports
192pub use rest::types::*;
193pub use types::*;
194pub use ws::types::*;