use serde::{Deserialize, Serialize};
use crate::Client;
use crate::Error;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Account {
#[serde(alias = "AccountID")]
pub account_id: String,
#[serde(default)]
pub account_type: Option<String>,
#[serde(default)]
pub currency: Option<String>,
#[serde(default)]
pub name: Option<String>,
#[serde(default)]
pub status: Option<String>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
struct AccountsResponse {
accounts: Vec<Account>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Balance {
pub account_id: Option<String>,
pub cash_balance: Option<String>,
pub equity: Option<String>,
pub market_value: Option<String>,
pub buying_power: Option<String>,
pub realized_profit_loss: Option<String>,
pub unrealized_profit_loss: Option<String>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
struct BalancesResponse {
balances: Vec<Balance>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Position {
pub account_id: Option<String>,
pub symbol: Option<String>,
pub quantity: Option<String>,
pub average_price: Option<String>,
pub last: Option<String>,
pub market_value: Option<String>,
pub unrealized_profit_loss: Option<String>,
pub unrealized_profit_loss_percent: Option<String>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
struct PositionsResponse {
positions: Vec<Position>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Order {
pub order_id: Option<String>,
pub account_id: Option<String>,
pub symbol: Option<String>,
pub quantity: Option<String>,
pub filled_quantity: Option<String>,
pub order_type: Option<String>,
pub status: Option<String>,
pub status_description: Option<String>,
pub limit_price: Option<String>,
pub stop_price: Option<String>,
pub trade_action: Option<String>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
struct OrdersResponse {
orders: Vec<Order>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct BodBalance {
pub account_id: Option<String>,
pub cash_balance: Option<String>,
pub equity: Option<String>,
pub market_value: Option<String>,
pub buying_power: Option<String>,
pub realized_profit_loss: Option<String>,
pub unrealized_profit_loss: Option<String>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
struct BodBalancesResponse {
#[serde(rename = "BODBalances")]
bod_balances: Vec<BodBalance>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Wallet {
pub currency: Option<String>,
pub balance: Option<String>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
struct WalletsResponse {
wallets: Vec<Wallet>,
}
impl Client {
pub async fn get_accounts(&mut self) -> Result<Vec<Account>, Error> {
let resp = self.get("/v3/brokerage/accounts").await?;
let data: AccountsResponse = resp.json().await?;
Ok(data.accounts)
}
pub async fn get_balances(&mut self, account_ids: &[&str]) -> Result<Vec<Balance>, Error> {
let ids = account_ids.join(",");
let resp = self
.get(&format!("/v3/brokerage/accounts/{ids}/balances"))
.await?;
let data: BalancesResponse = resp.json().await?;
Ok(data.balances)
}
pub async fn get_positions(&mut self, account_ids: &[&str]) -> Result<Vec<Position>, Error> {
let ids = account_ids.join(",");
let resp = self
.get(&format!("/v3/brokerage/accounts/{ids}/positions"))
.await?;
let data: PositionsResponse = resp.json().await?;
Ok(data.positions)
}
pub async fn get_orders(&mut self, account_ids: &[&str]) -> Result<Vec<Order>, Error> {
let ids = account_ids.join(",");
let resp = self
.get(&format!("/v3/brokerage/accounts/{ids}/orders"))
.await?;
let data: OrdersResponse = resp.json().await?;
Ok(data.orders)
}
pub async fn get_bod_balances(
&mut self,
account_ids: &[&str],
) -> Result<Vec<BodBalance>, Error> {
let ids = account_ids.join(",");
let resp = self
.get(&format!("/v3/brokerage/accounts/{ids}/bodbalances"))
.await?;
let data: BodBalancesResponse = resp.json().await?;
Ok(data.bod_balances)
}
pub async fn get_orders_by_id(
&mut self,
account_ids: &[&str],
order_ids: &[&str],
) -> Result<Vec<Order>, Error> {
let ids = account_ids.join(",");
let oids = order_ids.join(",");
let resp = self
.get(&format!("/v3/brokerage/accounts/{ids}/orders/{oids}"))
.await?;
let data: OrdersResponse = resp.json().await?;
Ok(data.orders)
}
pub async fn get_historical_orders(
&mut self,
account_ids: &[&str],
since: &str,
) -> Result<Vec<Order>, Error> {
let ids = account_ids.join(",");
let headers = self.auth_headers().await?;
let url = format!(
"{}/v3/brokerage/accounts/{ids}/historicalorders",
self.base_url()
);
let resp = self
.http
.get(&url)
.headers(headers)
.query(&[("since", since)])
.send()
.await?;
if !resp.status().is_success() {
let status = resp.status().as_u16();
let body = resp.text().await.unwrap_or_default();
return Err(Error::Api {
status,
message: body,
});
}
let data: OrdersResponse = resp.json().await?;
Ok(data.orders)
}
pub async fn get_historical_orders_by_id(
&mut self,
account_ids: &[&str],
order_ids: &[&str],
) -> Result<Vec<Order>, Error> {
let ids = account_ids.join(",");
let oids = order_ids.join(",");
let resp = self
.get(&format!(
"/v3/brokerage/accounts/{ids}/historicalorders/{oids}"
))
.await?;
let data: OrdersResponse = resp.json().await?;
Ok(data.orders)
}
pub async fn get_wallets(&mut self, account_ids: &[&str]) -> Result<Vec<Wallet>, Error> {
let ids = account_ids.join(",");
let resp = self
.get(&format!("/v3/brokerage/accounts/{ids}/wallets"))
.await?;
let data: WalletsResponse = resp.json().await?;
Ok(data.wallets)
}
}