webull_rs/endpoints/
orders.rs

1use crate::auth::AuthManager;
2use crate::endpoints::base::BaseEndpoint;
3use crate::error::WebullResult;
4use crate::models::order::{
5    OptionOrderPreviewRequest, OptionOrderPreviewResponse, OptionOrderRequest, Order,
6    OrderQueryParams, OrderRequest, OrderResponse,
7};
8use reqwest::Client;
9use std::sync::Arc;
10
11/// Endpoints for order operations.
12pub struct OrderEndpoints {
13    /// Base endpoint
14    base: BaseEndpoint,
15}
16
17impl OrderEndpoints {
18    /// Create new order endpoints.
19    pub fn new(client: Client, base_url: String, auth_manager: Arc<AuthManager>) -> Self {
20        Self {
21            base: BaseEndpoint::new(client, base_url, auth_manager),
22        }
23    }
24
25    /// Place an order.
26    pub async fn place_order(&self, order: &OrderRequest) -> WebullResult<OrderResponse> {
27        self.base.post("/api/trade/order", order).await
28    }
29
30    /// Cancel an order.
31    pub async fn cancel_order(&self, order_id: &str) -> WebullResult<()> {
32        let path = format!("/api/trade/cancel/{}", order_id);
33        self.base.delete(&path).await
34    }
35
36    /// Get an order by ID.
37    pub async fn get_order(&self, order_id: &str) -> WebullResult<Order> {
38        let path = format!("/api/trade/order/{}", order_id);
39        self.base.get(&path).await
40    }
41
42    /// Get orders based on query parameters.
43    pub async fn get_orders(&self, params: &OrderQueryParams) -> WebullResult<Vec<Order>> {
44        self.base.post("/api/trade/orders", params).await
45    }
46
47    /// Get active orders.
48    pub async fn get_active_orders(&self) -> WebullResult<Vec<Order>> {
49        self.base.get("/api/trade/active").await
50    }
51
52    /// Get filled orders.
53    pub async fn get_filled_orders(&self) -> WebullResult<Vec<Order>> {
54        self.base.get("/api/trade/filled").await
55    }
56
57    /// Modify an existing order.
58    pub async fn modify_order(
59        &self,
60        order_id: &str,
61        order: &OrderRequest,
62    ) -> WebullResult<OrderResponse> {
63        let path = format!("/api/trade/modify/{}", order_id);
64        self.base.put(&path, order).await
65    }
66
67    /// Get open orders for an account.
68    pub async fn get_open_orders(&self, account_id: &str) -> WebullResult<Vec<Order>> {
69        let path = format!("/api/trade/account/{}/orders/open", account_id);
70        self.base.get(&path).await
71    }
72
73    /// Get open orders for an account with pagination.
74    pub async fn get_open_orders_paged(
75        &self,
76        account_id: &str,
77        page_size: u32,
78        last_order_id: Option<&str>,
79    ) -> WebullResult<Vec<Order>> {
80        #[derive(serde::Serialize)]
81        struct OpenOrdersRequest {
82            account_id: String,
83            page_size: u32,
84            #[serde(skip_serializing_if = "Option::is_none")]
85            last_client_order_id: Option<String>,
86        }
87
88        let mut request = OpenOrdersRequest {
89            account_id: account_id.to_string(),
90            page_size,
91            last_client_order_id: None,
92        };
93
94        if let Some(order_id) = last_order_id {
95            request.last_client_order_id = Some(order_id.to_string());
96        }
97
98        self.base.post("/api/trade/orders/open", &request).await
99    }
100
101    /// Get today's orders for an account.
102    pub async fn get_today_orders(&self, account_id: &str) -> WebullResult<Vec<Order>> {
103        let path = format!("/api/trade/account/{}/orders/today", account_id);
104        self.base.get(&path).await
105    }
106
107    /// Get today's orders for an account with pagination.
108    pub async fn get_today_orders_paged(
109        &self,
110        account_id: &str,
111        page_size: u32,
112        last_order_id: Option<&str>,
113    ) -> WebullResult<Vec<Order>> {
114        #[derive(serde::Serialize)]
115        struct TodayOrdersRequest {
116            account_id: String,
117            page_size: u32,
118            #[serde(skip_serializing_if = "Option::is_none")]
119            last_client_order_id: Option<String>,
120        }
121
122        let mut request = TodayOrdersRequest {
123            account_id: account_id.to_string(),
124            page_size,
125            last_client_order_id: None,
126        };
127
128        if let Some(order_id) = last_order_id {
129            request.last_client_order_id = Some(order_id.to_string());
130        }
131
132        self.base.post("/api/trade/orders/today", &request).await
133    }
134
135    /// Preview an option order.
136    pub async fn preview_option_order(
137        &self,
138        preview_request: &OptionOrderPreviewRequest,
139    ) -> WebullResult<OptionOrderPreviewResponse> {
140        self.base
141            .post("/api/trade/option/preview", preview_request)
142            .await
143    }
144
145    /// Place an option order.
146    pub async fn place_option_order(
147        &self,
148        account_id: &str,
149        orders: &[OptionOrderRequest],
150    ) -> WebullResult<Vec<OrderResponse>> {
151        #[derive(serde::Serialize)]
152        struct PlaceOptionRequest<'a> {
153            account_id: &'a str,
154            new_orders: &'a [OptionOrderRequest],
155        }
156
157        let request = PlaceOptionRequest {
158            account_id,
159            new_orders: orders,
160        };
161
162        self.base.post("/api/trade/option/place", &request).await
163    }
164
165    /// Replace an option order.
166    pub async fn replace_option_order(
167        &self,
168        account_id: &str,
169        orders: &[OptionOrderRequest],
170    ) -> WebullResult<Vec<OrderResponse>> {
171        #[derive(serde::Serialize)]
172        struct ReplaceOptionRequest<'a> {
173            account_id: &'a str,
174            modify_orders: &'a [OptionOrderRequest],
175        }
176
177        let request = ReplaceOptionRequest {
178            account_id,
179            modify_orders: orders,
180        };
181
182        self.base.post("/api/trade/option/replace", &request).await
183    }
184
185    /// Cancel an option order.
186    pub async fn cancel_option_order(
187        &self,
188        account_id: &str,
189        client_order_id: &str,
190    ) -> WebullResult<()> {
191        #[derive(serde::Serialize)]
192        struct CancelOptionRequest<'a> {
193            account_id: &'a str,
194            client_order_id: &'a str,
195        }
196
197        let request = CancelOptionRequest {
198            account_id,
199            client_order_id,
200        };
201
202        self.base.post("/api/trade/option/cancel", &request).await
203    }
204}