ibapi/lib.rs
1//! [![github]](https://github.com/wboayue/rust-ibapi) [![crates-io]](https://crates.io/crates/ibapi) [![license]](https://opensource.org/licenses/MIT)
2//!
3//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
4//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
5//! [license]: https://img.shields.io/badge/License-MIT-blue.svg?style=for-the-badge&labelColor=555555
6//!
7//! <br>
8//!
9//! A comprehensive Rust implementation of the Interactive Brokers TWS API, providing a robust and
10//! user-friendly interface for TWS and IB Gateway. Designed with simplicity in mind, it integrates smoothly into trading systems.
11//!
12//! **API Documentation:**
13//! * [TWS API Reference](https://interactivebrokers.github.io/tws-api/introduction.html) - Detailed technical documentation
14//! * [IBKR Campus](https://ibkrcampus.com/ibkr-api-page/trader-workstation-api/) - IB's official learning platform
15//!
16//! This fully featured API enables the retrieval of account information, access to real-time and historical market data, order management,
17//! market scanning, and access to news and Wall Street Horizons (WSH) event data. Future updates will focus on bug fixes,
18//! maintaining parity with the official API, and enhancing usability.
19//!
20//! For an overview of API usage, refer to the [README](https://github.com/wboayue/rust-ibapi/blob/main/README.md).
21
22#![warn(missing_docs)]
23// Allow octal-looking escapes in string literals (used in test data)
24#![allow(clippy::octal_escapes)]
25#![allow(clippy::bool_assert_comparison)]
26#![allow(clippy::useless_format)]
27#![allow(clippy::uninlined_format_args)]
28#![allow(clippy::assertions_on_constants)]
29
30// Feature guards
31#[cfg(not(any(feature = "sync", feature = "async")))]
32compile_error!(
33 "You must enable at least one of the 'sync' or 'async' features to use this crate.\n\
34 The 'async' feature is enabled by default; if you disabled default features, be sure to\n\
35 opt back into either API:\n\
36 ibapi = { version = \"2.0\", default-features = false, features = [\"sync\"] }\n\
37 ibapi = { version = \"2.0\", default-features = false, features = [\"async\"] }\n\
38 You may also enable both to access the synchronous API under `client::blocking`."
39);
40
41/// Describes items present in an account.
42pub mod accounts;
43
44/// TWS API Client.
45///
46/// The Client establishes the connection to TWS or the Gateway.
47/// It manages the routing of messages between TWS and the application.
48pub mod client;
49
50pub(crate) mod transport;
51
52/// Connection management
53pub(crate) mod connection;
54
55/// Callback for handling unsolicited messages during connection setup.
56///
57/// When TWS sends messages like `OpenOrder` or `OrderStatus` during the connection
58/// handshake, this callback is invoked to allow the application to process them
59/// instead of discarding them.
60///
61/// # Example
62///
63/// ```no_run
64/// use ibapi::{Client, StartupMessageCallback};
65/// use ibapi::messages::IncomingMessages;
66/// use std::sync::{Arc, Mutex};
67///
68/// #[tokio::main]
69/// async fn main() {
70/// let orders = Arc::new(Mutex::new(Vec::new()));
71/// let orders_clone = orders.clone();
72///
73/// let callback: StartupMessageCallback = Box::new(move |msg| {
74/// match msg.message_type() {
75/// IncomingMessages::OpenOrder | IncomingMessages::OrderStatus => {
76/// orders_clone.lock().unwrap().push(msg);
77/// }
78/// _ => {}
79/// }
80/// });
81///
82/// let client = Client::connect_with_callback("127.0.0.1:4002", 100, Some(callback))
83/// .await
84/// .expect("connection failed");
85///
86/// println!("Received {} startup orders", orders.lock().unwrap().len());
87/// }
88/// ```
89pub use connection::StartupMessageCallback;
90
91/// Common utilities shared across modules
92pub(crate) mod common;
93
94/// Display groups subscription support
95pub mod display_groups;
96
97/// Subscription types for streaming data
98pub mod subscriptions;
99
100/// A [Contract](crate::contracts::Contract) object represents trading instruments such as a stocks, futures or options.
101///
102/// Every time a new request that requires a contract (i.e. market data, order placing, etc.) is sent to the API, the system will try to match the provided contract object with a single candidate. If there is more than one contract matching the same description, the API will return an error notifying you there is an ambiguity. In these cases the API needs further information to narrow down the list of contracts matching the provided description to a single element.
103pub mod contracts;
104// Describes primary data structures used by the model.
105pub mod errors;
106/// APIs for retrieving market data
107pub mod market_data;
108pub mod messages;
109/// APIs for retrieving news data including articles, bulletins, and providers
110pub mod news;
111/// Data types for building and placing orders.
112pub mod orders;
113/// APIs for working with the market scanner.
114pub mod scanner;
115/// APIs for working with Wall Street Horizon: Earnings Calendar & Event Data.
116pub mod wsh;
117
118/// Server interaction tracing for debugging and monitoring
119pub mod trace;
120
121/// A prelude module for convenient importing of commonly used types.
122pub mod prelude;
123
124/// Protocol version checking and constants for TWS API features.
125pub mod protocol;
126
127mod server_versions;
128
129#[doc(inline)]
130pub use errors::Error;
131
132#[doc(inline)]
133pub use client::Client;
134use std::sync::LazyLock;
135use time::{
136 format_description::{self, BorrowedFormatItem},
137 Date,
138};
139
140#[cfg(test)]
141pub(crate) mod stubs;
142
143#[cfg(test)]
144pub(crate) mod tests;
145
146#[cfg(test)]
147pub(crate) mod testdata;
148
149// ToField
150
151pub(crate) trait ToField {
152 fn to_field(&self) -> String;
153}
154
155impl ToField for bool {
156 fn to_field(&self) -> String {
157 if *self {
158 String::from("1")
159 } else {
160 String::from("0")
161 }
162 }
163}
164
165impl ToField for String {
166 fn to_field(&self) -> String {
167 self.clone()
168 }
169}
170
171impl ToField for Option<String> {
172 fn to_field(&self) -> String {
173 encode_option_field(self)
174 }
175}
176
177impl ToField for &str {
178 fn to_field(&self) -> String {
179 <&str>::clone(self).to_string()
180 }
181}
182
183impl ToField for Option<&str> {
184 fn to_field(&self) -> String {
185 encode_option_field(self)
186 }
187}
188
189impl ToField for usize {
190 fn to_field(&self) -> String {
191 self.to_string()
192 }
193}
194
195impl ToField for i32 {
196 fn to_field(&self) -> String {
197 self.to_string()
198 }
199}
200
201impl ToField for Option<i32> {
202 fn to_field(&self) -> String {
203 encode_option_field(self)
204 }
205}
206
207impl ToField for f64 {
208 fn to_field(&self) -> String {
209 self.to_string()
210 }
211}
212
213impl ToField for Option<f64> {
214 fn to_field(&self) -> String {
215 encode_option_field(self)
216 }
217}
218
219fn date_format() -> Vec<BorrowedFormatItem<'static>> {
220 format_description::parse("[year][month][day]").unwrap()
221}
222
223static DATE_FORMAT: LazyLock<Vec<BorrowedFormatItem<'static>>> = LazyLock::new(date_format);
224
225impl ToField for Date {
226 fn to_field(&self) -> String {
227 self.format(&DATE_FORMAT).unwrap()
228 }
229}
230
231impl ToField for Option<Date> {
232 fn to_field(&self) -> String {
233 encode_option_field(self)
234 }
235}
236
237fn encode_option_field<T: ToField>(val: &Option<T>) -> String {
238 match val {
239 Some(val) => val.to_field(),
240 None => String::from(""),
241 }
242}
243
244// max attempts to retry failed tws requests
245const MAX_RETRIES: i32 = 5;