1use super::order::{Direction, OrderType, Status, TimeInForce};
7use crate::application::models::market::InstrumentType;
8use crate::presentation::MarketState;
9use pretty_simple_display::DisplaySimple;
10use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12use std::ops::Add;
13
14#[derive(Debug, Clone, Deserialize)]
16pub struct AccountInfo {
17 pub accounts: Vec<Account>,
19}
20
21#[derive(Debug, Clone, Deserialize)]
23pub struct Account {
24 #[serde(rename = "accountId")]
26 pub account_id: String,
27 #[serde(rename = "accountName")]
29 pub account_name: String,
30 #[serde(rename = "accountType")]
32 pub account_type: String,
33 pub balance: AccountBalance,
35 pub currency: String,
37 pub status: String,
39 pub preferred: bool,
41}
42
43#[derive(Debug, Clone, Deserialize)]
45pub struct AccountBalance {
46 pub balance: f64,
48 pub deposit: f64,
50 #[serde(rename = "profitLoss")]
52 pub profit_loss: f64,
53 pub available: f64,
55}
56
57#[derive(Debug, Clone, Deserialize)]
59pub struct AccountActivity {
60 pub activities: Vec<Activity>,
62 pub metadata: Option<ActivityMetadata>,
64}
65
66#[derive(Debug, Clone, Deserialize)]
68pub struct ActivityMetadata {
69 pub paging: Option<ActivityPaging>,
71}
72
73#[derive(Debug, Clone, Deserialize)]
75pub struct ActivityPaging {
76 pub size: Option<i32>,
78 pub next: Option<String>,
80}
81
82#[derive(Debug, Copy, Clone, DisplaySimple, Deserialize, Serialize)]
83pub enum ActivityType {
85 #[serde(rename = "EDIT_STOP_AND_LIMIT")]
87 EditStopAndLimit,
88 #[serde(rename = "POSITION")]
90 Position,
91 #[serde(rename = "SYSTEM")]
93 System,
94 #[serde(rename = "WORKING_ORDER")]
96 WorkingOrder,
97}
98
99#[derive(Debug, Clone, DisplaySimple, Deserialize, Serialize)]
101pub struct Activity {
102 pub date: String,
104 #[serde(rename = "dealId", default)]
106 pub deal_id: Option<String>,
107 #[serde(default)]
109 pub epic: Option<String>,
110 #[serde(default)]
112 pub period: Option<String>,
113 #[serde(rename = "dealReference", default)]
115 pub deal_reference: Option<String>,
116 #[serde(rename = "type")]
118 pub activity_type: ActivityType,
119 #[serde(default)]
121 pub status: Option<Status>,
122 #[serde(default)]
124 pub description: Option<String>,
125 #[serde(default)]
128 pub details: Option<ActivityDetails>,
129 #[serde(default)]
131 pub channel: Option<String>,
132 #[serde(default)]
134 pub currency: Option<String>,
135 #[serde(default)]
137 pub level: Option<String>,
138}
139
140#[derive(Debug, Clone, DisplaySimple, Deserialize, Serialize)]
143pub struct ActivityDetails {
144 #[serde(rename = "dealReference", default)]
146 pub deal_reference: Option<String>,
147 #[serde(default)]
149 pub actions: Vec<ActivityAction>,
150 #[serde(rename = "marketName", default)]
152 pub market_name: Option<String>,
153 #[serde(rename = "goodTillDate", default)]
155 pub good_till_date: Option<String>,
156 #[serde(default)]
158 pub currency: Option<String>,
159 #[serde(default)]
161 pub size: Option<f64>,
162 #[serde(default)]
164 pub direction: Option<Direction>,
165 #[serde(default)]
167 pub level: Option<f64>,
168 #[serde(rename = "stopLevel", default)]
170 pub stop_level: Option<f64>,
171 #[serde(rename = "stopDistance", default)]
173 pub stop_distance: Option<f64>,
174 #[serde(rename = "guaranteedStop", default)]
176 pub guaranteed_stop: Option<bool>,
177 #[serde(rename = "trailingStopDistance", default)]
179 pub trailing_stop_distance: Option<f64>,
180 #[serde(rename = "trailingStep", default)]
182 pub trailing_step: Option<f64>,
183 #[serde(rename = "limitLevel", default)]
185 pub limit_level: Option<f64>,
186 #[serde(rename = "limitDistance", default)]
188 pub limit_distance: Option<f64>,
189}
190
191#[derive(Debug, Copy, Clone, DisplaySimple, Deserialize, Serialize)]
193pub enum ActionType {
194 #[serde(rename = "LIMIT_ORDER_DELETED")]
196 LimitOrderDeleted,
197 #[serde(rename = "LIMIT_ORDER_FILLED")]
199 LimitOrderFilled,
200 #[serde(rename = "LIMIT_ORDER_OPENED")]
202 LimitOrderOpened,
203 #[serde(rename = "LIMIT_ORDER_ROLLED")]
205 LimitOrderRolled,
206 #[serde(rename = "POSITION_CLOSED")]
208 PositionClosed,
209 #[serde(rename = "POSITION_DELETED")]
211 PositionDeleted,
212 #[serde(rename = "POSITION_OPENED")]
214 PositionOpened,
215 #[serde(rename = "POSITION_PARTIALLY_CLOSED")]
217 PositionPartiallyClosed,
218 #[serde(rename = "POSITION_ROLLED")]
220 PositionRolled,
221 #[serde(rename = "STOP_LIMIT_AMENDED")]
223 StopLimitAmended,
224 #[serde(rename = "STOP_ORDER_AMENDED")]
226 StopOrderAmended,
227 #[serde(rename = "STOP_ORDER_DELETED")]
229 StopOrderDeleted,
230 #[serde(rename = "STOP_ORDER_FILLED")]
232 StopOrderFilled,
233 #[serde(rename = "STOP_ORDER_OPENED")]
235 StopOrderOpened,
236 #[serde(rename = "STOP_ORDER_ROLLED")]
238 StopOrderRolled,
239 #[serde(rename = "UNKNOWN")]
241 Unknown,
242 #[serde(rename = "WORKING_ORDER_DELETED")]
244 WorkingOrderDeleted,
245}
246
247#[derive(Debug, Clone, DisplaySimple, Deserialize, Serialize)]
249pub struct ActivityAction {
250 #[serde(rename = "actionType")]
252 pub action_type: ActionType,
253 #[serde(rename = "affectedDealId", default)]
255 pub affected_deal_id: Option<String>,
256}
257
258#[derive(Debug, Clone, DisplaySimple, Deserialize, Serialize, Default)]
260pub struct Positions {
261 pub positions: Vec<Position>,
263}
264
265impl Positions {
266 pub fn compact_by_epic(positions: Vec<Position>) -> Vec<Position> {
277 let mut epic_map: HashMap<String, Position> = std::collections::HashMap::new();
278
279 for position in positions {
280 let epic = position.market.epic.clone();
281 epic_map
282 .entry(epic)
283 .and_modify(|existing| {
284 *existing = existing.clone() + position.clone();
285 })
286 .or_insert(position);
287 }
288
289 epic_map.into_values().collect()
290 }
291}
292
293#[derive(Debug, Clone, DisplaySimple, Serialize, Deserialize)]
295pub struct Position {
296 pub position: PositionDetails,
298 pub market: PositionMarket,
300 pub pnl: Option<f64>,
302}
303
304impl Add for Position {
305 type Output = Position;
306
307 fn add(self, other: Position) -> Position {
308 if self.market.epic != other.market.epic {
309 panic!("Cannot add positions from different markets");
310 }
311 Position {
312 position: self.position + other.position,
313 market: self.market,
314 pnl: match (self.pnl, other.pnl) {
315 (Some(a), Some(b)) => Some(a + b),
316 (Some(a), None) => Some(a),
317 (None, Some(b)) => Some(b),
318 (None, None) => None,
319 },
320 }
321 }
322}
323
324#[derive(Debug, Clone, DisplaySimple, Deserialize, Serialize)]
326pub struct PositionDetails {
327 #[serde(rename = "contractSize")]
329 pub contract_size: f64,
330 #[serde(rename = "createdDate")]
332 pub created_date: String,
333 #[serde(rename = "createdDateUTC")]
335 pub created_date_utc: String,
336 #[serde(rename = "dealId")]
338 pub deal_id: String,
339 #[serde(rename = "dealReference")]
341 pub deal_reference: String,
342 pub direction: Direction,
344 #[serde(rename = "limitLevel")]
346 pub limit_level: Option<f64>,
347 pub level: f64,
349 pub size: f64,
351 #[serde(rename = "stopLevel")]
353 pub stop_level: Option<f64>,
354 #[serde(rename = "trailingStep")]
356 pub trailing_step: Option<f64>,
357 #[serde(rename = "trailingStopDistance")]
359 pub trailing_stop_distance: Option<f64>,
360 pub currency: String,
362 #[serde(rename = "controlledRisk")]
364 pub controlled_risk: bool,
365 #[serde(rename = "limitedRiskPremium")]
367 pub limited_risk_premium: Option<f64>,
368}
369
370impl Add for PositionDetails {
371 type Output = PositionDetails;
372
373 fn add(self, other: PositionDetails) -> PositionDetails {
374 let (contract_size, size) = if self.direction != other.direction {
375 (
376 (self.contract_size - other.contract_size).abs(),
377 (self.size - other.size).abs(),
378 )
379 } else {
380 (
381 self.contract_size + other.contract_size,
382 self.size + other.size,
383 )
384 };
385
386 PositionDetails {
387 contract_size,
388 created_date: self.created_date,
389 created_date_utc: self.created_date_utc,
390 deal_id: self.deal_id,
391 deal_reference: self.deal_reference,
392 direction: self.direction,
393 limit_level: other.limit_level.or(self.limit_level),
394 level: (self.level + other.level) / 2.0, size,
396 stop_level: other.stop_level.or(self.stop_level),
397 trailing_step: other.trailing_step.or(self.trailing_step),
398 trailing_stop_distance: other.trailing_stop_distance.or(self.trailing_stop_distance),
399 currency: self.currency.clone(),
400 controlled_risk: self.controlled_risk || other.controlled_risk,
401 limited_risk_premium: other.limited_risk_premium.or(self.limited_risk_premium),
402 }
403 }
404}
405
406#[derive(Debug, Clone, DisplaySimple, Deserialize, Serialize)]
408pub struct PositionMarket {
409 #[serde(rename = "instrumentName")]
411 pub instrument_name: String,
412 pub expiry: String,
414 pub epic: String,
416 #[serde(rename = "instrumentType")]
418 pub instrument_type: String,
419 #[serde(rename = "lotSize")]
421 pub lot_size: f64,
422 pub high: Option<f64>,
424 pub low: Option<f64>,
426 #[serde(rename = "percentageChange")]
428 pub percentage_change: f64,
429 #[serde(rename = "netChange")]
431 pub net_change: f64,
432 pub bid: Option<f64>,
434 pub offer: Option<f64>,
436 #[serde(rename = "updateTime")]
438 pub update_time: String,
439 #[serde(rename = "updateTimeUTC")]
441 pub update_time_utc: String,
442 #[serde(rename = "delayTime")]
444 pub delay_time: i64,
445 #[serde(rename = "streamingPricesAvailable")]
447 pub streaming_prices_available: bool,
448 #[serde(rename = "marketStatus")]
450 pub market_status: String,
451 #[serde(rename = "scalingFactor")]
453 pub scaling_factor: i64,
454}
455
456#[derive(Debug, Clone, DisplaySimple, Deserialize, Serialize)]
458pub struct WorkingOrders {
459 #[serde(rename = "workingOrders")]
461 pub working_orders: Vec<WorkingOrder>,
462}
463
464#[derive(Debug, Clone, DisplaySimple, Deserialize, Serialize)]
466pub struct WorkingOrder {
467 #[serde(rename = "workingOrderData")]
469 pub working_order_data: WorkingOrderData,
470 #[serde(rename = "marketData")]
472 pub market_data: AccountMarketData,
473}
474
475#[derive(Debug, Clone, DisplaySimple, Deserialize, Serialize)]
477pub struct WorkingOrderData {
478 #[serde(rename = "dealId")]
480 pub deal_id: String,
481 pub direction: Direction,
483 pub epic: String,
485 #[serde(rename = "orderSize")]
487 pub order_size: f64,
488 #[serde(rename = "orderLevel")]
490 pub order_level: f64,
491 #[serde(rename = "timeInForce")]
493 pub time_in_force: TimeInForce,
494 #[serde(rename = "goodTillDate")]
496 pub good_till_date: Option<String>,
497 #[serde(rename = "goodTillDateISO")]
499 pub good_till_date_iso: Option<String>,
500 #[serde(rename = "createdDate")]
502 pub created_date: String,
503 #[serde(rename = "createdDateUTC")]
505 pub created_date_utc: String,
506 #[serde(rename = "guaranteedStop")]
508 pub guaranteed_stop: bool,
509 #[serde(rename = "orderType")]
511 pub order_type: OrderType,
512 #[serde(rename = "stopDistance")]
514 pub stop_distance: Option<f64>,
515 #[serde(rename = "limitDistance")]
517 pub limit_distance: Option<f64>,
518 #[serde(rename = "currencyCode")]
520 pub currency_code: String,
521 pub dma: bool,
523 #[serde(rename = "limitedRiskPremium")]
525 pub limited_risk_premium: Option<f64>,
526 #[serde(rename = "limitLevel", default)]
528 pub limit_level: Option<f64>,
529 #[serde(rename = "stopLevel", default)]
531 pub stop_level: Option<f64>,
532 #[serde(rename = "dealReference", default)]
534 pub deal_reference: Option<String>,
535}
536
537#[derive(Debug, Clone, DisplaySimple, Deserialize, Serialize)]
539pub struct AccountMarketData {
540 #[serde(rename = "instrumentName")]
542 pub instrument_name: String,
543 #[serde(rename = "exchangeId")]
545 pub exchange_id: String,
546 pub expiry: String,
548 #[serde(rename = "marketStatus")]
550 pub market_status: MarketState,
551 pub epic: String,
553 #[serde(rename = "instrumentType")]
555 pub instrument_type: InstrumentType,
556 #[serde(rename = "lotSize")]
558 pub lot_size: f64,
559 pub high: Option<f64>,
561 pub low: Option<f64>,
563 #[serde(rename = "percentageChange")]
565 pub percentage_change: f64,
566 #[serde(rename = "netChange")]
568 pub net_change: f64,
569 pub bid: Option<f64>,
571 pub offer: Option<f64>,
573 #[serde(rename = "updateTime")]
575 pub update_time: String,
576 #[serde(rename = "updateTimeUTC")]
578 pub update_time_utc: String,
579 #[serde(rename = "delayTime")]
581 pub delay_time: i64,
582 #[serde(rename = "streamingPricesAvailable")]
584 pub streaming_prices_available: bool,
585 #[serde(rename = "scalingFactor")]
587 pub scaling_factor: i64,
588}
589
590#[derive(Debug, Clone, DisplaySimple, Deserialize, Serialize)]
592pub struct TransactionHistory {
593 pub transactions: Vec<AccountTransaction>,
595 pub metadata: TransactionMetadata,
597}
598
599#[derive(Debug, Clone, DisplaySimple, Deserialize, Serialize)]
601pub struct TransactionMetadata {
602 #[serde(rename = "pageData")]
604 pub page_data: PageData,
605 pub size: i32,
607}
608
609#[derive(Debug, Clone, DisplaySimple, Deserialize, Serialize)]
611pub struct PageData {
612 #[serde(rename = "pageNumber")]
614 pub page_number: i32,
615 #[serde(rename = "pageSize")]
617 pub page_size: i32,
618 #[serde(rename = "totalPages")]
620 pub total_pages: i32,
621}
622
623#[derive(Debug, Clone, DisplaySimple, Deserialize, Serialize)]
625pub struct AccountTransaction {
626 pub date: String,
628 #[serde(rename = "dateUtc")]
630 pub date_utc: String,
631 #[serde(rename = "openDateUtc")]
633 pub open_date_utc: String,
634 #[serde(rename = "instrumentName")]
636 pub instrument_name: String,
637 pub period: String,
639 #[serde(rename = "profitAndLoss")]
641 pub profit_and_loss: String,
642 #[serde(rename = "transactionType")]
644 pub transaction_type: String,
645 pub reference: String,
647 #[serde(rename = "openLevel")]
649 pub open_level: String,
650 #[serde(rename = "closeLevel")]
652 pub close_level: String,
653 pub size: String,
655 pub currency: String,
657 #[serde(rename = "cashTransaction")]
659 pub cash_transaction: bool,
660}