1use serde::{Deserialize, Serialize};
15
16use crate::Client;
17use crate::Error;
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
23#[serde(rename_all = "PascalCase")]
24pub struct Account {
25 #[serde(alias = "AccountID")]
27 pub account_id: String,
28 #[serde(default)]
30 pub account_type: Option<String>,
31 #[serde(default)]
33 pub currency: Option<String>,
34 #[serde(default)]
36 pub name: Option<String>,
37 #[serde(default)]
39 pub status: Option<String>,
40}
41
42#[derive(Debug, Deserialize)]
43#[serde(rename_all = "PascalCase")]
44struct AccountsResponse {
45 accounts: Vec<Account>,
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
52#[serde(rename_all = "PascalCase")]
53pub struct Balance {
54 pub account_id: Option<String>,
56 pub cash_balance: Option<String>,
58 pub equity: Option<String>,
60 pub market_value: Option<String>,
62 pub buying_power: Option<String>,
64 pub realized_profit_loss: Option<String>,
66 pub unrealized_profit_loss: Option<String>,
68}
69
70#[derive(Debug, Deserialize)]
71#[serde(rename_all = "PascalCase")]
72struct BalancesResponse {
73 balances: Vec<Balance>,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize)]
80#[serde(rename_all = "PascalCase")]
81pub struct Position {
82 pub account_id: Option<String>,
84 pub symbol: Option<String>,
86 pub quantity: Option<String>,
88 pub average_price: Option<String>,
90 pub last: Option<String>,
92 pub market_value: Option<String>,
94 pub unrealized_profit_loss: Option<String>,
96 pub unrealized_profit_loss_percent: Option<String>,
98}
99
100#[derive(Debug, Deserialize)]
101#[serde(rename_all = "PascalCase")]
102struct PositionsResponse {
103 positions: Vec<Position>,
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize)]
110#[serde(rename_all = "PascalCase")]
111pub struct Order {
112 pub order_id: Option<String>,
114 pub account_id: Option<String>,
116 pub symbol: Option<String>,
118 pub quantity: Option<String>,
120 pub filled_quantity: Option<String>,
122 pub order_type: Option<String>,
124 pub status: Option<String>,
126 pub status_description: Option<String>,
128 pub limit_price: Option<String>,
130 pub stop_price: Option<String>,
132 pub trade_action: Option<String>,
134}
135
136#[derive(Debug, Deserialize)]
137#[serde(rename_all = "PascalCase")]
138struct OrdersResponse {
139 orders: Vec<Order>,
140}
141
142#[derive(Debug, Clone, Serialize, Deserialize)]
146#[serde(rename_all = "PascalCase")]
147pub struct BodBalance {
148 pub account_id: Option<String>,
150 pub cash_balance: Option<String>,
152 pub equity: Option<String>,
154 pub market_value: Option<String>,
156 pub buying_power: Option<String>,
158 pub realized_profit_loss: Option<String>,
160 pub unrealized_profit_loss: Option<String>,
162}
163
164#[derive(Debug, Deserialize)]
165#[serde(rename_all = "PascalCase")]
166struct BodBalancesResponse {
167 #[serde(rename = "BODBalances")]
168 bod_balances: Vec<BodBalance>,
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
175#[serde(rename_all = "PascalCase")]
176pub struct Wallet {
177 pub currency: Option<String>,
179 pub balance: Option<String>,
181}
182
183#[derive(Debug, Deserialize)]
184#[serde(rename_all = "PascalCase")]
185struct WalletsResponse {
186 wallets: Vec<Wallet>,
187}
188
189impl Client {
190 pub async fn get_accounts(&mut self) -> Result<Vec<Account>, Error> {
192 let resp = self.get("/v3/brokerage/accounts").await?;
193 let data: AccountsResponse = resp.json().await?;
194 Ok(data.accounts)
195 }
196
197 pub async fn get_balances(&mut self, account_ids: &[&str]) -> Result<Vec<Balance>, Error> {
199 let ids = account_ids.join(",");
200 let resp = self
201 .get(&format!("/v3/brokerage/accounts/{ids}/balances"))
202 .await?;
203 let data: BalancesResponse = resp.json().await?;
204 Ok(data.balances)
205 }
206
207 pub async fn get_positions(&mut self, account_ids: &[&str]) -> Result<Vec<Position>, Error> {
209 let ids = account_ids.join(",");
210 let resp = self
211 .get(&format!("/v3/brokerage/accounts/{ids}/positions"))
212 .await?;
213 let data: PositionsResponse = resp.json().await?;
214 Ok(data.positions)
215 }
216
217 pub async fn get_orders(&mut self, account_ids: &[&str]) -> Result<Vec<Order>, Error> {
219 let ids = account_ids.join(",");
220 let resp = self
221 .get(&format!("/v3/brokerage/accounts/{ids}/orders"))
222 .await?;
223 let data: OrdersResponse = resp.json().await?;
224 Ok(data.orders)
225 }
226
227 pub async fn get_bod_balances(
229 &mut self,
230 account_ids: &[&str],
231 ) -> Result<Vec<BodBalance>, Error> {
232 let ids = account_ids.join(",");
233 let resp = self
234 .get(&format!("/v3/brokerage/accounts/{ids}/bodbalances"))
235 .await?;
236 let data: BodBalancesResponse = resp.json().await?;
237 Ok(data.bod_balances)
238 }
239
240 pub async fn get_orders_by_id(
242 &mut self,
243 account_ids: &[&str],
244 order_ids: &[&str],
245 ) -> Result<Vec<Order>, Error> {
246 let ids = account_ids.join(",");
247 let oids = order_ids.join(",");
248 let resp = self
249 .get(&format!("/v3/brokerage/accounts/{ids}/orders/{oids}"))
250 .await?;
251 let data: OrdersResponse = resp.json().await?;
252 Ok(data.orders)
253 }
254
255 pub async fn get_historical_orders(
260 &mut self,
261 account_ids: &[&str],
262 since: &str,
263 ) -> Result<Vec<Order>, Error> {
264 let ids = account_ids.join(",");
265 let headers = self.auth_headers().await?;
266 let url = format!(
267 "{}/v3/brokerage/accounts/{ids}/historicalorders",
268 self.base_url()
269 );
270 let resp = self
271 .http
272 .get(&url)
273 .headers(headers)
274 .query(&[("since", since)])
275 .send()
276 .await?;
277 if !resp.status().is_success() {
278 let status = resp.status().as_u16();
279 let body = resp.text().await.unwrap_or_default();
280 return Err(Error::Api {
281 status,
282 message: body,
283 });
284 }
285 let data: OrdersResponse = resp.json().await?;
286 Ok(data.orders)
287 }
288
289 pub async fn get_historical_orders_by_id(
291 &mut self,
292 account_ids: &[&str],
293 order_ids: &[&str],
294 ) -> Result<Vec<Order>, Error> {
295 let ids = account_ids.join(",");
296 let oids = order_ids.join(",");
297 let resp = self
298 .get(&format!(
299 "/v3/brokerage/accounts/{ids}/historicalorders/{oids}"
300 ))
301 .await?;
302 let data: OrdersResponse = resp.json().await?;
303 Ok(data.orders)
304 }
305
306 pub async fn get_wallets(&mut self, account_ids: &[&str]) -> Result<Vec<Wallet>, Error> {
308 let ids = account_ids.join(",");
309 let resp = self
310 .get(&format!("/v3/brokerage/accounts/{ids}/wallets"))
311 .await?;
312 let data: WalletsResponse = resp.json().await?;
313 Ok(data.wallets)
314 }
315}