1use serde::{Deserialize, Serialize};
8
9use crate::{impl_json_debug_pretty, impl_json_display};
10#[derive(Clone, Serialize, Deserialize)]
12pub struct AccountSummary {
13 pub currency: String,
15 pub balance: f64,
17 pub equity: f64,
19 pub available_funds: f64,
21 pub margin_balance: f64,
23 pub unrealized_pnl: f64,
25 pub realized_pnl: f64,
27 pub total_pl: f64,
29 pub session_funding: f64,
31 pub session_rpl: f64,
33 pub session_upl: f64,
35 pub maintenance_margin: f64,
37 pub initial_margin: f64,
39 pub available_withdrawal_funds: Option<f64>,
41 pub cross_collateral_enabled: Option<bool>,
43 pub delta_total: Option<f64>,
45 pub futures_pl: Option<f64>,
47 pub futures_session_rpl: Option<f64>,
49 pub futures_session_upl: Option<f64>,
51 pub options_delta: Option<f64>,
53 pub options_gamma: Option<f64>,
55 pub options_pl: Option<f64>,
57 pub options_session_rpl: Option<f64>,
59 pub options_session_upl: Option<f64>,
61 pub options_theta: Option<f64>,
63 pub options_vega: Option<f64>,
65 pub portfolio_margining_enabled: Option<bool>,
67 pub projected_delta_total: Option<f64>,
69 pub projected_initial_margin: Option<f64>,
71 pub projected_maintenance_margin: Option<f64>,
73 pub system_name: Option<String>,
75 #[serde(rename = "type")]
77 pub account_type: String,
78 pub delta_total_map: std::collections::HashMap<String, f64>,
81 pub deposit_address: String,
83 pub fees: Vec<std::collections::HashMap<String, f64>>,
85 pub limits: std::collections::HashMap<String, f64>,
87}
88
89impl AccountSummary {
90 pub fn margin_utilization(&self) -> f64 {
92 if self.equity != 0.0 {
93 (self.initial_margin / self.equity) * 100.0
94 } else {
95 0.0
96 }
97 }
98
99 pub fn available_margin(&self) -> f64 {
101 self.equity - self.initial_margin
102 }
103
104 pub fn is_at_risk(&self, threshold: f64) -> bool {
106 self.margin_utilization() > threshold
107 }
108
109 pub fn return_on_equity(&self) -> f64 {
111 if self.equity != 0.0 {
112 (self.total_pl / self.equity) * 100.0
113 } else {
114 0.0
115 }
116 }
117}
118
119#[derive(Clone, Serialize, Deserialize)]
121pub struct Subaccount {
122 pub email: String,
124 pub id: u64,
126 pub login_enabled: bool,
128 pub portfolio: Option<PortfolioInfo>,
130 pub receive_notifications: bool,
132 pub system_name: String,
134 pub tif: Option<String>,
136 #[serde(rename = "type")]
138 pub subaccount_type: String,
139 pub username: String,
141}
142
143#[derive(Clone, Serialize, Deserialize)]
145pub struct PortfolioInfo {
146 pub available_funds: f64,
148 pub available_withdrawal_funds: f64,
150 pub balance: f64,
152 pub currency: String,
154 pub delta_total: f64,
156 pub equity: f64,
158 pub initial_margin: f64,
160 pub maintenance_margin: f64,
162 pub margin_balance: f64,
164 pub session_rpl: f64,
166 pub session_upl: f64,
168 pub total_pl: f64,
170}
171
172#[derive(Clone, Serialize, Deserialize)]
174pub struct Portfolio {
175 pub currency: String,
177 pub accounts: Vec<AccountSummary>,
179 pub total_usd_value: Option<f64>,
181 pub cross_margin_enabled: bool,
183}
184
185impl Portfolio {
186 pub fn new(currency: String) -> Self {
188 Self {
189 currency,
190 accounts: Vec::new(),
191 total_usd_value: None,
192 cross_margin_enabled: false,
193 }
194 }
195
196 pub fn add_account(&mut self, account: AccountSummary) {
198 self.accounts.push(account);
199 }
200
201 pub fn get_account(&self, currency: &String) -> Option<&AccountSummary> {
203 self.accounts.iter().find(|acc| &acc.currency == currency)
204 }
205
206 pub fn total_equity(&self) -> f64 {
208 self.accounts.iter().map(|acc| acc.equity).sum()
209 }
210
211 pub fn total_unrealized_pnl(&self) -> f64 {
213 self.accounts.iter().map(|acc| acc.unrealized_pnl).sum()
214 }
215
216 pub fn total_realized_pnl(&self) -> f64 {
218 self.accounts.iter().map(|acc| acc.realized_pnl).sum()
219 }
220}
221
222impl_json_debug_pretty!(AccountSummary, Portfolio, Subaccount, PortfolioInfo);
224
225impl_json_display!(AccountSummary, Portfolio, Subaccount, PortfolioInfo);