nautilus_interactive_brokers/
config.rs1use std::collections::{HashMap, HashSet};
19
20use nautilus_model::identifiers::InstrumentId;
21use serde::{Deserialize, Serialize};
22
23use crate::common::consts::{DEFAULT_CLIENT_ID, DEFAULT_HOST, DEFAULT_PORT};
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
27#[cfg_attr(
28 feature = "python",
29 pyo3::pyclass(
30 module = "nautilus_trader.core.nautilus_pyo3.interactive_brokers",
31 from_py_object
32 )
33)]
34#[derive(Default)]
35pub enum MarketDataType {
36 #[default]
38 Realtime = 1,
39 Frozen = 2,
41 Delayed = 3,
43 DelayedFrozen = 4,
45}
46
47impl From<MarketDataType> for ibapi::market_data::MarketDataType {
48 fn from(data_type: MarketDataType) -> Self {
49 match data_type {
50 MarketDataType::Realtime => Self::Realtime,
51 MarketDataType::Frozen => Self::Frozen,
52 MarketDataType::Delayed => Self::Delayed,
53 MarketDataType::DelayedFrozen => Self::DelayedFrozen,
54 }
55 }
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize, bon::Builder)]
60#[serde(default)]
61#[cfg_attr(
62 feature = "python",
63 pyo3::pyclass(
64 module = "nautilus_trader.core.nautilus_pyo3.interactive_brokers",
65 subclass,
66 from_py_object
67 )
68)]
69pub struct InteractiveBrokersDataClientConfig {
70 #[builder(default = DEFAULT_HOST.to_string())]
72 pub host: String,
73 #[builder(default = DEFAULT_PORT)]
75 pub port: u16,
76 #[builder(default = DEFAULT_CLIENT_ID)]
78 pub client_id: i32,
79 #[builder(default = true)]
81 pub use_regular_trading_hours: bool,
82 #[builder(default)]
84 pub market_data_type: MarketDataType,
85 #[builder(default)]
87 pub ignore_quote_tick_size_updates: bool,
88 #[builder(default = 300)]
90 pub connection_timeout: u64,
91 #[builder(default = 60)]
95 pub request_timeout: u64,
96 #[builder(default)]
98 pub handle_revised_bars: bool,
99 #[builder(default = true)]
101 pub batch_quotes: bool,
102}
103
104impl Default for InteractiveBrokersDataClientConfig {
105 fn default() -> Self {
106 Self::builder().build()
107 }
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize, bon::Builder)]
112#[serde(default)]
113#[cfg_attr(
114 feature = "python",
115 pyo3::pyclass(
116 module = "nautilus_trader.core.nautilus_pyo3.interactive_brokers",
117 subclass,
118 from_py_object
119 )
120)]
121pub struct InteractiveBrokersExecClientConfig {
122 #[builder(default = DEFAULT_HOST.to_string())]
124 pub host: String,
125 #[builder(default = DEFAULT_PORT)]
127 pub port: u16,
128 #[builder(default = DEFAULT_CLIENT_ID)]
130 pub client_id: i32,
131 pub account_id: Option<String>,
133 #[builder(default = 300)]
135 pub connection_timeout: u64,
136 #[builder(default = 60)]
138 pub request_timeout: u64,
139 #[builder(default)]
141 pub fetch_all_open_orders: bool,
142 #[builder(default)]
144 pub track_option_exercise_from_position_update: bool,
145}
146
147impl Default for InteractiveBrokersExecClientConfig {
148 fn default() -> Self {
149 Self::builder().build()
150 }
151}
152
153#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
155#[cfg_attr(
156 feature = "python",
157 pyo3::pyclass(
158 module = "nautilus_trader.core.nautilus_pyo3.interactive_brokers",
159 from_py_object
160 )
161)]
162#[derive(Default)]
163pub enum SymbologyMethod {
164 #[serde(rename = "simplified")]
166 #[default]
167 Simplified,
168 #[serde(rename = "raw")]
170 Raw,
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize, bon::Builder)]
175#[serde(default)]
176#[cfg_attr(
177 feature = "python",
178 pyo3::pyclass(
179 module = "nautilus_trader.core.nautilus_pyo3.interactive_brokers",
180 subclass,
181 from_py_object
182 )
183)]
184pub struct InteractiveBrokersInstrumentProviderConfig {
185 #[builder(default)]
187 pub symbology_method: SymbologyMethod,
188 #[builder(default)]
190 pub load_ids: HashSet<InstrumentId>,
191 #[builder(default)]
193 pub load_contracts: Vec<serde_json::Value>,
194 pub min_expiry_days: Option<u32>,
196 pub max_expiry_days: Option<u32>,
198 pub build_options_chain: Option<bool>,
200 pub build_futures_chain: Option<bool>,
202 pub cache_validity_days: Option<u32>,
204 #[builder(default)]
206 pub convert_exchange_to_mic_venue: bool,
207 #[builder(default)]
209 pub symbol_to_mic_venue: HashMap<String, String>,
210 #[builder(default)]
212 pub filter_sec_types: HashSet<String>,
213 pub cache_path: Option<String>,
216}
217
218impl Default for InteractiveBrokersInstrumentProviderConfig {
219 fn default() -> Self {
220 Self::builder().build()
221 }
222}
223
224#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
226#[cfg_attr(
227 feature = "python",
228 pyo3::pyclass(
229 module = "nautilus_trader.core.nautilus_pyo3.interactive_brokers",
230 from_py_object
231 )
232)]
233#[derive(Default)]
234pub enum TradingMode {
235 #[serde(rename = "paper")]
237 #[default]
238 Paper,
239 #[serde(rename = "live")]
241 Live,
242}
243
244#[derive(Debug, Clone, Serialize, Deserialize, bon::Builder)]
249#[serde(default)]
250#[cfg_attr(
251 feature = "python",
252 pyo3::pyclass(
253 module = "nautilus_trader.core.nautilus_pyo3.interactive_brokers",
254 subclass,
255 from_py_object
256 )
257)]
258pub struct DockerizedIBGatewayConfig {
259 pub username: Option<String>,
261 pub password: Option<String>,
263 #[builder(default)]
265 pub trading_mode: TradingMode,
266 #[builder(default = true)]
268 pub read_only_api: bool,
269 #[builder(default = 300)]
271 pub timeout: u64,
272 #[builder(default = "ghcr.io/gnzsnz/ib-gateway:stable".to_string())]
274 pub container_image: String,
275 pub vnc_port: Option<u16>,
277}
278
279impl DockerizedIBGatewayConfig {
280 pub fn mask_sensitive_info(value: &str) -> String {
282 if value.len() <= 2 {
283 "*".repeat(value.len())
284 } else {
285 format!(
286 "{}{}{}",
287 &value[0..1],
288 "*".repeat(value.len() - 2),
289 &value[value.len() - 1..]
290 )
291 }
292 }
293
294 pub fn validate(&self) -> anyhow::Result<()> {
300 if self.timeout == 0 {
301 anyhow::bail!("Timeout must be greater than 0");
302 }
303
304 if self.timeout > 3600 {
305 anyhow::bail!("Timeout must be less than 3600 seconds");
306 }
307
308 if let Some(port) = self.vnc_port
309 && (!(5900..=5999).contains(&port))
310 {
311 anyhow::bail!("VNC port must be between 5900 and 5999");
312 }
313
314 Ok(())
315 }
316}
317
318impl Default for DockerizedIBGatewayConfig {
319 fn default() -> Self {
320 Self::builder()
321 .maybe_username(std::env::var("TWS_USERNAME").ok())
322 .maybe_password(std::env::var("TWS_PASSWORD").ok())
323 .build()
324 }
325}