dxlink/
lib.rs

1//! # dxlink
2//!
3//! `dxlink` is a Rust client library for the DXLink WebSocket protocol used by tastytrade
4//! for real-time market data. This library provides a clean and type-safe API for connecting
5//! to DXLink servers, subscribing to market events, and processing real-time market data.
6//!
7//! ## Features
8//!
9//! - Full implementation of the DXLink WebSocket protocol (AsyncAPI 2.4.0)
10//! - Strongly typed event definitions for Quote, Trade, Greeks, and more
11//! - Async/await based API for efficient resource usage
12//! - Automatic handling of authentication and connection maintenance
13//! - Support for multiple subscription channels
14//! - Callback and stream-based APIs for event processing
15//! - Robust error handling and reconnection logic
16//!
17//! ref: <https://raw.githubusercontent.com/dxFeed/dxLink/refs/heads/main/dxlink-specification/asyncapi.yml>
18//!
19//! ## Example
20//!
21//! Here's a basic example of using the library to connect to a DXLink server
22//! and subscribe to market data:
23//!
24//! ```rust,no_run
25//! use std::error::Error;
26//! use dxlink::{DXLinkClient, EventType, FeedSubscription, MarketEvent};
27//! use tokio::time::sleep;
28//! use std::time::Duration;
29//!
30//! #[tokio::main]
31//! async fn main() -> Result<(), Box<dyn Error>> {
32//!     
33//!     // Create a new DXLink client with the API token
34//!     // (typically obtained from tastytrade API)
35//!     use tracing::info;
36//! let token = "your_api_token_here";
37//!     let url = "wss://tasty-openapi-ws.dxfeed.com/realtime";
38//!     let mut client = DXLinkClient::new(url, token);
39//!     
40//!     // Connect to the DXLink server
41//!     client.connect().await?;
42//!     
43//!     // Create a feed channel with AUTO contract type
44//!     let channel_id = client.create_feed_channel("AUTO").await?;
45//!     
46//!     // Configure the channel for Quote and Trade events
47//!     client.setup_feed(channel_id, &[EventType::Quote, EventType::Trade]).await?;
48//!     
49//!     // Register a callback for specific symbol
50//!     client.on_event("SPY", |event| {
51//!         info!("Event received for SPY: {:?}", event);
52//!     });
53//!     
54//!     // Get a stream for all events
55//!     let mut event_stream = client.event_stream()?;
56//!     
57//!     // Process events in a separate task
58//!     tokio::spawn(async move {
59//!         while let Some(event) = event_stream.recv().await {
60//!             match &event {
61//!                 MarketEvent::Quote(quote) => {
62//!                     info!(
63//!                         "Quote: {} - Bid: {} x {}, Ask: {} x {}",
64//!                         quote.event_symbol,
65//!                         quote.bid_price,
66//!                         quote.bid_size,
67//!                         quote.ask_price,
68//!                         quote.ask_size
69//!                     );
70//!                 },
71//!                 MarketEvent::Trade(trade) => {
72//!                     info!(
73//!                         "Trade: {} - Price: {}, Size: {}, Volume: {}",
74//!                         trade.event_symbol,
75//!                         trade.price,
76//!                         trade.size,
77//!                         trade.day_volume
78//!                     );
79//!                 },
80//!                 _ => info!("Other event type: {:?}", event),
81//!             }
82//!         }
83//!     });
84//!     
85//!     // Subscribe to some symbols
86//!     let subscriptions = vec![
87//!         FeedSubscription {
88//!             event_type: "Quote".to_string(),
89//!             symbol: "SPY".to_string(),
90//!             from_time: None,
91//!             source: None,
92//!         },
93//!         FeedSubscription {
94//!             event_type: "Trade".to_string(),
95//!             symbol: "SPY".to_string(),
96//!             from_time: None,
97//!             source: None,
98//!         },
99//!     ];
100//!     
101//!     client.subscribe(channel_id, subscriptions).await?;
102//!     
103//!     // Keep the connection active for some time
104//!     sleep(Duration::from_secs(60)).await;
105//!     
106//!     // Cleanup
107//!     client.disconnect().await?;
108//!     
109//!     Ok(())
110//! }
111//! ```
112//!
113//! ## Working with historical data
114//!
115//! DXLink supports subscribing to historical data through Candle events.
116//! When subscribing to candle events, you need to specify the period,
117//! type, and a timestamp from which to fetch the data:
118//!
119//! ```rust,no_run
120//! use dxlink::FeedSubscription;
121//! use std::time::{SystemTime, UNIX_EPOCH};
122//!
123//! // Get current timestamp in milliseconds
124//! let now = SystemTime::now()
125//!     .duration_since(UNIX_EPOCH)
126//!     .unwrap()
127//!     .as_millis() as i64;
128//!
129//! // Timestamp for 24 hours ago
130//! let one_day_ago = now - (24 * 60 * 60 * 1000);
131//!
132//! // Subscribe to 5-minute candles for SPY for the last 24 hours
133//! let candle_subscription = FeedSubscription {
134//!     event_type: "Candle".to_string(),
135//!     symbol: "SPY{=5m}".to_string(),  // 5-minute candles
136//!     from_time: Some(one_day_ago),
137//!     source: None,
138//! };
139//! ```
140//!
141//! ## Error Handling
142//!
143//! The library uses a custom error type `DXLinkError` that encompasses
144//! various error cases that can occur when interacting with the DXLink API:
145//!
146//! ```rust,no_run
147//! use tracing::{error, info};
148//! use dxlink::{DXLinkClient, DXLinkError};
149//!
150//! async fn example_error_handling() {
151//!     let mut client = DXLinkClient::new("wss://example.com", "token");
152//!     match client.connect().await {
153//!         Ok(_) => info!("Connected successfully!"),
154//!         Err(DXLinkError::Authentication(e)) => error!("Authentication failed: {}", e),
155//!         Err(DXLinkError::Connection(e)) => error!("Connection error: {}", e),
156//!         Err(e) => error!("Other error: {}", e),
157//!     }
158//! }
159//! ```
160//!
161//! ## Available Event Types
162//!
163//! The library supports the following event types:
164//!
165//! - `Quote` - Current bid/ask prices and sizes
166//! - `Trade` - Last trade information
167//! - `Greeks` - Option greeks data (delta, gamma, theta, etc.)
168//! - `Summary` - Daily summary information
169//! - `Profile` - Instrument profile information
170//! - `Candle` - OHLC (Open, High, Low, Close) data for time periods
171//! - And more!
172//!
173//!
174//! ## License
175//!
176//! This project is licensed under the MIT License. See the LICENSE file for details.
177//!
178//!  ## Setup Instructions
179//!  
180//!  1. Clone the repository:
181//!  ```shell
182//!  git clone https://github.com/joaquinbejar/DXlink
183//!  cd DXlink
184//!  ```
185//!  
186//!  2. Build the project:
187//!  ```shell
188//!  make build
189//!  ```
190//!  
191//!  3. Run tests:
192//!  ```shell
193//!  make test
194//!  ```
195//!  
196//!  4. Format the code:
197//!  ```shell
198//!  make fmt
199//!  ```
200//!  
201//!  5. Run linting:
202//!  ```shell
203//!  make lint
204//!  ```
205//!  
206//!  6. Clean the project:
207//!  ```shell
208//!  make clean
209//!  ```
210//!  
211//!  7. Run the project:
212//!  ```shell
213//!  make run
214//!  ```
215//!  
216//!  8. Fix issues:
217//!  ```shell
218//!  make fix
219//!  ```
220//!  
221//!  9. Run pre-push checks:
222//!  ```shell
223//!  make pre-push
224//!  ```
225//!  
226//!  10. Generate documentation:
227//!  ```shell
228//!  make doc
229//!  ```
230//!  
231//!  11. Publish the package:
232//!  ```shell
233//!  make publish
234//!  ```
235//!  
236//!  12. Generate coverage report:
237//!  ```shell
238//!  make coverage
239//!  ```
240//!
241//!
242//!  ## Testing
243//!  
244//!  To run unit tests:
245//!  ```shell
246//!  make test
247//!  ```
248//!  
249//!  To run tests with coverage:
250//!  ```shell
251//!  make coverage
252//!  ```
253//!  
254//!  ## Contribution and Contact
255//!  
256//!  We welcome contributions to this project! If you would like to contribute, please follow these steps:
257//!  
258//!  1. Fork the repository.
259//!  2. Create a new branch for your feature or bug fix.
260//!  3. Make your changes and ensure that the project still builds and all tests pass.
261//!  4. Commit your changes and push your branch to your forked repository.
262//!  5. Submit a pull request to the main repository.
263//!  
264//!  If you have any questions, issues, or would like to provide feedback, please feel free to contact the project maintainer:
265//!  
266//!  **Joaquín Béjar García**
267//!  - Email: jb@taunais.com
268//!  - GitHub: [joaquinbejar](https://github.com/joaquinbejar)
269//!  
270//!  We appreciate your interest and look forward to your contributions!
271//!  
272
273/// Client module for the DXLink WebSocket library.
274///
275/// This module provides the main `DXLinkClient` struct, which handles WebSocket connections,
276/// authentication, event subscriptions, and message processing for the DXLink protocol.
277///
278/// Key features include:
279/// - Establishing and managing WebSocket connections
280/// - Authenticating with the DXLink server
281/// - Creating and managing communication channels
282/// - Subscribing to market data feeds
283/// - Processing real-time market events
284/// - Handling connection lifecycle (connect, disconnect)
285pub mod client;
286
287/// WebSocket connection management module.
288///
289/// This module defines the `WebSocketConnection` struct, which provides low-level
290/// WebSocket communication capabilities. It handles:
291/// - Establishing secure WebSocket connections
292/// - Sending and receiving messages
293/// - Managing read and write streams
294/// - Implementing keep-alive mechanisms
295/// - Thread-safe connection handling
296pub mod connection;
297
298/// Error handling module for the DXLink WebSocket library.
299///
300/// Defines a comprehensive error enum `DXLinkError` that covers various potential
301/// error conditions during DXLink interactions, including:
302/// - WebSocket connection errors
303/// - Serialization/deserialization failures
304/// - Authentication issues
305/// - Connection problems
306/// - Protocol violations
307/// - Timeout scenarios
308/// - Unexpected message handling
309pub mod error;
310
311/// Event types and structures for market data.
312///
313/// This module provides:
314/// - Enum and structs representing different market event types
315/// - Support for Quote, Trade, and Greeks events
316/// - Serialization and deserialization of market events
317/// - Flexible event handling with a unified `MarketEvent` enum
318pub mod events;
319
320/// Message structures for the DXLink protocol.
321///
322/// Contains serializable structs representing various message types used in
323/// DXLink communication, including:
324/// - Authentication messages
325/// - Channel management messages
326/// - Feed subscription messages
327/// - Setup and configuration messages
328/// - Error messages
329pub mod messages;
330
331/// Utility functions for parsing and processing market data.
332///
333/// Provides helper functions for:
334/// - Parsing compact data formats
335/// - Converting raw data into structured market events
336/// - Supporting efficient event processing
337mod utils;
338
339pub use client::DXLinkClient;
340pub use error::DXLinkError;
341pub use events::{EventType, MarketEvent};
342pub use messages::FeedSubscription;
343pub use utils::parse_compact_data;