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