use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum AccountType {
Cfd,
Physical,
Spreadbet,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", default)]
pub struct AccountBalance {
pub balance: Option<f64>,
pub deposit: Option<f64>,
pub profit_loss: Option<f64>,
pub available_cash: Option<f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", default)]
#[allow(clippy::struct_excessive_bools)] pub struct Account {
pub account_id: String,
pub account_alias: Option<String>,
pub account_type: AccountType,
pub account_name: String,
#[serde(rename = "canTransferToMA")]
pub can_transfer_to_ma: Option<bool>,
#[serde(rename = "canTransferFromMA")]
pub can_transfer_from_ma: Option<bool>,
pub default_account: bool,
pub preferred: bool,
pub balance: AccountBalance,
}
impl Default for Account {
fn default() -> Self {
Self {
account_id: String::new(),
account_alias: None,
account_type: AccountType::Cfd,
account_name: String::new(),
can_transfer_to_ma: None,
can_transfer_from_ma: None,
default_account: false,
preferred: false,
balance: AccountBalance::default(),
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", default)]
pub struct AccountPreferences {
pub trailing_stops_enabled: bool,
}
#[derive(Debug, Clone)]
pub struct UpdatePreferences {
pub trailing_stops_enabled: bool,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct UpdatePreferencesWire<'a> {
pub trailing_stops_enabled: &'a str,
}
impl UpdatePreferences {
pub(super) fn to_wire(&self) -> UpdatePreferencesWire<'_> {
UpdatePreferencesWire {
trailing_stops_enabled: if self.trailing_stops_enabled {
"true"
} else {
"false"
},
}
}
}
#[cfg(feature = "polars")]
impl crate::dataframe::IntoDataFrame for Vec<Account> {
fn to_dataframe(&self) -> crate::Result<polars::prelude::DataFrame> {
use polars::prelude::*;
let account_id: Vec<&str> = self.iter().map(|a| a.account_id.as_str()).collect();
let account_alias: Vec<Option<&str>> =
self.iter().map(|a| a.account_alias.as_deref()).collect();
let account_type: Vec<&str> = self
.iter()
.map(|a| match a.account_type {
AccountType::Cfd => "CFD",
AccountType::Physical => "PHYSICAL",
AccountType::Spreadbet => "SPREADBET",
})
.collect();
let account_name: Vec<&str> = self.iter().map(|a| a.account_name.as_str()).collect();
let can_transfer_to_ma: Vec<Option<bool>> =
self.iter().map(|a| a.can_transfer_to_ma).collect();
let can_transfer_from_ma: Vec<Option<bool>> =
self.iter().map(|a| a.can_transfer_from_ma).collect();
let default_account: Vec<bool> = self.iter().map(|a| a.default_account).collect();
let preferred: Vec<bool> = self.iter().map(|a| a.preferred).collect();
let balance: Vec<Option<f64>> = self.iter().map(|a| a.balance.balance).collect();
let deposit: Vec<Option<f64>> = self.iter().map(|a| a.balance.deposit).collect();
let profit_loss: Vec<Option<f64>> = self.iter().map(|a| a.balance.profit_loss).collect();
let available_cash: Vec<Option<f64>> =
self.iter().map(|a| a.balance.available_cash).collect();
DataFrame::new(vec![
Column::new("account_id".into(), account_id),
Column::new("account_alias".into(), account_alias),
Column::new("account_type".into(), account_type),
Column::new("account_name".into(), account_name),
Column::new("can_transfer_to_ma".into(), can_transfer_to_ma),
Column::new("can_transfer_from_ma".into(), can_transfer_from_ma),
Column::new("default_account".into(), default_account),
Column::new("preferred".into(), preferred),
Column::new("balance".into(), balance),
Column::new("deposit".into(), deposit),
Column::new("profit_loss".into(), profit_loss),
Column::new("available_cash".into(), available_cash),
])
.map_err(|e| crate::Error::Config(format!("polars conversion failed: {e}")))
}
}