ccxt_exchanges/binance/options.rs
1//! Binance-specific options and configuration.
2
3use ccxt_core::types::default_type::{DefaultSubType, DefaultType};
4use serde::{Deserialize, Deserializer, Serialize};
5use std::str::FromStr;
6
7/// Binance-specific options.
8///
9/// # Example
10///
11/// ```rust
12/// use ccxt_exchanges::binance::BinanceOptions;
13/// use ccxt_core::types::default_type::{DefaultType, DefaultSubType};
14///
15/// let options = BinanceOptions {
16/// default_type: DefaultType::Swap,
17/// default_sub_type: Some(DefaultSubType::Linear),
18/// ..Default::default()
19/// };
20/// ```
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct BinanceOptions {
23 /// Enables time synchronization.
24 pub adjust_for_time_difference: bool,
25 /// Receive window in milliseconds.
26 pub recv_window: u64,
27 /// Default trading type (spot/margin/swap/futures/option).
28 ///
29 /// This determines which API endpoints to use for operations.
30 /// Supports both `DefaultType` enum and string values for backward compatibility.
31 #[serde(deserialize_with = "deserialize_default_type")]
32 pub default_type: DefaultType,
33 /// Default sub-type for contract settlement (linear/inverse).
34 ///
35 /// - `Linear`: USDT-margined contracts (FAPI)
36 /// - `Inverse`: Coin-margined contracts (DAPI)
37 ///
38 /// Only applicable when `default_type` is `Swap`, `Futures`, or `Option`.
39 /// Ignored for `Spot` and `Margin` types.
40 #[serde(default, skip_serializing_if = "Option::is_none")]
41 pub default_sub_type: Option<DefaultSubType>,
42 /// Enables testnet mode.
43 pub test: bool,
44 /// Time sync interval in seconds.
45 ///
46 /// Controls how often the time offset is refreshed when auto sync is enabled.
47 /// Default: 30 seconds.
48 #[serde(default = "default_sync_interval")]
49 pub time_sync_interval_secs: u64,
50 /// Enable automatic periodic time sync.
51 ///
52 /// When enabled, the time offset will be automatically refreshed
53 /// based on `time_sync_interval_secs`.
54 /// Default: true.
55 #[serde(default = "default_auto_sync")]
56 pub auto_time_sync: bool,
57 /// Rate limit in requests per second.
58 ///
59 /// Default: 50.
60 #[serde(default = "default_rate_limit")]
61 pub rate_limit: u32,
62}
63
64fn default_sync_interval() -> u64 {
65 30
66}
67
68fn default_auto_sync() -> bool {
69 true
70}
71
72fn default_rate_limit() -> u32 {
73 50
74}
75
76/// Custom deserializer for DefaultType that accepts both enum values and strings.
77///
78/// This provides backward compatibility with configurations that use string values
79/// like "spot", "future", "swap", etc.
80fn deserialize_default_type<'de, D>(deserializer: D) -> std::result::Result<DefaultType, D::Error>
81where
82 D: Deserializer<'de>,
83{
84 use serde::de::Error;
85
86 // First try to deserialize as a string (for backward compatibility)
87 // Then try as the enum directly
88 #[derive(Deserialize)]
89 #[serde(untagged)]
90 enum StringOrDefaultType {
91 String(String),
92 DefaultType(DefaultType),
93 }
94
95 match StringOrDefaultType::deserialize(deserializer)? {
96 StringOrDefaultType::String(s) => {
97 // Handle legacy "future" value (map to Swap for perpetuals)
98 let lowercase = s.to_lowercase();
99 let normalized = match lowercase.as_str() {
100 "future" => "swap", // Legacy: "future" typically meant perpetual futures
101 "delivery" => "futures", // Legacy: "delivery" meant dated futures
102 _ => lowercase.as_str(),
103 };
104 DefaultType::from_str(normalized).map_err(|e| D::Error::custom(e.to_string()))
105 }
106 StringOrDefaultType::DefaultType(dt) => Ok(dt),
107 }
108}
109
110impl Default for BinanceOptions {
111 fn default() -> Self {
112 Self {
113 adjust_for_time_difference: false,
114 recv_window: 5000,
115 default_type: DefaultType::default(), // Defaults to Spot
116 default_sub_type: None,
117 test: false,
118 time_sync_interval_secs: default_sync_interval(),
119 auto_time_sync: default_auto_sync(),
120 rate_limit: default_rate_limit(),
121 }
122 }
123}