nautilus_deribit/
config.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 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 structures for the Deribit adapter.
17
18use nautilus_model::identifiers::{AccountId, TraderId};
19
20use crate::{
21    common::urls::{get_http_base_url, get_ws_url},
22    http::models::DeribitInstrumentKind,
23};
24
25/// Configuration for the Deribit data client.
26#[derive(Clone, Debug)]
27pub struct DeribitDataClientConfig {
28    /// Optional API key for authenticated endpoints.
29    pub api_key: Option<String>,
30    /// Optional API secret for authenticated endpoints.
31    pub api_secret: Option<String>,
32    /// Instrument kinds to load (e.g., Future, Option, Spot).
33    pub instrument_kinds: Vec<DeribitInstrumentKind>,
34    /// Optional override for the HTTP base URL.
35    pub base_url_http: Option<String>,
36    /// Optional override for the WebSocket URL.
37    pub base_url_ws: Option<String>,
38    /// When true the client will use Deribit testnet endpoints.
39    pub use_testnet: bool,
40    /// Optional HTTP timeout in seconds.
41    pub http_timeout_secs: Option<u64>,
42    /// Optional maximum retry attempts for requests.
43    pub max_retries: Option<u32>,
44    /// Optional initial retry delay in milliseconds.
45    pub retry_delay_initial_ms: Option<u64>,
46    /// Optional maximum retry delay in milliseconds.
47    pub retry_delay_max_ms: Option<u64>,
48    /// Optional heartbeat interval in seconds for WebSocket connection.
49    pub heartbeat_interval_secs: Option<u64>,
50    /// Optional interval for refreshing instruments (in minutes).
51    pub update_instruments_interval_mins: Option<u64>,
52}
53
54impl Default for DeribitDataClientConfig {
55    fn default() -> Self {
56        Self {
57            api_key: None,
58            api_secret: None,
59            instrument_kinds: vec![DeribitInstrumentKind::Future],
60            base_url_http: None,
61            base_url_ws: None,
62            use_testnet: false,
63            http_timeout_secs: Some(60),
64            max_retries: Some(3),
65            retry_delay_initial_ms: Some(1_000),
66            retry_delay_max_ms: Some(10_000),
67            heartbeat_interval_secs: Some(30),
68            update_instruments_interval_mins: Some(60),
69        }
70    }
71}
72
73impl DeribitDataClientConfig {
74    /// Creates a new configuration with default settings.
75    #[must_use]
76    pub fn new() -> Self {
77        Self::default()
78    }
79
80    /// Returns `true` when API credentials are available (in config or env vars).
81    #[must_use]
82    pub fn has_api_credentials(&self) -> bool {
83        let (key_env, secret_env) = if self.use_testnet {
84            ("DERIBIT_TESTNET_API_KEY", "DERIBIT_TESTNET_API_SECRET")
85        } else {
86            ("DERIBIT_API_KEY", "DERIBIT_API_SECRET")
87        };
88
89        let has_key = self.api_key.is_some() || std::env::var(key_env).is_ok();
90        let has_secret = self.api_secret.is_some() || std::env::var(secret_env).is_ok();
91        has_key && has_secret
92    }
93
94    /// Returns the HTTP base URL, falling back to the default when unset.
95    #[must_use]
96    pub fn http_base_url(&self) -> String {
97        self.base_url_http
98            .clone()
99            .unwrap_or_else(|| get_http_base_url(self.use_testnet).to_string())
100    }
101
102    /// Returns the WebSocket URL, respecting the testnet flag and overrides.
103    #[must_use]
104    pub fn ws_url(&self) -> String {
105        self.base_url_ws
106            .clone()
107            .unwrap_or_else(|| get_ws_url(self.use_testnet).to_string())
108    }
109}
110
111// ------------------------------------------------------------------------------------------------
112
113/// Configuration for the Deribit execution client.
114#[derive(Clone, Debug)]
115pub struct DeribitExecClientConfig {
116    /// The trader ID for this client.
117    pub trader_id: TraderId,
118    /// The account ID for this client.
119    pub account_id: AccountId,
120    /// Optional API key for authenticated endpoints.
121    pub api_key: Option<String>,
122    /// Optional API secret for authenticated endpoints.
123    pub api_secret: Option<String>,
124    /// Instrument kinds to load (e.g., Future, Option, Spot).
125    pub instrument_kinds: Vec<DeribitInstrumentKind>,
126    /// Optional override for the HTTP base URL.
127    pub base_url_http: Option<String>,
128    /// Optional override for the WebSocket URL.
129    pub base_url_ws: Option<String>,
130    /// When true the client will use Deribit testnet endpoints.
131    pub use_testnet: bool,
132    /// Optional HTTP timeout in seconds.
133    pub http_timeout_secs: Option<u64>,
134    /// Optional maximum retry attempts for requests.
135    pub max_retries: Option<u32>,
136    /// Optional initial retry delay in milliseconds.
137    pub retry_delay_initial_ms: Option<u64>,
138    /// Optional maximum retry delay in milliseconds.
139    pub retry_delay_max_ms: Option<u64>,
140}
141
142impl Default for DeribitExecClientConfig {
143    fn default() -> Self {
144        Self {
145            trader_id: TraderId::default(),
146            account_id: AccountId::from("DERIBIT-001"),
147            api_key: None,
148            api_secret: None,
149            instrument_kinds: vec![DeribitInstrumentKind::Future],
150            base_url_http: None,
151            base_url_ws: None,
152            use_testnet: false,
153            http_timeout_secs: Some(60),
154            max_retries: Some(3),
155            retry_delay_initial_ms: Some(1_000),
156            retry_delay_max_ms: Some(10_000),
157        }
158    }
159}
160
161impl DeribitExecClientConfig {
162    /// Creates a new configuration with default settings.
163    #[must_use]
164    pub fn new(trader_id: TraderId, account_id: AccountId) -> Self {
165        Self {
166            trader_id,
167            account_id,
168            ..Default::default()
169        }
170    }
171
172    /// Returns `true` when API credentials are available (in config or env vars).
173    #[must_use]
174    pub fn has_api_credentials(&self) -> bool {
175        let (key_env, secret_env) = if self.use_testnet {
176            ("DERIBIT_TESTNET_API_KEY", "DERIBIT_TESTNET_API_SECRET")
177        } else {
178            ("DERIBIT_API_KEY", "DERIBIT_API_SECRET")
179        };
180
181        let has_key = self.api_key.is_some() || std::env::var(key_env).is_ok();
182        let has_secret = self.api_secret.is_some() || std::env::var(secret_env).is_ok();
183        has_key && has_secret
184    }
185
186    /// Returns the HTTP base URL, falling back to the default when unset.
187    #[must_use]
188    pub fn http_base_url(&self) -> String {
189        self.base_url_http
190            .clone()
191            .unwrap_or_else(|| get_http_base_url(self.use_testnet).to_string())
192    }
193
194    /// Returns the WebSocket URL, respecting the testnet flag and overrides.
195    #[must_use]
196    pub fn ws_url(&self) -> String {
197        self.base_url_ws
198            .clone()
199            .unwrap_or_else(|| get_ws_url(self.use_testnet).to_string())
200    }
201}
202
203#[cfg(test)]
204mod tests {
205    use rstest::rstest;
206
207    use super::*;
208
209    #[rstest]
210    fn test_default_config() {
211        let config = DeribitDataClientConfig::default();
212        assert!(!config.use_testnet);
213        assert_eq!(config.instrument_kinds.len(), 1);
214        assert_eq!(config.http_timeout_secs, Some(60));
215    }
216
217    #[rstest]
218    fn test_http_base_url_default() {
219        let config = DeribitDataClientConfig::default();
220        assert_eq!(config.http_base_url(), "https://www.deribit.com");
221    }
222
223    #[rstest]
224    fn test_http_base_url_testnet() {
225        let config = DeribitDataClientConfig {
226            use_testnet: true,
227            ..Default::default()
228        };
229        assert_eq!(config.http_base_url(), "https://test.deribit.com");
230    }
231
232    #[rstest]
233    fn test_ws_url_default() {
234        let config = DeribitDataClientConfig::default();
235        assert_eq!(config.ws_url(), "wss://www.deribit.com/ws/api/v2");
236    }
237
238    #[rstest]
239    fn test_ws_url_testnet() {
240        let config = DeribitDataClientConfig {
241            use_testnet: true,
242            ..Default::default()
243        };
244        assert_eq!(config.ws_url(), "wss://test.deribit.com/ws/api/v2");
245    }
246
247    #[rstest]
248    fn test_has_api_credentials_in_config() {
249        let config = DeribitDataClientConfig {
250            api_key: Some("test_key".to_string()),
251            api_secret: Some("test_secret".to_string()),
252            ..Default::default()
253        };
254        assert!(config.has_api_credentials());
255    }
256}