Skip to main content

bybit_api/api/
trade.rs

1//! Trade API endpoints.
2
3use crate::client::BybitClient;
4use crate::error::Result;
5use crate::models::trade::*;
6use crate::models::*;
7use tracing::info;
8
9impl BybitClient {
10    /// Place an order.
11    ///
12    /// # Arguments
13    /// * `params` - Order parameters
14    ///
15    /// # Example
16    /// ```rust,no_run
17    /// # use bybit_api::{BybitClient, Category, Side};
18    /// # use bybit_api::trade::PlaceOrderParams;
19    /// # async fn example() -> bybit_api::Result<()> {
20    /// let client = BybitClient::testnet("key", "secret")?;
21    /// let params = PlaceOrderParams::market(Category::Linear, "BTCUSDT", Side::Buy, "0.01");
22    /// let result = client.place_order(params).await?;
23    /// println!("Order ID: {}", result.order_id);
24    /// # Ok(())
25    /// # }
26    /// ```
27    pub async fn place_order(&self, params: PlaceOrderParams) -> Result<OrderResponse> {
28        // Validate parameters before sending (fund safety)
29        params.validate()?;
30
31        info!(
32            symbol = %params.symbol,
33            side = ?params.side,
34            order_type = ?params.order_type,
35            qty = %params.qty,
36            "Placing order"
37        );
38
39        self.post("/v5/order/create", &params).await
40    }
41
42    /// Amend an existing order.
43    pub async fn amend_order(&self, params: AmendOrderParams) -> Result<OrderResponse> {
44        info!(
45            symbol = %params.symbol,
46            order_id = ?params.order_id,
47            "Amending order"
48        );
49
50        self.post("/v5/order/amend", &params).await
51    }
52
53    /// Cancel an order.
54    pub async fn cancel_order(&self, params: CancelOrderParams) -> Result<OrderResponse> {
55        info!(
56            symbol = %params.symbol,
57            order_id = ?params.order_id,
58            "Cancelling order"
59        );
60
61        self.post("/v5/order/cancel", &params).await
62    }
63
64    /// Cancel all orders.
65    ///
66    /// # Arguments
67    /// * `category` - Product category
68    /// * `symbol` - Optional symbol filter (cancel all if None)
69    pub async fn cancel_all_orders(
70        &self,
71        category: Category,
72        symbol: Option<&str>,
73    ) -> Result<CancelAllResponse> {
74        let params = CancelAllOrdersParams {
75            category,
76            symbol: symbol.map(|s| s.to_string()),
77            base_coin: None,
78            settle_coin: None,
79        };
80
81        info!(category = ?category, symbol = ?symbol, "Cancelling all orders");
82
83        self.post("/v5/order/cancel-all", &params).await
84    }
85
86    /// Place batch orders (up to 10 orders).
87    ///
88    /// # Arguments
89    /// * `category` - Product category
90    /// * `orders` - List of orders to place
91    pub async fn place_batch_order(
92        &self,
93        category: Category,
94        orders: Vec<PlaceOrderParams>,
95    ) -> Result<BatchOrderResponse> {
96        // Validate all orders
97        for order in &orders {
98            order.validate()?;
99        }
100
101        let request = BatchOrderRequest {
102            category,
103            request: orders,
104        };
105
106        info!(category = ?category, "Placing batch orders");
107
108        self.post("/v5/order/create-batch", &request).await
109    }
110
111    /// Amend batch orders.
112    pub async fn amend_batch_order(
113        &self,
114        category: Category,
115        orders: Vec<AmendOrderParams>,
116    ) -> Result<BatchOrderResponse> {
117        #[derive(serde::Serialize)]
118        #[serde(rename_all = "camelCase")]
119        struct BatchAmendRequest {
120            category: Category,
121            request: Vec<AmendOrderParams>,
122        }
123
124        let request = BatchAmendRequest {
125            category,
126            request: orders,
127        };
128
129        self.post("/v5/order/amend-batch", &request).await
130    }
131
132    /// Cancel batch orders.
133    pub async fn cancel_batch_order(
134        &self,
135        category: Category,
136        orders: Vec<CancelOrderParams>,
137    ) -> Result<BatchOrderResponse> {
138        #[derive(serde::Serialize)]
139        #[serde(rename_all = "camelCase")]
140        struct BatchCancelRequest {
141            category: Category,
142            request: Vec<CancelOrderParams>,
143        }
144
145        let request = BatchCancelRequest {
146            category,
147            request: orders,
148        };
149
150        self.post("/v5/order/cancel-batch", &request).await
151    }
152
153    /// Get open orders (realtime).
154    ///
155    /// # Arguments
156    /// * `category` - Product category
157    /// * `symbol` - Optional symbol filter
158    pub async fn get_open_orders(
159        &self,
160        category: Category,
161        symbol: Option<&str>,
162    ) -> Result<OrdersList> {
163        let cat_str = category.to_string();
164        let mut params = vec![("category", cat_str.as_str())];
165
166        if let Some(s) = symbol {
167            params.push(("symbol", s));
168        }
169
170        self.get("/v5/order/realtime", &params).await
171    }
172
173    /// Get order history.
174    ///
175    /// # Arguments
176    /// * `category` - Product category
177    /// * `symbol` - Optional symbol filter
178    /// * `limit` - Optional limit (default 20)
179    pub async fn get_order_history(
180        &self,
181        category: Category,
182        symbol: Option<&str>,
183        limit: Option<u32>,
184    ) -> Result<OrdersList> {
185        let cat_str = category.to_string();
186        let limit_str = limit.unwrap_or(20).to_string();
187        let mut params = vec![
188            ("category", cat_str.as_str()),
189            ("limit", limit_str.as_str()),
190        ];
191
192        if let Some(s) = symbol {
193            params.push(("symbol", s));
194        }
195
196        self.get("/v5/order/history", &params).await
197    }
198}