nautilus_binance/
config.rs1use std::{any::Any, collections::HashMap};
19
20use nautilus_common::factories::ClientConfig;
21use nautilus_model::{
22 identifiers::{AccountId, TraderId},
23 types::Currency,
24};
25use nautilus_network::websocket::TransportBackend;
26use rust_decimal::Decimal;
27use serde::{Deserialize, Serialize};
28
29use crate::common::enums::{BinanceEnvironment, BinanceMarginType, BinanceProductType};
30
31#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
33#[cfg_attr(
34 feature = "python",
35 pyo3::pyclass(
36 module = "nautilus_trader.core.nautilus_pyo3.binance",
37 eq,
38 from_py_object
39 )
40)]
41#[cfg_attr(
42 feature = "python",
43 pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.binance")
44)]
45pub enum BinanceSpotMarketDataMode {
46 #[default]
47 Sbe,
49 Json,
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize, bon::Builder)]
57#[serde(default, deny_unknown_fields)]
58#[cfg_attr(
59 feature = "python",
60 pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.binance", from_py_object)
61)]
62#[cfg_attr(
63 feature = "python",
64 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.adapters.binance")
65)]
66pub struct BinanceDataClientConfig {
67 #[builder(default = BinanceProductType::Spot)]
69 pub product_type: BinanceProductType,
70 #[builder(default = BinanceEnvironment::Live)]
72 pub environment: BinanceEnvironment,
73 pub base_url_http: Option<String>,
75 pub base_url_ws: Option<String>,
80 pub api_key: Option<String>,
82 pub api_secret: Option<String>,
84 #[builder(default)]
89 pub spot_market_data_mode: BinanceSpotMarketDataMode,
90 #[builder(default = 3600)]
93 pub instrument_status_poll_secs: u64,
94 #[builder(default)]
96 pub transport_backend: TransportBackend,
97}
98
99impl Default for BinanceDataClientConfig {
100 fn default() -> Self {
101 Self::builder().build()
102 }
103}
104
105impl ClientConfig for BinanceDataClientConfig {
106 fn as_any(&self) -> &dyn Any {
107 self
108 }
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize, bon::Builder)]
117#[serde(default, deny_unknown_fields)]
118#[cfg_attr(
119 feature = "python",
120 pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.binance", from_py_object)
121)]
122#[cfg_attr(
123 feature = "python",
124 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.adapters.binance")
125)]
126pub struct BinanceExecClientConfig {
127 #[builder(default = TraderId::from("TRADER-001"))]
129 pub trader_id: TraderId,
130 #[builder(default = AccountId::from("BINANCE-001"))]
132 pub account_id: AccountId,
133 #[builder(default = BinanceProductType::Spot)]
135 pub product_type: BinanceProductType,
136 #[builder(default = BinanceEnvironment::Live)]
138 pub environment: BinanceEnvironment,
139 pub base_url_http: Option<String>,
141 pub base_url_ws: Option<String>,
145 pub base_url_ws_trading: Option<String>,
147 #[builder(default = true)]
149 pub use_ws_trading: bool,
150 #[builder(default = true)]
157 pub use_position_ids: bool,
158 #[builder(default = Decimal::new(4, 4))]
164 pub default_taker_fee: Decimal,
165 pub api_key: Option<String>,
167 pub api_secret: Option<String>,
169 pub futures_leverages: Option<HashMap<String, u32>>,
171 pub futures_margin_types: Option<HashMap<String, BinanceMarginType>>,
173 #[builder(default = Currency::USDT())]
175 pub bnfcr_currency: Currency,
176 #[builder(default = false)]
181 pub treat_expired_as_canceled: bool,
182 #[builder(default = false)]
186 pub use_trade_lite: bool,
187 #[builder(default)]
189 pub transport_backend: TransportBackend,
190}
191
192impl Default for BinanceExecClientConfig {
193 fn default() -> Self {
194 Self::builder().build()
195 }
196}
197
198impl ClientConfig for BinanceExecClientConfig {
199 fn as_any(&self) -> &dyn Any {
200 self
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use rstest::rstest;
207
208 use super::*;
209
210 #[rstest]
211 fn test_data_config_toml_minimal() {
212 let config: BinanceDataClientConfig = toml::from_str(
213 r#"
214environment = "Testnet"
215product_type = "USD_M"
216instrument_status_poll_secs = 600
217"#,
218 )
219 .unwrap();
220
221 assert_eq!(config.environment, BinanceEnvironment::Testnet);
222 assert_eq!(config.product_type, BinanceProductType::UsdM);
223 assert_eq!(config.spot_market_data_mode, BinanceSpotMarketDataMode::Sbe);
224 assert_eq!(config.instrument_status_poll_secs, 600);
225 }
226
227 #[rstest]
228 fn test_data_config_toml_spot_market_data_mode_override() {
229 let config: BinanceDataClientConfig = toml::from_str(
230 r#"
231spot_market_data_mode = "Json"
232"#,
233 )
234 .unwrap();
235
236 assert_eq!(
237 config.spot_market_data_mode,
238 BinanceSpotMarketDataMode::Json
239 );
240 }
241
242 #[rstest]
243 fn test_data_config_toml_rejects_plural_product_types() {
244 let result = toml::from_str::<BinanceDataClientConfig>(
245 r#"
246product_types = ["SPOT", "USD_M"]
247"#,
248 );
249
250 let message = result.unwrap_err().to_string();
251 assert!(message.contains("unknown field `product_types`"));
252 }
253
254 #[rstest]
255 fn test_exec_config_toml_empty_uses_defaults() {
256 let config: BinanceExecClientConfig = toml::from_str("").unwrap();
257 let expected = BinanceExecClientConfig::default();
258
259 assert_eq!(config.environment, expected.environment);
260 assert_eq!(config.product_type, expected.product_type);
261 assert_eq!(config.use_ws_trading, expected.use_ws_trading);
262 assert_eq!(config.use_position_ids, expected.use_position_ids);
263 assert_eq!(config.default_taker_fee, expected.default_taker_fee);
264 assert_eq!(
265 config.treat_expired_as_canceled,
266 expected.treat_expired_as_canceled,
267 );
268 assert_eq!(config.use_trade_lite, expected.use_trade_lite);
269 assert_eq!(config.transport_backend, expected.transport_backend);
270 }
271}