nautilus_deribit/
config.rs1use nautilus_model::identifiers::{AccountId, TraderId};
19use nautilus_network::websocket::TransportBackend;
20use serde::{Deserialize, Serialize};
21
22use crate::{
23 common::{
24 credential::credential_env_vars,
25 enums::DeribitEnvironment,
26 urls::{get_http_base_url, get_ws_url},
27 },
28 http::models::DeribitProductType,
29};
30
31#[derive(Debug, Clone, Serialize, Deserialize, bon::Builder)]
33#[serde(default, deny_unknown_fields)]
34#[cfg_attr(
35 feature = "python",
36 pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.deribit", from_py_object)
37)]
38#[cfg_attr(
39 feature = "python",
40 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.adapters.deribit")
41)]
42pub struct DeribitDataClientConfig {
43 pub api_key: Option<String>,
45 pub api_secret: Option<String>,
47 #[builder(default = vec![DeribitProductType::Future])]
49 pub product_types: Vec<DeribitProductType>,
50 pub base_url_http: Option<String>,
52 pub base_url_ws: Option<String>,
54 pub proxy_url: Option<String>,
56 #[builder(default)]
58 pub environment: DeribitEnvironment,
59 #[builder(default = 60)]
61 pub http_timeout_secs: u64,
62 #[builder(default = 3)]
64 pub max_retries: u32,
65 #[builder(default = 1_000)]
67 pub retry_delay_initial_ms: u64,
68 #[builder(default = 10_000)]
70 pub retry_delay_max_ms: u64,
71 #[builder(default = 30)]
73 pub heartbeat_interval_secs: u64,
74 #[builder(default = 60)]
76 pub update_instruments_interval_mins: u64,
77 #[builder(default = false)]
79 pub auto_load_missing_instruments: bool,
80 #[builder(default)]
82 pub transport_backend: TransportBackend,
83}
84
85impl Default for DeribitDataClientConfig {
86 fn default() -> Self {
87 Self::builder().build()
88 }
89}
90
91impl DeribitDataClientConfig {
92 #[must_use]
94 pub fn new() -> Self {
95 Self::default()
96 }
97
98 #[must_use]
100 pub fn has_api_credentials(&self) -> bool {
101 let (key_env, secret_env) = credential_env_vars(self.environment);
102 let has_key = self.api_key.is_some() || std::env::var(key_env).is_ok();
103 let has_secret = self.api_secret.is_some() || std::env::var(secret_env).is_ok();
104 has_key && has_secret
105 }
106
107 #[must_use]
109 pub fn http_base_url(&self) -> String {
110 self.base_url_http
111 .clone()
112 .unwrap_or_else(|| get_http_base_url(self.environment).to_string())
113 }
114
115 #[must_use]
117 pub fn ws_url(&self) -> String {
118 self.base_url_ws
119 .clone()
120 .unwrap_or_else(|| get_ws_url(self.environment).to_string())
121 }
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize, bon::Builder)]
126#[serde(default, deny_unknown_fields)]
127#[cfg_attr(
128 feature = "python",
129 pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.deribit", from_py_object)
130)]
131#[cfg_attr(
132 feature = "python",
133 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.adapters.deribit")
134)]
135pub struct DeribitExecClientConfig {
136 #[builder(default)]
138 pub trader_id: TraderId,
139 #[builder(default = AccountId::from("DERIBIT-001"))]
141 pub account_id: AccountId,
142 pub api_key: Option<String>,
144 pub api_secret: Option<String>,
146 #[builder(default = vec![DeribitProductType::Future])]
148 pub product_types: Vec<DeribitProductType>,
149 pub base_url_http: Option<String>,
151 pub base_url_ws: Option<String>,
153 pub proxy_url: Option<String>,
155 #[builder(default)]
157 pub environment: DeribitEnvironment,
158 #[builder(default = 60)]
160 pub http_timeout_secs: u64,
161 #[builder(default = 3)]
163 pub max_retries: u32,
164 #[builder(default = 1_000)]
166 pub retry_delay_initial_ms: u64,
167 #[builder(default = 10_000)]
169 pub retry_delay_max_ms: u64,
170 #[builder(default)]
172 pub transport_backend: TransportBackend,
173}
174
175impl Default for DeribitExecClientConfig {
176 fn default() -> Self {
177 Self::builder().build()
178 }
179}
180
181impl DeribitExecClientConfig {
182 #[must_use]
184 pub fn has_api_credentials(&self) -> bool {
185 let (key_env, secret_env) = credential_env_vars(self.environment);
186 let has_key = self.api_key.is_some() || std::env::var(key_env).is_ok();
187 let has_secret = self.api_secret.is_some() || std::env::var(secret_env).is_ok();
188 has_key && has_secret
189 }
190
191 #[must_use]
193 pub fn http_base_url(&self) -> String {
194 self.base_url_http
195 .clone()
196 .unwrap_or_else(|| get_http_base_url(self.environment).to_string())
197 }
198
199 #[must_use]
201 pub fn ws_url(&self) -> String {
202 self.base_url_ws
203 .clone()
204 .unwrap_or_else(|| get_ws_url(self.environment).to_string())
205 }
206}
207
208#[cfg(test)]
209mod tests {
210 use rstest::rstest;
211
212 use super::*;
213
214 #[rstest]
215 fn test_default_config() {
216 let config = DeribitDataClientConfig::default();
217 assert_eq!(config.environment, DeribitEnvironment::Mainnet);
218 assert_eq!(config.product_types.len(), 1);
219 assert_eq!(config.http_timeout_secs, 60);
220 }
221
222 #[rstest]
223 fn test_http_base_url_default() {
224 let config = DeribitDataClientConfig::default();
225 assert_eq!(config.http_base_url(), "https://www.deribit.com");
226 }
227
228 #[rstest]
229 fn test_http_base_url_testnet() {
230 let config = DeribitDataClientConfig {
231 environment: DeribitEnvironment::Testnet,
232 ..Default::default()
233 };
234 assert_eq!(config.http_base_url(), "https://test.deribit.com");
235 }
236
237 #[rstest]
238 fn test_ws_url_default() {
239 let config = DeribitDataClientConfig::default();
240 assert_eq!(config.ws_url(), "wss://www.deribit.com/ws/api/v2");
241 }
242
243 #[rstest]
244 fn test_ws_url_testnet() {
245 let config = DeribitDataClientConfig {
246 environment: DeribitEnvironment::Testnet,
247 ..Default::default()
248 };
249 assert_eq!(config.ws_url(), "wss://test.deribit.com/ws/api/v2");
250 }
251
252 #[rstest]
253 fn test_has_api_credentials_in_config() {
254 let config = DeribitDataClientConfig {
255 api_key: Some("test_key".to_string()),
256 api_secret: Some("test_secret".to_string()),
257 ..Default::default()
258 };
259 assert!(config.has_api_credentials());
260 }
261
262 #[rstest]
263 fn test_data_config_toml_minimal() {
264 let config: DeribitDataClientConfig = toml::from_str(
265 r#"
266environment = "testnet"
267product_types = ["future", "option"]
268heartbeat_interval_secs = 15
269auto_load_missing_instruments = true
270"#,
271 )
272 .unwrap();
273
274 assert_eq!(config.environment, DeribitEnvironment::Testnet);
275 assert_eq!(
276 config.product_types,
277 vec![DeribitProductType::Future, DeribitProductType::Option]
278 );
279 assert_eq!(config.heartbeat_interval_secs, 15);
280 assert!(config.auto_load_missing_instruments);
281 }
282
283 #[rstest]
284 fn test_exec_config_toml_empty_uses_defaults() {
285 let config: DeribitExecClientConfig = toml::from_str("").unwrap();
286 let expected = DeribitExecClientConfig::default();
287
288 assert_eq!(config.trader_id, expected.trader_id);
289 assert_eq!(config.account_id, expected.account_id);
290 assert_eq!(config.environment, expected.environment);
291 assert_eq!(config.product_types, expected.product_types);
292 assert_eq!(config.http_timeout_secs, expected.http_timeout_secs);
293 assert_eq!(config.max_retries, expected.max_retries);
294 assert_eq!(config.transport_backend, expected.transport_backend);
295 }
296}