nautilus_binance/spot/websocket/streams/subscription.rs
1// -------------------------------------------------------------------------------------------------
2// Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3// https://nautechsystems.io
4//
5// Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6// You may not use this file except in compliance with the License.
7// You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Stream subscription management for Binance Spot WebSocket.
17//!
18//! ## Stream Names
19//!
20//! - `<symbol>@trade` - Trade stream
21//! - `<symbol>@bestBidAsk` - Best bid/ask stream (with auto-culling)
22//! - `<symbol>@depth` - Diff depth stream (50ms updates)
23//! - `<symbol>@depth20` - Partial book depth (top 20 levels, 50ms updates)
24//!
25//! ## Connection URL Patterns
26//!
27//! Single stream: `/ws/<streamName>`
28//! Multiple streams: `/stream?streams=<stream1>/<stream2>/...`
29
30/// Maximum number of streams per connection.
31pub const MAX_STREAMS_PER_CONNECTION: usize = 1024;
32
33/// Maximum number of connections per pool.
34pub const MAX_CONNECTIONS: usize = 20;
35
36/// Stream type for subscription management.
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
38pub enum StreamType {
39 /// Trade stream (`<symbol>@trade`).
40 Trade,
41 /// Best bid/ask stream (`<symbol>@bestBidAsk`).
42 BestBidAsk,
43 /// Diff depth stream (`<symbol>@depth`).
44 DepthDiff,
45 /// Partial book depth stream (`<symbol>@depth<N>`).
46 DepthSnapshot { levels: u8 },
47}
48
49impl StreamType {
50 /// Build stream name for a symbol.
51 #[must_use]
52 pub fn stream_name(&self, symbol: &str) -> String {
53 let symbol_lower = symbol.to_lowercase();
54 match self {
55 Self::Trade => format!("{symbol_lower}@trade"),
56 Self::BestBidAsk => format!("{symbol_lower}@bestBidAsk"),
57 Self::DepthDiff => format!("{symbol_lower}@depth"),
58 Self::DepthSnapshot { levels } => format!("{symbol_lower}@depth{levels}"),
59 }
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use rstest::rstest;
66
67 use super::*;
68
69 #[rstest]
70 fn test_stream_names() {
71 assert_eq!(StreamType::Trade.stream_name("BTCUSDT"), "btcusdt@trade");
72 assert_eq!(
73 StreamType::BestBidAsk.stream_name("ETHUSDT"),
74 "ethusdt@bestBidAsk"
75 );
76 assert_eq!(
77 StreamType::DepthDiff.stream_name("BTCUSDT"),
78 "btcusdt@depth"
79 );
80 assert_eq!(
81 StreamType::DepthSnapshot { levels: 20 }.stream_name("BTCUSDT"),
82 "btcusdt@depth20"
83 );
84 }
85}