Skip to main content

bybit_rust_api/ws/private/
order.rs

1//! Order stream — real-time order status updates.
2//!
3//! # Topics
4//! - `order` (all categories)
5//! - `order.linear`, `order.inverse`, `order.spot`, `order.option`
6
7use serde::Deserialize;
8
9/// Order update data from private WebSocket.
10#[derive(Debug, Clone, Deserialize)]
11pub struct OrderData {
12    /// Category: "linear", "inverse", "spot", "option"
13    #[serde(rename = "category")]
14    #[serde(default)]
15    pub category: Option<String>,
16    /// Symbol
17    #[serde(rename = "symbol")]
18    #[serde(default)]
19    pub symbol: Option<String>,
20    /// Order ID
21    #[serde(rename = "orderId")]
22    #[serde(default)]
23    pub order_id: Option<String>,
24    /// Client-specified order link ID
25    #[serde(rename = "orderLinkId")]
26    #[serde(default)]
27    pub order_link_id: Option<String>,
28    /// Whether this is a block trade order
29    #[serde(rename = "blockTradeId")]
30    #[serde(default)]
31    pub block_trade_id: Option<String>,
32    /// Side: "Buy" or "Sell"
33    #[serde(rename = "side")]
34    #[serde(default)]
35    pub side: Option<String>,
36    /// Order type: "Market", "Limit"
37    #[serde(rename = "orderType")]
38    #[serde(default)]
39    pub order_type: Option<String>,
40    /// Stop order type
41    #[serde(rename = "stopOrderType")]
42    #[serde(default)]
43    pub stop_order_type: Option<String>,
44    /// Order price
45    #[serde(rename = "price")]
46    #[serde(default)]
47    pub price: Option<String>,
48    /// Order quantity
49    #[serde(rename = "qty")]
50    #[serde(default)]
51    pub qty: Option<String>,
52    /// Time in force: "GTC", "IOC", "FOK", "PostOnly"
53    #[serde(rename = "timeInForce")]
54    #[serde(default)]
55    pub time_in_force: Option<String>,
56    /// Order status
57    #[serde(rename = "orderStatus")]
58    #[serde(default)]
59    pub order_status: Option<String>,
60    /// Leaves quantity (remaining)
61    #[serde(rename = "leavesQty")]
62    #[serde(default)]
63    pub leaves_qty: Option<String>,
64    /// Cumulative executed quantity
65    #[serde(rename = "cumExecQty")]
66    #[serde(default)]
67    pub cum_exec_qty: Option<String>,
68    /// Cumulative executed value
69    #[serde(rename = "cumExecValue")]
70    #[serde(default)]
71    pub cum_exec_value: Option<String>,
72    /// Cumulative executed fee
73    #[serde(rename = "cumExecFee")]
74    #[serde(default)]
75    pub cum_exec_fee: Option<String>,
76    /// Average fill price
77    #[serde(rename = "avgPrice")]
78    #[serde(default)]
79    pub avg_price: Option<String>,
80    /// Reject reason (if rejected)
81    #[serde(rename = "rejectReason")]
82    #[serde(default)]
83    pub reject_reason: Option<String>,
84    /// Cancel type: "CancelByUser", "CancelByReduceOnly", etc.
85    #[serde(rename = "cancelType")]
86    #[serde(default)]
87    pub cancel_type: Option<String>,
88    /// Create type: "CreateByUser", "CreateByClosing"
89    #[serde(rename = "createType")]
90    #[serde(default)]
91    pub create_type: Option<String>,
92    /// Is leverage token?
93    #[serde(rename = "isLeverage")]
94    #[serde(default)]
95    pub is_leverage: Option<String>,
96    /// Position index
97    #[serde(rename = "positionIdx")]
98    #[serde(default)]
99    pub position_idx: Option<i32>,
100    /// Take profit price
101    #[serde(rename = "takeProfit")]
102    #[serde(default)]
103    pub take_profit: Option<String>,
104    /// Stop loss price
105    #[serde(rename = "stopLoss")]
106    #[serde(default)]
107    pub stop_loss: Option<String>,
108    /// Trigger price (for conditional orders)
109    #[serde(rename = "triggerPrice")]
110    #[serde(default)]
111    pub trigger_price: Option<String>,
112    /// Trigger direction: 1=rise, 2=fall
113    #[serde(rename = "triggerDirection")]
114    #[serde(default)]
115    pub trigger_direction: Option<i32>,
116    /// Trigger by: "LastPrice", "IndexPrice", "MarkPrice"
117    #[serde(rename = "triggerBy")]
118    #[serde(default)]
119    pub trigger_by: Option<String>,
120    /// Whether to reduce-only
121    #[serde(rename = "reduceOnly")]
122    #[serde(default)]
123    pub reduce_only: Option<bool>,
124    /// Whether to close on trigger
125    #[serde(rename = "closeOnTrigger")]
126    #[serde(default)]
127    pub close_on_trigger: Option<bool>,
128    /// SMP type
129    #[serde(rename = "smpType")]
130    #[serde(default)]
131    pub smp_type: Option<String>,
132    /// SMP group
133    #[serde(rename = "smpGroup")]
134    #[serde(default)]
135    pub smp_group: Option<i32>,
136    /// Created timestamp
137    #[serde(rename = "createdTime")]
138    #[serde(default)]
139    pub created_time: Option<String>,
140    /// Updated timestamp
141    #[serde(rename = "updatedTime")]
142    #[serde(default)]
143    pub updated_time: Option<String>,
144}
145
146#[cfg(test)]
147mod tests {
148    use super::*;
149
150    #[test]
151    fn test_parse_order() {
152        let json = serde_json::json!({
153            "category": "linear",
154            "symbol": "BTCUSDT",
155            "orderId": "order-789",
156            "side": "Buy",
157            "orderType": "Limit",
158            "price": "50000.00",
159            "qty": "0.01",
160            "orderStatus": "New",
161            "leavesQty": "0.01",
162            "cumExecQty": "0"
163        });
164
165        let order: OrderData = serde_json::from_value(json).unwrap();
166        assert_eq!(order.symbol.as_deref(), Some("BTCUSDT"));
167        assert_eq!(order.order_status.as_deref(), Some("New"));
168        assert_eq!(order.qty.as_deref(), Some("0.01"));
169    }
170}