1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
//! # rithmic-rs
//!
//! `rithmic-rs` is a Rust client library for the Rithmic R | Protocol API.
//!
//! ## Features
//!
//! - Stream real-time market data (trades, quotes, order book depth)
//! - Submit and manage orders (bracket orders, modifications, cancellations)
//! - Access historical market data (ticks and time bars)
//! - Manage risk and track positions and P&L
//! - Connection health monitoring with heartbeat and forced logout handling
//!
//! ## Quick Start
//!
//! ```no_run
//! use rithmic_rs::{
//! RithmicConfig, RithmicEnv, ConnectStrategy, RithmicTickerPlant,
//! rti::messages::RithmicMessage,
//! };
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Load configuration from environment variables
//! let config = RithmicConfig::from_env(RithmicEnv::Demo)?;
//!
//! // Connect with Retry strategy (recommended default)
//! let ticker_plant = RithmicTickerPlant::connect(&config, ConnectStrategy::Retry).await?;
//! let mut handle = ticker_plant.get_handle();
//!
//! // Login and subscribe to market data
//! handle.login().await?;
//! handle.subscribe("ESM6", "CME").await?;
//!
//! // Process real-time updates
//! loop {
//! match handle.subscription_receiver.recv().await {
//! Ok(update) => {
//! // Check for connection health issues
//! if let Some(err) = &update.error {
//! eprintln!("Error: {}", err);
//! if err.is_connection_issue() { break; }
//! continue;
//! }
//!
//! // Process market data
//! match update.message {
//! RithmicMessage::LastTrade(trade) => {
//! println!("Trade: {:?}", trade);
//! }
//! RithmicMessage::BestBidOffer(bbo) => {
//! println!("BBO: {:?}", bbo);
//! }
//! _ => {}
//! }
//! }
//! Err(e) => {
//! eprintln!("Channel error: {}", e);
//! break;
//! }
//! }
//! }
//!
//! Ok(())
//! }
//! ```
//!
//! ## Connection Strategies
//!
//! The library provides three connection strategies:
//!
//! - [`ConnectStrategy::Simple`]: Single connection attempt, fast-fail
//! - [`ConnectStrategy::Retry`]: Indefinite retries with exponential backoff capped at 60s (recommended default)
//! - [`ConnectStrategy::AlternateWithRetry`]: Alternates between primary and beta URLs
//!
//! A graceful `disconnect().await` logs out first and then closes the WebSocket.
//! On a healthy connection, that shutdown path does not emit synthetic
//! `HeartbeatTimeout` or `ConnectionError` subscription updates; reserve those
//! for unexpected connection-health failures and reconnect logic.
//!
//! ## Configuration
//!
//! Use [`RithmicConfig`] for modern, ergonomic configuration:
//!
//! ```no_run
//! use rithmic_rs::{RithmicAccount, RithmicConfig, RithmicEnv};
//!
//! fn example() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
//! // From environment variables
//! let config = RithmicConfig::from_env(RithmicEnv::Demo)?;
//! let account = RithmicAccount::from_env(RithmicEnv::Demo)?;
//!
//! // Or using builder pattern
//! let config = RithmicConfig::builder(RithmicEnv::Demo)
//! .user("your_user".to_string())
//! .password("your_password".to_string())
//! .system_name("Rithmic Paper Trading".to_string())
//! .app_name("your_app_name".to_string())
//! .app_version("1".to_string())
//! .build()?;
//!
//! let account = RithmicAccount::new("your_fcm", "your_ib", "your_account");
//! let _ = (config, account);
//! Ok(())
//! }
//! ```
//!
//! ## Error Handling
//!
//! All plant handle methods return [`Result<_, RithmicError>`]. The [`RithmicError`] enum
//! lets you programmatically distinguish error kinds:
//!
//! ```ignore
//! use rithmic_rs::RithmicError;
//!
//! match handle.subscribe("ESM6", "CME").await {
//! Ok(resp) => { /* success */ }
//! Err(RithmicError::ConnectionClosed | RithmicError::SendFailed) => {
//! handle.abort();
//! // reconnect — see examples/reconnect.rs
//! }
//! Err(RithmicError::RequestRejected(err)) => {
//! eprintln!(
//! "Server rejected: code={} msg={}",
//! err.code.as_deref().unwrap_or("?"),
//! err.message.as_deref().unwrap_or(""),
//! );
//! }
//! Err(RithmicError::ProtocolError(msg)) => {
//! eprintln!("Protocol error: {msg}");
//! }
//! Err(e) => eprintln!("{e}"),
//! }
//! ```
//!
//! For inspecting a `RithmicResponse` directly, match on `response.error` — it
//! is `Option<RithmicError>` with `RequestRejected` for rp_code rejections and
//! `ProtocolError` for other non-transport failures. Use
//! [`RithmicError::is_connection_issue`] to distinguish transport-level events
//! that warrant reconnection. The raw rp_code payload is available via
//! `response.rp_code()`, `response.rp_code_num()`, and `response.rp_code_text()`.
//!
//! A graceful `disconnect().await` is separate from that reconnect path: it
//! shuts the plant down without sending synthetic `HeartbeatTimeout` or
//! `ConnectionError` updates to subscribers when the close handshake succeeds.
//!
//! `RithmicError` implements [`std::error::Error`], so `?` works in functions
//! returning `Box<dyn Error>`.
//!
//! ## Feature Flags
//!
//! | Flag | Default | Description |
//! |------|---------|-------------|
//! | `serde` | off | Adds `Serialize`/`Deserialize` derives on trading types (`RithmicEnv`, `OrderSide`, `OrderType`, `TimeInForce`, `OrderStatus`, `RithmicOrder`, `TrailingStop`) |
//!
//! **TLS backend:** The crate uses `native-tls` (via `tokio-tungstenite`) for all
//! WebSocket connections. There is currently no `rustls` option.
//!
//! ## Module Organization
//!
//! - [`plants`]: Specialized clients for different data types (ticker, order, P&L, history)
//! - [`config`]: Configuration API for connecting to Rithmic
//! - [`error`]: Typed error enum for plant handle methods
//! - [`api`]: Low-level API interfaces for sending and receiving messages
//! - [`rti`]: Protocol message definitions
//! - [`ws`]: WebSocket connectivity and connection strategies
//! - [`util`]: Utility types and helpers (timestamps, order status, instrument info)
/// Low-level API types for Rithmic communication.
///
/// This module provides the command types and response structures used internally
/// by the plant modules. Most users should use the high-level plant APIs instead.
///
/// Re-exports include order types ([`RithmicBracketOrder`], [`RithmicModifyOrder`], etc.)
/// and their associated enums for transaction types, durations, and price types.
/// Configuration API for connecting to Rithmic
/// Error types for plant handle methods.
/// Specialized clients ("plants") for different Rithmic services.
///
/// Each plant connects to a specific Rithmic infrastructure component:
///
/// - [`ticker_plant`](plants::ticker_plant): Real-time market data (trades, quotes, order book)
/// - [`order_plant`](plants::order_plant): Order entry and management
/// - [`history_plant`](plants::history_plant): Historical tick and bar data
/// - [`pnl_plant`](plants::pnl_plant): Position and P&L tracking
///
/// Plants run as independent async tasks using the actor pattern, communicating
/// via tokio channels. This allows running multiple plants concurrently and
/// reconnecting them independently.
/// Rithmic protocol message definitions (protobuf-generated).
///
/// This module contains the protocol buffer message types used by the Rithmic API.
/// The main type you'll interact with is [`rti::messages::RithmicMessage`], an enum
/// covering all message types including market data, order notifications, and
/// connection health events.
/// High-level trading types with optional serde support.
/// Utility types for working with Rithmic data.
/// WebSocket connectivity layer
// Re-export plant types for easier access
pub use ;
pub use ;
pub use ;
pub use ;
// Re-export modern configuration types for convenience
pub use ;
// Re-export error types
pub use ;
// Re-export connection strategy
pub use ConnectStrategy;
// Re-export API types
pub use ;
// Re-export utility types for convenience
pub use ;
// Re-export high-level trading types
pub use ;