Skip to main content

nautilus_binance/spot/websocket/trading/
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 WebSocket API message types.
17//!
18//! This module defines:
19//! - [`BinanceSpotWsTradingCommand`]: Commands sent from the client to the handler.
20//! - [`BinanceSpotWsTradingMessage`]: Output messages emitted by the handler to the client.
21//! - Request/response structures for the Binance Spot WebSocket Trading API.
22
23use nautilus_network::websocket::WebSocketClient;
24use serde::{Deserialize, Serialize};
25
26use super::user_data::{
27    BinanceSpotAccountPositionMsg, BinanceSpotBalanceUpdateMsg, BinanceSpotExecutionReport,
28    BinanceSpotListStatus,
29};
30use crate::spot::http::{
31    models::{
32        BinanceCancelOpenOrdersResponse, BinanceCancelOrderResponse, BinanceNewOrderResponse,
33    },
34    query::{CancelOrderParams, CancelReplaceOrderParams, NewOrderParams},
35};
36
37/// Commands sent from the outer client to the inner handler.
38///
39/// The handler runs in a dedicated Tokio task and processes these commands
40/// to perform WebSocket API operations (request/response pattern).
41#[allow(
42    missing_debug_implementations,
43    clippy::large_enum_variant,
44    reason = "Commands are ephemeral and immediately consumed"
45)]
46pub enum BinanceSpotWsTradingCommand {
47    /// Sets the WebSocket client after connection.
48    SetClient(WebSocketClient),
49    /// Disconnects and cleans up.
50    Disconnect,
51    /// Places a new order.
52    PlaceOrder {
53        /// Request ID for correlation.
54        id: String,
55        /// Order parameters.
56        params: NewOrderParams,
57    },
58    /// Cancels an order.
59    CancelOrder {
60        /// Request ID for correlation.
61        id: String,
62        /// Cancel parameters.
63        params: CancelOrderParams,
64    },
65    /// Cancels and replaces an order atomically.
66    CancelReplaceOrder {
67        /// Request ID for correlation.
68        id: String,
69        /// Cancel-replace parameters.
70        params: CancelReplaceOrderParams,
71    },
72    /// Cancels all open orders for a symbol.
73    CancelAllOrders {
74        /// Request ID for correlation.
75        id: String,
76        /// Symbol to cancel all orders for.
77        symbol: String,
78    },
79    /// Authenticates the WebSocket session via `session.logon`.
80    SessionLogon,
81    /// Subscribes to the user data stream via `userDataStream.subscribe`.
82    SubscribeUserData,
83}
84
85/// Normalized output message from the WebSocket API handler.
86///
87/// These messages are emitted by the handler and consumed by the client
88/// for routing to callers or the execution engine.
89#[derive(Debug, Clone)]
90pub enum BinanceSpotWsTradingMessage {
91    /// Connection established.
92    Connected,
93    /// Session authenticated successfully.
94    Authenticated,
95    /// Session authentication was rejected or could not be sent.
96    AuthenticationRejected(String),
97    /// Connection was re-established after disconnect.
98    Reconnected,
99    /// Order accepted by venue.
100    OrderAccepted {
101        /// Request ID for correlation.
102        request_id: String,
103        /// Order response from venue.
104        response: BinanceNewOrderResponse,
105    },
106    /// Order rejected by venue.
107    OrderRejected {
108        /// Request ID for correlation.
109        request_id: String,
110        /// Venue response status.
111        status: u16,
112        /// Error code from venue.
113        code: i32,
114        /// Error message from venue.
115        msg: String,
116    },
117    /// Order canceled successfully.
118    OrderCanceled {
119        /// Request ID for correlation.
120        request_id: String,
121        /// Cancel response from venue.
122        response: BinanceCancelOrderResponse,
123    },
124    /// Cancel rejected by venue.
125    CancelRejected {
126        /// Request ID for correlation.
127        request_id: String,
128        /// Venue response status.
129        status: u16,
130        /// Error code from venue.
131        code: i32,
132        /// Error message from venue.
133        msg: String,
134    },
135    /// Cancel-replace response (new order after cancel).
136    CancelReplaceAccepted {
137        /// Request ID for correlation.
138        request_id: String,
139        /// Cancel response.
140        cancel_response: BinanceCancelOrderResponse,
141        /// New order response.
142        new_order_response: BinanceNewOrderResponse,
143    },
144    /// Cancel-replace rejected.
145    CancelReplaceRejected {
146        /// Request ID for correlation.
147        request_id: String,
148        /// Venue response status.
149        status: u16,
150        /// Error code from venue.
151        code: i32,
152        /// Error message from venue.
153        msg: String,
154    },
155    /// Request failed without a structured venue response.
156    RequestFailed {
157        /// Request ID for correlation.
158        request_id: String,
159        /// Failure reason.
160        msg: String,
161    },
162    /// All orders canceled for a symbol.
163    AllOrdersCanceled {
164        /// Request ID for correlation.
165        request_id: String,
166        /// Canceled order responses.
167        responses: Vec<BinanceCancelOpenOrdersResponse>,
168    },
169    /// User data stream subscribed.
170    UserDataSubscribed {
171        /// Subscription ID from Binance.
172        subscription_id: String,
173    },
174    /// User data subscription was rejected or could not be sent.
175    UserDataSubscriptionRejected(String),
176    /// Order execution report from user data stream.
177    ExecutionReport(Box<BinanceSpotExecutionReport>),
178    /// Order-list lifecycle update from user data stream.
179    ListStatus(BinanceSpotListStatus),
180    /// Account position update from user data stream.
181    AccountPosition(BinanceSpotAccountPositionMsg),
182    /// Balance update from user data stream.
183    BalanceUpdate(BinanceSpotBalanceUpdateMsg),
184    /// Server shutdown notice (sent ~10 minutes before disconnection).
185    ServerShutdown {
186        /// Event time in milliseconds.
187        event_time: i64,
188    },
189    /// Error from venue or network.
190    Error(String),
191}
192
193/// Metadata for a pending request.
194///
195/// Stored in the handler to match responses to their originating requests.
196#[derive(Debug, Clone, Copy)]
197pub enum BinanceSpotWsTradingRequestMeta {
198    /// Pending order placement.
199    PlaceOrder,
200    /// Pending order cancellation.
201    CancelOrder,
202    /// Pending cancel-replace.
203    CancelReplaceOrder,
204    /// Pending cancel-all.
205    CancelAllOrders,
206    /// Pending session logon.
207    SessionLogon,
208    /// Pending user data subscription.
209    SubscribeUserData,
210}
211
212/// WebSocket API request wrapper.
213///
214/// Requests are sent as JSON text frames, responses come back as SBE binary.
215#[derive(Debug, Clone, Serialize)]
216pub struct BinanceSpotWsTradingRequest {
217    /// Unique request ID for correlation.
218    pub id: String,
219    /// API method name (e.g., "order.place").
220    pub method: String,
221    /// Request parameters.
222    pub params: serde_json::Value,
223}
224
225impl BinanceSpotWsTradingRequest {
226    /// Creates a new WebSocket API request.
227    #[must_use]
228    pub fn new(
229        id: impl Into<String>,
230        method: impl Into<String>,
231        params: serde_json::Value,
232    ) -> Self {
233        Self {
234            id: id.into(),
235            method: method.into(),
236            params,
237        }
238    }
239}
240
241/// WebSocket API error response (JSON).
242#[derive(Debug, Clone, Deserialize)]
243pub struct BinanceSpotWsTradingResponseError {
244    /// Error code from venue.
245    pub code: i32,
246    /// Error message from venue.
247    pub msg: String,
248    /// Request ID if available.
249    pub id: Option<String>,
250}
251
252/// WebSocket API method names.
253pub mod method {
254    /// Places a new order.
255    pub const ORDER_PLACE: &str = "order.place";
256    /// Cancels an order.
257    pub const ORDER_CANCEL: &str = "order.cancel";
258    /// Cancels and replaces an order.
259    pub const ORDER_CANCEL_REPLACE: &str = "order.cancelReplace";
260    /// Cancels all open orders for a symbol.
261    pub const OPEN_ORDERS_CANCEL_ALL: &str = "openOrders.cancelAll";
262    /// Initiates session logon.
263    pub const SESSION_LOGON: &str = "session.logon";
264    /// Queries session status.
265    pub const SESSION_STATUS: &str = "session.status";
266    /// Initiates session logout.
267    pub const SESSION_LOGOUT: &str = "session.logout";
268}