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/// ```ignore
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::ConnectionOptions;
90pub use connection::StartupMessageCallback;
91
92/// Common utilities shared across modules
93pub(crate) mod common;
94
95/// Display groups subscription support
96pub mod display_groups;
97
98/// Subscription types for streaming data
99pub mod subscriptions;
100
101/// A [Contract](crate::contracts::Contract) object represents trading instruments such as a stocks, futures or options.
102///
103/// 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.
104pub mod contracts;
105// Describes primary data structures used by the model.
106pub mod errors;
107/// APIs for retrieving market data
108pub mod market_data;
109pub mod messages;
110/// APIs for retrieving news data including articles, bulletins, and providers
111pub mod news;
112/// Data types for building and placing orders.
113pub mod orders;
114/// APIs for working with the market scanner.
115pub mod scanner;
116/// APIs for working with Wall Street Horizon: Earnings Calendar & Event Data.
117pub mod wsh;
118
119/// Server interaction tracing for debugging and monitoring
120pub mod trace;
121
122/// A prelude module for convenient importing of commonly used types.
123pub mod prelude;
124
125/// Protocol version checking and constants for TWS API features.
126pub mod protocol;
127
128/// Generated protobuf message types for the TWS API wire protocol.
129#[cfg(feature = "proto")]
130pub mod proto;
131
132mod server_versions;
133
134#[doc(inline)]
135pub use errors::Error;
136
137#[doc(inline)]
138pub use client::Client;
139use std::sync::LazyLock;
140use time::{
141 format_description::{self, BorrowedFormatItem},
142 Date,
143};
144
145#[cfg(test)]
146pub(crate) mod stubs;
147
148#[cfg(test)]
149pub(crate) mod tests;
150
151#[cfg(test)]
152pub(crate) mod testdata;
153
154// ToField
155
156pub(crate) trait ToField {
157 fn to_field(&self) -> String;
158}
159
160impl ToField for bool {
161 fn to_field(&self) -> String {
162 if *self {
163 String::from("1")
164 } else {
165 String::from("0")
166 }
167 }
168}
169
170impl ToField for String {
171 fn to_field(&self) -> String {
172 self.clone()
173 }
174}
175
176impl ToField for Option<String> {
177 fn to_field(&self) -> String {
178 encode_option_field(self)
179 }
180}
181
182impl ToField for &str {
183 fn to_field(&self) -> String {
184 <&str>::clone(self).to_string()
185 }
186}
187
188impl ToField for Option<&str> {
189 fn to_field(&self) -> String {
190 encode_option_field(self)
191 }
192}
193
194impl ToField for usize {
195 fn to_field(&self) -> String {
196 self.to_string()
197 }
198}
199
200impl ToField for i32 {
201 fn to_field(&self) -> String {
202 self.to_string()
203 }
204}
205
206impl ToField for Option<i32> {
207 fn to_field(&self) -> String {
208 encode_option_field(self)
209 }
210}
211
212impl ToField for f64 {
213 fn to_field(&self) -> String {
214 self.to_string()
215 }
216}
217
218impl ToField for Option<f64> {
219 fn to_field(&self) -> String {
220 encode_option_field(self)
221 }
222}
223
224fn date_format() -> Vec<BorrowedFormatItem<'static>> {
225 format_description::parse("[year][month][day]").unwrap()
226}
227
228static DATE_FORMAT: LazyLock<Vec<BorrowedFormatItem<'static>>> = LazyLock::new(date_format);
229
230impl ToField for Date {
231 fn to_field(&self) -> String {
232 self.format(&DATE_FORMAT).unwrap()
233 }
234}
235
236impl ToField for Option<Date> {
237 fn to_field(&self) -> String {
238 encode_option_field(self)
239 }
240}
241
242fn encode_option_field<T: ToField>(val: &Option<T>) -> String {
243 match val {
244 Some(val) => val.to_field(),
245 None => String::from(""),
246 }
247}
248
249// max attempts to retry failed tws requests
250const MAX_RETRIES: i32 = 5;