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)]
244mod tests {
245 use super::*;
246
247 #[test]
248 fn test_direction_as_str() {
249 assert_eq!(Direction::Buy.as_str(), "buy");
250 assert_eq!(Direction::Sell.as_str(), "sell");
251 assert_eq!(Direction::Zero.as_str(), "zero");
252 }
253
254 #[test]
255 fn test_direction_serialization() {
256 let dir = Direction::Buy;
257 let json = serde_json::to_string(&dir).expect("serialize");
258 assert_eq!(json, "\"buy\"");
259 }
260
261 #[test]
262 fn test_direction_deserialization() {
263 let dir: Direction = serde_json::from_str("\"sell\"").expect("deserialize");
264 assert_eq!(dir, Direction::Sell);
265 }
266
267 #[test]
268 fn test_position_deserialization() {
269 let json = r#"{
270 "average_price": 50000.0,
271 "direction": "buy",
272 "instrument_name": "BTC-PERPETUAL",
273 "size": 100.0,
274 "floating_profit_loss": 50.0,
275 "mark_price": 50050.0
276 }"#;
277
278 let position: Position = serde_json::from_str(json).expect("deserialize");
279 assert_eq!(position.instrument_name, "BTC-PERPETUAL");
280 assert_eq!(position.size, 100.0);
281 assert_eq!(position.direction, Direction::Buy);
282 assert_eq!(position.average_price, 50000.0);
283 }
284
285 #[test]
286 fn test_currency_summary_deserialization() {
287 let json = r#"{
288 "currency": "BTC",
289 "balance": 1.5,
290 "equity": 1.6,
291 "available_funds": 1.0,
292 "margin_balance": 1.5,
293 "maintenance_margin": 0.1,
294 "initial_margin": 0.2
295 }"#;
296
297 let summary: CurrencySummary = serde_json::from_str(json).expect("deserialize");
298 assert_eq!(summary.currency, "BTC");
299 assert_eq!(summary.balance, 1.5);
300 assert_eq!(summary.equity, 1.6);
301 }
302
303 #[test]
304 fn test_account_summary_deserialization() {
305 let json = r#"{
306 "currency": "BTC",
307 "balance": 1.5,
308 "equity": 1.6,
309 "available_funds": 1.0,
310 "margin_balance": 1.5,
311 "initial_margin": 0.2,
312 "maintenance_margin": 0.1,
313 "delta_total": 0.5
314 }"#;
315
316 let summary: AccountSummary = serde_json::from_str(json).expect("deserialize");
317 assert_eq!(summary.currency, Some("BTC".to_string()));
318 assert_eq!(summary.balance, Some(1.5));
319 }
320}