deribit_websocket/lib.rs
1//! # Deribit WebSocket Client
2//!
3//! A high-performance, production-ready WebSocket client for the Deribit cryptocurrency derivatives exchange.
4//! This crate provides comprehensive real-time market data streaming, trading operations, and account management
5//! through Deribit's WebSocket API v2.
6//!
7//! ## Features
8//!
9//! - ๐ **WebSocket Connection Management** - Robust connection handling with automatic reconnection and heartbeat
10//! - ๐ก **JSON-RPC Protocol** - Complete JSON-RPC 2.0 implementation for Deribit API
11//! - ๐ **Real-time Market Data** - Live ticker, order book, trades, and chart data streaming
12//! - ๐ **Advanced Subscriptions** - Chart data aggregation and user position change notifications
13//! - ๐ฐ **Mass Quote System** - High-performance mass quoting with MMP (Market Maker Protection) groups
14//! - ๐ **Authentication** - Secure API key and signature-based authentication with typed responses
15//! - ๐ **Trading Operations** - Full order lifecycle: buy, sell, cancel, edit orders
16//! - ๐ผ **Account Management** - Position queries, account summaries, order history
17//! - ๐ **Session Management** - Heartbeat control, client identification, cancel-on-disconnect
18//! - ๐ก๏ธ **Error Handling** - Comprehensive error types with detailed recovery mechanisms
19//! - โก **Async/Await** - Full async support with tokio runtime for high concurrency
20//! - ๐ **Callback System** - Flexible message processing with primary and error callbacks
21//! - ๐ **Subscription Management** - Intelligent subscription tracking and channel management
22//! - ๐งช **Testing Support** - Complete test coverage with working examples
23//!
24//! ## Supported Subscription Channels
25//!
26//! ### Market Data Channels
27//! - `ticker.{instrument}` - Real-time ticker updates
28//! - `book.{instrument}.{group}` - Order book snapshots and updates
29//! - `trades.{instrument}` - Live trade executions
30//! - `chart.trades.{instrument}.{resolution}` - Aggregated chart data for technical analysis
31//!
32//! ### User Data Channels (Requires Authentication)
33//! - `user.orders` - Order status updates and fills
34//! - `user.trades` - User trade executions
35//! - `user.changes.{instrument}.{interval}` - Position and portfolio changes
36//!
37//! ## Protocol Support
38//!
39//! | Feature | Status | Description |
40//! |---------|--------|-------------|
41//! | JSON-RPC over WebSocket | โ
Full Support | Complete JSON-RPC 2.0 implementation |
42//! | Market Data Subscriptions | โ
Full Support | All public channels supported |
43//! | User Data Subscriptions | โ
Full Support | Private channels with authentication |
44//! | Chart Data Streaming | โ
Full Support | Real-time OHLCV data aggregation |
45//! | Authentication | โ
API Key + Signature | Secure credential-based auth |
46//! | Connection Management | โ
Auto-reconnect | Robust connection handling |
47//! | Error Recovery | โ
Comprehensive | Detailed error types and handling |
48//!
49//! ## Quick Start
50//!
51//! ```rust,no_run
52//! use deribit_websocket::prelude::*;
53//!
54//! #[tokio::main]
55//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
56//! // Install the rustls crypto provider that matches the active TLS feature.
57//! // See the crate-level "TLS backends" section or `Cargo features` in the
58//! // README for the available backends.
59//! deribit_websocket::install_default_crypto_provider()?;
60//!
61//! // Create client for testnet
62//! let config = WebSocketConfig::default();
63//! let mut client = DeribitWebSocketClient::new(&config)?;
64//!
65//! // Set up message processing
66//! client.set_message_handler(
67//! |message| {
68//! tracing::info!("Received: {}", message);
69//! Ok(())
70//! },
71//! |message, error| {
72//! tracing::error!("Error processing {}: {}", message, error);
73//! }
74//! );
75//!
76//! // Connect and subscribe
77//! client.connect().await?;
78//! client.subscribe(vec!["ticker.BTC-PERPETUAL".to_string()]).await?;
79//!
80//! // Start processing messages
81//! client.start_message_processing_loop().await?;
82//! Ok(())
83//! }
84//! ```
85//!
86//! ## Advanced Usage
87//!
88//! The client supports advanced subscription patterns for professional trading applications:
89//!
90//! ### Chart Data Streaming
91//! ```rust,no_run
92//! # use deribit_websocket::prelude::*;
93//! # #[tokio::main]
94//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
95//! # let config = WebSocketConfig::default();
96//! # let client = DeribitWebSocketClient::new(&config)?;
97//! // Subscribe to 1-minute chart data for BTC perpetual
98//! client.subscribe(vec!["chart.trades.BTC-PERPETUAL.1".to_string()]).await?;
99//! # Ok(())
100//! # }
101//! ```
102//!
103//! ### Position Change Monitoring
104//! ```rust,no_run
105//! # use deribit_websocket::prelude::*;
106//! # #[tokio::main]
107//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
108//! # let config = WebSocketConfig::default();
109//! # let client = DeribitWebSocketClient::new(&config)?;
110//! // Monitor real-time position changes (requires authentication)
111//! client.authenticate("client_id", "client_secret").await?;
112//! client.subscribe(vec!["user.changes.BTC-PERPETUAL.raw".to_string()]).await?;
113//! # Ok(())
114//! # }
115//! ```
116//!
117//! ### Mass Quote System
118//! ```rust,no_run
119//! # use deribit_websocket::prelude::*;
120//! # #[tokio::main]
121//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
122//! # let config = WebSocketConfig::default();
123//! # let mut client = DeribitWebSocketClient::new(&config)?;
124//! # client.connect().await?;
125//! # client.authenticate("client_id", "client_secret").await?;
126//! // Set up MMP group for mass quoting
127//! let mmp_config = MmpGroupConfig::new(
128//! "btc_market_making".to_string(),
129//! 10.0, // quantity_limit
130//! 5.0, // delta_limit
131//! 1000, // interval (ms)
132//! 5000, // frozen_time (ms)
133//! )?;
134//! client.set_mmp_config(mmp_config).await?;
135//!
136//! // Create and place mass quotes
137//! let quotes = vec![
138//! Quote::buy("BTC-PERPETUAL".to_string(), 0.1, 45000.0),
139//! Quote::sell("BTC-PERPETUAL".to_string(), 0.1, 55000.0),
140//! ];
141//! let request = MassQuoteRequest::new("btc_market_making".to_string(), quotes);
142//! let response = client.mass_quote(request).await?;
143//! # Ok(())
144//! # }
145//! ```
146//!
147//! ## Examples
148//!
149//! The crate includes comprehensive examples demonstrating:
150//!
151//! ### Core Examples
152//! - **`basic_client.rs`** - Basic connection, subscription, and message handling
153//! - **`callback_example.rs`** - Advanced callback system with error handling
154//! - **`advanced_subscriptions.rs`** - Chart data and position change subscriptions
155//!
156//! ### Trading & Account Management (v0.2.0)
157//! - **`trading_operations.rs`** - Buy, sell, cancel, edit orders
158//! - **`account_operations.rs`** - Get positions, account summary, order history
159//! - **`position_management.rs`** - Close positions, move positions between subaccounts
160//!
161//! ### Session Management (v0.2.0)
162//! - **`session_management.rs`** - Hello, heartbeat, typed responses (AuthResponse, HelloResponse, TestResponse)
163//! - **`cancel_on_disconnect.rs`** - Enable/disable/get cancel-on-disconnect status
164//! - **`unsubscribe_all.rs`** - Public and private unsubscribe_all operations
165//!
166//! ### Market Data Subscriptions
167//! - **`new_channels_subscription.rs`** - Grouped order book, incremental ticker, trades by kind
168//! - **`perpetual_subscription.rs`** - Perpetual funding rate subscriptions
169//! - **`quote_subscription.rs`** - Quote data subscriptions
170//! - **`price_index_subscription.rs`** - Price index subscriptions
171//!
172//! ### Mass Quoting
173//! - **`mass_quote_basic.rs`** - Basic mass quoting with MMP group setup
174//! - **`mass_quote_advanced.rs`** - Advanced mass quoting with multiple MMP groups
175//! - **`mass_quote_options.rs`** - Options-specific mass quoting with delta management
176//!
177//! ## Timeouts
178//!
179//! Two deadlines bound the most common sources of indefinite hangs in a
180//! network client. Both live on `WebSocketConfig` and can be set via
181//! builder methods or the corresponding environment variables:
182//!
183//! - **`connection_timeout`** (default 10s, env `DERIBIT_CONNECTION_TIMEOUT`) โ
184//! upper bound on the WebSocket handshake (TCP + TLS + HTTP upgrade).
185//! A peer that accepts the TCP connection but never completes the
186//! upgrade makes `DeribitWebSocketClient::connect` / `Dispatcher::connect`
187//! fail with `WebSocketError::Timeout` instead of hanging.
188//! - **`request_timeout`** (default 30s, env `DERIBIT_REQUEST_TIMEOUT`) โ
189//! upper bound on each `send_request` call, covering enqueue, write,
190//! and response wait. On the deadline the dispatcher evicts the
191//! now-orphaned waiter so the id-map stays small under repeated
192//! timeouts.
193//!
194//! Planned follow-ups: `read_idle_timeout` (maximum gap between frames)
195//! and granular per-operation overrides.
196//!
197//! ## Backpressure
198//!
199//! The client and dispatcher communicate over two **bounded**
200//! `tokio::sync::mpsc` channels, both using **Strategy A (await-send)** โ
201//! the producer blocks on a full channel, so frames are not dropped due
202//! to backpressure. Frames can still be discarded if the notification
203//! receiver has already been closed (for example during shutdown or
204//! disconnect).
205//!
206//! - **`notification_channel_capacity`** (default 1024) โ notifications
207//! from the dispatcher to the consumer. When full, the dispatcher
208//! stops polling the WebSocket stream and the TCP recv buffer fills,
209//! which makes the Deribit server apply flow control. Every
210//! full-channel event emits a `tracing::warn!` so slow consumers are
211//! visible in logs.
212//! - **`dispatcher_command_capacity`** โ outbound commands from the
213//! client to the dispatcher (request sends, cancel-request on timeout,
214//! shutdown). When full, the caller blocks until the dispatcher drains
215//! a slot; `request_timeout` on `send_request` still applies, so the
216//! caller surfaces `WebSocketError::Timeout` if the deadline elapses
217//! while waiting on the channel.
218//!
219//! Strategy A was chosen over drop-oldest / drop-newest variants because
220//! the notification stream carries private trading events (order
221//! updates, trade reports) where silent loss is unacceptable.
222//!
223//! ## Architecture
224//!
225//! The client is built with a modular architecture:
226//! - **Connection Layer** - Low-level WebSocket connection management
227//! - **Session Layer** - Protocol-aware session handling with authentication
228//! - **Message Layer** - JSON-RPC request/response and notification handling
229//! - **Subscription Layer** - Channel management and subscription tracking
230//! - **Callback Layer** - Flexible message processing with error recovery
231//!
232//! ## TLS backends
233//!
234//! `deribit-websocket` exposes three mutually-exclusive TLS backends as
235//! Cargo features, with a compile-time mutex (see the `tls` module)
236//! that rejects any other combination:
237//!
238//! | Feature | Default | Behaviour |
239//! | ---------------- | :-----: | ------------------------------------------------------------------ |
240//! | `rustls-aws-lc` | โ
| `rustls` with the `aws-lc-rs` crypto provider + OS root store |
241//! | `rustls-ring` | | `rustls` with the `ring` crypto provider + OS root store |
242//! | `native-tls` | | OS-native TLS stack (SChannel / SecureTransport / OpenSSL) |
243//!
244//! Selecting a non-default backend:
245//!
246//! ```toml
247//! # Cargo.toml
248//! [dependencies]
249//! deribit-websocket = { version = "0.2", default-features = false, features = ["rustls-ring"] }
250//! ```
251//!
252//! or, from the command line:
253//!
254//! ```sh
255//! cargo add deribit-websocket --no-default-features --features native-tls
256//! ```
257//!
258//! Applications must call `install_default_crypto_provider` once at
259//! startup โ it picks the right provider for the active feature and is
260//! a no-op under `native-tls`.
261//!
262//! Because both `rustls-*` backends use the OS-native root store via
263//! `rustls-native-certs`, minimal container images (Alpine, distroless)
264//! must have `ca-certificates` (or equivalent) installed so the trust
265//! store is populated.
266
267#![warn(missing_docs)]
268#![deny(unsafe_code)]
269// Catch dead rustdoc links and missing crate-level docs in CI via
270// `RUSTDOCFLAGS="-D warnings" cargo doc`. `missing_crate_level_docs`
271// is technically redundant with the substantial `//!` header above
272// but it guards against the header ever being deleted in a refactor.
273#![warn(rustdoc::broken_intra_doc_links)]
274#![warn(rustdoc::missing_crate_level_docs)]
275// Regression guard against future `std::sync::Mutex` use across `.await`.
276// Tokio's mutex (which this crate uses) is intentionally allowed.
277#![warn(clippy::await_holding_lock)]
278// Ban `.unwrap()`/`.expect()` in library code. `#[cfg(test)]` modules inside
279// `src/` keep the default behaviour so existing unit tests continue to work.
280#![cfg_attr(not(test), deny(clippy::unwrap_used, clippy::expect_used))]
281
282pub mod callback;
283pub mod client;
284pub mod config;
285pub mod connection;
286pub mod constants;
287pub mod error;
288pub mod message;
289pub mod model;
290/// Prelude module with commonly used types
291pub mod prelude;
292pub mod session;
293pub mod subscriptions;
294pub mod tls;
295/// Utility functions and helpers
296pub mod utils;
297
298pub use tls::{CryptoProviderError, install_default_crypto_provider};