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