Skip to main content

nautilus_binance/spot/websocket/public_json/
messages.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//! Binance Spot public JSON WebSocket message types.
17
18use nautilus_network::websocket::WebSocketClient;
19use serde::{Deserialize, Serialize};
20use ustr::Ustr;
21
22use crate::{
23    common::enums::{BinanceKlineInterval, BinanceWsMethod},
24    spot::websocket::streams::messages::{
25        BinanceWsErrorMsg, BinanceWsErrorResponse, BinanceWsResponse,
26    },
27};
28
29/// Output message from the Spot public JSON WebSocket handler.
30#[derive(Debug, Clone)]
31pub enum BinanceSpotPublicWsMessage {
32    /// Trade stream event.
33    Trade(BinanceSpotTradeMsg),
34    /// Best bid/ask stream event.
35    BookTicker(BinanceSpotBookTickerMsg),
36    /// Partial depth snapshot stream event.
37    DepthSnapshot(BinanceSpotPartialDepthMsg),
38    /// Depth diff stream event.
39    DepthDiff(BinanceSpotDepthDiffMsg),
40    /// Kline/candlestick stream event.
41    Kline(BinanceSpotKlineMsg),
42    /// Server shutdown notice.
43    ServerShutdown(BinanceSpotServerShutdownMsg),
44    /// Raw JSON message (unhandled or unknown event).
45    RawJson(serde_json::Value),
46    /// Error from the server.
47    Error(BinanceWsErrorMsg),
48    /// WebSocket reconnected.
49    Reconnected,
50}
51
52/// Commands sent from the outer client to the inner handler.
53#[allow(
54    missing_debug_implementations,
55    clippy::large_enum_variant,
56    reason = "Commands are ephemeral and immediately consumed"
57)]
58pub enum BinanceSpotPublicWsCommand {
59    /// Set the WebSocket client after connection.
60    SetClient(WebSocketClient),
61    /// Disconnect and clean up.
62    Disconnect,
63    /// Subscribe to streams.
64    Subscribe { streams: Vec<String> },
65    /// Unsubscribe from streams.
66    Unsubscribe { streams: Vec<String> },
67}
68
69/// Binance WebSocket subscription request.
70#[derive(Debug, Clone, Serialize)]
71pub struct BinanceWsSubscription {
72    /// Request method.
73    pub method: BinanceWsMethod,
74    /// Stream names to subscribe/unsubscribe.
75    pub params: Vec<String>,
76    /// Request ID for correlation.
77    pub id: u64,
78}
79
80impl BinanceWsSubscription {
81    /// Create a subscribe request.
82    #[must_use]
83    pub fn subscribe(streams: Vec<String>, id: u64) -> Self {
84        Self {
85            method: BinanceWsMethod::Subscribe,
86            params: streams,
87            id,
88        }
89    }
90
91    /// Create an unsubscribe request.
92    #[must_use]
93    pub fn unsubscribe(streams: Vec<String>, id: u64) -> Self {
94        Self {
95            method: BinanceWsMethod::Unsubscribe,
96            params: streams,
97            id,
98        }
99    }
100}
101
102/// Combined stream wrapper used by `/stream` endpoint.
103#[derive(Debug, Clone, Deserialize)]
104pub struct BinanceCombinedStreamEvent {
105    /// Stream name (e.g., `btcusdt@depth20`).
106    pub stream: String,
107    /// Payload data.
108    pub data: serde_json::Value,
109}
110
111/// Trade stream message.
112#[derive(Debug, Clone, Deserialize)]
113pub struct BinanceSpotTradeMsg {
114    /// Event type.
115    #[serde(rename = "e")]
116    pub event_type: String,
117    /// Event time in milliseconds.
118    #[serde(rename = "E")]
119    pub event_time: i64,
120    /// Symbol.
121    #[serde(rename = "s")]
122    pub symbol: Ustr,
123    /// Trade ID.
124    #[serde(rename = "t")]
125    pub trade_id: u64,
126    /// Price.
127    #[serde(rename = "p")]
128    pub price: String,
129    /// Quantity.
130    #[serde(rename = "q")]
131    pub quantity: String,
132    /// Trade time in milliseconds.
133    #[serde(rename = "T")]
134    pub trade_time: i64,
135    /// Is buyer the market maker.
136    #[serde(rename = "m")]
137    pub is_buyer_maker: bool,
138}
139
140/// Best bid/ask stream message.
141#[derive(Debug, Clone, Deserialize)]
142pub struct BinanceSpotBookTickerMsg {
143    /// Event type.
144    #[serde(rename = "e", default)]
145    pub event_type: Option<String>,
146    /// Event time in milliseconds.
147    #[serde(rename = "E", default)]
148    pub event_time: Option<i64>,
149    /// Symbol.
150    #[serde(rename = "s")]
151    pub symbol: Ustr,
152    /// Order book update id.
153    #[serde(rename = "u")]
154    pub book_update_id: u64,
155    /// Best bid price.
156    #[serde(rename = "b")]
157    pub best_bid_price: String,
158    /// Best bid quantity.
159    #[serde(rename = "B")]
160    pub best_bid_qty: String,
161    /// Best ask price.
162    #[serde(rename = "a")]
163    pub best_ask_price: String,
164    /// Best ask quantity.
165    #[serde(rename = "A")]
166    pub best_ask_qty: String,
167    /// Transaction time in milliseconds (if provided).
168    #[serde(rename = "T", default)]
169    pub transaction_time: Option<i64>,
170}
171
172/// Partial depth stream message with symbol inferred from stream name.
173#[derive(Debug, Clone)]
174pub struct BinanceSpotPartialDepthMsg {
175    /// Symbol.
176    pub symbol: Ustr,
177    /// Last update ID.
178    pub last_update_id: u64,
179    /// Bid levels `[price, qty]`.
180    pub bids: Vec<[String; 2]>,
181    /// Ask levels `[price, qty]`.
182    pub asks: Vec<[String; 2]>,
183}
184
185/// Raw partial depth payload from Spot JSON stream.
186#[derive(Debug, Clone, Deserialize)]
187pub struct BinanceSpotPartialDepthPayload {
188    /// Last update ID.
189    #[serde(rename = "lastUpdateId")]
190    pub last_update_id: u64,
191    /// Bid levels `[price, qty]`.
192    pub bids: Vec<[String; 2]>,
193    /// Ask levels `[price, qty]`.
194    pub asks: Vec<[String; 2]>,
195}
196
197/// Diff depth stream message.
198#[derive(Debug, Clone, Deserialize)]
199pub struct BinanceSpotDepthDiffMsg {
200    /// Event type.
201    #[serde(rename = "e")]
202    pub event_type: String,
203    /// Event time in milliseconds.
204    #[serde(rename = "E")]
205    pub event_time: i64,
206    /// Symbol.
207    #[serde(rename = "s")]
208    pub symbol: Ustr,
209    /// First update ID in event.
210    #[serde(rename = "U")]
211    pub first_update_id: u64,
212    /// Final update ID in event.
213    #[serde(rename = "u")]
214    pub final_update_id: u64,
215    /// Bid updates `[price, qty]`.
216    #[serde(rename = "b")]
217    pub bids: Vec<[String; 2]>,
218    /// Ask updates `[price, qty]`.
219    #[serde(rename = "a")]
220    pub asks: Vec<[String; 2]>,
221}
222
223/// Kline stream message.
224#[derive(Debug, Clone, Deserialize)]
225pub struct BinanceSpotKlineMsg {
226    /// Event type.
227    #[serde(rename = "e")]
228    pub event_type: String,
229    /// Event time in milliseconds.
230    #[serde(rename = "E")]
231    pub event_time: i64,
232    /// Symbol.
233    #[serde(rename = "s")]
234    pub symbol: Ustr,
235    /// Kline data.
236    #[serde(rename = "k")]
237    pub kline: BinanceSpotKlineData,
238}
239
240/// Kline data within kline message.
241#[derive(Debug, Clone, Deserialize)]
242pub struct BinanceSpotKlineData {
243    /// Kline start time.
244    #[serde(rename = "t")]
245    pub start_time: i64,
246    /// Kline close time.
247    #[serde(rename = "T")]
248    pub close_time: i64,
249    /// Symbol.
250    #[serde(rename = "s")]
251    pub symbol: Ustr,
252    /// Kline interval.
253    #[serde(rename = "i")]
254    pub interval: BinanceKlineInterval,
255    /// First trade ID.
256    #[serde(rename = "f")]
257    pub first_trade_id: i64,
258    /// Last trade ID.
259    #[serde(rename = "L")]
260    pub last_trade_id: i64,
261    /// Open price.
262    #[serde(rename = "o")]
263    pub open: String,
264    /// Close price.
265    #[serde(rename = "c")]
266    pub close: String,
267    /// High price.
268    #[serde(rename = "h")]
269    pub high: String,
270    /// Low price.
271    #[serde(rename = "l")]
272    pub low: String,
273    /// Base asset volume.
274    #[serde(rename = "v")]
275    pub volume: String,
276    /// Number of trades.
277    #[serde(rename = "n")]
278    pub num_trades: i64,
279    /// Is this kline closed.
280    #[serde(rename = "x")]
281    pub is_closed: bool,
282}
283
284/// Server shutdown event sent before Binance disconnects clients.
285#[derive(Debug, Clone, Deserialize)]
286pub struct BinanceSpotServerShutdownMsg {
287    /// Event type (`"serverShutdown"`).
288    #[serde(rename = "e")]
289    pub event_type: String,
290    /// Event time in milliseconds.
291    #[serde(rename = "E")]
292    pub event_time: i64,
293}
294
295pub type BinanceSpotWsResponse = BinanceWsResponse;
296pub type BinanceSpotWsErrorResponse = BinanceWsErrorResponse;