ccxt_exchanges/bybit/
builder.rs1use super::{Bybit, BybitOptions};
7use ccxt_core::config::{ProxyConfig, RetryPolicy};
8use ccxt_core::types::default_type::{DefaultSubType, DefaultType};
9use ccxt_core::{ExchangeConfig, Result};
10use serde_json::Value;
11use std::collections::HashMap;
12use std::time::Duration;
13
14#[derive(Debug, Clone)]
33pub struct BybitBuilder {
34 config: ExchangeConfig,
36 options: BybitOptions,
38}
39
40impl Default for BybitBuilder {
41 fn default() -> Self {
42 Self::new()
43 }
44}
45
46impl BybitBuilder {
47 pub fn new() -> Self {
57 Self {
58 config: ExchangeConfig {
59 id: "bybit".to_string(),
60 name: "Bybit".to_string(),
61 ..Default::default()
62 },
63 options: BybitOptions::default(),
64 }
65 }
66
67 pub fn api_key(mut self, key: impl Into<String>) -> Self {
73 self.config.api_key = Some(ccxt_core::SecretString::new(key));
74 self
75 }
76
77 pub fn secret(mut self, secret: impl Into<String>) -> Self {
83 self.config.secret = Some(ccxt_core::SecretString::new(secret));
84 self
85 }
86
87 pub fn sandbox(mut self, enabled: bool) -> Self {
99 self.config.sandbox = enabled;
100 self.options.testnet = enabled;
101 self
102 }
103
104 pub fn testnet(mut self, enabled: bool) -> Self {
116 self.config.sandbox = enabled;
117 self.options.testnet = enabled;
118 self
119 }
120
121 pub fn account_type(mut self, account_type: impl Into<String>) -> Self {
129 self.options.account_type = account_type.into();
130 self
131 }
132
133 pub fn default_type(mut self, default_type: impl Into<DefaultType>) -> Self {
158 self.options.default_type = default_type.into();
159 self
160 }
161
162 pub fn default_sub_type(mut self, sub_type: DefaultSubType) -> Self {
187 self.options.default_sub_type = Some(sub_type);
188 self
189 }
190
191 pub fn recv_window(mut self, millis: u64) -> Self {
200 self.options.recv_window = millis;
201 self
202 }
203
204 pub fn timeout(mut self, timeout: Duration) -> Self {
206 self.config.timeout = timeout;
207 self
208 }
209
210 pub fn timeout_secs(mut self, seconds: u64) -> Self {
212 self.config.timeout = Duration::from_secs(seconds);
213 self
214 }
215
216 pub fn connect_timeout(mut self, timeout: Duration) -> Self {
222 self.config.connect_timeout = timeout;
223 self
224 }
225
226 pub fn connect_timeout_secs(mut self, seconds: u64) -> Self {
232 self.config.connect_timeout = Duration::from_secs(seconds);
233 self
234 }
235
236 pub fn retry_policy(mut self, policy: RetryPolicy) -> Self {
238 self.config.retry_policy = Some(policy);
239 self
240 }
241
242 pub fn enable_rate_limit(mut self, enabled: bool) -> Self {
248 self.config.enable_rate_limit = enabled;
249 self
250 }
251
252 pub fn proxy(mut self, proxy: ProxyConfig) -> Self {
254 self.config.proxy = Some(proxy);
255 self
256 }
257
258 pub fn proxy_url(mut self, url: impl Into<String>) -> Self {
260 self.config.proxy = Some(ProxyConfig::new(url));
261 self
262 }
263
264 pub fn verbose(mut self, enabled: bool) -> Self {
270 self.config.verbose = enabled;
271 self
272 }
273
274 pub fn option(mut self, key: impl Into<String>, value: Value) -> Self {
281 self.config.options.insert(key.into(), value);
282 self
283 }
284
285 pub fn options(mut self, options: HashMap<String, Value>) -> Self {
291 self.config.options.extend(options);
292 self
293 }
294
295 #[cfg(test)]
297 pub fn get_config(&self) -> &ExchangeConfig {
298 &self.config
299 }
300
301 #[cfg(test)]
303 pub fn get_options(&self) -> &BybitOptions {
304 &self.options
305 }
306
307 pub fn build(self) -> Result<Bybit> {
317 Bybit::new_with_options(self.config, self.options)
318 }
319}
320
321#[cfg(test)]
322mod tests {
323 use super::*;
324
325 #[test]
326 fn test_builder_default() {
327 let builder = BybitBuilder::new();
328 assert_eq!(builder.config.id, "bybit");
329 assert_eq!(builder.config.name, "Bybit");
330 assert!(!builder.config.sandbox);
331 assert_eq!(builder.options.account_type, "UNIFIED");
332 assert_eq!(builder.options.recv_window, 5000);
333 }
334
335 #[test]
336 fn test_builder_api_key() {
337 let builder = BybitBuilder::new().api_key("test-key");
338 assert_eq!(
339 builder.config.api_key.as_ref().map(|s| s.expose_secret()),
340 Some("test-key")
341 );
342 }
343
344 #[test]
345 fn test_builder_secret() {
346 let builder = BybitBuilder::new().secret("test-secret");
347 assert_eq!(
348 builder.config.secret.as_ref().map(|s| s.expose_secret()),
349 Some("test-secret")
350 );
351 }
352
353 #[test]
354 fn test_builder_sandbox() {
355 let builder = BybitBuilder::new().sandbox(true);
356 assert!(builder.config.sandbox);
357 assert!(builder.options.testnet);
358 }
359
360 #[test]
361 fn test_builder_testnet() {
362 let builder = BybitBuilder::new().testnet(true);
363 assert!(builder.config.sandbox);
364 assert!(builder.options.testnet);
365 }
366
367 #[test]
368 fn test_builder_sandbox_testnet_equivalence() {
369 let sandbox_builder = BybitBuilder::new().sandbox(true);
371 let testnet_builder = BybitBuilder::new().testnet(true);
372
373 assert_eq!(
374 sandbox_builder.config.sandbox,
375 testnet_builder.config.sandbox
376 );
377 assert_eq!(
378 sandbox_builder.options.testnet,
379 testnet_builder.options.testnet
380 );
381 }
382
383 #[test]
384 fn test_builder_account_type() {
385 let builder = BybitBuilder::new().account_type("CONTRACT");
386 assert_eq!(builder.options.account_type, "CONTRACT");
387 }
388
389 #[test]
390 fn test_builder_default_type() {
391 let builder = BybitBuilder::new().default_type(DefaultType::Swap);
392 assert_eq!(builder.options.default_type, DefaultType::Swap);
393 }
394
395 #[test]
396 fn test_builder_default_type_from_string() {
397 let builder = BybitBuilder::new().default_type("futures");
398 assert_eq!(builder.options.default_type, DefaultType::Futures);
399 }
400
401 #[test]
402 fn test_builder_default_sub_type() {
403 let builder = BybitBuilder::new().default_sub_type(DefaultSubType::Inverse);
404 assert_eq!(
405 builder.options.default_sub_type,
406 Some(DefaultSubType::Inverse)
407 );
408 }
409
410 #[test]
411 fn test_builder_default_type_and_sub_type() {
412 let builder = BybitBuilder::new()
413 .default_type(DefaultType::Swap)
414 .default_sub_type(DefaultSubType::Linear);
415 assert_eq!(builder.options.default_type, DefaultType::Swap);
416 assert_eq!(
417 builder.options.default_sub_type,
418 Some(DefaultSubType::Linear)
419 );
420 }
421
422 #[test]
423 fn test_builder_recv_window() {
424 let builder = BybitBuilder::new().recv_window(10000);
425 assert_eq!(builder.options.recv_window, 10000);
426 }
427
428 #[test]
429 fn test_builder_timeout() {
430 let builder = BybitBuilder::new().timeout(Duration::from_secs(60));
431 assert_eq!(builder.config.timeout, Duration::from_secs(60));
432 }
433
434 #[test]
435 fn test_builder_connect_timeout() {
436 let builder = BybitBuilder::new().connect_timeout(Duration::from_secs(15));
437 assert_eq!(builder.config.connect_timeout, Duration::from_secs(15));
438 }
439
440 #[test]
441 fn test_builder_connect_timeout_secs() {
442 let builder = BybitBuilder::new().connect_timeout_secs(20);
443 assert_eq!(builder.config.connect_timeout, Duration::from_secs(20));
444 }
445
446 #[test]
447 fn test_builder_chaining() {
448 let builder = BybitBuilder::new()
449 .api_key("key")
450 .secret("secret")
451 .testnet(true)
452 .timeout(Duration::from_secs(30))
453 .recv_window(10000)
454 .account_type("SPOT")
455 .default_type(DefaultType::Swap)
456 .default_sub_type(DefaultSubType::Linear);
457
458 assert_eq!(
459 builder.config.api_key.as_ref().map(|s| s.expose_secret()),
460 Some("key")
461 );
462 assert_eq!(
463 builder.config.secret.as_ref().map(|s| s.expose_secret()),
464 Some("secret")
465 );
466 assert!(builder.config.sandbox);
467 assert_eq!(builder.config.timeout, Duration::from_secs(30));
468 assert_eq!(builder.options.recv_window, 10000);
469 assert_eq!(builder.options.account_type, "SPOT");
470 assert_eq!(builder.options.default_type, DefaultType::Swap);
471 assert_eq!(
472 builder.options.default_sub_type,
473 Some(DefaultSubType::Linear)
474 );
475 }
476
477 #[test]
478 fn test_builder_build() {
479 let result = BybitBuilder::new().build();
480 assert!(result.is_ok());
481
482 let bybit = result.unwrap();
483 assert_eq!(bybit.id(), "bybit");
484 assert_eq!(bybit.name(), "Bybit");
485 }
486
487 #[test]
488 fn test_builder_build_with_credentials() {
489 let result = BybitBuilder::new()
490 .api_key("test-key")
491 .secret("test-secret")
492 .build();
493
494 assert!(result.is_ok());
495 }
496
497 #[test]
498 fn test_builder_enable_rate_limit() {
499 let builder = BybitBuilder::new().enable_rate_limit(false);
500 assert!(!builder.config.enable_rate_limit);
501 }
502
503 #[test]
504 fn test_builder_proxy() {
505 let builder = BybitBuilder::new().proxy(ProxyConfig::new("http://proxy.example.com:8080"));
506 assert_eq!(
507 builder.config.proxy,
508 Some(ProxyConfig::new("http://proxy.example.com:8080"))
509 );
510 }
511
512 #[test]
513 fn test_builder_verbose() {
514 let builder = BybitBuilder::new().verbose(true);
515 assert!(builder.config.verbose);
516 }
517}