ccxt_exchanges/okx/
builder.rs1use super::{Okx, OkxOptions};
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)]
34pub struct OkxBuilder {
35 config: ExchangeConfig,
37 options: OkxOptions,
39}
40
41impl Default for OkxBuilder {
42 fn default() -> Self {
43 Self::new()
44 }
45}
46
47impl OkxBuilder {
48 pub fn new() -> Self {
58 Self {
59 config: ExchangeConfig {
60 id: "okx".to_string(),
61 name: "OKX".to_string(),
62 ..Default::default()
63 },
64 options: OkxOptions::default(),
65 }
66 }
67
68 pub fn api_key(mut self, key: impl Into<String>) -> Self {
74 self.config.api_key = Some(ccxt_core::SecretString::new(key));
75 self
76 }
77
78 pub fn secret(mut self, secret: impl Into<String>) -> Self {
84 self.config.secret = Some(ccxt_core::SecretString::new(secret));
85 self
86 }
87
88 pub fn passphrase(mut self, passphrase: impl Into<String>) -> Self {
96 self.config.password = Some(ccxt_core::SecretString::new(passphrase));
97 self
98 }
99
100 pub fn sandbox(mut self, enabled: bool) -> Self {
109 self.config.sandbox = enabled;
110 self.options.testnet = enabled;
111 self
112 }
113
114 pub fn account_mode(mut self, mode: impl Into<String>) -> Self {
122 self.options.account_mode = mode.into();
123 self
124 }
125
126 pub fn default_type(mut self, default_type: impl Into<DefaultType>) -> Self {
147 self.options.default_type = default_type.into();
148 self
149 }
150
151 pub fn default_sub_type(mut self, sub_type: DefaultSubType) -> Self {
176 self.options.default_sub_type = Some(sub_type);
177 self
178 }
179
180 pub fn timeout(mut self, timeout: Duration) -> Self {
182 self.config.timeout = timeout;
183 self
184 }
185
186 pub fn timeout_secs(mut self, seconds: u64) -> Self {
188 self.config.timeout = Duration::from_secs(seconds);
189 self
190 }
191
192 pub fn connect_timeout(mut self, timeout: Duration) -> Self {
198 self.config.connect_timeout = timeout;
199 self
200 }
201
202 pub fn connect_timeout_secs(mut self, seconds: u64) -> Self {
208 self.config.connect_timeout = Duration::from_secs(seconds);
209 self
210 }
211
212 pub fn retry_policy(mut self, policy: RetryPolicy) -> Self {
214 self.config.retry_policy = Some(policy);
215 self
216 }
217
218 pub fn enable_rate_limit(mut self, enabled: bool) -> Self {
224 self.config.enable_rate_limit = enabled;
225 self
226 }
227
228 pub fn proxy(mut self, proxy: ProxyConfig) -> Self {
230 self.config.proxy = Some(proxy);
231 self
232 }
233
234 pub fn proxy_url(mut self, url: impl Into<String>) -> Self {
236 self.config.proxy = Some(ProxyConfig::new(url));
237 self
238 }
239
240 pub fn verbose(mut self, enabled: bool) -> Self {
246 self.config.verbose = enabled;
247 self
248 }
249
250 pub fn option(mut self, key: impl Into<String>, value: Value) -> Self {
257 self.config.options.insert(key.into(), value);
258 self
259 }
260
261 pub fn options(mut self, options: HashMap<String, Value>) -> Self {
267 self.config.options.extend(options);
268 self
269 }
270
271 #[cfg(test)]
273 pub fn get_config(&self) -> &ExchangeConfig {
274 &self.config
275 }
276
277 #[cfg(test)]
279 pub fn get_options(&self) -> &OkxOptions {
280 &self.options
281 }
282
283 pub fn build(self) -> Result<Okx> {
293 Okx::new_with_options(self.config, self.options)
294 }
295}
296
297#[cfg(test)]
298mod tests {
299 use super::*;
300
301 #[test]
302 fn test_builder_default() {
303 let builder = OkxBuilder::new();
304 assert_eq!(builder.config.id, "okx");
305 assert_eq!(builder.config.name, "OKX");
306 assert!(!builder.config.sandbox);
307 assert_eq!(builder.options.account_mode, "cash");
308 }
309
310 #[test]
311 fn test_builder_api_key() {
312 let builder = OkxBuilder::new().api_key("test-key");
313 assert_eq!(
314 builder.config.api_key.as_ref().map(|s| s.expose_secret()),
315 Some("test-key")
316 );
317 }
318
319 #[test]
320 fn test_builder_secret() {
321 let builder = OkxBuilder::new().secret("test-secret");
322 assert_eq!(
323 builder.config.secret.as_ref().map(|s| s.expose_secret()),
324 Some("test-secret")
325 );
326 }
327
328 #[test]
329 fn test_builder_passphrase() {
330 let builder = OkxBuilder::new().passphrase("test-passphrase");
331 assert_eq!(
332 builder.config.password.as_ref().map(|s| s.expose_secret()),
333 Some("test-passphrase")
334 );
335 }
336
337 #[test]
338 fn test_builder_sandbox() {
339 let builder = OkxBuilder::new().sandbox(true);
340 assert!(builder.config.sandbox);
341 assert!(builder.options.testnet);
342 }
343
344 #[test]
345 fn test_builder_account_mode() {
346 let builder = OkxBuilder::new().account_mode("cross");
347 assert_eq!(builder.options.account_mode, "cross");
348 }
349
350 #[test]
351 fn test_builder_default_type() {
352 let builder = OkxBuilder::new().default_type(DefaultType::Swap);
353 assert_eq!(builder.options.default_type, DefaultType::Swap);
354 }
355
356 #[test]
357 fn test_builder_default_type_from_string() {
358 let builder = OkxBuilder::new().default_type("futures");
359 assert_eq!(builder.options.default_type, DefaultType::Futures);
360 }
361
362 #[test]
363 fn test_builder_default_sub_type() {
364 let builder = OkxBuilder::new().default_sub_type(DefaultSubType::Inverse);
365 assert_eq!(
366 builder.options.default_sub_type,
367 Some(DefaultSubType::Inverse)
368 );
369 }
370
371 #[test]
372 fn test_builder_default_type_and_sub_type() {
373 let builder = OkxBuilder::new()
374 .default_type(DefaultType::Swap)
375 .default_sub_type(DefaultSubType::Linear);
376 assert_eq!(builder.options.default_type, DefaultType::Swap);
377 assert_eq!(
378 builder.options.default_sub_type,
379 Some(DefaultSubType::Linear)
380 );
381 }
382
383 #[test]
384 fn test_builder_timeout() {
385 let builder = OkxBuilder::new().timeout(Duration::from_secs(60));
386 assert_eq!(builder.config.timeout, Duration::from_secs(60));
387 }
388
389 #[test]
390 fn test_builder_connect_timeout() {
391 let builder = OkxBuilder::new().connect_timeout(Duration::from_secs(15));
392 assert_eq!(builder.config.connect_timeout, Duration::from_secs(15));
393 }
394
395 #[test]
396 fn test_builder_connect_timeout_secs() {
397 let builder = OkxBuilder::new().connect_timeout_secs(20);
398 assert_eq!(builder.config.connect_timeout, Duration::from_secs(20));
399 }
400
401 #[test]
402 fn test_builder_chaining() {
403 let builder = OkxBuilder::new()
404 .api_key("key")
405 .secret("secret")
406 .passphrase("pass")
407 .sandbox(true)
408 .timeout(Duration::from_secs(30))
409 .account_mode("isolated");
410
411 assert_eq!(
412 builder.config.api_key.as_ref().map(|s| s.expose_secret()),
413 Some("key")
414 );
415 assert_eq!(
416 builder.config.secret.as_ref().map(|s| s.expose_secret()),
417 Some("secret")
418 );
419 assert_eq!(
420 builder.config.password.as_ref().map(|s| s.expose_secret()),
421 Some("pass")
422 );
423 assert!(builder.config.sandbox);
424 assert_eq!(builder.config.timeout, Duration::from_secs(30));
425 assert_eq!(builder.options.account_mode, "isolated");
426 }
427
428 #[test]
429 fn test_builder_build() {
430 let result = OkxBuilder::new().build();
431 assert!(result.is_ok());
432
433 let okx = result.unwrap();
434 assert_eq!(okx.id(), "okx");
435 assert_eq!(okx.name(), "OKX");
436 }
437
438 #[test]
439 fn test_builder_build_with_credentials() {
440 let result = OkxBuilder::new()
441 .api_key("test-key")
442 .secret("test-secret")
443 .passphrase("test-passphrase")
444 .build();
445
446 assert!(result.is_ok());
447 }
448
449 #[test]
450 fn test_builder_enable_rate_limit() {
451 let builder = OkxBuilder::new().enable_rate_limit(false);
452 assert!(!builder.config.enable_rate_limit);
453 }
454
455 #[test]
456 fn test_builder_proxy() {
457 let builder = OkxBuilder::new().proxy(ProxyConfig::new("http://proxy.example.com:8080"));
458 assert_eq!(
459 builder.config.proxy,
460 Some(ProxyConfig::new("http://proxy.example.com:8080"))
461 );
462 }
463
464 #[test]
465 fn test_builder_verbose() {
466 let builder = OkxBuilder::new().verbose(true);
467 assert!(builder.config.verbose);
468 }
469}