ccxt_exchanges/bybit/
builder.rs1use super::{Bybit, BybitOptions};
7use ccxt_core::types::default_type::{DefaultSubType, DefaultType};
8use ccxt_core::{ExchangeConfig, Result};
9use serde_json::Value;
10use std::collections::HashMap;
11
12#[derive(Debug, Clone)]
31pub struct BybitBuilder {
32 config: ExchangeConfig,
34 options: BybitOptions,
36}
37
38impl Default for BybitBuilder {
39 fn default() -> Self {
40 Self::new()
41 }
42}
43
44impl BybitBuilder {
45 pub fn new() -> Self {
55 Self {
56 config: ExchangeConfig {
57 id: "bybit".to_string(),
58 name: "Bybit".to_string(),
59 ..Default::default()
60 },
61 options: BybitOptions::default(),
62 }
63 }
64
65 pub fn api_key(mut self, key: impl Into<String>) -> Self {
71 self.config.api_key = Some(key.into());
72 self
73 }
74
75 pub fn secret(mut self, secret: impl Into<String>) -> Self {
81 self.config.secret = Some(secret.into());
82 self
83 }
84
85 pub fn sandbox(mut self, enabled: bool) -> Self {
97 self.config.sandbox = enabled;
98 self.options.testnet = enabled;
99 self
100 }
101
102 pub fn testnet(mut self, enabled: bool) -> Self {
114 self.config.sandbox = enabled;
115 self.options.testnet = enabled;
116 self
117 }
118
119 pub fn account_type(mut self, account_type: impl Into<String>) -> Self {
127 self.options.account_type = account_type.into();
128 self
129 }
130
131 pub fn default_type(mut self, default_type: impl Into<DefaultType>) -> Self {
156 self.options.default_type = default_type.into();
157 self
158 }
159
160 pub fn default_sub_type(mut self, sub_type: DefaultSubType) -> Self {
185 self.options.default_sub_type = Some(sub_type);
186 self
187 }
188
189 pub fn recv_window(mut self, millis: u64) -> Self {
198 self.options.recv_window = millis;
199 self
200 }
201
202 pub fn timeout(mut self, seconds: u64) -> Self {
208 self.config.timeout = seconds;
209 self
210 }
211
212 pub fn enable_rate_limit(mut self, enabled: bool) -> Self {
218 self.config.enable_rate_limit = enabled;
219 self
220 }
221
222 pub fn proxy(mut self, proxy: impl Into<String>) -> Self {
228 self.config.proxy = Some(proxy.into());
229 self
230 }
231
232 pub fn verbose(mut self, enabled: bool) -> Self {
238 self.config.verbose = enabled;
239 self
240 }
241
242 pub fn option(mut self, key: impl Into<String>, value: Value) -> Self {
249 self.config.options.insert(key.into(), value);
250 self
251 }
252
253 pub fn options(mut self, options: HashMap<String, Value>) -> Self {
259 self.config.options.extend(options);
260 self
261 }
262
263 #[cfg(test)]
265 pub fn get_config(&self) -> &ExchangeConfig {
266 &self.config
267 }
268
269 #[cfg(test)]
271 pub fn get_options(&self) -> &BybitOptions {
272 &self.options
273 }
274
275 pub fn build(self) -> Result<Bybit> {
285 Bybit::new_with_options(self.config, self.options)
286 }
287}
288
289#[cfg(test)]
290mod tests {
291 use super::*;
292
293 #[test]
294 fn test_builder_default() {
295 let builder = BybitBuilder::new();
296 assert_eq!(builder.config.id, "bybit");
297 assert_eq!(builder.config.name, "Bybit");
298 assert!(!builder.config.sandbox);
299 assert_eq!(builder.options.account_type, "UNIFIED");
300 assert_eq!(builder.options.recv_window, 5000);
301 }
302
303 #[test]
304 fn test_builder_api_key() {
305 let builder = BybitBuilder::new().api_key("test-key");
306 assert_eq!(builder.config.api_key, Some("test-key".to_string()));
307 }
308
309 #[test]
310 fn test_builder_secret() {
311 let builder = BybitBuilder::new().secret("test-secret");
312 assert_eq!(builder.config.secret, Some("test-secret".to_string()));
313 }
314
315 #[test]
316 fn test_builder_sandbox() {
317 let builder = BybitBuilder::new().sandbox(true);
318 assert!(builder.config.sandbox);
319 assert!(builder.options.testnet);
320 }
321
322 #[test]
323 fn test_builder_testnet() {
324 let builder = BybitBuilder::new().testnet(true);
325 assert!(builder.config.sandbox);
326 assert!(builder.options.testnet);
327 }
328
329 #[test]
330 fn test_builder_sandbox_testnet_equivalence() {
331 let sandbox_builder = BybitBuilder::new().sandbox(true);
333 let testnet_builder = BybitBuilder::new().testnet(true);
334
335 assert_eq!(
336 sandbox_builder.config.sandbox,
337 testnet_builder.config.sandbox
338 );
339 assert_eq!(
340 sandbox_builder.options.testnet,
341 testnet_builder.options.testnet
342 );
343 }
344
345 #[test]
346 fn test_builder_account_type() {
347 let builder = BybitBuilder::new().account_type("CONTRACT");
348 assert_eq!(builder.options.account_type, "CONTRACT");
349 }
350
351 #[test]
352 fn test_builder_default_type() {
353 let builder = BybitBuilder::new().default_type(DefaultType::Swap);
354 assert_eq!(builder.options.default_type, DefaultType::Swap);
355 }
356
357 #[test]
358 fn test_builder_default_type_from_string() {
359 let builder = BybitBuilder::new().default_type("futures");
360 assert_eq!(builder.options.default_type, DefaultType::Futures);
361 }
362
363 #[test]
364 fn test_builder_default_sub_type() {
365 let builder = BybitBuilder::new().default_sub_type(DefaultSubType::Inverse);
366 assert_eq!(
367 builder.options.default_sub_type,
368 Some(DefaultSubType::Inverse)
369 );
370 }
371
372 #[test]
373 fn test_builder_default_type_and_sub_type() {
374 let builder = BybitBuilder::new()
375 .default_type(DefaultType::Swap)
376 .default_sub_type(DefaultSubType::Linear);
377 assert_eq!(builder.options.default_type, DefaultType::Swap);
378 assert_eq!(
379 builder.options.default_sub_type,
380 Some(DefaultSubType::Linear)
381 );
382 }
383
384 #[test]
385 fn test_builder_recv_window() {
386 let builder = BybitBuilder::new().recv_window(10000);
387 assert_eq!(builder.options.recv_window, 10000);
388 }
389
390 #[test]
391 fn test_builder_timeout() {
392 let builder = BybitBuilder::new().timeout(60);
393 assert_eq!(builder.config.timeout, 60);
394 }
395
396 #[test]
397 fn test_builder_chaining() {
398 let builder = BybitBuilder::new()
399 .api_key("key")
400 .secret("secret")
401 .testnet(true)
402 .timeout(30)
403 .recv_window(10000)
404 .account_type("SPOT")
405 .default_type(DefaultType::Swap)
406 .default_sub_type(DefaultSubType::Linear);
407
408 assert_eq!(builder.config.api_key, Some("key".to_string()));
409 assert_eq!(builder.config.secret, Some("secret".to_string()));
410 assert!(builder.config.sandbox);
411 assert_eq!(builder.config.timeout, 30);
412 assert_eq!(builder.options.recv_window, 10000);
413 assert_eq!(builder.options.account_type, "SPOT");
414 assert_eq!(builder.options.default_type, DefaultType::Swap);
415 assert_eq!(
416 builder.options.default_sub_type,
417 Some(DefaultSubType::Linear)
418 );
419 }
420
421 #[test]
422 fn test_builder_build() {
423 let result = BybitBuilder::new().build();
424 assert!(result.is_ok());
425
426 let bybit = result.unwrap();
427 assert_eq!(bybit.id(), "bybit");
428 assert_eq!(bybit.name(), "Bybit");
429 }
430
431 #[test]
432 fn test_builder_build_with_credentials() {
433 let result = BybitBuilder::new()
434 .api_key("test-key")
435 .secret("test-secret")
436 .build();
437
438 assert!(result.is_ok());
439 }
440
441 #[test]
442 fn test_builder_enable_rate_limit() {
443 let builder = BybitBuilder::new().enable_rate_limit(false);
444 assert!(!builder.config.enable_rate_limit);
445 }
446
447 #[test]
448 fn test_builder_proxy() {
449 let builder = BybitBuilder::new().proxy("http://proxy.example.com:8080");
450 assert_eq!(
451 builder.config.proxy,
452 Some("http://proxy.example.com:8080".to_string())
453 );
454 }
455
456 #[test]
457 fn test_builder_verbose() {
458 let builder = BybitBuilder::new().verbose(true);
459 assert!(builder.config.verbose);
460 }
461}