Skip to main content

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}