1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(rename_all = "lowercase")]
11pub enum Direction {
12 Buy,
14 Sell,
16 Zero,
18}
19
20impl Direction {
21 #[must_use]
23 pub fn as_str(&self) -> &'static str {
24 match self {
25 Direction::Buy => "buy",
26 Direction::Sell => "sell",
27 Direction::Zero => "zero",
28 }
29 }
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct Position {
35 pub average_price: f64,
37 #[serde(default)]
39 pub average_price_usd: Option<f64>,
40 #[serde(default)]
42 pub delta: Option<f64>,
43 pub direction: Direction,
45 #[serde(default)]
47 pub estimated_liquidation_price: Option<f64>,
48 #[serde(default)]
50 pub floating_profit_loss: Option<f64>,
51 #[serde(default)]
53 pub floating_profit_loss_usd: Option<f64>,
54 #[serde(default)]
56 pub gamma: Option<f64>,
57 #[serde(default)]
59 pub index_price: Option<f64>,
60 #[serde(default)]
62 pub initial_margin: Option<f64>,
63 pub instrument_name: String,
65 #[serde(default)]
67 pub interest_value: Option<f64>,
68 #[serde(default)]
70 pub kind: Option<String>,
71 #[serde(default)]
73 pub leverage: Option<i32>,
74 #[serde(default)]
76 pub maintenance_margin: Option<f64>,
77 #[serde(default)]
79 pub mark_price: Option<f64>,
80 #[serde(default)]
82 pub open_orders_margin: Option<f64>,
83 #[serde(default)]
85 pub realized_funding: Option<f64>,
86 #[serde(default)]
88 pub realized_profit_loss: Option<f64>,
89 #[serde(default)]
91 pub settlement_price: Option<f64>,
92 pub size: f64,
94 #[serde(default)]
96 pub size_currency: Option<f64>,
97 #[serde(default)]
99 pub theta: Option<f64>,
100 #[serde(default)]
102 pub total_profit_loss: Option<f64>,
103 #[serde(default)]
105 pub vega: Option<f64>,
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
110pub struct CurrencySummary {
111 pub currency: String,
113 pub balance: f64,
115 pub equity: f64,
117 pub available_funds: f64,
119 pub margin_balance: f64,
121 #[serde(default)]
123 pub total_pl: Option<f64>,
124 #[serde(default)]
126 pub session_rpl: Option<f64>,
127 #[serde(default)]
129 pub session_upl: Option<f64>,
130 pub maintenance_margin: f64,
132 pub initial_margin: f64,
134 #[serde(default)]
136 pub available_withdrawal_funds: Option<f64>,
137 #[serde(default)]
139 pub cross_collateral_enabled: Option<bool>,
140 #[serde(default)]
142 pub delta_total: Option<f64>,
143 #[serde(default)]
145 pub futures_pl: Option<f64>,
146 #[serde(default)]
148 pub futures_session_rpl: Option<f64>,
149 #[serde(default)]
151 pub futures_session_upl: Option<f64>,
152 #[serde(default)]
154 pub options_delta: Option<f64>,
155 #[serde(default)]
157 pub options_gamma: Option<f64>,
158 #[serde(default)]
160 pub options_pl: Option<f64>,
161 #[serde(default)]
163 pub options_session_rpl: Option<f64>,
164 #[serde(default)]
166 pub options_session_upl: Option<f64>,
167 #[serde(default)]
169 pub options_theta: Option<f64>,
170 #[serde(default)]
172 pub options_vega: Option<f64>,
173 #[serde(default)]
175 pub portfolio_margining_enabled: Option<bool>,
176}
177
178#[derive(Debug, Clone, Serialize, Deserialize)]
180pub struct AccountSummary {
181 #[serde(default)]
183 pub id: Option<u64>,
184 #[serde(default)]
186 pub email: Option<String>,
187 #[serde(default)]
189 pub system_name: Option<String>,
190 #[serde(default)]
192 pub username: Option<String>,
193 #[serde(default)]
195 pub creation_timestamp: Option<u64>,
196 #[serde(rename = "type", default)]
198 pub account_type: Option<String>,
199 #[serde(default)]
201 pub mmp_enabled: Option<bool>,
202 #[serde(default)]
204 pub summaries: Option<Vec<CurrencySummary>>,
205 #[serde(default)]
207 pub currency: Option<String>,
208 #[serde(default)]
210 pub balance: Option<f64>,
211 #[serde(default)]
213 pub equity: Option<f64>,
214 #[serde(default)]
216 pub available_funds: Option<f64>,
217 #[serde(default)]
219 pub margin_balance: Option<f64>,
220 #[serde(default)]
222 pub initial_margin: Option<f64>,
223 #[serde(default)]
225 pub maintenance_margin: Option<f64>,
226 #[serde(default)]
228 pub delta_total: Option<f64>,
229 #[serde(default)]
231 pub options_value: Option<f64>,
232 #[serde(default)]
234 pub futures_pl: Option<f64>,
235 #[serde(default)]
237 pub options_pl: Option<f64>,
238 #[serde(default)]
240 pub total_pl: Option<f64>,
241}
242
243#[cfg(test)]
244#[allow(clippy::unwrap_used, clippy::expect_used)]
245mod tests {
246 use super::*;
247
248 #[test]
249 fn test_direction_as_str() {
250 assert_eq!(Direction::Buy.as_str(), "buy");
251 assert_eq!(Direction::Sell.as_str(), "sell");
252 assert_eq!(Direction::Zero.as_str(), "zero");
253 }
254
255 #[test]
256 fn test_direction_serialization() {
257 let dir = Direction::Buy;
258 let json = serde_json::to_string(&dir).expect("serialize");
259 assert_eq!(json, "\"buy\"");
260 }
261
262 #[test]
263 fn test_direction_deserialization() {
264 let dir: Direction = serde_json::from_str("\"sell\"").expect("deserialize");
265 assert_eq!(dir, Direction::Sell);
266 }
267
268 #[test]
269 fn test_position_deserialization() {
270 let json = r#"{
271 "average_price": 50000.0,
272 "direction": "buy",
273 "instrument_name": "BTC-PERPETUAL",
274 "size": 100.0,
275 "floating_profit_loss": 50.0,
276 "mark_price": 50050.0
277 }"#;
278
279 let position: Position = serde_json::from_str(json).expect("deserialize");
280 assert_eq!(position.instrument_name, "BTC-PERPETUAL");
281 assert_eq!(position.size, 100.0);
282 assert_eq!(position.direction, Direction::Buy);
283 assert_eq!(position.average_price, 50000.0);
284 }
285
286 #[test]
287 fn test_currency_summary_deserialization() {
288 let json = r#"{
289 "currency": "BTC",
290 "balance": 1.5,
291 "equity": 1.6,
292 "available_funds": 1.0,
293 "margin_balance": 1.5,
294 "maintenance_margin": 0.1,
295 "initial_margin": 0.2
296 }"#;
297
298 let summary: CurrencySummary = serde_json::from_str(json).expect("deserialize");
299 assert_eq!(summary.currency, "BTC");
300 assert_eq!(summary.balance, 1.5);
301 assert_eq!(summary.equity, 1.6);
302 }
303
304 #[test]
305 fn test_account_summary_deserialization() {
306 let json = r#"{
307 "currency": "BTC",
308 "balance": 1.5,
309 "equity": 1.6,
310 "available_funds": 1.0,
311 "margin_balance": 1.5,
312 "initial_margin": 0.2,
313 "maintenance_margin": 0.1,
314 "delta_total": 0.5
315 }"#;
316
317 let summary: AccountSummary = serde_json::from_str(json).expect("deserialize");
318 assert_eq!(summary.currency, Some("BTC".to_string()));
319 assert_eq!(summary.balance, Some(1.5));
320 }
321}