nautilus_binance/common/
consts.rs1use std::{num::NonZeroU32, sync::LazyLock, time::Duration};
19
20use nautilus_model::identifiers::{ClientId, Venue};
21use nautilus_network::ratelimiter::quota::Quota;
22use ustr::Ustr;
23
24use super::enums::{BinanceRateLimitInterval, BinanceRateLimitType};
25
26pub const BINANCE: &str = "BINANCE";
28
29pub static BINANCE_VENUE: LazyLock<Venue> = LazyLock::new(|| Venue::new(Ustr::from(BINANCE)));
31
32pub static BINANCE_CLIENT_ID: LazyLock<ClientId> =
34 LazyLock::new(|| ClientId::new(Ustr::from(BINANCE)));
35
36pub const BINANCE_NAUTILUS_SPOT_BROKER_ID: &str = "TD67BGP9";
40
41pub const BINANCE_NAUTILUS_FUTURES_BROKER_ID: &str = "aHRE4BCj";
45
46pub const BINANCE_SPOT_HTTP_URL: &str = "https://api.binance.com";
48
49pub const BINANCE_US_SPOT_HTTP_URL: &str = "https://api.binance.us";
51
52pub const BINANCE_FUTURES_USD_HTTP_URL: &str = "https://fapi.binance.com";
54
55pub const BINANCE_FUTURES_COIN_HTTP_URL: &str = "https://dapi.binance.com";
57
58pub const BINANCE_WS_HEARTBEAT_SECS: u64 = 20;
63
64pub const BINANCE_OPTIONS_HTTP_URL: &str = "https://eapi.binance.com";
66
67pub const BINANCE_OPTIONS_TESTNET_HTTP_URL: &str = "https://testnet.binancefuture.com";
69
70pub const BINANCE_SPOT_TESTNET_HTTP_URL: &str = "https://testnet.binance.vision";
72
73pub const BINANCE_FUTURES_USD_TESTNET_HTTP_URL: &str = "https://testnet.binancefuture.com";
75
76pub const BINANCE_FUTURES_COIN_TESTNET_HTTP_URL: &str = "https://testnet.binancefuture.com";
78
79pub const BINANCE_SPOT_DEMO_HTTP_URL: &str = "https://demo-api.binance.com";
81
82pub const BINANCE_FUTURES_USD_DEMO_HTTP_URL: &str = "https://demo-fapi.binance.com";
84
85pub const BINANCE_FUTURES_COIN_DEMO_HTTP_URL: &str = "https://demo-dapi.binance.com";
87
88pub const BINANCE_SPOT_WS_URL: &str = "wss://stream.binance.com:9443/ws";
90
91pub const BINANCE_US_SPOT_WS_URL: &str = "wss://stream.binance.us:9443/ws";
93
94pub const BINANCE_US_SPOT_USER_WS_URL: &str = "wss://stream.binance.us:443";
96
97pub const BINANCE_FUTURES_USD_WS_URL: &str = "wss://fstream.binance.com/market/ws";
99
100pub const BINANCE_FUTURES_USD_WS_PUBLIC_URL: &str = "wss://fstream.binance.com/public/ws";
102
103pub const BINANCE_FUTURES_USD_WS_PRIVATE_URL: &str = "wss://fstream.binance.com/private/ws";
105
106pub const BINANCE_FUTURES_COIN_WS_URL: &str = "wss://dstream.binance.com/ws";
108
109pub const BINANCE_OPTIONS_WS_URL: &str = "wss://nbstream.binance.com/eoptions";
111
112pub const BINANCE_OPTIONS_TESTNET_WS_URL: &str = "wss://fstream.binancefuture.com/market/ws";
114
115pub const BINANCE_OPTIONS_TESTNET_WS_PUBLIC_URL: &str = "wss://fstream.binancefuture.com/public/ws";
117
118pub const BINANCE_OPTIONS_TESTNET_WS_PRIVATE_URL: &str =
120 "wss://fstream.binancefuture.com/private/ws";
121
122pub const BINANCE_SPOT_SBE_WS_URL: &str = "wss://stream-sbe.binance.com/ws";
124
125pub const BINANCE_SPOT_SBE_WS_API_URL: &str =
127 "wss://ws-api.binance.com:443/ws-api/v3?responseFormat=sbe&sbeSchemaId=3&sbeSchemaVersion=5";
128
129pub const BINANCE_FUTURES_USD_WS_API_URL: &str = "wss://ws-fapi.binance.com/ws-fapi/v1";
131
132pub const BINANCE_FUTURES_USD_WS_API_TESTNET_URL: &str =
134 "wss://testnet.binancefuture.com/ws-fapi/v1";
135
136pub const BINANCE_SPOT_SBE_WS_API_TESTNET_URL: &str = "wss://ws-api.testnet.binance.vision/ws-api/v3?responseFormat=sbe&sbeSchemaId=3&sbeSchemaVersion=5";
138
139pub const BINANCE_SPOT_SBE_WS_API_DEMO_URL: &str =
141 "wss://demo-ws-api.binance.com/ws-api/v3?responseFormat=sbe&sbeSchemaId=3&sbeSchemaVersion=5";
142
143pub const BINANCE_SPOT_TESTNET_WS_URL: &str = "wss://stream.testnet.binance.vision/ws";
145
146pub const BINANCE_SPOT_DEMO_WS_URL: &str = "wss://demo-stream.binance.com/ws";
148
149pub const BINANCE_FUTURES_USD_DEMO_WS_URL: &str = "wss://demo-fstream.binance.com/ws";
151
152pub const BINANCE_FUTURES_COIN_DEMO_WS_URL: &str = "wss://demo-dstream.binance.com/ws";
154
155pub const BINANCE_FUTURES_USD_TESTNET_WS_URL: &str = "wss://fstream.binancefuture.com/ws";
157
158pub const BINANCE_FUTURES_COIN_TESTNET_WS_URL: &str = "wss://dstream.binancefuture.com/ws";
160
161pub const BINANCE_API_KEY_HEADER: &str = "X-MBX-APIKEY";
163
164pub const BINANCE_RETRY_AFTER_HEADER: &str = "Retry-After";
166
167pub const BINANCE_SPOT_API_PATH: &str = "/api/v3";
169
170pub const BINANCE_FAPI_PATH: &str = "/fapi/v1";
172
173pub const BINANCE_DAPI_PATH: &str = "/dapi/v1";
175
176pub const BINANCE_EAPI_PATH: &str = "/eapi/v1";
178
179pub const BINANCE_SAPI_PATH: &str = "/sapi/v1";
181
182#[derive(Clone, Copy, Debug)]
184pub struct BinanceRateLimitQuota {
185 pub rate_limit_type: BinanceRateLimitType,
187 pub interval: BinanceRateLimitInterval,
189 pub interval_num: u32,
191 pub limit: u32,
193}
194
195pub const BINANCE_SPOT_RATE_LIMITS: &[BinanceRateLimitQuota] = &[
200 BinanceRateLimitQuota {
201 rate_limit_type: BinanceRateLimitType::RequestWeight,
202 interval: BinanceRateLimitInterval::Minute,
203 interval_num: 1,
204 limit: 1_200,
205 },
206 BinanceRateLimitQuota {
207 rate_limit_type: BinanceRateLimitType::Orders,
208 interval: BinanceRateLimitInterval::Second,
209 interval_num: 1,
210 limit: 10,
211 },
212 BinanceRateLimitQuota {
213 rate_limit_type: BinanceRateLimitType::Orders,
214 interval: BinanceRateLimitInterval::Day,
215 interval_num: 1,
216 limit: 100_000,
217 },
218];
219
220pub const BINANCE_FAPI_RATE_LIMITS: &[BinanceRateLimitQuota] = &[
225 BinanceRateLimitQuota {
226 rate_limit_type: BinanceRateLimitType::RequestWeight,
227 interval: BinanceRateLimitInterval::Minute,
228 interval_num: 1,
229 limit: 2_400,
230 },
231 BinanceRateLimitQuota {
232 rate_limit_type: BinanceRateLimitType::Orders,
233 interval: BinanceRateLimitInterval::Second,
234 interval_num: 10,
235 limit: 300,
236 },
237 BinanceRateLimitQuota {
238 rate_limit_type: BinanceRateLimitType::Orders,
239 interval: BinanceRateLimitInterval::Minute,
240 interval_num: 1,
241 limit: 1_200,
242 },
243];
244
245pub const BINANCE_DAPI_RATE_LIMITS: &[BinanceRateLimitQuota] = &[
250 BinanceRateLimitQuota {
251 rate_limit_type: BinanceRateLimitType::RequestWeight,
252 interval: BinanceRateLimitInterval::Minute,
253 interval_num: 1,
254 limit: 2_400,
255 },
256 BinanceRateLimitQuota {
257 rate_limit_type: BinanceRateLimitType::Orders,
258 interval: BinanceRateLimitInterval::Second,
259 interval_num: 10,
260 limit: 300,
261 },
262 BinanceRateLimitQuota {
263 rate_limit_type: BinanceRateLimitType::Orders,
264 interval: BinanceRateLimitInterval::Minute,
265 interval_num: 1,
266 limit: 1_200,
267 },
268];
269
270pub const BINANCE_EAPI_RATE_LIMITS: &[BinanceRateLimitQuota] = &[
275 BinanceRateLimitQuota {
276 rate_limit_type: BinanceRateLimitType::RequestWeight,
277 interval: BinanceRateLimitInterval::Minute,
278 interval_num: 1,
279 limit: 3_000,
280 },
281 BinanceRateLimitQuota {
282 rate_limit_type: BinanceRateLimitType::Orders,
283 interval: BinanceRateLimitInterval::Second,
284 interval_num: 1,
285 limit: 5,
286 },
287 BinanceRateLimitQuota {
288 rate_limit_type: BinanceRateLimitType::Orders,
289 interval: BinanceRateLimitInterval::Minute,
290 interval_num: 1,
291 limit: 200,
292 },
293];
294
295pub static BINANCE_WS_SUBSCRIPTION_QUOTA: LazyLock<Quota> =
304 LazyLock::new(|| Quota::with_period(Duration::from_millis(300)).expect("valid constant"));
305
306pub static BINANCE_WS_CONNECTION_QUOTA: LazyLock<Quota> = LazyLock::new(|| {
311 Quota::per_second(NonZeroU32::new(1).expect("non-zero")).expect("valid constant")
312});
313
314pub static BINANCE_RATE_LIMIT_KEY_SUBSCRIPTION: LazyLock<[Ustr; 1]> =
316 LazyLock::new(|| [Ustr::from("subscription")]);
317
318pub const BINANCE_GTX_ORDER_REJECT_CODE: i64 = -5022;
322
323pub const BINANCE_NEW_ORDER_REJECTED_CODE: i64 = -2010;
328
329pub const BINANCE_NO_SUCH_ORDER_CODE: i64 = -2013;
331
332pub const BINANCE_UNEXPECTED_RESPONSE_CODE: i64 = -1006;
334
335pub const BINANCE_STATUS_UNKNOWN_CODE: i64 = -1007;
337
338pub const BINANCE_FUTURES_DUAL_SIDE_SYNC_REJECT_CODE: i64 = -4531;
344
345pub const BINANCE_SPOT_POST_ONLY_REJECT_MSG: &str = "Order would immediately match and take.";
349
350pub const BINANCE_BOOK_DEPTHS: [u32; 7] = [5, 10, 20, 50, 100, 500, 1000];
352
353#[cfg(test)]
354mod tests {
355 use rstest::rstest;
356
357 use super::*;
358
359 #[rstest]
360 fn test_venue_error_code_values() {
361 assert_eq!(BINANCE_GTX_ORDER_REJECT_CODE, -5022);
362 assert_eq!(BINANCE_NEW_ORDER_REJECTED_CODE, -2010);
363 assert_eq!(BINANCE_NO_SUCH_ORDER_CODE, -2013);
364 assert_eq!(BINANCE_UNEXPECTED_RESPONSE_CODE, -1006);
365 assert_eq!(BINANCE_STATUS_UNKNOWN_CODE, -1007);
366 assert_eq!(BINANCE_FUTURES_DUAL_SIDE_SYNC_REJECT_CODE, -4531);
367 }
368
369 #[rstest]
370 #[case(BINANCE_SPOT_SBE_WS_API_URL)]
371 #[case(BINANCE_SPOT_SBE_WS_API_TESTNET_URL)]
372 #[case(BINANCE_SPOT_SBE_WS_API_DEMO_URL)]
373 fn test_spot_sbe_ws_api_urls_use_current_schema(#[case] url: &str) {
374 assert!(url.ends_with("sbeSchemaId=3&sbeSchemaVersion=5"));
375 }
376
377 #[rstest]
378 fn test_ws_subscription_quota_paces_one_message_per_period() {
379 let quota = *BINANCE_WS_SUBSCRIPTION_QUOTA;
380 assert_eq!(quota.burst_size().get(), 1);
381 assert_eq!(quota.replenish_interval(), Duration::from_millis(300));
382 }
383}