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;