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