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 /// Connection was re-established after disconnect.
93 Reconnected,
94 /// Order accepted by venue.
95 OrderAccepted {
96 /// Request ID for correlation.
97 request_id: String,
98 /// Order response from venue.
99 response: BinanceNewOrderResponse,
100 },
101 /// Order rejected by venue.
102 OrderRejected {
103 /// Request ID for correlation.
104 request_id: String,
105 /// Error code from venue.
106 code: i32,
107 /// Error message from venue.
108 msg: String,
109 },
110 /// Order canceled successfully.
111 OrderCanceled {
112 /// Request ID for correlation.
113 request_id: String,
114 /// Cancel response from venue.
115 response: BinanceCancelOrderResponse,
116 },
117 /// Cancel rejected by venue.
118 CancelRejected {
119 /// Request ID for correlation.
120 request_id: String,
121 /// Error code from venue.
122 code: i32,
123 /// Error message from venue.
124 msg: String,
125 },
126 /// Cancel-replace response (new order after cancel).
127 CancelReplaceAccepted {
128 /// Request ID for correlation.
129 request_id: String,
130 /// Cancel response.
131 cancel_response: BinanceCancelOrderResponse,
132 /// New order response.
133 new_order_response: BinanceNewOrderResponse,
134 },
135 /// Cancel-replace rejected.
136 CancelReplaceRejected {
137 /// Request ID for correlation.
138 request_id: String,
139 /// Error code from venue.
140 code: i32,
141 /// Error message from venue.
142 msg: String,
143 },
144 /// Request failed without a structured venue response.
145 RequestFailed {
146 /// Request ID for correlation.
147 request_id: String,
148 /// Failure reason.
149 msg: String,
150 },
151 /// All orders canceled for a symbol.
152 AllOrdersCanceled {
153 /// Request ID for correlation.
154 request_id: String,
155 /// Canceled order responses.
156 responses: Vec<BinanceCancelOrderResponse>,
157 },
158 /// User data stream subscribed.
159 UserDataSubscribed {
160 /// Subscription ID from Binance.
161 subscription_id: String,
162 },
163 /// Order execution report from user data stream.
164 ExecutionReport(Box<BinanceSpotExecutionReport>),
165 /// Account position update from user data stream.
166 AccountPosition(BinanceSpotAccountPositionMsg),
167 /// Balance update from user data stream.
168 BalanceUpdate(BinanceSpotBalanceUpdateMsg),
169 /// Server shutdown notice (sent ~10 minutes before disconnection).
170 ServerShutdown {
171 /// Event time in milliseconds.
172 event_time: i64,
173 },
174 /// Error from venue or network.
175 Error(String),
176}
177
178/// Metadata for a pending request.
179///
180/// Stored in the handler to match responses to their originating requests.
181#[derive(Debug, Clone, Copy)]
182pub enum BinanceSpotWsTradingRequestMeta {
183 /// Pending order placement.
184 PlaceOrder,
185 /// Pending order cancellation.
186 CancelOrder,
187 /// Pending cancel-replace.
188 CancelReplaceOrder,
189 /// Pending cancel-all.
190 CancelAllOrders,
191 /// Pending session logon.
192 SessionLogon,
193 /// Pending user data subscription.
194 SubscribeUserData,
195}
196
197/// WebSocket API request wrapper.
198///
199/// Requests are sent as JSON text frames, responses come back as SBE binary.
200#[derive(Debug, Clone, Serialize)]
201pub struct BinanceSpotWsTradingRequest {
202 /// Unique request ID for correlation.
203 pub id: String,
204 /// API method name (e.g., "order.place").
205 pub method: String,
206 /// Request parameters.
207 pub params: serde_json::Value,
208}
209
210impl BinanceSpotWsTradingRequest {
211 /// Creates a new WebSocket API request.
212 #[must_use]
213 pub fn new(
214 id: impl Into<String>,
215 method: impl Into<String>,
216 params: serde_json::Value,
217 ) -> Self {
218 Self {
219 id: id.into(),
220 method: method.into(),
221 params,
222 }
223 }
224}
225
226/// WebSocket API error response (JSON).
227#[derive(Debug, Clone, Deserialize)]
228pub struct BinanceSpotWsTradingResponseError {
229 /// Error code from venue.
230 pub code: i32,
231 /// Error message from venue.
232 pub msg: String,
233 /// Request ID if available.
234 pub id: Option<String>,
235}
236
237/// WebSocket API method names.
238pub mod method {
239 /// Places a new order.
240 pub const ORDER_PLACE: &str = "order.place";
241 /// Cancels an order.
242 pub const ORDER_CANCEL: &str = "order.cancel";
243 /// Cancels and replaces an order.
244 pub const ORDER_CANCEL_REPLACE: &str = "order.cancelReplace";
245 /// Cancels all open orders for a symbol.
246 pub const OPEN_ORDERS_CANCEL_ALL: &str = "openOrders.cancelAll";
247 /// Initiates session logon.
248 pub const SESSION_LOGON: &str = "session.logon";
249 /// Queries session status.
250 pub const SESSION_STATUS: &str = "session.status";
251 /// Initiates session logout.
252 pub const SESSION_LOGOUT: &str = "session.logout";
253}