bybit_rust_api/rest/order/
order_client.rs1use crate::rest::client::{RestClient, SecType, ServerResponse};
2use crate::rest::enums::category::Category;
3use crate::rest::order::dto::*;
4use crate::rest::BybitResult as Result;
5use serde_json::json;
6
7#[derive(Clone)]
8pub struct OrderClient {
9 client: RestClient,
10}
11
12impl OrderClient {
13 pub fn new(client: RestClient) -> Self {
14 OrderClient { client }
15 }
16
17 pub async fn place_order(
22 &self,
23 order: PlaceOrderRequest,
24 ) -> Result<ServerResponse<PlaceOrderResponse>> {
25 let endpoint = "v5/order/create";
26 let body = serde_json::to_value(&order)?;
27
28 let response: ServerResponse<PlaceOrderResponse> =
29 self.client.post(endpoint, body, SecType::Signed).await?;
30 Ok(response)
31 }
32
33 pub async fn batch_place_orders(
38 &self,
39 category: Category,
40 orders: Vec<PlaceOrderRequest>,
41 ) -> Result<ServerResponse<BatchPlaceOrderResponse>> {
42 let endpoint = "v5/order/create-batch";
43 let body = json!({
44 "category": category,
45 "request": orders
46 });
47
48 let response: ServerResponse<BatchPlaceOrderResponse> =
49 self.client.post(endpoint, body, SecType::Signed).await?;
50 Ok(response)
51 }
52
53 pub async fn amend_order(
58 &self,
59 amend_request: AmendOrderRequest,
60 ) -> Result<ServerResponse<AmendOrderResponse>> {
61 let endpoint = "v5/order/amend";
62 let body = serde_json::to_value(&amend_request)?;
63
64 let response: ServerResponse<AmendOrderResponse> =
65 self.client.post(endpoint, body, SecType::Signed).await?;
66 Ok(response)
67 }
68
69 pub async fn batch_amend_orders(
74 &self,
75 category: Category,
76 amendments: Vec<AmendOrderRequest>,
77 ) -> Result<ServerResponse<BatchAmendOrderResponse>> {
78 let endpoint = "v5/order/amend-batch";
79 let body = json!({
80 "category": category,
81 "request": amendments
82 });
83
84 let response: ServerResponse<BatchAmendOrderResponse> =
85 self.client.post(endpoint, body, SecType::Signed).await?;
86 Ok(response)
87 }
88
89 pub async fn cancel_order(
94 &self,
95 cancel_request: CancelOrderRequest,
96 ) -> Result<ServerResponse<CancelOrderResponse>> {
97 let endpoint = "v5/order/cancel";
98 let body = serde_json::to_value(&cancel_request)?;
99
100 let response: ServerResponse<CancelOrderResponse> =
101 self.client.post(endpoint, body, SecType::Signed).await?;
102 Ok(response)
103 }
104
105 pub async fn batch_cancel_orders(
110 &self,
111 category: Category,
112 cancellations: Vec<CancelOrderRequest>,
113 ) -> Result<ServerResponse<BatchCancelOrderResponse>> {
114 let endpoint = "v5/order/cancel-batch";
115 let body = json!({
116 "category": category,
117 "request": cancellations
118 });
119
120 let response: ServerResponse<BatchCancelOrderResponse> =
121 self.client.post(endpoint, body, SecType::Signed).await?;
122 Ok(response)
123 }
124
125 pub async fn cancel_all_orders(
130 &self,
131 category: Category,
132 symbol: Option<&str>,
133 base_coin: Option<&str>,
134 settle_coin: Option<&str>,
135 order_filter: Option<&str>,
136 ) -> Result<ServerResponse<CancelAllOrdersResponse>> {
137 let endpoint = "v5/order/cancel-all";
138 let mut body = json!({
139 "category": category,
140 });
141
142 if let Some(symbol) = symbol {
143 body["symbol"] = json!(symbol);
144 }
145 if let Some(base_coin) = base_coin {
146 body["baseCoin"] = json!(base_coin);
147 }
148 if let Some(settle_coin) = settle_coin {
149 body["settleCoin"] = json!(settle_coin);
150 }
151 if let Some(order_filter) = order_filter {
152 body["orderFilter"] = json!(order_filter);
153 }
154
155 let response: ServerResponse<CancelAllOrdersResponse> =
156 self.client.post(endpoint, body, SecType::Signed).await?;
157 Ok(response)
158 }
159
160 pub async fn get_open_orders(
165 &self,
166 category: Category,
167 symbol: Option<&str>,
168 base_coin: Option<&str>,
169 settle_coin: Option<&str>,
170 order_id: Option<&str>,
171 order_link_id: Option<&str>,
172 open_only: Option<i32>,
173 order_filter: Option<&str>,
174 limit: Option<i32>,
175 cursor: Option<&str>,
176 ) -> Result<ServerResponse<GetOrdersResponse>> {
177 let endpoint = "v5/order/realtime";
178 let mut params = json!({
179 "category": category,
180 });
181
182 if let Some(symbol) = symbol {
183 params["symbol"] = json!(symbol);
184 }
185 if let Some(base_coin) = base_coin {
186 params["baseCoin"] = json!(base_coin);
187 }
188 if let Some(settle_coin) = settle_coin {
189 params["settleCoin"] = json!(settle_coin);
190 }
191 if let Some(order_id) = order_id {
192 params["orderId"] = json!(order_id);
193 }
194 if let Some(order_link_id) = order_link_id {
195 params["orderLinkId"] = json!(order_link_id);
196 }
197 if let Some(open_only) = open_only {
198 params["openOnly"] = json!(open_only);
199 }
200 if let Some(order_filter) = order_filter {
201 params["orderFilter"] = json!(order_filter);
202 }
203 if let Some(limit) = limit {
204 params["limit"] = json!(limit);
205 }
206 if let Some(cursor) = cursor {
207 params["cursor"] = json!(cursor);
208 }
209
210 let response: ServerResponse<GetOrdersResponse> =
211 self.client.get(endpoint, params, SecType::Signed).await?;
212 Ok(response)
213 }
214
215 pub async fn get_order_history(
220 &self,
221 category: Category,
222 symbol: Option<&str>,
223 base_coin: Option<&str>,
224 settle_coin: Option<&str>,
225 order_id: Option<&str>,
226 order_link_id: Option<&str>,
227 order_filter: Option<&str>,
228 order_status: Option<&str>,
229 start_time: Option<i64>,
230 end_time: Option<i64>,
231 limit: Option<i32>,
232 cursor: Option<&str>,
233 ) -> Result<ServerResponse<GetOrdersResponse>> {
234 let endpoint = "v5/order/history";
235 let mut params = json!({
236 "category": category,
237 });
238
239 if let Some(symbol) = symbol {
240 params["symbol"] = json!(symbol);
241 }
242 if let Some(base_coin) = base_coin {
243 params["baseCoin"] = json!(base_coin);
244 }
245 if let Some(settle_coin) = settle_coin {
246 params["settleCoin"] = json!(settle_coin);
247 }
248 if let Some(order_id) = order_id {
249 params["orderId"] = json!(order_id);
250 }
251 if let Some(order_link_id) = order_link_id {
252 params["orderLinkId"] = json!(order_link_id);
253 }
254 if let Some(order_filter) = order_filter {
255 params["orderFilter"] = json!(order_filter);
256 }
257 if let Some(order_status) = order_status {
258 params["orderStatus"] = json!(order_status);
259 }
260 if let Some(start_time) = start_time {
261 params["startTime"] = json!(start_time);
262 }
263 if let Some(end_time) = end_time {
264 params["endTime"] = json!(end_time);
265 }
266 if let Some(limit) = limit {
267 params["limit"] = json!(limit);
268 }
269 if let Some(cursor) = cursor {
270 params["cursor"] = json!(cursor);
271 }
272
273 let response: ServerResponse<GetOrdersResponse> =
274 self.client.get(endpoint, params, SecType::Signed).await?;
275 Ok(response)
276 }
277
278 pub async fn get_trade_history(
283 &self,
284 category: Category,
285 symbol: Option<&str>,
286 order_id: Option<&str>,
287 order_link_id: Option<&str>,
288 base_coin: Option<&str>,
289 start_time: Option<i64>,
290 end_time: Option<i64>,
291 exec_type: Option<&str>,
292 limit: Option<i32>,
293 cursor: Option<&str>,
294 ) -> Result<ServerResponse<GetTradeHistoryResponse>> {
295 let endpoint = "v5/execution/list";
296 let mut params = json!({
297 "category": category,
298 });
299
300 if let Some(symbol) = symbol {
301 params["symbol"] = json!(symbol);
302 }
303 if let Some(order_id) = order_id {
304 params["orderId"] = json!(order_id);
305 }
306 if let Some(order_link_id) = order_link_id {
307 params["orderLinkId"] = json!(order_link_id);
308 }
309 if let Some(base_coin) = base_coin {
310 params["baseCoin"] = json!(base_coin);
311 }
312 if let Some(start_time) = start_time {
313 params["startTime"] = json!(start_time);
314 }
315 if let Some(end_time) = end_time {
316 params["endTime"] = json!(end_time);
317 }
318 if let Some(exec_type) = exec_type {
319 params["execType"] = json!(exec_type);
320 }
321 if let Some(limit) = limit {
322 params["limit"] = json!(limit);
323 }
324 if let Some(cursor) = cursor {
325 params["cursor"] = json!(cursor);
326 }
327
328 let response: ServerResponse<GetTradeHistoryResponse> =
329 self.client.get(endpoint, params, SecType::Signed).await?;
330 Ok(response)
331 }
332
333 pub async fn spot_borrow_check(
338 &self,
339 category: &str,
340 symbol: &str,
341 side: &str,
342 ) -> Result<ServerResponse<serde_json::Value>> {
343 let endpoint = "v5/order/spot-borrow-check";
344 let params = json!({
345 "category": category,
346 "symbol": symbol,
347 "side": side,
348 });
349
350 let response = self.client.get(endpoint, params, SecType::Signed).await?;
351 Ok(response)
352 }
353}
354
355#[cfg(test)]
356mod tests {
357 use super::*;
358 use crate::rest::enums::order_type::OrderType;
359 use crate::rest::enums::side::Side;
360 use crate::rest::enums::time_in_force::TimeInForce;
361 use crate::rest::ApiKeyPair;
362
363 fn create_test_client() -> OrderClient {
364 let api_key_pair = ApiKeyPair::new(
365 "test".to_string(),
366 "test_key".to_string(),
367 "test_secret".to_string(),
368 );
369 let rest_client =
370 RestClient::new(api_key_pair, "https://api-testnet.bybit.com".to_string());
371 OrderClient::new(rest_client)
372 }
373
374 #[test]
375 fn test_order_client_creation() {
376 let _client = create_test_client();
377 }
378
379 #[test]
380 fn test_place_order_request_creation() {
381 let order = PlaceOrderRequest {
382 category: Category::Spot,
383 symbol: "BTCUSDT".to_string(),
384 side: Side::Buy,
385 order_type: OrderType::Limit,
386 qty: "0.001".to_string(),
387 price: Some("40000".to_string()),
388 time_in_force: Some(TimeInForce::GTC),
389 ..Default::default()
390 };
391
392 assert_eq!(order.symbol, "BTCUSDT");
393 assert_eq!(order.qty, "0.001");
394 }
395
396 #[test]
397 fn test_cancel_order_request_creation() {
398 let cancel_request = CancelOrderRequest {
399 category: Category::Spot,
400 symbol: "BTCUSDT".to_string(),
401 order_id: Some("123456".to_string()),
402 ..Default::default()
403 };
404
405 assert_eq!(cancel_request.symbol, "BTCUSDT");
406 assert_eq!(cancel_request.order_id, Some("123456".to_string()));
407 }
408
409 #[test]
410 fn test_batch_request_creation() {
411 let orders = vec![
412 PlaceOrderRequest {
413 category: Category::Spot,
414 symbol: "BTCUSDT".to_string(),
415 side: Side::Buy,
416 order_type: OrderType::Limit,
417 qty: "0.001".to_string(),
418 ..Default::default()
419 },
420 PlaceOrderRequest {
421 category: Category::Spot,
422 symbol: "ETHUSDT".to_string(),
423 side: Side::Buy,
424 order_type: OrderType::Limit,
425 qty: "0.01".to_string(),
426 ..Default::default()
427 },
428 ];
429
430 assert_eq!(orders.len(), 2);
431 assert_eq!(orders[0].symbol, "BTCUSDT");
432 assert_eq!(orders[1].symbol, "ETHUSDT");
433 }
434}