use serde::{Deserialize, Serialize};
use crate::client::Client;
use crate::error::Error;
use crate::models::transaction::{ClientConfigureRejectTransaction, ClientConfigureTransaction};
use crate::models::{
Account, AccountChanges, AccountChangesState, AccountId, AccountProperties, AccountSummary,
DecimalNumber, Instrument, InstrumentName, TransactionId,
};
impl Client {
pub async fn account(
&self,
account_id: impl Into<AccountId>,
) -> Result<AccountResponse, Error> {
let account_id = account_id.into();
self.execute(self.get(&["accounts", account_id.as_str()]))
.await
}
pub fn account_changes(&self, account_id: impl Into<AccountId>) -> AccountChangesRequest {
AccountChangesRequest {
client: self.clone(),
account_id: account_id.into(),
since_transaction_id: None,
}
}
pub async fn list_accounts(&self) -> Result<ListAccountsResponse, Error> {
self.execute(self.get(&["accounts"])).await
}
pub async fn account_summary(
&self,
account_id: impl Into<AccountId>,
) -> Result<AccountSummaryResponse, Error> {
let account_id = account_id.into();
self.execute(self.get(&["accounts", account_id.as_str(), "summary"]))
.await
}
pub fn account_instruments(
&self,
account_id: impl Into<AccountId>,
) -> AccountInstrumentsRequest {
AccountInstrumentsRequest {
client: self.clone(),
account_id: account_id.into(),
instruments: None,
}
}
pub fn configure_account(&self, account_id: impl Into<AccountId>) -> ConfigureAccountRequest {
ConfigureAccountRequest {
client: self.clone(),
account_id: account_id.into(),
body: ConfigureAccountBody {
alias: None,
margin_rate: None,
},
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AccountResponse {
#[serde(rename = "account")]
pub account: Account,
#[serde(rename = "lastTransactionID", skip_serializing_if = "Option::is_none")]
pub last_transaction_id: Option<TransactionId>,
}
#[derive(Debug)]
pub struct AccountChangesRequest {
client: Client,
account_id: AccountId,
since_transaction_id: Option<TransactionId>,
}
impl AccountChangesRequest {
pub fn since_transaction_id(mut self, id: impl Into<TransactionId>) -> Self {
self.since_transaction_id = Some(id.into());
self
}
pub async fn send(self) -> Result<AccountChangesResponse, Error> {
let mut request = self
.client
.get(&["accounts", self.account_id.as_str(), "changes"]);
if let Some(id) = &self.since_transaction_id {
request = request.query(&[("sinceTransactionID", id.as_str())]);
}
self.client.execute(request).await
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AccountChangesResponse {
#[serde(rename = "changes", skip_serializing_if = "Option::is_none")]
pub changes: Option<AccountChanges>,
#[serde(rename = "state", skip_serializing_if = "Option::is_none")]
pub state: Option<AccountChangesState>,
#[serde(rename = "lastTransactionID", skip_serializing_if = "Option::is_none")]
pub last_transaction_id: Option<TransactionId>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct ListAccountsResponse {
#[serde(rename = "accounts", default, skip_serializing_if = "Vec::is_empty")]
pub accounts: Vec<AccountProperties>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AccountSummaryResponse {
#[serde(rename = "account")]
pub account: AccountSummary,
#[serde(rename = "lastTransactionID", skip_serializing_if = "Option::is_none")]
pub last_transaction_id: Option<TransactionId>,
}
#[derive(Debug)]
pub struct AccountInstrumentsRequest {
client: Client,
account_id: AccountId,
instruments: Option<Vec<InstrumentName>>,
}
impl AccountInstrumentsRequest {
pub fn instruments<I>(mut self, instruments: I) -> Self
where
I: IntoIterator,
I::Item: Into<InstrumentName>,
{
self.instruments = Some(instruments.into_iter().map(Into::into).collect());
self
}
pub async fn send(self) -> Result<AccountInstrumentsResponse, Error> {
let mut request = self
.client
.get(&["accounts", self.account_id.as_str(), "instruments"]);
if let Some(instruments) = &self.instruments {
request = request.query(&[("instruments", join_names(instruments))]);
}
self.client.execute(request).await
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AccountInstrumentsResponse {
#[serde(rename = "instruments", default, skip_serializing_if = "Vec::is_empty")]
pub instruments: Vec<Instrument>,
#[serde(rename = "lastTransactionID", skip_serializing_if = "Option::is_none")]
pub last_transaction_id: Option<TransactionId>,
}
#[derive(Debug)]
pub struct ConfigureAccountRequest {
client: Client,
account_id: AccountId,
body: ConfigureAccountBody,
}
#[derive(Debug, Serialize)]
struct ConfigureAccountBody {
#[serde(rename = "alias", skip_serializing_if = "Option::is_none")]
alias: Option<String>,
#[serde(rename = "marginRate", skip_serializing_if = "Option::is_none")]
margin_rate: Option<DecimalNumber>,
}
impl ConfigureAccountRequest {
pub fn alias(mut self, alias: impl Into<String>) -> Self {
self.body.alias = Some(alias.into());
self
}
pub fn margin_rate(mut self, margin_rate: impl Into<DecimalNumber>) -> Self {
self.body.margin_rate = Some(margin_rate.into());
self
}
pub async fn send(self) -> Result<ConfigureAccountResponse, Error> {
let request = self
.client
.patch(&["accounts", self.account_id.as_str(), "configuration"])
.json(&self.body);
self.client.execute(request).await
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct ConfigureAccountResponse {
#[serde(
rename = "clientConfigureTransaction",
skip_serializing_if = "Option::is_none"
)]
pub client_configure_transaction: Option<ClientConfigureTransaction>,
#[serde(rename = "lastTransactionID", skip_serializing_if = "Option::is_none")]
pub last_transaction_id: Option<TransactionId>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct ConfigureAccountRejectBody {
#[serde(
rename = "clientConfigureRejectTransaction",
skip_serializing_if = "Option::is_none"
)]
pub client_configure_reject_transaction: Option<ClientConfigureRejectTransaction>,
#[serde(rename = "lastTransactionID", skip_serializing_if = "Option::is_none")]
pub last_transaction_id: Option<TransactionId>,
}
pub(crate) fn join_names(instruments: &[InstrumentName]) -> String {
instruments
.iter()
.map(InstrumentName::as_str)
.collect::<Vec<_>>()
.join(",")
}