ibkr_flex_statement/
equity_summary.rs1use super::currency::Currency;
2use super::time_utils;
3use crate::node_utils::NodeWrapper;
4use crate::statement_section::StatementSection;
5use anyhow::Result;
6
7#[derive(Debug, PartialEq)]
8pub struct EquitySummary {
9 pub account_id: String,
10 pub cash_balance: f64,
11 pub cash_balance_long: f64,
12 pub cash_balance_short: f64,
13 pub currency: Currency,
14 pub interest_accrual_mtd: f64,
15 pub interest_accrual_mtd_long: f64,
16 pub interest_accrual_mtd_short: f64,
17 pub stock_balance: f64,
18 pub stock_balance_long: f64,
19 pub stock_balance_short: f64,
20 pub timestamp_eod_ms: i64,
21}
22
23impl StatementSection for EquitySummary {
24 fn from_node(node: &NodeWrapper) -> Result<EquitySummary> {
25 Ok(EquitySummary {
26 account_id: node.get_attribute("accountId")?,
27 cash_balance: node.parse_attribute("cash")?,
28 cash_balance_long: node.parse_attribute("cashLong")?,
29 cash_balance_short: node.parse_attribute("cashShort")?,
30 currency: Currency::try_from(node.node.attribute("currency").unwrap())?,
31 interest_accrual_mtd: node.parse_attribute("interestAccruals")?,
32 interest_accrual_mtd_long: node.parse_attribute("interestAccrualsLong")?,
33 interest_accrual_mtd_short: node.parse_attribute("interestAccrualsShort")?,
34 stock_balance: node.parse_attribute("stock")?,
35 stock_balance_long: node.parse_attribute("stockLong")?,
36 stock_balance_short: node.parse_attribute("stockShort")?,
37 timestamp_eod_ms: time_utils::trading_eod_after_hours_timestamp_ms(
38 node.node.attribute("reportDate").unwrap(),
39 )?,
40 })
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47 use crate::Parser;
48 use crate::currency::Currency;
49 use anyhow::Result;
50
51 const PARTIAL_STATEMENT_EXAMPLE: &str = r##"
52 <FlexQueryResponse queryName="example-query" type="AF">
53 <FlexStatements count="1">
54 <FlexStatement accountId="U1234567" fromDate="2025-04-25" toDate="2025-04-25" period="LastBusinessDay" whenGenerated="2025-04-26;13:34:28 EDT">
55 <AccountInformation accountId="U1234567" accountType="Individual" customerType="Individual" accountCapabilities="Portfolio Margin" tradingPermissions="Stocks,Options,Warrants,Forex,Futures,Crypto Currencies,Mutual Funds,Fully Paid Stock Loan" />
56 <EquitySummaryInBase>
57 <EquitySummaryByReportDateInBase accountId="U1234567" currency="USD" cash="-1755658.753685009" cashLong="0.000832235" cashShort="-1755658.754517244" commodities="0" commoditiesLong="0" commoditiesShort="0" dividendAccruals="0" dividendAccrualsLong="0" dividendAccrualsShort="0" interestAccruals="1292.18" interestAccrualsLong="1591.34" interestAccrualsShort="-299.16" stock="3441241" stockLong="3441241" stockShort="0" funds="0" fundsLong="0" fundsShort="0" brokerInterestAccrualsComponent="186.32" brokerInterestAccrualsComponentLong="485.48" brokerInterestAccrualsComponentShort="-299.16" brokerFeesAccrualsComponent="0" brokerFeesAccrualsComponentLong="0" brokerFeesAccrualsComponentShort="0" total="1686874.426314991" totalLong="3442832.340832235" totalShort="-1755957.914517244" reportDate="2025-04-24" />
58 <EquitySummaryByReportDateInBase
59 accountId="U1234567"
60 currency="USD"
61 cash="-1856140.99825062"
62 cashLong="0.000832132"
63 cashShort="-1856140.999082752"
64 commodities="0"
65 commoditiesLong="0"
66 commoditiesShort="0"
67 dividendAccruals="0"
68 dividendAccrualsLong="0"
69 dividendAccrualsShort="0"
70 interestAccruals="1051.42"
71 interestAccrualsLong="1591.34"
72 interestAccrualsShort="-539.92"
73 stock="3664457"
74 stockLong="3664457"
75 stockShort="0"
76 funds="0"
77 fundsLong="0"
78 fundsShort="0"
79 brokerInterestAccrualsComponent="-54.44"
80 brokerInterestAccrualsComponentLong="485.48"
81 brokerInterestAccrualsComponentShort="-539.92"
82 brokerFeesAccrualsComponent="0"
83 brokerFeesAccrualsComponentLong="0"
84 brokerFeesAccrualsComponentShort="0"
85 total="1809367.421749379"
86 totalLong="3666048.340832131"
87 totalShort="-1856680.919082752"
88 reportDate="2025-04-25" />
89 </EquitySummaryInBase>
90 </FlexStatement>
91 </FlexStatements>
92 </FlexQueryResponse>
93 "##;
94
95 #[test]
96 fn equity_summaries_parse() -> Result<()> {
97 let statements = Parser::new()?.parse_flex_query_response(PARTIAL_STATEMENT_EXAMPLE)?;
98 assert_eq!(statements.len(), 1);
99 let result = &statements[0];
100
101 assert_eq!(result.equity_summaries.len(), 2);
103
104 assert_eq!(
105 result.equity_summaries[1],
106 EquitySummary {
107 account_id: "U1234567".to_string(),
108 cash_balance: -1856140.99825062,
109 cash_balance_long: 0.000832132,
110 cash_balance_short: -1856140.999082752,
111 currency: Currency::USD,
112 interest_accrual_mtd: 1051.42,
113 interest_accrual_mtd_long: 1591.34,
114 interest_accrual_mtd_short: -539.92,
115 stock_balance: 3664457.0,
116 stock_balance_long: 3664457.0,
117 stock_balance_short: 0.0,
118 timestamp_eod_ms: result.equity_summaries[1].timestamp_eod_ms,
119 }
120 );
121 Ok(())
122 }
123}