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//! - [`HandlerCommand`]: Commands sent from the client to the handler.
20//! - [`NautilusWsApiMessage`]: Output messages emitted by the handler to the client.
21//! - Request/response structures for the Binance WebSocket API.
22
23use nautilus_network::websocket::WebSocketClient;
24use serde::{Deserialize, Serialize};
25
26use crate::spot::http::{
27    models::{BinanceCancelOrderResponse, BinanceNewOrderResponse},
28    query::{CancelOrderParams, CancelReplaceOrderParams, NewOrderParams},
29};
30
31/// Commands sent from the outer client to the inner handler.
32///
33/// The handler runs in a dedicated Tokio task and processes these commands
34/// to perform WebSocket API operations (request/response pattern).
35#[allow(
36    missing_debug_implementations,
37    clippy::large_enum_variant,
38    reason = "Commands are ephemeral and immediately consumed"
39)]
40pub enum HandlerCommand {
41    /// Set the WebSocket client after connection.
42    SetClient(WebSocketClient),
43    /// Disconnect and clean up.
44    Disconnect,
45    /// Place a new order.
46    PlaceOrder {
47        /// Request ID for correlation.
48        id: String,
49        /// Order parameters.
50        params: NewOrderParams,
51    },
52    /// Cancel an order.
53    CancelOrder {
54        /// Request ID for correlation.
55        id: String,
56        /// Cancel parameters.
57        params: CancelOrderParams,
58    },
59    /// Cancel and replace an order atomically.
60    CancelReplaceOrder {
61        /// Request ID for correlation.
62        id: String,
63        /// Cancel-replace parameters.
64        params: CancelReplaceOrderParams,
65    },
66    /// Cancel all open orders for a symbol.
67    CancelAllOrders {
68        /// Request ID for correlation.
69        id: String,
70        /// Symbol to cancel all orders for.
71        symbol: String,
72    },
73}
74
75/// Normalized output message from the WebSocket API handler.
76///
77/// These messages are emitted by the handler and consumed by the client
78/// for routing to callers or the execution engine.
79#[derive(Debug, Clone)]
80pub enum NautilusWsApiMessage {
81    /// Connection established.
82    Connected,
83    /// Session authenticated successfully.
84    Authenticated,
85    /// Connection was re-established after disconnect.
86    Reconnected,
87    /// Order accepted by venue.
88    OrderAccepted {
89        /// Request ID for correlation.
90        request_id: String,
91        /// Order response from venue.
92        response: BinanceNewOrderResponse,
93    },
94    /// Order rejected by venue.
95    OrderRejected {
96        /// Request ID for correlation.
97        request_id: String,
98        /// Error code from venue.
99        code: i32,
100        /// Error message from venue.
101        msg: String,
102    },
103    /// Order canceled successfully.
104    OrderCanceled {
105        /// Request ID for correlation.
106        request_id: String,
107        /// Cancel response from venue.
108        response: BinanceCancelOrderResponse,
109    },
110    /// Cancel rejected by venue.
111    CancelRejected {
112        /// Request ID for correlation.
113        request_id: String,
114        /// Error code from venue.
115        code: i32,
116        /// Error message from venue.
117        msg: String,
118    },
119    /// Cancel-replace response (new order after cancel).
120    CancelReplaceAccepted {
121        /// Request ID for correlation.
122        request_id: String,
123        /// Cancel response.
124        cancel_response: BinanceCancelOrderResponse,
125        /// New order response.
126        new_order_response: BinanceNewOrderResponse,
127    },
128    /// Cancel-replace rejected.
129    CancelReplaceRejected {
130        /// Request ID for correlation.
131        request_id: String,
132        /// Error code from venue.
133        code: i32,
134        /// Error message from venue.
135        msg: String,
136    },
137    /// All orders canceled for a symbol.
138    AllOrdersCanceled {
139        /// Request ID for correlation.
140        request_id: String,
141        /// Canceled order responses.
142        responses: Vec<BinanceCancelOrderResponse>,
143    },
144    /// Error from venue or network.
145    Error(String),
146}
147
148/// Metadata for a pending request.
149///
150/// Stored in the handler to match responses to their originating requests.
151#[derive(Debug, Clone)]
152pub enum RequestMeta {
153    /// Pending order placement.
154    PlaceOrder,
155    /// Pending order cancellation.
156    CancelOrder,
157    /// Pending cancel-replace.
158    CancelReplaceOrder,
159    /// Pending cancel-all.
160    CancelAllOrders,
161}
162
163/// WebSocket API request wrapper.
164///
165/// Requests are sent as JSON text frames, responses come back as SBE binary.
166#[derive(Debug, Clone, Serialize)]
167pub struct WsApiRequest {
168    /// Unique request ID for correlation.
169    pub id: String,
170    /// API method name (e.g., "order.place").
171    pub method: String,
172    /// Request parameters.
173    pub params: serde_json::Value,
174}
175
176impl WsApiRequest {
177    /// Create a new WebSocket API request.
178    #[must_use]
179    pub fn new(
180        id: impl Into<String>,
181        method: impl Into<String>,
182        params: serde_json::Value,
183    ) -> Self {
184        Self {
185            id: id.into(),
186            method: method.into(),
187            params,
188        }
189    }
190}
191
192/// WebSocket API error response (JSON).
193#[derive(Debug, Clone, Deserialize)]
194pub struct WsApiErrorResponse {
195    /// Error code from venue.
196    pub code: i32,
197    /// Error message from venue.
198    pub msg: String,
199    /// Request ID if available.
200    pub id: Option<String>,
201}
202
203/// WebSocket API method names.
204pub mod method {
205    /// Place a new order.
206    pub const ORDER_PLACE: &str = "order.place";
207    /// Cancel an order.
208    pub const ORDER_CANCEL: &str = "order.cancel";
209    /// Cancel and replace an order.
210    pub const ORDER_CANCEL_REPLACE: &str = "order.cancelReplace";
211    /// Cancel all open orders for a symbol.
212    pub const OPEN_ORDERS_CANCEL_ALL: &str = "openOrders.cancelAll";
213    /// Session logon.
214    pub const SESSION_LOGON: &str = "session.logon";
215    /// Session status.
216    pub const SESSION_STATUS: &str = "session.status";
217    /// Session logout.
218    pub const SESSION_LOGOUT: &str = "session.logout";
219}