nautilus_bitmex/
config.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Configuration types for the BitMEX adapter clients.
17
18use nautilus_model::identifiers::AccountId;
19
20use crate::common::consts::{
21    BITMEX_HTTP_TESTNET_URL, BITMEX_HTTP_URL, BITMEX_WS_TESTNET_URL, BITMEX_WS_URL,
22};
23
24/// Configuration for the BitMEX live data client.
25#[derive(Clone, Debug)]
26pub struct BitmexDataClientConfig {
27    /// Optional API key used for authenticated REST/WebSocket requests.
28    pub api_key: Option<String>,
29    /// Optional API secret used for authenticated REST/WebSocket requests.
30    pub api_secret: Option<String>,
31    /// Optional override for the REST base URL.
32    pub base_url_http: Option<String>,
33    /// Optional override for the WebSocket URL.
34    pub base_url_ws: Option<String>,
35    /// Optional HTTP proxy URL for general HTTP client operations.
36    pub http_proxy_url: Option<String>,
37    /// Optional WebSocket proxy URL for WebSocket client.
38    ///
39    /// Note: WebSocket proxy support is not yet implemented. This field is reserved
40    /// for future functionality. Use `http_proxy_url` for REST API proxy support.
41    pub ws_proxy_url: Option<String>,
42    /// Optional REST timeout in seconds.
43    pub http_timeout_secs: Option<u64>,
44    /// Optional maximum retry attempts for REST requests.
45    pub max_retries: Option<u32>,
46    /// Optional initial retry backoff in milliseconds.
47    pub retry_delay_initial_ms: Option<u64>,
48    /// Optional maximum retry backoff in milliseconds.
49    pub retry_delay_max_ms: Option<u64>,
50    /// Optional heartbeat interval (seconds) for the WebSocket client.
51    pub heartbeat_interval_secs: Option<u64>,
52    /// Optional receive window in milliseconds for signed requests (default 10_000).
53    ///
54    /// This value determines how far in the future the `api-expires` timestamp will be set
55    /// for signed REST requests. BitMEX uses seconds-granularity Unix timestamps in the
56    /// `api-expires` header, calculated as: `current_timestamp + (recv_window_ms / 1000)`.
57    ///
58    /// **Note**: This parameter is specified in milliseconds for consistency with other
59    /// adapter configurations (e.g., Bybit's `recv_window_ms`), but BitMEX only supports
60    /// seconds-granularity timestamps. The value is converted via integer division, so
61    /// 10000ms becomes 10 seconds, 15500ms becomes 15 seconds, etc.
62    ///
63    /// A larger window provides more tolerance for clock skew and network latency, but
64    /// increases the replay attack window. The default of 10 seconds should be sufficient
65    /// for most deployments. Consider increasing this value (e.g., to 30_000ms = 30s) if you
66    /// experience request expiration errors due to clock drift or high network latency.
67    pub recv_window_ms: Option<u64>,
68    /// When `true`, only active instruments are requested during bootstrap.
69    pub active_only: bool,
70    /// Optional interval (minutes) for instrument refresh from REST.
71    pub update_instruments_interval_mins: Option<u64>,
72    /// When `true`, use BitMEX testnet endpoints by default.
73    pub use_testnet: bool,
74    /// Maximum number of requests per second (burst limit).
75    pub max_requests_per_second: Option<u32>,
76    /// Maximum number of requests per minute (rolling window).
77    pub max_requests_per_minute: Option<u32>,
78}
79
80impl Default for BitmexDataClientConfig {
81    fn default() -> Self {
82        Self {
83            api_key: None,
84            api_secret: None,
85            base_url_http: None,
86            base_url_ws: None,
87            http_proxy_url: None,
88            ws_proxy_url: None,
89            http_timeout_secs: Some(60),
90            max_retries: Some(3),
91            retry_delay_initial_ms: Some(1_000),
92            retry_delay_max_ms: Some(10_000),
93            heartbeat_interval_secs: None,
94            recv_window_ms: Some(10_000),
95            active_only: true,
96            update_instruments_interval_mins: None,
97            use_testnet: false,
98            max_requests_per_second: Some(10),
99            max_requests_per_minute: Some(120),
100        }
101    }
102}
103
104impl BitmexDataClientConfig {
105    /// Creates a configuration with default values.
106    #[must_use]
107    pub fn new() -> Self {
108        Self::default()
109    }
110
111    /// Returns `true` if both API key and secret are available.
112    #[must_use]
113    pub fn has_api_credentials(&self) -> bool {
114        self.api_key.is_some() && self.api_secret.is_some()
115    }
116
117    /// Returns the REST base URL, considering overrides and the testnet flag.
118    #[must_use]
119    pub fn http_base_url(&self) -> String {
120        self.base_url_http.clone().unwrap_or_else(|| {
121            if self.use_testnet {
122                BITMEX_HTTP_TESTNET_URL.to_string()
123            } else {
124                BITMEX_HTTP_URL.to_string()
125            }
126        })
127    }
128
129    /// Returns the WebSocket URL, considering overrides and the testnet flag.
130    #[must_use]
131    pub fn ws_url(&self) -> String {
132        self.base_url_ws.clone().unwrap_or_else(|| {
133            if self.use_testnet {
134                BITMEX_WS_TESTNET_URL.to_string()
135            } else {
136                BITMEX_WS_URL.to_string()
137            }
138        })
139    }
140}
141
142/// Configuration for the BitMEX live execution client.
143#[derive(Clone, Debug)]
144pub struct BitmexExecClientConfig {
145    /// API key used for authenticated requests.
146    pub api_key: Option<String>,
147    /// API secret used for authenticated requests.
148    pub api_secret: Option<String>,
149    /// Optional override for the REST base URL.
150    pub base_url_http: Option<String>,
151    /// Optional override for the WebSocket URL.
152    pub base_url_ws: Option<String>,
153    /// Optional HTTP proxy URL for general HTTP client operations.
154    pub http_proxy_url: Option<String>,
155    /// Optional WebSocket proxy URL for WebSocket client.
156    ///
157    /// Note: WebSocket proxy support is not yet implemented. This field is reserved
158    /// for future functionality. Use `http_proxy_url` for REST API proxy support.
159    pub ws_proxy_url: Option<String>,
160    /// Optional REST timeout in seconds.
161    pub http_timeout_secs: Option<u64>,
162    /// Optional maximum retry attempts for REST requests.
163    pub max_retries: Option<u32>,
164    /// Optional initial retry backoff in milliseconds.
165    pub retry_delay_initial_ms: Option<u64>,
166    /// Optional maximum retry backoff in milliseconds.
167    pub retry_delay_max_ms: Option<u64>,
168    /// Optional heartbeat interval (seconds) for the WebSocket client.
169    pub heartbeat_interval_secs: Option<u64>,
170    /// Optional receive window in milliseconds for signed requests (default 10000).
171    ///
172    /// This value determines how far in the future the `api-expires` timestamp will be set
173    /// for signed REST requests. BitMEX uses seconds-granularity Unix timestamps in the
174    /// `api-expires` header, calculated as: `current_timestamp + (recv_window_ms / 1000)`.
175    ///
176    /// **Note**: This parameter is specified in milliseconds for consistency with other
177    /// adapter configurations (e.g., Bybit's `recv_window_ms`), but BitMEX only supports
178    /// seconds-granularity timestamps. The value is converted via integer division, so
179    /// 10000ms becomes 10 seconds, 15500ms becomes 15 seconds, etc.
180    ///
181    /// A larger window provides more tolerance for clock skew and network latency, but
182    /// increases the replay attack window. The default of 10 seconds should be sufficient
183    /// for most deployments. Consider increasing this value (e.g., to 30000ms = 30s) if you
184    /// experience request expiration errors due to clock drift or high network latency.
185    pub recv_window_ms: Option<u64>,
186    /// When `true`, only active instruments are requested during bootstrap.
187    pub active_only: bool,
188    /// When `true`, use BitMEX testnet endpoints by default.
189    pub use_testnet: bool,
190    /// Optional account identifier to associate with the execution client.
191    pub account_id: Option<AccountId>,
192    /// Maximum number of requests per second (burst limit).
193    pub max_requests_per_second: Option<u32>,
194    /// Maximum number of requests per minute (rolling window).
195    pub max_requests_per_minute: Option<u32>,
196    /// Number of HTTP clients in the submit broadcaster pool (defaults to 1).
197    pub submitter_pool_size: Option<usize>,
198    /// Number of HTTP clients in the cancel broadcaster pool (defaults to 1).
199    pub canceller_pool_size: Option<usize>,
200    /// Optional list of proxy URLs for submit broadcaster pool (path diversity).
201    pub submitter_proxy_urls: Option<Vec<String>>,
202    /// Optional list of proxy URLs for cancel broadcaster pool (path diversity).
203    pub canceller_proxy_urls: Option<Vec<String>>,
204}
205
206impl Default for BitmexExecClientConfig {
207    fn default() -> Self {
208        Self {
209            api_key: None,
210            api_secret: None,
211            base_url_http: None,
212            base_url_ws: None,
213            http_proxy_url: None,
214            ws_proxy_url: None,
215            http_timeout_secs: Some(60),
216            max_retries: Some(3),
217            retry_delay_initial_ms: Some(1_000),
218            retry_delay_max_ms: Some(10_000),
219            heartbeat_interval_secs: Some(5),
220            recv_window_ms: Some(10_000),
221            active_only: true,
222            use_testnet: false,
223            account_id: None,
224            max_requests_per_second: Some(10),
225            max_requests_per_minute: Some(120),
226            submitter_pool_size: None,
227            canceller_pool_size: None,
228            submitter_proxy_urls: None,
229            canceller_proxy_urls: None,
230        }
231    }
232}
233
234impl BitmexExecClientConfig {
235    /// Creates a configuration with default values.
236    #[must_use]
237    pub fn new() -> Self {
238        Self::default()
239    }
240
241    /// Returns `true` if both API key and secret are available.
242    #[must_use]
243    pub fn has_api_credentials(&self) -> bool {
244        self.api_key.is_some() && self.api_secret.is_some()
245    }
246
247    /// Returns the REST base URL, considering overrides and the testnet flag.
248    #[must_use]
249    pub fn http_base_url(&self) -> String {
250        self.base_url_http.clone().unwrap_or_else(|| {
251            if self.use_testnet {
252                BITMEX_HTTP_TESTNET_URL.to_string()
253            } else {
254                BITMEX_HTTP_URL.to_string()
255            }
256        })
257    }
258
259    /// Returns the WebSocket URL, considering overrides and the testnet flag.
260    #[must_use]
261    pub fn ws_url(&self) -> String {
262        self.base_url_ws.clone().unwrap_or_else(|| {
263            if self.use_testnet {
264                BITMEX_WS_TESTNET_URL.to_string()
265            } else {
266                BITMEX_WS_URL.to_string()
267            }
268        })
269    }
270}